Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / client / X11 / xfreerdp.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * X11 Client
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22
23 #ifdef WITH_XCURSOR
24 #include <X11/Xcursor/Xcursor.h>
25 #endif
26
27 #ifdef WITH_XINERAMA
28 #include <X11/extensions/Xinerama.h>
29 #endif
30
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <locale.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <termios.h>
38 #include <pthread.h>
39 #include <sys/wait.h>
40 #include <sys/types.h>
41 #include <sys/select.h>
42 #include <freerdp/constants.h>
43 #include <freerdp/codec/nsc.h>
44 #include <freerdp/codec/rfx.h>
45 #include <freerdp/codec/color.h>
46 #include <freerdp/codec/bitmap.h>
47 #include <freerdp/utils/args.h>
48 #include <freerdp/utils/memory.h>
49 #include <freerdp/utils/semaphore.h>
50 #include <freerdp/utils/memory.h>
51 #include <freerdp/utils/event.h>
52 #include <freerdp/utils/signal.h>
53 #include <freerdp/utils/passphrase.h>
54 #include <freerdp/plugins/cliprdr.h>
55 #include <freerdp/rail.h>
56
57 #include "xf_gdi.h"
58 #include "xf_rail.h"
59 #include "xf_tsmf.h"
60 #include "xf_event.h"
61 #include "xf_cliprdr.h"
62 #include "xf_monitor.h"
63 #include "xf_graphics.h"
64 #include "xf_keyboard.h"
65
66 #include "xfreerdp.h"
67
68 static freerdp_sem g_sem;
69 static int g_thread_count = 0;
70 static uint8 g_disconnect_reason = 0;
71
72 static long xv_port = 0;
73 static const size_t password_size = 512;
74
75 struct thread_data
76 {
77         freerdp* instance;
78 };
79
80 int xf_process_client_args(rdpSettings* settings, const char* opt, const char* val, void* user_data);
81 int xf_process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data);
82
83 void xf_context_new(freerdp* instance, rdpContext* context)
84 {
85         context->channels = freerdp_channels_new();
86 }
87
88 void xf_context_free(freerdp* instance, rdpContext* context)
89 {
90
91 }
92
93 void xf_sw_begin_paint(rdpContext* context)
94 {
95         rdpGdi* gdi = context->gdi;
96         gdi->primary->hdc->hwnd->invalid->null = 1;
97         gdi->primary->hdc->hwnd->ninvalid = 0;
98 }
99
100 void xf_sw_end_paint(rdpContext* context)
101 {
102         rdpGdi* gdi;
103         xfInfo* xfi;
104         sint32 x, y;
105         uint32 w, h;
106
107         xfi = ((xfContext*) context)->xfi;
108         gdi = context->gdi;
109
110         if (xfi->remote_app != true)
111         {
112                 if (xfi->complex_regions != true)
113                 {
114                         if (gdi->primary->hdc->hwnd->invalid->null)
115                                 return;
116
117                         x = gdi->primary->hdc->hwnd->invalid->x;
118                         y = gdi->primary->hdc->hwnd->invalid->y;
119                         w = gdi->primary->hdc->hwnd->invalid->w;
120                         h = gdi->primary->hdc->hwnd->invalid->h;
121
122                         XPutImage(xfi->display, xfi->primary, xfi->gc, xfi->image, x, y, x, y, w, h);
123                         XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y);
124                 }
125                 else
126                 {
127                         int i;
128                         int ninvalid;
129                         HGDI_RGN cinvalid;
130
131                         if (gdi->primary->hdc->hwnd->ninvalid < 1)
132                                 return;
133
134                         ninvalid = gdi->primary->hdc->hwnd->ninvalid;
135                         cinvalid = gdi->primary->hdc->hwnd->cinvalid;
136
137                         for (i = 0; i < ninvalid; i++)
138                         {
139                                 x = cinvalid[i].x;
140                                 y = cinvalid[i].y;
141                                 w = cinvalid[i].w;
142                                 h = cinvalid[i].h;
143
144                                 XPutImage(xfi->display, xfi->primary, xfi->gc, xfi->image, x, y, x, y, w, h);
145                                 XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y);
146                         }
147
148                         XFlush(xfi->display);
149                 }
150         }
151         else
152         {
153                 if (gdi->primary->hdc->hwnd->invalid->null)
154                         return;
155
156                 x = gdi->primary->hdc->hwnd->invalid->x;
157                 y = gdi->primary->hdc->hwnd->invalid->y;
158                 w = gdi->primary->hdc->hwnd->invalid->w;
159                 h = gdi->primary->hdc->hwnd->invalid->h;
160
161                 xf_rail_paint(xfi, context->rail, x, y, x + w - 1, y + h - 1);
162         }
163 }
164
165 void xf_sw_desktop_resize(rdpContext* context)
166 {
167         xfInfo* xfi;
168         rdpSettings* settings;
169
170         xfi = ((xfContext*) context)->xfi;
171         settings = xfi->instance->settings;
172
173         if (xfi->fullscreen != true)
174         {
175                 rdpGdi* gdi = context->gdi;
176                 gdi_resize(gdi, xfi->width, xfi->height);
177
178                 if (xfi->image)
179                 {
180                         xfi->image->data = NULL;
181                         XDestroyImage(xfi->image);
182                         xfi->image = XCreateImage(xfi->display, xfi->visual, xfi->depth, ZPixmap, 0,
183                                         (char*) gdi->primary_buffer, gdi->width, gdi->height, xfi->scanline_pad, 0);
184                 }
185         }
186 }
187
188 void xf_hw_begin_paint(rdpContext* context)
189 {
190         xfInfo* xfi;
191         xfi = ((xfContext*) context)->xfi;
192         xfi->hdc->hwnd->invalid->null = 1;
193         xfi->hdc->hwnd->ninvalid = 0;
194 }
195
196 void xf_hw_end_paint(rdpContext* context)
197 {
198         xfInfo* xfi;
199         sint32 x, y;
200         uint32 w, h;
201
202         xfi = ((xfContext*) context)->xfi;
203
204         if (xfi->remote_app)
205         {
206                 if (xfi->hdc->hwnd->invalid->null)
207                         return;
208
209                 x = xfi->hdc->hwnd->invalid->x;
210                 y = xfi->hdc->hwnd->invalid->y;
211                 w = xfi->hdc->hwnd->invalid->w;
212                 h = xfi->hdc->hwnd->invalid->h;
213
214                 xf_rail_paint(xfi, context->rail, x, y, x + w - 1, y + h - 1);
215         }
216 }
217
218 void xf_hw_desktop_resize(rdpContext* context)
219 {
220         xfInfo* xfi;
221         boolean same;
222         rdpSettings* settings;
223
224         xfi = ((xfContext*) context)->xfi;
225         settings = xfi->instance->settings;
226
227         if (xfi->fullscreen != true)
228         {
229                 xfi->width = settings->width;
230                 xfi->height = settings->height;
231
232                 if (xfi->window)
233                         xf_ResizeDesktopWindow(xfi, xfi->window, settings->width, settings->height);
234
235                 if (xfi->primary)
236                 {
237                         same = (xfi->primary == xfi->drawing) ? true : false;
238
239                         XFreePixmap(xfi->display, xfi->primary);
240
241                         xfi->primary = XCreatePixmap(xfi->display, xfi->drawable,
242                                         xfi->width, xfi->height, xfi->depth);
243
244                         if (same)
245                                 xfi->drawing = xfi->primary;
246                 }
247         }
248 }
249
250 boolean xf_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount)
251 {
252         xfInfo* xfi = ((xfContext*) instance->context)->xfi;
253
254         rfds[*rcount] = (void*)(long)(xfi->xfds);
255         (*rcount)++;
256
257         return true;
258 }
259
260 boolean xf_check_fds(freerdp* instance, fd_set* set)
261 {
262         XEvent xevent;
263         xfInfo* xfi = ((xfContext*) instance->context)->xfi;
264
265         while (XPending(xfi->display))
266         {
267                 memset(&xevent, 0, sizeof(xevent));
268                 XNextEvent(xfi->display, &xevent);
269
270                 if (xf_event_process(instance, &xevent) != true)
271                         return false;
272         }
273
274         return true;
275 }
276
277 void xf_create_window(xfInfo* xfi)
278 {
279         XEvent xevent;
280         char* win_title;
281         int width, height;
282
283         width = xfi->width;
284         height = xfi->height;
285
286         xfi->attribs.background_pixel = BlackPixelOfScreen(xfi->screen);
287         xfi->attribs.border_pixel = WhitePixelOfScreen(xfi->screen);
288         xfi->attribs.backing_store = xfi->primary ? NotUseful : Always;
289         xfi->attribs.override_redirect = xfi->fullscreen;
290         xfi->attribs.colormap = xfi->colormap;
291         xfi->attribs.bit_gravity = ForgetGravity;
292         xfi->attribs.win_gravity = StaticGravity;
293
294         if (xfi->instance->settings->window_title != NULL)
295         {
296                 win_title = xstrdup(xfi->instance->settings->window_title);
297         }
298         else if (xfi->instance->settings->port == 3389)
299         {
300                 win_title = xmalloc(1 + sizeof("FreeRDP: ") + strlen(xfi->instance->settings->hostname));
301                 sprintf(win_title, "FreeRDP: %s", xfi->instance->settings->hostname);
302         }
303         else
304         {
305                 win_title = xmalloc(1 + sizeof("FreeRDP: ") + strlen(xfi->instance->settings->hostname) + sizeof(":00000"));
306                 sprintf(win_title, "FreeRDP: %s:%i", xfi->instance->settings->hostname, xfi->instance->settings->port);
307         }
308
309         xfi->window = xf_CreateDesktopWindow(xfi, win_title, width, height, xfi->decorations);
310         xfree(win_title);
311
312         if (xfi->parent_window)
313                 XReparentWindow(xfi->display, xfi->window->handle, xfi->parent_window, 0, 0);
314
315         if (xfi->fullscreen)
316                 xf_SetWindowFullscreen(xfi, xfi->window, xfi->fullscreen);
317
318         /* wait for VisibilityNotify */
319         do
320         {
321                 XMaskEvent(xfi->display, VisibilityChangeMask, &xevent);
322         }
323         while (xevent.type != VisibilityNotify);
324
325         xfi->unobscured = (xevent.xvisibility.state == VisibilityUnobscured);
326
327         XSetWMProtocols(xfi->display, xfi->window->handle, &(xfi->WM_DELETE_WINDOW), 1);
328         xfi->drawable = xfi->window->handle;
329 }
330
331 void xf_toggle_fullscreen(xfInfo* xfi)
332 {
333         Pixmap contents = 0;
334
335         contents = XCreatePixmap(xfi->display, xfi->window->handle, xfi->width, xfi->height, xfi->depth);
336         XCopyArea(xfi->display, xfi->primary, contents, xfi->gc, 0, 0, xfi->width, xfi->height, 0, 0);
337
338         XDestroyWindow(xfi->display, xfi->window->handle);
339         xfi->fullscreen = (xfi->fullscreen) ? false : true;
340         xf_create_window(xfi);
341
342         XCopyArea(xfi->display, contents, xfi->primary, xfi->gc, 0, 0, xfi->width, xfi->height, 0, 0);
343         XFreePixmap(xfi->display, contents);
344 }
345
346 boolean xf_get_pixmap_info(xfInfo* xfi)
347 {
348         int i;
349         int vi_count;
350         int pf_count;
351         XVisualInfo* vi;
352         XVisualInfo* vis;
353         XVisualInfo template;
354         XPixmapFormatValues* pf;
355         XPixmapFormatValues* pfs;
356
357         pfs = XListPixmapFormats(xfi->display, &pf_count);
358
359         if (pfs == NULL)
360         {
361                 printf("xf_get_pixmap_info: XListPixmapFormats failed\n");
362                 return 1;
363         }
364
365         for (i = 0; i < pf_count; i++)
366         {
367                 pf = pfs + i;
368
369                 if (pf->depth == xfi->depth)
370                 {
371                         xfi->bpp = pf->bits_per_pixel;
372                         xfi->scanline_pad = pf->scanline_pad;
373                         break;
374                 }
375         }
376         XFree(pfs);
377
378         memset(&template, 0, sizeof(template));
379         template.class = TrueColor;
380         template.screen = xfi->screen_number;
381
382         vis = XGetVisualInfo(xfi->display, VisualClassMask | VisualScreenMask, &template, &vi_count);
383
384         if (vis == NULL)
385         {
386                 printf("xf_get_pixmap_info: XGetVisualInfo failed\n");
387                 return false;
388         }
389
390         vi = NULL;
391         for (i = 0; i < vi_count; i++)
392         {
393                 vi = vis + i;
394
395                 if (vi->depth == xfi->depth)
396                 {
397                         xfi->visual = vi->visual;
398                         break;
399                 }
400         }
401
402         if (vi)
403         {
404                 /*
405                  * Detect if the server visual has an inverted colormap
406                  * (BGR vs RGB, or red being the least significant byte)
407                  */
408
409                 if (vi->red_mask & 0xFF) 
410                 {
411                         xfi->clrconv->invert = true;
412                 }
413         }
414
415         XFree(vis);
416
417         if ((xfi->visual == NULL) || (xfi->scanline_pad == 0))
418         {
419                 return false;
420         }
421
422         return true;
423 }
424
425 static int (*_def_error_handler)(Display*, XErrorEvent*);
426 int xf_error_handler(Display* d, XErrorEvent* ev)
427 {
428         char buf[256];
429         int do_abort = true;
430
431         XGetErrorText(d, ev->error_code, buf, sizeof(buf));
432         printf("%s", buf);
433
434         if (do_abort)
435                 abort();
436
437         _def_error_handler(d, ev);
438
439         return false;
440 }
441
442 int _xf_error_handler(Display* d, XErrorEvent* ev)
443 {
444         /*
445          * ungrab the keyboard, in case a debugger is running in
446          * another window. This make xf_error_handler() a potential
447          * debugger breakpoint.
448          */
449         XUngrabKeyboard(d, CurrentTime);
450         return xf_error_handler(d, ev);
451 }
452
453 boolean xf_pre_connect(freerdp* instance)
454 {
455         xfInfo* xfi;
456         boolean bitmap_cache;
457         rdpSettings* settings;
458         int arg_parse_result;
459         
460         xfi = (xfInfo*) xzalloc(sizeof(xfInfo));
461         ((xfContext*) instance->context)->xfi = xfi;
462
463         xfi->_context = instance->context;
464         xfi->context = (xfContext*) instance->context;
465         xfi->context->settings = instance->settings;
466         xfi->instance = instance;
467         
468         arg_parse_result = freerdp_parse_args(instance->settings, instance->context->argc,instance->context->argv,
469                                 xf_process_plugin_args, instance->context->channels, xf_process_client_args, xfi);
470         
471         if (arg_parse_result < 0)
472         {
473                 if (arg_parse_result == FREERDP_ARGS_PARSE_FAILURE)
474                         printf("failed to parse arguments.\n");
475                 
476                 exit(XF_EXIT_PARSE_ARGUMENTS);
477         }
478
479         settings = instance->settings;
480         bitmap_cache = settings->bitmap_cache;
481
482         settings->os_major_type = OSMAJORTYPE_UNIX;
483         settings->os_minor_type = OSMINORTYPE_NATIVE_XSERVER;
484         settings->order_support[NEG_DSTBLT_INDEX] = true;
485         settings->order_support[NEG_PATBLT_INDEX] = true;
486         settings->order_support[NEG_SCRBLT_INDEX] = true;
487         settings->order_support[NEG_OPAQUE_RECT_INDEX] = true;
488         settings->order_support[NEG_DRAWNINEGRID_INDEX] = false;
489         settings->order_support[NEG_MULTIDSTBLT_INDEX] = false;
490         settings->order_support[NEG_MULTIPATBLT_INDEX] = false;
491         settings->order_support[NEG_MULTISCRBLT_INDEX] = false;
492         settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = true;
493         settings->order_support[NEG_MULTI_DRAWNINEGRID_INDEX] = false;
494         settings->order_support[NEG_LINETO_INDEX] = true;
495         settings->order_support[NEG_POLYLINE_INDEX] = true;
496         settings->order_support[NEG_MEMBLT_INDEX] = bitmap_cache;
497         settings->order_support[NEG_MEM3BLT_INDEX] = false;
498         settings->order_support[NEG_MEMBLT_V2_INDEX] = bitmap_cache;
499         settings->order_support[NEG_MEM3BLT_V2_INDEX] = false;
500         settings->order_support[NEG_SAVEBITMAP_INDEX] = false;
501         settings->order_support[NEG_GLYPH_INDEX_INDEX] = true;
502         settings->order_support[NEG_FAST_INDEX_INDEX] = true;
503         settings->order_support[NEG_FAST_GLYPH_INDEX] = true;
504         settings->order_support[NEG_POLYGON_SC_INDEX] = false;
505         settings->order_support[NEG_POLYGON_CB_INDEX] = false;
506         settings->order_support[NEG_ELLIPSE_SC_INDEX] = false;
507         settings->order_support[NEG_ELLIPSE_CB_INDEX] = false;
508
509         freerdp_channels_pre_connect(xfi->_context->channels, instance);
510
511         xfi->display = XOpenDisplay(NULL);
512
513         if (xfi->display == NULL)
514         {
515                 printf("xf_pre_connect: failed to open display: %s\n", XDisplayName(NULL));
516                 printf("Please check that the $DISPLAY environment variable is properly set.\n");
517                 return false;
518         }
519
520         if (xfi->debug)
521         {
522                 printf("Enabling X11 debug mode.\n");
523                 XSynchronize(xfi->display, true);
524                 _def_error_handler = XSetErrorHandler(_xf_error_handler);
525         }
526
527         xfi->_NET_WM_ICON = XInternAtom(xfi->display, "_NET_WM_ICON", False);
528         xfi->_MOTIF_WM_HINTS = XInternAtom(xfi->display, "_MOTIF_WM_HINTS", False);
529         xfi->_NET_CURRENT_DESKTOP = XInternAtom(xfi->display, "_NET_CURRENT_DESKTOP", False);
530         xfi->_NET_WORKAREA = XInternAtom(xfi->display, "_NET_WORKAREA", False);
531         xfi->_NET_WM_STATE = XInternAtom(xfi->display, "_NET_WM_STATE", False);
532         xfi->_NET_WM_STATE_FULLSCREEN = XInternAtom(xfi->display, "_NET_WM_STATE_FULLSCREEN", False);
533         xfi->_NET_WM_WINDOW_TYPE = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE", False);
534
535         xfi->_NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
536         xfi->_NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
537         xfi->_NET_WM_WINDOW_TYPE_POPUP= XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_POPUP", False);
538         xfi->_NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
539         xfi->_NET_WM_WINDOW_TYPE_DROPDOWN_MENU = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False);
540         xfi->_NET_WM_STATE_SKIP_TASKBAR = XInternAtom(xfi->display, "_NET_WM_STATE_SKIP_TASKBAR", False);
541         xfi->_NET_WM_STATE_SKIP_PAGER = XInternAtom(xfi->display, "_NET_WM_STATE_SKIP_PAGER", False);
542         xfi->_NET_WM_MOVERESIZE = XInternAtom(xfi->display, "_NET_WM_MOVERESIZE", False);
543         xfi->_NET_MOVERESIZE_WINDOW = XInternAtom(xfi->display, "_NET_MOVERESIZE_WINDOW", False);
544
545         xfi->WM_PROTOCOLS = XInternAtom(xfi->display, "WM_PROTOCOLS", False);
546         xfi->WM_DELETE_WINDOW = XInternAtom(xfi->display, "WM_DELETE_WINDOW", False);
547
548         xf_kbd_init(xfi);
549
550         xfi->clrconv = freerdp_clrconv_new(CLRCONV_ALPHA);
551
552         instance->context->cache = cache_new(instance->settings);
553
554         xfi->xfds = ConnectionNumber(xfi->display);
555         xfi->screen_number = DefaultScreen(xfi->display);
556         xfi->screen = ScreenOfDisplay(xfi->display, xfi->screen_number);
557         xfi->depth = DefaultDepthOfScreen(xfi->screen);
558         xfi->big_endian = (ImageByteOrder(xfi->display) == MSBFirst);
559
560         xfi->mouse_motion = settings->mouse_motion;
561         xfi->complex_regions = true;
562         xfi->decorations = settings->decorations;
563         xfi->fullscreen = settings->fullscreen;
564         xfi->grab_keyboard = settings->grab_keyboard;
565         xfi->fullscreen_toggle = true;
566         xfi->sw_gdi = settings->sw_gdi;
567         xfi->parent_window = (Window) settings->parent_window_xid;
568
569         xf_detect_monitors(xfi, settings);
570
571         return true;
572 }
573
574 void cpuid(unsigned info, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
575 {
576 #ifdef __GNUC__
577 #if defined(__i386__) || defined(__x86_64__)
578         *eax = info;
579         __asm volatile
580                 ("mov %%ebx, %%edi;" /* 32bit PIC: don't clobber ebx */
581                  "cpuid;"
582                  "mov %%ebx, %%esi;"
583                  "mov %%edi, %%ebx;"
584                  :"+a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
585                  : :"edi");
586 #endif
587 #endif
588 }
589  
590 uint32 xf_detect_cpu()
591 {
592         unsigned int eax, ebx, ecx, edx = 0;
593         uint32 cpu_opt = 0;
594
595         cpuid(1, &eax, &ebx, &ecx, &edx);
596
597         if (edx & (1<<26)) 
598         {
599                 DEBUG("SSE2 detected");
600                 cpu_opt |= CPU_SSE2;
601         }
602
603         return cpu_opt;
604 }
605
606 boolean xf_post_connect(freerdp* instance)
607 {
608         xfInfo* xfi;
609         XGCValues gcv;
610         rdpCache* cache;
611         rdpChannels* channels;
612         RFX_CONTEXT* rfx_context = NULL;
613
614         xfi = ((xfContext*) instance->context)->xfi;
615         cache = instance->context->cache;
616         channels = xfi->_context->channels;
617
618         if (xf_get_pixmap_info(xfi) != true)
619                 return false;
620
621         xf_register_graphics(instance->context->graphics);
622
623         if (xfi->sw_gdi)
624         {
625                 rdpGdi* gdi;
626                 uint32 flags;
627
628                 flags = CLRCONV_ALPHA;
629
630                 if (xfi->bpp > 16)
631                         flags |= CLRBUF_32BPP;
632                 else
633                         flags |= CLRBUF_16BPP;
634
635                 gdi_init(instance, flags, NULL);
636                 gdi = instance->context->gdi;
637                 xfi->primary_buffer = gdi->primary_buffer;
638
639                 rfx_context = gdi->rfx_context;
640         }
641         else
642         {
643                 xfi->srcBpp = instance->settings->color_depth;
644                 xf_gdi_register_update_callbacks(instance->update);
645
646                 xfi->hdc = gdi_CreateDC(xfi->clrconv, xfi->bpp);
647
648                 if (instance->settings->rfx_codec)
649                 {
650                         rfx_context = (void*) rfx_context_new();
651                         xfi->rfx_context = rfx_context;
652                 }
653
654                 if (instance->settings->ns_codec)
655                         xfi->nsc_context = (void*) nsc_context_new();
656         }
657
658         if (rfx_context)
659         {
660 #ifdef WITH_SSE2
661                 /* detect only if needed */
662                 rfx_context_set_cpu_opt(rfx_context, xf_detect_cpu());
663 #endif
664         }
665
666         xfi->width = instance->settings->width;
667         xfi->height = instance->settings->height;
668
669         xf_create_window(xfi);
670
671         memset(&gcv, 0, sizeof(gcv));
672         xfi->modifier_map = XGetModifierMapping(xfi->display);
673
674         xfi->gc = XCreateGC(xfi->display, xfi->drawable, GCGraphicsExposures, &gcv);
675         xfi->primary = XCreatePixmap(xfi->display, xfi->drawable, xfi->width, xfi->height, xfi->depth);
676         xfi->drawing = xfi->primary;
677
678         xfi->bitmap_mono = XCreatePixmap(xfi->display, xfi->drawable, 8, 8, 1);
679         xfi->gc_mono = XCreateGC(xfi->display, xfi->bitmap_mono, GCGraphicsExposures, &gcv);
680
681         XSetForeground(xfi->display, xfi->gc, BlackPixelOfScreen(xfi->screen));
682         XFillRectangle(xfi->display, xfi->primary, xfi->gc, 0, 0, xfi->width, xfi->height);
683
684         xfi->image = XCreateImage(xfi->display, xfi->visual, xfi->depth, ZPixmap, 0,
685                         (char*) xfi->primary_buffer, xfi->width, xfi->height, xfi->scanline_pad, 0);
686
687         xfi->bmp_codec_none = (uint8*) xmalloc(64 * 64 * 4);
688
689         if (xfi->sw_gdi)
690         {
691                 instance->update->BeginPaint = xf_sw_begin_paint;
692                 instance->update->EndPaint = xf_sw_end_paint;
693                 instance->update->DesktopResize = xf_sw_desktop_resize;
694         }
695         else
696         {
697                 instance->update->BeginPaint = xf_hw_begin_paint;
698                 instance->update->EndPaint = xf_hw_end_paint;
699                 instance->update->DesktopResize = xf_hw_desktop_resize;
700         }
701
702         pointer_cache_register_callbacks(instance->update);
703
704         if (xfi->sw_gdi != true)
705         {
706                 glyph_cache_register_callbacks(instance->update);
707                 brush_cache_register_callbacks(instance->update);
708                 bitmap_cache_register_callbacks(instance->update);
709                 offscreen_cache_register_callbacks(instance->update);
710                 palette_cache_register_callbacks(instance->update);
711         }
712
713         instance->context->rail = rail_new(instance->settings);
714         rail_register_update_callbacks(instance->context->rail, instance->update);
715         xf_rail_register_callbacks(xfi, instance->context->rail);
716
717         freerdp_channels_post_connect(channels, instance);
718
719         xf_tsmf_init(xfi, xv_port);
720
721         xf_cliprdr_init(xfi, channels);
722
723         return true;
724 }
725
726 boolean xf_authenticate(freerdp* instance, char** username, char** password, char** domain)
727 {
728         *password = xmalloc(password_size * sizeof(char));
729
730         if (freerdp_passphrase_read("Password: ", *password, password_size) == NULL)
731                 return false;
732
733         return true;
734 }
735
736 boolean xf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint)
737 {
738         char answer;
739
740         printf("Certificate details:\n");
741         printf("\tSubject: %s\n", subject);
742         printf("\tIssuer: %s\n", issuer);
743         printf("\tThumbprint: %s\n", fingerprint);
744         printf("The above X.509 certificate could not be verified, possibly because you do not have "
745                 "the CA certificate in your certificate store, or the certificate has expired. "
746                 "Please look at the documentation on how to create local certificate store for a private CA.\n");
747
748         while (1)
749         {
750                 printf("Do you trust the above certificate? (Y/N) ");
751                 answer = fgetc(stdin);
752
753                 if (answer == 'y' || answer == 'Y')
754                 {
755                         return true;
756                 }
757                 else if (answer == 'n' || answer == 'N')
758                 {
759                         break;
760                 }
761                 printf("\n");
762         }
763
764         return false;
765 }
766
767 int xf_process_client_args(rdpSettings* settings, const char* opt, const char* val, void* user_data)
768 {
769         int argc = 0;
770         xfInfo* xfi = (xfInfo*) user_data;
771
772         if (strcmp("--kbd-list", opt) == 0)
773         {
774                 int i;
775                 rdpKeyboardLayout* layouts;
776
777                 layouts = freerdp_kbd_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD);
778                 printf("\nKeyboard Layouts\n");
779                 for (i = 0; layouts[i].code; i++)
780                         printf("0x%08X\t%s\n", layouts[i].code, layouts[i].name);
781                 free(layouts);
782
783                 layouts = freerdp_kbd_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_VARIANT);
784                 printf("\nKeyboard Layout Variants\n");
785                 for (i = 0; layouts[i].code; i++)
786                         printf("0x%08X\t%s\n", layouts[i].code, layouts[i].name);
787                 free(layouts);
788
789                 layouts = freerdp_kbd_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_IME);
790                 printf("\nKeyboard Input Method Editors (IMEs)\n");
791                 for (i = 0; layouts[i].code; i++)
792                         printf("0x%08X\t%s\n", layouts[i].code, layouts[i].name);
793                 free(layouts);
794
795                 exit(0);
796         }
797         else if (strcmp("--xv-port", opt) == 0)
798         {
799                 xv_port = atoi(val);
800                 argc = 2;
801         }
802         else if (strcmp("--dbg-x11", opt) == 0)
803         {
804                 xfi->debug = true;
805                 argc = 1;
806         }
807
808         return argc;
809 }
810
811 int xf_process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data)
812 {
813         rdpChannels* channels = (rdpChannels*) user_data;
814
815         printf("loading plugin %s\n", name);
816         freerdp_channels_load_plugin(channels, settings, name, plugin_data);
817
818         return 1;
819 }
820
821 int xf_receive_channel_data(freerdp* instance, int channelId, uint8* data, int size, int flags, int total_size)
822 {
823         return freerdp_channels_data(instance, channelId, data, size, flags, total_size);
824 }
825
826 void xf_process_channel_event(rdpChannels* chanman, freerdp* instance)
827 {
828         xfInfo* xfi;
829         RDP_EVENT* event;
830
831         xfi = ((xfContext*) instance->context)->xfi;
832
833         event = freerdp_channels_pop_event(chanman);
834
835         if (event)
836         {
837                 switch (event->event_class)
838                 {
839                         case RDP_EVENT_CLASS_RAIL:
840                                 xf_process_rail_event(xfi, chanman, event);
841                                 break;
842
843                         case RDP_EVENT_CLASS_TSMF:
844                                 xf_process_tsmf_event(xfi, event);
845                                 break;
846
847                         case RDP_EVENT_CLASS_CLIPRDR:
848                                 xf_process_cliprdr_event(xfi, event);
849                                 break;
850
851                         default:
852                                 break;
853                 }
854
855                 freerdp_event_free(event);
856         }
857 }
858
859 void xf_window_free(xfInfo* xfi)
860 {
861         rdpContext* context = xfi->instance->context;
862
863         XFreeModifiermap(xfi->modifier_map);
864         xfi->modifier_map = 0;
865
866         XFreeGC(xfi->display, xfi->gc);
867         xfi->gc = 0;
868
869         XFreeGC(xfi->display, xfi->gc_mono);
870         xfi->gc_mono = 0;
871
872         if (xfi->window != NULL)
873         {
874                 xf_DestroyWindow(xfi, xfi->window);
875                 xfi->window = NULL;
876         }
877
878         if (xfi->primary)
879         {
880                 XFreePixmap(xfi->display, xfi->primary);
881                 xfi->primary = 0;
882         }
883
884         if (xfi->image)
885         {
886                 xfi->image->data = NULL;
887                 XDestroyImage(xfi->image);
888                 xfi->image = NULL;
889         }
890
891         if (context != NULL)
892         {
893                         cache_free(context->cache);
894                         context->cache = NULL;
895
896                         rail_free(context->rail);
897                         context->rail = NULL;
898         }
899
900         if (xfi->rfx_context) 
901         {
902                 rfx_context_free(xfi->rfx_context);
903                 xfi->rfx_context = NULL;
904         }
905
906         freerdp_clrconv_free(xfi->clrconv);
907
908         if (xfi->hdc)
909                 gdi_DeleteDC(xfi->hdc);
910
911         xf_tsmf_uninit(xfi);
912         xf_cliprdr_uninit(xfi);
913 }
914
915 void xf_free(xfInfo* xfi)
916 {
917         xf_window_free(xfi);
918
919         xfree(xfi->bmp_codec_none);
920
921         XCloseDisplay(xfi->display);
922
923         xfree(xfi);
924 }
925
926 int xfreerdp_run(freerdp* instance)
927 {
928         int i;
929         int fds;
930         xfInfo* xfi;
931         int max_fds;
932         int rcount;
933         int wcount;
934         int ret = 0;
935         void* rfds[32];
936         void* wfds[32];
937         fd_set rfds_set;
938         fd_set wfds_set;
939         int select_status;
940         rdpChannels* channels;
941         struct timeval timeout;
942
943         memset(rfds, 0, sizeof(rfds));
944         memset(wfds, 0, sizeof(wfds));
945         memset(&timeout, 0, sizeof(struct timeval));
946
947         if (!freerdp_connect(instance))
948                 return XF_EXIT_CONN_FAILED;
949
950         xfi = ((xfContext*) instance->context)->xfi;
951         channels = instance->context->channels;
952
953         while (!xfi->disconnect && !freerdp_shall_disconnect(instance))
954         {
955                 rcount = 0;
956                 wcount = 0;
957
958                 if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != true)
959                 {
960                         printf("Failed to get FreeRDP file descriptor\n");
961                         ret = XF_EXIT_CONN_FAILED;
962                         break;
963                 }
964                 if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != true)
965                 {
966                         printf("Failed to get channel manager file descriptor\n");
967                         ret = XF_EXIT_CONN_FAILED;
968                         break;
969                 }
970                 if (xf_get_fds(instance, rfds, &rcount, wfds, &wcount) != true)
971                 {
972                         printf("Failed to get xfreerdp file descriptor\n");
973                         ret = XF_EXIT_CONN_FAILED;
974                         break;
975                 }
976
977                 max_fds = 0;
978                 FD_ZERO(&rfds_set);
979                 FD_ZERO(&wfds_set);
980
981                 for (i = 0; i < rcount; i++)
982                 {
983                         fds = (int)(long)(rfds[i]);
984
985                         if (fds > max_fds)
986                                 max_fds = fds;
987
988                         FD_SET(fds, &rfds_set);
989                 }
990
991                 if (max_fds == 0)
992                         break;
993
994                 timeout.tv_sec = 5;
995                 select_status = select(max_fds + 1, &rfds_set, &wfds_set, NULL, &timeout);
996
997                 if (select_status == 0)
998                 {
999                         //freerdp_send_keep_alive(instance);
1000                         continue;
1001                 }
1002                 else if (select_status == -1)
1003                 {
1004                         /* these are not really errors */
1005                         if (!((errno == EAGAIN) ||
1006                                 (errno == EWOULDBLOCK) ||
1007                                 (errno == EINPROGRESS) ||
1008                                 (errno == EINTR))) /* signal occurred */
1009                         {
1010                                 printf("xfreerdp_run: select failed\n");
1011                                 break;
1012                         }
1013                 }
1014
1015                 if (freerdp_check_fds(instance) != true)
1016                 {
1017                         printf("Failed to check FreeRDP file descriptor\n");
1018                         break;
1019                 }
1020                 if (xf_check_fds(instance, &rfds_set) != true)
1021                 {
1022                         printf("Failed to check xfreerdp file descriptor\n");
1023                         break;
1024                 }
1025                 if (freerdp_channels_check_fds(channels, instance) != true)
1026                 {
1027                         printf("Failed to check channel manager file descriptor\n");
1028                         break;
1029                 }
1030                 xf_process_channel_event(channels, instance);
1031         }
1032
1033         if (!ret)
1034                 ret = freerdp_error_info(instance);
1035
1036         freerdp_channels_close(channels, instance);
1037         freerdp_channels_free(channels);
1038         freerdp_disconnect(instance);
1039         gdi_free(instance);
1040         xf_free(xfi);
1041
1042         freerdp_free(instance);
1043
1044         return ret;
1045 }
1046
1047 void* thread_func(void* param)
1048 {
1049         struct thread_data* data;
1050         data = (struct thread_data*) param;
1051
1052         g_disconnect_reason = xfreerdp_run(data->instance);
1053
1054         xfree(data);
1055
1056         pthread_detach(pthread_self());
1057
1058         g_thread_count--;
1059
1060         if (g_thread_count < 1)
1061                 freerdp_sem_signal(g_sem);
1062
1063         pthread_exit(NULL);
1064 }
1065
1066 static uint8 exit_code_from_disconnect_reason(uint32 reason)
1067 {
1068         if (reason == 0 ||
1069            (reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_CONN_FAILED))
1070                  return reason;
1071
1072         /* Licence error set */
1073         else if (reason >= 0x100 && reason <= 0x10A)
1074                  reason -= 0x100 + XF_EXIT_LICENSE_INTERNAL;
1075
1076         /* RDP protocol error set */
1077         else if (reason >= 0x10c9 && reason <= 0x1193)
1078                  reason = XF_EXIT_RDP;
1079
1080         /* There's no need to test protocol-independent codes: they match */
1081         else if (!(reason <= 0xB))
1082                  reason = XF_EXIT_UNKNOWN;
1083
1084         return reason;
1085 }
1086
1087 int main(int argc, char* argv[])
1088 {
1089         pthread_t thread;
1090         freerdp* instance;
1091         struct thread_data* data;
1092
1093         freerdp_handle_signals();
1094
1095         setlocale(LC_ALL, "");
1096
1097         freerdp_channels_global_init();
1098
1099         g_sem = freerdp_sem_new(1);
1100
1101         instance = freerdp_new();
1102         instance->PreConnect = xf_pre_connect;
1103         instance->PostConnect = xf_post_connect;
1104         instance->Authenticate = xf_authenticate;
1105         instance->VerifyCertificate = xf_verify_certificate;
1106         instance->ReceiveChannelData = xf_receive_channel_data;
1107
1108         instance->context_size = sizeof(xfContext);
1109         instance->ContextNew = (pContextNew) xf_context_new;
1110         instance->ContextFree = (pContextFree) xf_context_free;
1111         freerdp_context_new(instance);
1112
1113         instance->context->argc = argc;
1114         instance->context->argv = argv;
1115         instance->settings->sw_gdi = false;
1116
1117         data = (struct thread_data*) xzalloc(sizeof(struct thread_data));
1118         data->instance = instance;
1119
1120         g_thread_count++;
1121         pthread_create(&thread, 0, thread_func, data);
1122
1123         while (g_thread_count > 0)
1124         {
1125                 freerdp_sem_wait(g_sem);
1126         }
1127
1128         freerdp_channels_global_uninit();
1129
1130         return exit_code_from_disconnect_reason(g_disconnect_reason);
1131 }