FreeRDP
xf_client.c
1 
25 #include <freerdp/config.h>
26 
27 #include <math.h>
28 #include <winpr/assert.h>
29 #include <winpr/sspicli.h>
30 
31 #include <float.h>
32 
33 #include <X11/Xlib.h>
34 #include <X11/Xutil.h>
35 #include <X11/Xatom.h>
36 
37 #ifdef WITH_XRENDER
38 #include <X11/extensions/Xrender.h>
39 #endif
40 
41 #ifdef WITH_XI
42 #include <X11/extensions/XInput.h>
43 #include <X11/extensions/XInput2.h>
44 #endif
45 
46 #ifdef WITH_XCURSOR
47 #include <X11/Xcursor/Xcursor.h>
48 #endif
49 
50 #ifdef WITH_XINERAMA
51 #include <X11/extensions/Xinerama.h>
52 #endif
53 
54 #include <X11/XKBlib.h>
55 
56 #include <errno.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <locale.h>
60 #include <unistd.h>
61 #include <string.h>
62 #include <termios.h>
63 #include <pthread.h>
64 #include <sys/wait.h>
65 #include <sys/types.h>
66 #include <sys/select.h>
67 #include <fcntl.h>
68 #include <sys/stat.h>
69 
70 #include <freerdp/freerdp.h>
71 #include <freerdp/constants.h>
72 #include <freerdp/codec/nsc.h>
73 #include <freerdp/codec/rfx.h>
74 #include <freerdp/codec/color.h>
75 #include <freerdp/codec/bitmap.h>
76 
77 #include <freerdp/utils/signal.h>
78 #include <freerdp/utils/passphrase.h>
79 #include <freerdp/client/cliprdr.h>
80 #include <freerdp/client/channels.h>
81 
82 #include <freerdp/client/file.h>
83 #include <freerdp/client/cmdline.h>
84 
85 #include <winpr/crt.h>
86 #include <winpr/synch.h>
87 #include <winpr/file.h>
88 #include <winpr/print.h>
89 #include <winpr/sysinfo.h>
90 
91 #include "xf_rail.h"
92 #if defined(CHANNEL_TSMF_CLIENT)
93 #include "xf_tsmf.h"
94 #endif
95 #include "xf_event.h"
96 #include "xf_input.h"
97 #include "xf_cliprdr.h"
98 #include "xf_disp.h"
99 #include "xf_video.h"
100 #include "xf_monitor.h"
101 #include "xf_graphics.h"
102 #include "xf_keyboard.h"
103 #include "xf_channels.h"
104 #include "xf_client.h"
105 #include "xfreerdp.h"
106 #include "xf_utils.h"
107 
108 #include <freerdp/log.h>
109 #define TAG CLIENT_TAG("x11")
110 
111 #define MIN_PIXEL_DIFF 0.001
112 
113 struct xf_exit_code_map_t
114 {
115  DWORD error;
116  int rc;
117 };
118 static const struct xf_exit_code_map_t xf_exit_code_map[] = {
119  { FREERDP_ERROR_AUTHENTICATION_FAILED, XF_EXIT_AUTH_FAILURE },
120  { FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED, XF_EXIT_NEGO_FAILURE },
121  { FREERDP_ERROR_CONNECT_LOGON_FAILURE, XF_EXIT_LOGON_FAILURE },
122  { FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT, XF_EXIT_ACCOUNT_LOCKED_OUT },
123  { FREERDP_ERROR_PRE_CONNECT_FAILED, XF_EXIT_PRE_CONNECT_FAILED },
124  { FREERDP_ERROR_CONNECT_UNDEFINED, XF_EXIT_CONNECT_UNDEFINED },
125  { FREERDP_ERROR_POST_CONNECT_FAILED, XF_EXIT_POST_CONNECT_FAILED },
126  { FREERDP_ERROR_DNS_ERROR, XF_EXIT_DNS_ERROR },
127  { FREERDP_ERROR_DNS_NAME_NOT_FOUND, XF_EXIT_DNS_NAME_NOT_FOUND },
128  { FREERDP_ERROR_CONNECT_FAILED, XF_EXIT_CONNECT_FAILED },
129  { FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR, XF_EXIT_MCS_CONNECT_INITIAL_ERROR },
130  { FREERDP_ERROR_TLS_CONNECT_FAILED, XF_EXIT_TLS_CONNECT_FAILED },
131  { FREERDP_ERROR_INSUFFICIENT_PRIVILEGES, XF_EXIT_INSUFFICIENT_PRIVILEGES },
132  { FREERDP_ERROR_CONNECT_CANCELLED, XF_EXIT_CONNECT_CANCELLED },
133  { FREERDP_ERROR_CONNECT_TRANSPORT_FAILED, XF_EXIT_CONNECT_TRANSPORT_FAILED },
134  { FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED, XF_EXIT_CONNECT_PASSWORD_EXPIRED },
135  { FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE, XF_EXIT_CONNECT_PASSWORD_MUST_CHANGE },
136  { FREERDP_ERROR_CONNECT_KDC_UNREACHABLE, XF_EXIT_CONNECT_KDC_UNREACHABLE },
137  { FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED, XF_EXIT_CONNECT_ACCOUNT_DISABLED },
138  { FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED,
139  XF_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED },
140  { FREERDP_ERROR_CONNECT_CLIENT_REVOKED, XF_EXIT_CONNECT_CLIENT_REVOKED },
141  { FREERDP_ERROR_CONNECT_WRONG_PASSWORD, XF_EXIT_CONNECT_WRONG_PASSWORD },
142  { FREERDP_ERROR_CONNECT_ACCESS_DENIED, XF_EXIT_CONNECT_ACCESS_DENIED },
143  { FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION, XF_EXIT_CONNECT_ACCOUNT_RESTRICTION },
144  { FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED, XF_EXIT_CONNECT_ACCOUNT_EXPIRED },
145  { FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED, XF_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED },
146  { FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS, XF_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS }
147 };
148 
149 static BOOL xf_setup_x11(xfContext* xfc);
150 static void xf_teardown_x11(xfContext* xfc);
151 
152 static int xf_map_error_to_exit_code(DWORD error)
153 {
154  for (size_t x = 0; x < ARRAYSIZE(xf_exit_code_map); x++)
155  {
156  const struct xf_exit_code_map_t* cur = &xf_exit_code_map[x];
157  if (cur->error == error)
158  return cur->rc;
159  }
160 
161  return XF_EXIT_CONN_FAILED;
162 }
163 static int (*def_error_handler)(Display*, XErrorEvent*);
164 static int xf_error_handler_ex(Display* d, XErrorEvent* ev);
165 static void xf_check_extensions(xfContext* context);
166 static void xf_window_free(xfContext* xfc);
167 static BOOL xf_get_pixmap_info(xfContext* xfc);
168 
169 #ifdef WITH_XRENDER
170 static void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h)
171 {
172  XTransform transform = { 0 };
173  Picture windowPicture = 0;
174  Picture primaryPicture = 0;
175  XRenderPictureAttributes pa;
176  XRenderPictFormat* picFormat = NULL;
177  int x2 = 0;
178  int y2 = 0;
179  const char* filter = NULL;
180  WINPR_ASSERT(xfc);
181 
182  rdpSettings* settings = xfc->common.context.settings;
183  WINPR_ASSERT(settings);
184 
185  if (xfc->scaledWidth <= 0 || xfc->scaledHeight <= 0)
186  {
187  WLog_ERR(TAG, "the current window dimensions are invalid");
188  return;
189  }
190 
191  if (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= 0 ||
192  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= 0)
193  {
194  WLog_ERR(TAG, "the window dimensions are invalid");
195  return;
196  }
197 
198  const double xScalingFactor = 1.0 *
199  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) /
200  (double)xfc->scaledWidth;
201  const double yScalingFactor = 1.0 *
202  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) /
203  (double)xfc->scaledHeight;
204  XSetFillStyle(xfc->display, xfc->gc, FillSolid);
205  XSetForeground(xfc->display, xfc->gc, 0);
206  /* Black out possible space between desktop and window borders */
207  {
208  XRectangle box1 = { 0, 0, xfc->window->width, xfc->window->height };
209  XRectangle box2 = { xfc->offset_x, xfc->offset_y, xfc->scaledWidth, xfc->scaledHeight };
210  Region reg1 = XCreateRegion();
211  Region reg2 = XCreateRegion();
212  XUnionRectWithRegion(&box1, reg1, reg1);
213  XUnionRectWithRegion(&box2, reg2, reg2);
214 
215  if (XSubtractRegion(reg1, reg2, reg1) && !XEmptyRegion(reg1))
216  {
217  XSetRegion(xfc->display, xfc->gc, reg1);
218  XFillRectangle(xfc->display, xfc->window->handle, xfc->gc, 0, 0, xfc->window->width,
219  xfc->window->height);
220  XSetClipMask(xfc->display, xfc->gc, None);
221  }
222 
223  XDestroyRegion(reg1);
224  XDestroyRegion(reg2);
225  }
226  picFormat = XRenderFindVisualFormat(xfc->display, xfc->visual);
227  pa.subwindow_mode = IncludeInferiors;
228  primaryPicture =
229  XRenderCreatePicture(xfc->display, xfc->primary, picFormat, CPSubwindowMode, &pa);
230  windowPicture =
231  XRenderCreatePicture(xfc->display, xfc->window->handle, picFormat, CPSubwindowMode, &pa);
232  /* avoid blurry filter when scaling factor is 2x, 3x, etc
233  * useful when the client has high-dpi monitor */
234  filter = FilterBilinear;
235  if (fabs(xScalingFactor - yScalingFactor) < MIN_PIXEL_DIFF)
236  {
237  const double inverseX = 1.0 / xScalingFactor;
238  const double inverseRoundedX = round(inverseX);
239  const double absInverse = fabs(inverseX - inverseRoundedX);
240 
241  if (absInverse < MIN_PIXEL_DIFF)
242  filter = FilterNearest;
243  }
244  XRenderSetPictureFilter(xfc->display, primaryPicture, filter, 0, 0);
245  transform.matrix[0][0] = XDoubleToFixed(xScalingFactor);
246  transform.matrix[0][1] = XDoubleToFixed(0.0);
247  transform.matrix[0][2] = XDoubleToFixed(0.0);
248  transform.matrix[1][0] = XDoubleToFixed(0.0);
249  transform.matrix[1][1] = XDoubleToFixed(yScalingFactor);
250  transform.matrix[1][2] = XDoubleToFixed(0.0);
251  transform.matrix[2][0] = XDoubleToFixed(0.0);
252  transform.matrix[2][1] = XDoubleToFixed(0.0);
253  transform.matrix[2][2] = XDoubleToFixed(1.0);
254  /* calculate and fix up scaled coordinates */
255  x2 = x + w;
256  y2 = y + h;
257 
258  const double dx1 = floor(x / xScalingFactor);
259  const double dy1 = floor(y / yScalingFactor);
260  const double dx2 = ceil(x2 / xScalingFactor);
261  const double dy2 = ceil(y2 / yScalingFactor);
262  x = ((int)dx1) - 1;
263  y = ((int)dy1) - 1;
264  w = ((int)dx2) + 1 - x;
265  h = ((int)dy2) + 1 - y;
266  XRenderSetPictureTransform(xfc->display, primaryPicture, &transform);
267  XRenderComposite(xfc->display, PictOpSrc, primaryPicture, 0, windowPicture, x, y, 0, 0,
268  xfc->offset_x + x, xfc->offset_y + y, w, h);
269  XRenderFreePicture(xfc->display, primaryPicture);
270  XRenderFreePicture(xfc->display, windowPicture);
271 }
272 
273 BOOL xf_picture_transform_required(xfContext* xfc)
274 {
275  rdpSettings* settings = NULL;
276 
277  WINPR_ASSERT(xfc);
278 
279  settings = xfc->common.context.settings;
280  WINPR_ASSERT(settings);
281 
282  if ((xfc->offset_x != 0) || (xfc->offset_y != 0) ||
283  (xfc->scaledWidth != (INT64)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth)) ||
284  (xfc->scaledHeight != (INT64)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)))
285  {
286  return TRUE;
287  }
288 
289  return FALSE;
290 }
291 #endif /* WITH_XRENDER defined */
292 
293 void xf_draw_screen_(xfContext* xfc, int x, int y, int w, int h, const char* fkt, const char* file,
294  int line)
295 {
296  if (!xfc)
297  {
298  WLog_DBG(TAG, "called from [%s] xfc=%p", fkt, xfc);
299  return;
300  }
301 
302  if (w == 0 || h == 0)
303  {
304  WLog_WARN(TAG, "invalid width and/or height specified: w=%d h=%d", w, h);
305  return;
306  }
307 
308  if (!xfc->window)
309  {
310  WLog_WARN(TAG, "invalid xfc->window=%p", xfc->window);
311  return;
312  }
313 
314 #ifdef WITH_XRENDER
315 
316  if (xf_picture_transform_required(xfc))
317  {
318  xf_draw_screen_scaled(xfc, x, y, w, h);
319  return;
320  }
321 
322 #endif
323  XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y);
324 }
325 
326 static BOOL xf_desktop_resize(rdpContext* context)
327 {
328  rdpSettings* settings = NULL;
329  xfContext* xfc = (xfContext*)context;
330 
331  WINPR_ASSERT(xfc);
332 
333  settings = context->settings;
334  WINPR_ASSERT(settings);
335 
336  if (xfc->primary)
337  {
338  BOOL same = (xfc->primary == xfc->drawing) ? TRUE : FALSE;
339  XFreePixmap(xfc->display, xfc->primary);
340 
341  WINPR_ASSERT(xfc->depth != 0);
342  if (!(xfc->primary = XCreatePixmap(
343  xfc->display, xfc->drawable,
344  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
345  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight), xfc->depth)))
346  return FALSE;
347 
348  if (same)
349  xfc->drawing = xfc->primary;
350  }
351 
352 #ifdef WITH_XRENDER
353 
354  if (!freerdp_settings_get_bool(settings, FreeRDP_SmartSizing))
355  {
356  xfc->scaledWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
357  xfc->scaledHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
358  }
359 
360 #endif
361 
362  if (!xfc->fullscreen)
363  {
364  xf_ResizeDesktopWindow(xfc, xfc->window,
365  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
366  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
367  }
368  else
369  {
370 #ifdef WITH_XRENDER
371 
372  if (!freerdp_settings_get_bool(settings, FreeRDP_SmartSizing))
373 #endif
374  {
375  /* Update the saved width and height values the window will be
376  * resized to when toggling out of fullscreen */
377  xfc->savedWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
378  xfc->savedHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
379  }
380 
381  XSetFunction(xfc->display, xfc->gc, GXcopy);
382  XSetFillStyle(xfc->display, xfc->gc, FillSolid);
383  XSetForeground(xfc->display, xfc->gc, 0);
384  XFillRectangle(xfc->display, xfc->drawable, xfc->gc, 0, 0,
385  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
386  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
387  }
388 
389  return TRUE;
390 }
391 
392 static BOOL xf_paint(xfContext* xfc, const GDI_RGN* region)
393 {
394  WINPR_ASSERT(xfc);
395  WINPR_ASSERT(region);
396 
397  if (xfc->remote_app)
398  {
399  const RECTANGLE_16 rect = { .left = region->x,
400  .top = region->y,
401  .right = region->x + region->w,
402  .bottom = region->y + region->h };
403  xf_rail_paint(xfc, &rect);
404  }
405  else
406  {
407  XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, region->x, region->y, region->x,
408  region->y, region->w, region->h);
409  xf_draw_screen(xfc, region->x, region->y, region->w, region->h);
410  }
411  return TRUE;
412 }
413 
414 static BOOL xf_end_paint(rdpContext* context)
415 {
416  xfContext* xfc = (xfContext*)context;
417  rdpGdi* gdi = context->gdi;
418 
419  if (gdi->suppressOutput)
420  return TRUE;
421 
422  HGDI_DC hdc = gdi->primary->hdc;
423 
424  if (!xfc->complex_regions)
425  {
426  const GDI_RGN* rgn = hdc->hwnd->invalid;
427  if (rgn->null)
428  return TRUE;
429  xf_lock_x11(xfc);
430  if (!xf_paint(xfc, rgn))
431  return FALSE;
432  xf_unlock_x11(xfc);
433  }
434  else
435  {
436  const INT32 ninvalid = hdc->hwnd->ninvalid;
437  const GDI_RGN* cinvalid = hdc->hwnd->cinvalid;
438 
439  if (hdc->hwnd->ninvalid < 1)
440  return TRUE;
441 
442  xf_lock_x11(xfc);
443 
444  for (INT32 i = 0; i < ninvalid; i++)
445  {
446  const GDI_RGN* rgn = &cinvalid[i];
447  if (!xf_paint(xfc, rgn))
448  return FALSE;
449  }
450 
451  XFlush(xfc->display);
452  xf_unlock_x11(xfc);
453  }
454 
455  hdc->hwnd->invalid->null = TRUE;
456  hdc->hwnd->ninvalid = 0;
457  return TRUE;
458 }
459 
460 static BOOL xf_sw_desktop_resize(rdpContext* context)
461 {
462  rdpGdi* gdi = context->gdi;
463  xfContext* xfc = (xfContext*)context;
464  rdpSettings* settings = context->settings;
465  BOOL ret = FALSE;
466 
467  if (!gdi_resize(gdi, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
468  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)))
469  return FALSE;
470 
471  /* Do not lock during gdi_resize, there might still be drawing operations in progress.
472  * locking will deadlock. */
473  xf_lock_x11(xfc);
474  if (xfc->image)
475  {
476  xfc->image->data = NULL;
477  XDestroyImage(xfc->image);
478  }
479 
480  WINPR_ASSERT(xfc->depth != 0);
481  if (!(xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0,
482  (char*)gdi->primary_buffer, gdi->width, gdi->height,
483  xfc->scanline_pad, gdi->stride)))
484  {
485  goto out;
486  }
487 
488  xfc->image->byte_order = LSBFirst;
489  xfc->image->bitmap_bit_order = LSBFirst;
490  ret = xf_desktop_resize(context);
491 out:
492  xf_unlock_x11(xfc);
493  return ret;
494 }
495 
496 static BOOL xf_process_x_events(freerdp* instance)
497 {
498  BOOL status = TRUE;
499  int pending_status = 1;
500  xfContext* xfc = (xfContext*)instance->context;
501 
502  while (pending_status)
503  {
504  xf_lock_x11(xfc);
505  pending_status = XPending(xfc->display);
506 
507  if (pending_status)
508  {
509  XEvent xevent = { 0 };
510 
511  XNextEvent(xfc->display, &xevent);
512  status = xf_event_process(instance, &xevent);
513  }
514  xf_unlock_x11(xfc);
515  if (!status)
516  break;
517  }
518 
519  return status;
520 }
521 
522 static char* xf_window_get_title(rdpSettings* settings)
523 {
524  BOOL port = 0;
525  char* windowTitle = NULL;
526  size_t size = 0;
527  const char* prefix = "FreeRDP:";
528 
529  if (!settings)
530  return NULL;
531 
532  const char* name = freerdp_settings_get_string(settings, FreeRDP_ServerHostname);
533  const char* title = freerdp_settings_get_string(settings, FreeRDP_WindowTitle);
534 
535  if (title)
536  return _strdup(title);
537 
538  port = (freerdp_settings_get_uint32(settings, FreeRDP_ServerPort) != 3389);
539  /* Just assume a window title is never longer than a filename... */
540  size = strnlen(name, MAX_PATH) + 16;
541  windowTitle = calloc(size, sizeof(char));
542 
543  if (!windowTitle)
544  return NULL;
545 
546  if (!port)
547  (void)sprintf_s(windowTitle, size, "%s %s", prefix, name);
548  else
549  (void)sprintf_s(windowTitle, size, "%s %s:%" PRIu32, prefix, name,
550  freerdp_settings_get_uint32(settings, FreeRDP_ServerPort));
551 
552  return windowTitle;
553 }
554 
555 BOOL xf_create_window(xfContext* xfc)
556 {
557  XGCValues gcv = { 0 };
558  XEvent xevent = { 0 };
559  char* windowTitle = NULL;
560 
561  WINPR_ASSERT(xfc);
562  rdpSettings* settings = xfc->common.context.settings;
563  WINPR_ASSERT(settings);
564 
565  int width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
566  int height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
567 
568  const XSetWindowAttributes empty = { 0 };
569  xfc->attribs = empty;
570 
571  if (xfc->remote_app)
572  xfc->depth = 32;
573  else
574  xfc->depth = DefaultDepthOfScreen(xfc->screen);
575 
576  XVisualInfo vinfo = { 0 };
577  if (XMatchVisualInfo(xfc->display, xfc->screen_number, xfc->depth, TrueColor, &vinfo))
578  {
579  Window root = XDefaultRootWindow(xfc->display);
580  xfc->visual = vinfo.visual;
581  xfc->attribs.colormap = xfc->colormap =
582  XCreateColormap(xfc->display, root, vinfo.visual, AllocNone);
583  }
584  else
585  {
586  if (xfc->remote_app)
587  {
588  WLog_WARN(TAG, "running in remote app mode, but XServer does not support transparency");
589  WLog_WARN(TAG, "display of remote applications might be distorted (black frames, ...)");
590  }
591  xfc->depth = DefaultDepthOfScreen(xfc->screen);
592  xfc->visual = DefaultVisual(xfc->display, xfc->screen_number);
593  xfc->attribs.colormap = xfc->colormap = DefaultColormap(xfc->display, xfc->screen_number);
594  }
595 
596  /*
597  * Detect if the server visual has an inverted colormap
598  * (BGR vs RGB, or red being the least significant byte)
599  */
600  if (vinfo.red_mask & 0xFF)
601  {
602  xfc->invert = FALSE;
603  }
604 
605  if (!xfc->remote_app)
606  {
607  xfc->attribs.background_pixel = BlackPixelOfScreen(xfc->screen);
608  xfc->attribs.border_pixel = WhitePixelOfScreen(xfc->screen);
609  xfc->attribs.backing_store = xfc->primary ? NotUseful : Always;
610  xfc->attribs.override_redirect = False;
611 
612  xfc->attribs.bit_gravity = NorthWestGravity;
613  xfc->attribs.win_gravity = NorthWestGravity;
614  xfc->attribs_mask = CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
615  CWBorderPixel | CWWinGravity | CWBitGravity;
616 
617 #ifdef WITH_XRENDER
618  xfc->offset_x = 0;
619  xfc->offset_y = 0;
620 #endif
621  windowTitle = xf_window_get_title(settings);
622 
623  if (!windowTitle)
624  return FALSE;
625 
626 #ifdef WITH_XRENDER
627 
628  if (freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) && !xfc->fullscreen)
629  {
630  if (freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingWidth) > 0)
631  width = freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingWidth);
632 
633  if (freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingHeight) > 0)
634  height = freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingHeight);
635 
636  xfc->scaledWidth = width;
637  xfc->scaledHeight = height;
638  }
639 
640 #endif
641  xfc->window = xf_CreateDesktopWindow(xfc, windowTitle, width, height);
642  free(windowTitle);
643 
644  if (xfc->fullscreen)
645  xf_SetWindowFullscreen(xfc, xfc->window, xfc->fullscreen);
646 
647  xfc->unobscured = (xevent.xvisibility.state == VisibilityUnobscured);
648  XSetWMProtocols(xfc->display, xfc->window->handle, &(xfc->WM_DELETE_WINDOW), 1);
649  xfc->drawable = xfc->window->handle;
650  }
651  else
652  {
653  xfc->attribs.border_pixel = 0;
654  xfc->attribs.background_pixel = 0;
655  xfc->attribs.backing_store = xfc->primary ? NotUseful : Always;
656  xfc->attribs.override_redirect = False;
657 
658  xfc->attribs.bit_gravity = NorthWestGravity;
659  xfc->attribs.win_gravity = NorthWestGravity;
660  xfc->attribs_mask = CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
661  CWBorderPixel | CWWinGravity | CWBitGravity;
662 
663  xfc->drawable = xf_CreateDummyWindow(xfc);
664  }
665 
666  if (!xfc->gc)
667  xfc->gc = XCreateGC(xfc->display, xfc->drawable, GCGraphicsExposures, &gcv);
668 
669  WINPR_ASSERT(xfc->depth != 0);
670  if (!xfc->primary)
671  xfc->primary =
672  XCreatePixmap(xfc->display, xfc->drawable,
673  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
674  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight), xfc->depth);
675 
676  xfc->drawing = xfc->primary;
677 
678  if (!xfc->bitmap_mono)
679  xfc->bitmap_mono = XCreatePixmap(xfc->display, xfc->drawable, 8, 8, 1);
680 
681  if (!xfc->gc_mono)
682  xfc->gc_mono = XCreateGC(xfc->display, xfc->bitmap_mono, GCGraphicsExposures, &gcv);
683 
684  XSetFunction(xfc->display, xfc->gc, GXcopy);
685  XSetFillStyle(xfc->display, xfc->gc, FillSolid);
686  XSetForeground(xfc->display, xfc->gc, BlackPixelOfScreen(xfc->screen));
687  XFillRectangle(xfc->display, xfc->primary, xfc->gc, 0, 0,
688  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
689  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
690  XFlush(xfc->display);
691 
692  return TRUE;
693 }
694 
695 BOOL xf_create_image(xfContext* xfc)
696 {
697  WINPR_ASSERT(xfc);
698  if (!xfc->image)
699  {
700  const rdpSettings* settings = xfc->common.context.settings;
701  rdpGdi* cgdi = xfc->common.context.gdi;
702  WINPR_ASSERT(cgdi);
703 
704  WINPR_ASSERT(xfc->depth != 0);
705  xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0,
706  (char*)cgdi->primary_buffer,
707  freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
708  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight),
709  xfc->scanline_pad, cgdi->stride);
710  xfc->image->byte_order = LSBFirst;
711  xfc->image->bitmap_bit_order = LSBFirst;
712  }
713  return TRUE;
714 }
715 
716 static void xf_window_free(xfContext* xfc)
717 {
718  if (xfc->window)
719  {
720  xf_DestroyDesktopWindow(xfc, xfc->window);
721  xfc->window = NULL;
722  }
723 
724 #if defined(CHANNEL_TSMF_CLIENT)
725  if (xfc->xv_context)
726  {
727  xf_tsmf_uninit(xfc, NULL);
728  xfc->xv_context = NULL;
729  }
730 #endif
731 
732  if (xfc->image)
733  {
734  xfc->image->data = NULL;
735  XDestroyImage(xfc->image);
736  xfc->image = NULL;
737  }
738 
739  if (xfc->bitmap_mono)
740  {
741  XFreePixmap(xfc->display, xfc->bitmap_mono);
742  xfc->bitmap_mono = 0;
743  }
744 
745  if (xfc->gc_mono)
746  {
747  XFreeGC(xfc->display, xfc->gc_mono);
748  xfc->gc_mono = 0;
749  }
750 
751  if (xfc->primary)
752  {
753  XFreePixmap(xfc->display, xfc->primary);
754  xfc->primary = 0;
755  }
756 
757  if (xfc->gc)
758  {
759  XFreeGC(xfc->display, xfc->gc);
760  xfc->gc = 0;
761  }
762 }
763 
764 void xf_toggle_fullscreen(xfContext* xfc)
765 {
766  WindowStateChangeEventArgs e = { 0 };
767  rdpContext* context = (rdpContext*)xfc;
768  rdpSettings* settings = context->settings;
769 
770  /*
771  when debugging, ungrab keyboard when toggling fullscreen
772  to allow keyboard usage on the debugger
773  */
774  if (xfc->debug)
775  xf_ungrab(xfc);
776 
777  xfc->fullscreen = (xfc->fullscreen) ? FALSE : TRUE;
778  xfc->decorations =
779  (xfc->fullscreen) ? FALSE : freerdp_settings_get_bool(settings, FreeRDP_Decorations);
780  xf_SetWindowFullscreen(xfc, xfc->window, xfc->fullscreen);
781  EventArgsInit(&e, "xfreerdp");
782  e.state = xfc->fullscreen ? FREERDP_WINDOW_STATE_FULLSCREEN : 0;
783  PubSub_OnWindowStateChange(context->pubSub, context, &e);
784 }
785 
786 void xf_minimize(xfContext* xfc)
787 {
788  WindowStateChangeEventArgs e = { 0 };
789  rdpContext* context = (rdpContext*)xfc;
790  WINPR_ASSERT(context);
791 
792  /*
793  when debugging, ungrab keyboard when toggling fullscreen
794  to allow keyboard usage on the debugger
795  */
796  if (xfc->debug)
797  xf_ungrab(xfc);
798 
799  xf_SetWindowMinimized(xfc, xfc->window);
800 
801  e.state = xfc->fullscreen ? FREERDP_WINDOW_STATE_FULLSCREEN : 0;
802  PubSub_OnWindowStateChange(context->pubSub, context, &e);
803 }
804 
805 void xf_lock_x11_(xfContext* xfc, const char* fkt)
806 {
807 
808  if (!xfc->UseXThreads)
809  (void)WaitForSingleObject(xfc->mutex, INFINITE);
810  else
811  XLockDisplay(xfc->display);
812 
813  xfc->locked++;
814 #ifdef WITH_DEBUG_X11
815  WLog_VRB(TAG, "[%" PRIu32 "] from %s", xfc->locked, fkt);
816 #endif
817 }
818 
819 void xf_unlock_x11_(xfContext* xfc, const char* fkt)
820 {
821  if (xfc->locked == 0)
822  WLog_WARN(TAG, "X11: trying to unlock although not locked!");
823  else
824  xfc->locked--;
825 
826 #ifdef WITH_DEBUG_X11
827  WLog_VRB(TAG, "[%" PRIu32 "] from %s", xfc->locked, fkt);
828 #endif
829 
830  if (!xfc->UseXThreads)
831  (void)ReleaseMutex(xfc->mutex);
832  else
833  XUnlockDisplay(xfc->display);
834 }
835 
836 static BOOL xf_get_pixmap_info(xfContext* xfc)
837 {
838  int pf_count = 0;
839  XPixmapFormatValues* pfs = NULL;
840 
841  WINPR_ASSERT(xfc->display);
842  pfs = XListPixmapFormats(xfc->display, &pf_count);
843 
844  if (!pfs)
845  {
846  WLog_ERR(TAG, "XListPixmapFormats failed");
847  return 1;
848  }
849 
850  WINPR_ASSERT(xfc->depth != 0);
851  for (int i = 0; i < pf_count; i++)
852  {
853  const XPixmapFormatValues* pf = &pfs[i];
854 
855  if (pf->depth == xfc->depth)
856  {
857  xfc->scanline_pad = pf->scanline_pad;
858  break;
859  }
860  }
861 
862  XFree(pfs);
863  if ((xfc->visual == NULL) || (xfc->scanline_pad == 0))
864  return FALSE;
865 
866  return TRUE;
867 }
868 
869 static int xf_error_handler(Display* d, XErrorEvent* ev)
870 {
871  char buf[256] = { 0 };
872  XGetErrorText(d, ev->error_code, buf, sizeof(buf));
873  WLog_ERR(TAG, "%s", buf);
874  winpr_log_backtrace(TAG, WLOG_ERROR, 20);
875 
876 #if 0
877  const BOOL do_abort = TRUE;
878  if (do_abort)
879  abort();
880 #endif
881 
882  if (def_error_handler)
883  return def_error_handler(d, ev);
884 
885  return 0;
886 }
887 
888 static int xf_error_handler_ex(Display* d, XErrorEvent* ev)
889 {
890  /*
891  * ungrab the keyboard, in case a debugger is running in
892  * another window. This make xf_error_handler() a potential
893  * debugger breakpoint.
894  */
895 
896  XUngrabKeyboard(d, CurrentTime);
897  XUngrabPointer(d, CurrentTime);
898  return xf_error_handler(d, ev);
899 }
900 
901 static BOOL xf_play_sound(rdpContext* context, const PLAY_SOUND_UPDATE* play_sound)
902 {
903  xfContext* xfc = (xfContext*)context;
904  WINPR_UNUSED(play_sound);
905  XkbBell(xfc->display, None, 100, 0);
906  return TRUE;
907 }
908 
909 static void xf_check_extensions(xfContext* context)
910 {
911  int xkb_opcode = 0;
912  int xkb_event = 0;
913  int xkb_error = 0;
914  int xkb_major = XkbMajorVersion;
915  int xkb_minor = XkbMinorVersion;
916 
917  if (XkbLibraryVersion(&xkb_major, &xkb_minor) &&
918  XkbQueryExtension(context->display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major,
919  &xkb_minor))
920  {
921  context->xkbAvailable = TRUE;
922  }
923 
924 #ifdef WITH_XRENDER
925  {
926  int xrender_event_base = 0;
927  int xrender_error_base = 0;
928 
929  if (XRenderQueryExtension(context->display, &xrender_event_base, &xrender_error_base))
930  {
931  context->xrenderAvailable = TRUE;
932  }
933  }
934 #endif
935 }
936 
937 #ifdef WITH_XI
938 /* Input device which does NOT have the correct mapping. We must disregard */
939 /* this device when trying to find the input device which is the pointer. */
940 static const char TEST_PTR_STR[] = "Virtual core XTEST pointer";
941 static const size_t TEST_PTR_LEN = sizeof(TEST_PTR_STR) / sizeof(char);
942 #endif /* WITH_XI */
943 
944 static void xf_get_x11_button_map(xfContext* xfc, unsigned char* x11_map)
945 {
946 #ifdef WITH_XI
947  int opcode = 0;
948  int event = 0;
949  int error = 0;
950  XDevice* ptr_dev = NULL;
951  XExtensionVersion* version = NULL;
952  XDeviceInfo* devices1 = NULL;
953  XIDeviceInfo* devices2 = NULL;
954  int num_devices = 0;
955 
956  if (XQueryExtension(xfc->display, "XInputExtension", &opcode, &event, &error))
957  {
958  WLog_DBG(TAG, "Searching for XInput pointer device");
959  ptr_dev = NULL;
960  /* loop through every device, looking for a pointer */
961  version = XGetExtensionVersion(xfc->display, INAME);
962 
963  if (version->major_version >= 2)
964  {
965  /* XID of pointer device using XInput version 2 */
966  devices2 = XIQueryDevice(xfc->display, XIAllDevices, &num_devices);
967 
968  if (devices2)
969  {
970  for (int i = 0; i < num_devices; ++i)
971  {
972  if ((devices2[i].use == XISlavePointer) &&
973  (strncmp(devices2[i].name, TEST_PTR_STR, TEST_PTR_LEN) != 0))
974  {
975  ptr_dev = XOpenDevice(xfc->display, devices2[i].deviceid);
976  if (ptr_dev)
977  break;
978  }
979  }
980 
981  XIFreeDeviceInfo(devices2);
982  }
983  }
984  else
985  {
986  /* XID of pointer device using XInput version 1 */
987  devices1 = XListInputDevices(xfc->display, &num_devices);
988 
989  if (devices1)
990  {
991  for (int i = 0; i < num_devices; ++i)
992  {
993  if ((devices1[i].use == IsXExtensionPointer) &&
994  (strncmp(devices1[i].name, TEST_PTR_STR, TEST_PTR_LEN) != 0))
995  {
996  ptr_dev = XOpenDevice(xfc->display, devices1[i].id);
997  if (ptr_dev)
998  break;
999  }
1000  }
1001 
1002  XFreeDeviceList(devices1);
1003  }
1004  }
1005 
1006  XFree(version);
1007 
1008  /* get button mapping from input extension if there is a pointer device; */
1009  /* otherwise leave unchanged. */
1010  if (ptr_dev)
1011  {
1012  WLog_DBG(TAG, "Pointer device: %d", ptr_dev->device_id);
1013  XGetDeviceButtonMapping(xfc->display, ptr_dev, x11_map, NUM_BUTTONS_MAPPED);
1014  XCloseDevice(xfc->display, ptr_dev);
1015  }
1016  else
1017  {
1018  WLog_DBG(TAG, "No pointer device found!");
1019  }
1020  }
1021  else
1022 #endif /* WITH_XI */
1023  {
1024  WLog_DBG(TAG, "Get global pointer mapping (no XInput)");
1025  XGetPointerMapping(xfc->display, x11_map, NUM_BUTTONS_MAPPED);
1026  }
1027 }
1028 
1029 /* Assignment of physical (not logical) mouse buttons to wire flags. */
1030 /* Notice that the middle button is 2 in X11, but 3 in RDP. */
1031 static const button_map xf_button_flags[NUM_BUTTONS_MAPPED] = {
1032  { Button1, PTR_FLAGS_BUTTON1 },
1033  { Button2, PTR_FLAGS_BUTTON3 },
1034  { Button3, PTR_FLAGS_BUTTON2 },
1035  { Button4, PTR_FLAGS_WHEEL | 0x78 },
1036  /* Negative value is 9bit twos complement */
1037  { Button5, PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | (0x100 - 0x78) },
1038  { 6, PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE | (0x100 - 0x78) },
1039  { 7, PTR_FLAGS_HWHEEL | 0x78 },
1040  { 8, PTR_XFLAGS_BUTTON1 },
1041  { 9, PTR_XFLAGS_BUTTON2 },
1042  { 97, PTR_XFLAGS_BUTTON1 },
1043  { 112, PTR_XFLAGS_BUTTON2 }
1044 };
1045 
1046 static UINT16 get_flags_for_button(size_t button)
1047 {
1048  for (size_t x = 0; x < ARRAYSIZE(xf_button_flags); x++)
1049  {
1050  const button_map* map = &xf_button_flags[x];
1051 
1052  if (map->button == button)
1053  return map->flags;
1054  }
1055 
1056  return 0;
1057 }
1058 
1059 static void xf_button_map_init(xfContext* xfc)
1060 {
1061  size_t pos = 0;
1062  /* loop counter for array initialization */
1063 
1064  /* logical mouse button which is used for each physical mouse */
1065  /* button (indexed from zero). This is the default map. */
1066  unsigned char x11_map[112] = { 0 };
1067 
1068  WINPR_ASSERT(xfc);
1069  WINPR_ASSERT(xfc->common.context.settings);
1070 
1071  x11_map[0] = Button1;
1072  x11_map[1] = Button2;
1073  x11_map[2] = Button3;
1074  x11_map[3] = Button4;
1075  x11_map[4] = Button5;
1076  x11_map[5] = 6;
1077  x11_map[6] = 7;
1078  x11_map[7] = 8;
1079  x11_map[8] = 9;
1080  x11_map[96] = 97;
1081  x11_map[111] = 112;
1082 
1083  /* query system for actual remapping */
1084  if (freerdp_settings_get_bool(xfc->common.context.settings, FreeRDP_UnmapButtons))
1085  {
1086  xf_get_x11_button_map(xfc, x11_map);
1087  }
1088 
1089  /* iterate over all (mapped) physical buttons; for each of them */
1090  /* find the logical button in X11, and assign to this the */
1091  /* appropriate value to send over the RDP wire. */
1092  for (size_t physical = 0; physical < ARRAYSIZE(x11_map); ++physical)
1093  {
1094  const unsigned char logical = x11_map[physical];
1095  const UINT16 flags = get_flags_for_button(logical);
1096 
1097  if ((logical != 0) && (flags != 0))
1098  {
1099  if (pos >= NUM_BUTTONS_MAPPED)
1100  {
1101  WLog_ERR(TAG, "Failed to map mouse button to RDP button, no space");
1102  }
1103  else
1104  {
1105  button_map* map = &xfc->button_map[pos++];
1106  map->button = logical;
1107  map->flags = get_flags_for_button(physical + Button1);
1108  }
1109  }
1110  }
1111 }
1112 
1124 static BOOL xf_pre_connect(freerdp* instance)
1125 {
1126  rdpChannels* channels = NULL;
1127  rdpSettings* settings = NULL;
1128  rdpContext* context = NULL;
1129  xfContext* xfc = NULL;
1130  UINT32 maxWidth = 0;
1131  UINT32 maxHeight = 0;
1132 
1133  WINPR_ASSERT(instance);
1134 
1135  context = instance->context;
1136  xfc = (xfContext*)instance->context;
1137  WINPR_ASSERT(context);
1138 
1139  settings = context->settings;
1140  WINPR_ASSERT(settings);
1141 
1142  if (!freerdp_settings_set_bool(settings, FreeRDP_CertificateCallbackPreferPEM, TRUE))
1143  return FALSE;
1144 
1145  if (!freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly))
1146  {
1147  if (!xf_setup_x11(xfc))
1148  return FALSE;
1149  }
1150 
1151  channels = context->channels;
1152  WINPR_ASSERT(channels);
1153 
1154  if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNIX))
1155  return FALSE;
1156  if (!freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_NATIVE_XSERVER))
1157  return FALSE;
1158  PubSub_SubscribeChannelConnected(context->pubSub, xf_OnChannelConnectedEventHandler);
1159  PubSub_SubscribeChannelDisconnected(context->pubSub, xf_OnChannelDisconnectedEventHandler);
1160 
1161  if (!freerdp_settings_get_string(settings, FreeRDP_Username) &&
1162  !freerdp_settings_get_bool(settings, FreeRDP_CredentialsFromStdin) &&
1163  !freerdp_settings_get_bool(settings, FreeRDP_SmartcardLogon))
1164  {
1165  char login_name[MAX_PATH] = { 0 };
1166  ULONG size = sizeof(login_name) - 1;
1167 
1168  if (GetUserNameExA(NameSamCompatible, login_name, &size))
1169  {
1170  if (!freerdp_settings_set_string(settings, FreeRDP_Username, login_name))
1171  return FALSE;
1172 
1173  WLog_INFO(TAG, "No user name set. - Using login name: %s",
1174  freerdp_settings_get_string(settings, FreeRDP_Username));
1175  }
1176  }
1177 
1178  if (freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly))
1179  {
1180  /* Check +auth-only has a username and password. */
1181  if (!freerdp_settings_get_string(settings, FreeRDP_Password))
1182  {
1183  WLog_INFO(TAG, "auth-only, but no password set. Please provide one.");
1184  return FALSE;
1185  }
1186 
1187  WLog_INFO(TAG, "Authentication only. Don't connect to X.");
1188  }
1189 
1190  if (!freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly))
1191  {
1192  if (!xf_keyboard_init(xfc))
1193  return FALSE;
1194  if (!xf_detect_monitors(xfc, &maxWidth, &maxHeight))
1195  return FALSE;
1196  }
1197 
1198  if (maxWidth && maxHeight && !freerdp_settings_get_bool(settings, FreeRDP_SmartSizing))
1199  {
1200  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, maxWidth))
1201  return FALSE;
1202  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, maxHeight))
1203  return FALSE;
1204  }
1205 
1206 #ifdef WITH_XRENDER
1207 
1212  if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen) &&
1213  freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) &&
1214  (freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingWidth) > 0) &&
1215  (freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingHeight) > 0))
1216  {
1218  settings, FreeRDP_DesktopWidth,
1219  freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingWidth)))
1220  return FALSE;
1222  settings, FreeRDP_DesktopHeight,
1223  freerdp_settings_get_uint32(settings, FreeRDP_SmartSizingHeight)))
1224  return FALSE;
1225  }
1226 
1227 #endif
1228  xfc->fullscreen = freerdp_settings_get_bool(settings, FreeRDP_Fullscreen);
1229  xfc->decorations = freerdp_settings_get_bool(settings, FreeRDP_Decorations);
1230  xfc->grab_keyboard = freerdp_settings_get_bool(settings, FreeRDP_GrabKeyboard);
1231  xfc->fullscreen_toggle = freerdp_settings_get_bool(settings, FreeRDP_ToggleFullscreen);
1232  if (!freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly))
1233  xf_button_map_init(xfc);
1234  return TRUE;
1235 }
1236 
1237 static BOOL xf_inject_keypress(rdpContext* context, const char* buffer, size_t size)
1238 {
1239  WCHAR wbuffer[64] = { 0 };
1240  const SSIZE_T len = ConvertUtf8NToWChar(buffer, size, wbuffer, ARRAYSIZE(wbuffer));
1241  if (len < 0)
1242  return FALSE;
1243 
1244  rdpInput* input = context->input;
1245  WINPR_ASSERT(input);
1246 
1247  for (SSIZE_T x = 0; x < len; x++)
1248  {
1249  const WCHAR code = wbuffer[x];
1250  freerdp_input_send_unicode_keyboard_event(input, 0, code);
1251  Sleep(5);
1252  freerdp_input_send_unicode_keyboard_event(input, KBD_FLAGS_RELEASE, code);
1253  Sleep(5);
1254  }
1255  return TRUE;
1256 }
1257 
1258 static BOOL xf_process_pipe(rdpContext* context, const char* pipe)
1259 {
1260  int fd = open(pipe, O_NONBLOCK | O_RDONLY);
1261  if (fd < 0)
1262  {
1263  char ebuffer[256] = { 0 };
1264  WLog_ERR(TAG, "pipe '%s' open returned %s [%d]", pipe,
1265  winpr_strerror(errno, ebuffer, sizeof(ebuffer)), errno);
1266  return FALSE;
1267  }
1268  while (!freerdp_shall_disconnect_context(context))
1269  {
1270  char buffer[64] = { 0 };
1271  ssize_t rd = read(fd, buffer, sizeof(buffer) - 1);
1272  if (rd == 0)
1273  {
1274  char ebuffer[256] = { 0 };
1275  if ((errno == EAGAIN) || (errno == 0))
1276  {
1277  Sleep(100);
1278  continue;
1279  }
1280 
1281  // EOF, abort reading.
1282  WLog_ERR(TAG, "pipe '%s' read returned %s [%d]", pipe,
1283  winpr_strerror(errno, ebuffer, sizeof(ebuffer)), errno);
1284  break;
1285  }
1286  else if (rd < 0)
1287  {
1288  char ebuffer[256] = { 0 };
1289  WLog_ERR(TAG, "pipe '%s' read returned %s [%d]", pipe,
1290  winpr_strerror(errno, ebuffer, sizeof(ebuffer)), errno);
1291  break;
1292  }
1293  else
1294  {
1295  if (!xf_inject_keypress(context, buffer, rd))
1296  break;
1297  }
1298  }
1299  close(fd);
1300  return TRUE;
1301 }
1302 
1303 static void cleanup_pipe(int signum, const char* signame, void* context)
1304 {
1305  const char* pipe = context;
1306  if (!pipe)
1307  return;
1308  unlink(pipe);
1309 }
1310 
1311 static DWORD WINAPI xf_handle_pipe(void* arg)
1312 {
1313  xfContext* xfc = arg;
1314  WINPR_ASSERT(xfc);
1315 
1316  rdpContext* context = &xfc->common.context;
1317  WINPR_ASSERT(context);
1318 
1319  rdpSettings* settings = context->settings;
1320  WINPR_ASSERT(settings);
1321 
1322  const char* pipe = freerdp_settings_get_string(settings, FreeRDP_KeyboardPipeName);
1323  WINPR_ASSERT(pipe);
1324 
1325  const int rc = mkfifo(pipe, S_IWUSR | S_IRUSR);
1326  if (rc != 0)
1327  {
1328  char ebuffer[256] = { 0 };
1329  WLog_ERR(TAG, "Failed to create named pipe '%s': %s [%d]", pipe,
1330  winpr_strerror(errno, ebuffer, sizeof(ebuffer)), errno);
1331  return 0;
1332  }
1333 
1334  void* ctx = WINPR_CAST_CONST_PTR_AWAY(pipe, void*);
1335  freerdp_add_signal_cleanup_handler(ctx, cleanup_pipe);
1336 
1337  xf_process_pipe(context, pipe);
1338 
1339  freerdp_del_signal_cleanup_handler(ctx, cleanup_pipe);
1340 
1341  unlink(pipe);
1342  return 0;
1343 }
1344 
1350 static BOOL xf_post_connect(freerdp* instance)
1351 {
1352  ResizeWindowEventArgs e = { 0 };
1353 
1354  WINPR_ASSERT(instance);
1355  xfContext* xfc = (xfContext*)instance->context;
1356  rdpContext* context = instance->context;
1357  WINPR_ASSERT(context);
1358 
1359  rdpSettings* settings = context->settings;
1360  WINPR_ASSERT(settings);
1361 
1362  rdpUpdate* update = context->update;
1363  WINPR_ASSERT(update);
1364 
1365  if (freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode))
1366  xfc->remote_app = TRUE;
1367 
1368  if (!xf_create_window(xfc))
1369  return FALSE;
1370 
1371  if (!xf_get_pixmap_info(xfc))
1372  return FALSE;
1373 
1374  if (!gdi_init(instance, xf_get_local_color_format(xfc, TRUE)))
1375  return FALSE;
1376 
1377  if (!xf_create_image(xfc))
1378  return FALSE;
1379 
1380  if (!xf_register_pointer(context->graphics))
1381  return FALSE;
1382 
1383 #ifdef WITH_XRENDER
1384  xfc->scaledWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1385  xfc->scaledHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1386  xfc->offset_x = 0;
1387  xfc->offset_y = 0;
1388 #endif
1389 
1390  if (!xfc->xrenderAvailable)
1391  {
1392  if (freerdp_settings_get_bool(settings, FreeRDP_SmartSizing))
1393  {
1394  WLog_ERR(TAG, "XRender not available: disabling smart-sizing");
1395  if (!freerdp_settings_set_bool(settings, FreeRDP_SmartSizing, FALSE))
1396  return FALSE;
1397  }
1398 
1399  if (freerdp_settings_get_bool(settings, FreeRDP_MultiTouchGestures))
1400  {
1401  WLog_ERR(TAG, "XRender not available: disabling local multi-touch gestures");
1402  if (!freerdp_settings_set_bool(settings, FreeRDP_MultiTouchGestures, FALSE))
1403  return FALSE;
1404  }
1405  }
1406 
1407  update->DesktopResize = xf_sw_desktop_resize;
1408  update->EndPaint = xf_end_paint;
1409  update->PlaySound = xf_play_sound;
1410  update->SetKeyboardIndicators = xf_keyboard_set_indicators;
1411  update->SetKeyboardImeStatus = xf_keyboard_set_ime_status;
1412 
1413  const BOOL serverIsWindowsPlatform =
1414  (freerdp_settings_get_uint32(settings, FreeRDP_OsMajorType) == OSMAJORTYPE_WINDOWS);
1415  if (freerdp_settings_get_bool(settings, FreeRDP_RedirectClipboard) &&
1416  !(xfc->clipboard = xf_clipboard_new(xfc, !serverIsWindowsPlatform)))
1417  return FALSE;
1418 
1419  if (!(xfc->xfDisp = xf_disp_new(xfc)))
1420  return FALSE;
1421 
1422  const char* pipe = freerdp_settings_get_string(settings, FreeRDP_KeyboardPipeName);
1423  if (pipe)
1424  {
1425  xfc->pipethread = CreateThread(NULL, 0, xf_handle_pipe, xfc, 0, NULL);
1426  if (!xfc->pipethread)
1427  return FALSE;
1428  }
1429 
1430  EventArgsInit(&e, "xfreerdp");
1431  e.width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1432  e.height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1433  PubSub_OnResizeWindow(context->pubSub, xfc, &e);
1434  return TRUE;
1435 }
1436 
1437 static void xf_post_disconnect(freerdp* instance)
1438 {
1439  xfContext* xfc = NULL;
1440  rdpContext* context = NULL;
1441 
1442  if (!instance || !instance->context)
1443  return;
1444 
1445  context = instance->context;
1446  xfc = (xfContext*)context;
1447  PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
1448  xf_OnChannelConnectedEventHandler);
1449  PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
1450  xf_OnChannelDisconnectedEventHandler);
1451  gdi_free(instance);
1452 
1453  if (xfc->pipethread)
1454  {
1455  (void)WaitForSingleObject(xfc->pipethread, INFINITE);
1456  (void)CloseHandle(xfc->pipethread);
1457  xfc->pipethread = NULL;
1458  }
1459  if (xfc->clipboard)
1460  {
1461  xf_clipboard_free(xfc->clipboard);
1462  xfc->clipboard = NULL;
1463  }
1464 
1465  if (xfc->xfDisp)
1466  {
1467  xf_disp_free(xfc->xfDisp);
1468  xfc->xfDisp = NULL;
1469  }
1470 
1471  if ((xfc->window != NULL) && (xfc->drawable == xfc->window->handle))
1472  xfc->drawable = 0;
1473  else
1474  xf_DestroyDummyWindow(xfc, xfc->drawable);
1475 
1476  xf_window_free(xfc);
1477 }
1478 
1479 static void xf_post_final_disconnect(freerdp* instance)
1480 {
1481  xfContext* xfc = NULL;
1482  rdpContext* context = NULL;
1483 
1484  if (!instance || !instance->context)
1485  return;
1486 
1487  context = instance->context;
1488  xfc = (xfContext*)context;
1489 
1490  xf_keyboard_free(xfc);
1491  xf_teardown_x11(xfc);
1492 }
1493 
1494 static int xf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
1495 {
1496  xfContext* xfc = (xfContext*)instance->context;
1497  const char* str_data = freerdp_get_logon_error_info_data(data);
1498  const char* str_type = freerdp_get_logon_error_info_type(type);
1499  WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type);
1500  if (type != LOGON_MSG_SESSION_CONTINUE)
1501  {
1502  xf_rail_disable_remoteapp_mode(xfc);
1503  }
1504  return 1;
1505 }
1506 
1507 static BOOL handle_window_events(freerdp* instance)
1508 {
1509  if (!xf_process_x_events(instance))
1510  {
1511  WLog_DBG(TAG, "Closed from X11");
1512  return FALSE;
1513  }
1514 
1515  return TRUE;
1516 }
1517 
1526 static DWORD WINAPI xf_client_thread(LPVOID param)
1527 {
1528  DWORD exit_code = 0;
1529  DWORD waitStatus = 0;
1530  HANDLE inputEvent = NULL;
1531  HANDLE timer = NULL;
1532  LARGE_INTEGER due = { 0 };
1533  TimerEventArgs timerEvent = { 0 };
1534 
1535  EventArgsInit(&timerEvent, "xfreerdp");
1536  freerdp* instance = (freerdp*)param;
1537  WINPR_ASSERT(instance);
1538 
1539  const BOOL status = freerdp_connect(instance);
1540  rdpContext* context = instance->context;
1541  WINPR_ASSERT(context);
1542  xfContext* xfc = (xfContext*)instance->context;
1543  WINPR_ASSERT(xfc);
1544 
1545  rdpSettings* settings = context->settings;
1546  WINPR_ASSERT(settings);
1547 
1548  if (!status)
1549  {
1550  UINT32 error = freerdp_get_last_error(instance->context);
1551  exit_code = xf_map_error_to_exit_code(error);
1552  }
1553  else
1554  exit_code = XF_EXIT_SUCCESS;
1555 
1556  if (!status)
1557  goto end;
1558 
1559  /* --authonly ? */
1560  if (freerdp_settings_get_bool(settings, FreeRDP_AuthenticationOnly))
1561  {
1562  WLog_ERR(TAG, "Authentication only, exit status %" PRId32 "", !status);
1563  goto disconnect;
1564  }
1565 
1566  if (!status)
1567  {
1568  WLog_ERR(TAG, "Freerdp connect error exit status %" PRId32 "", !status);
1569  exit_code = freerdp_error_info(instance);
1570 
1571  if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_AUTHENTICATION_FAILED)
1572  exit_code = XF_EXIT_AUTH_FAILURE;
1573  else if (exit_code == ERRINFO_SUCCESS)
1574  exit_code = XF_EXIT_CONN_FAILED;
1575 
1576  goto disconnect;
1577  }
1578 
1579  timer = CreateWaitableTimerA(NULL, FALSE, "mainloop-periodic-timer");
1580 
1581  if (!timer)
1582  {
1583  WLog_ERR(TAG, "failed to create timer");
1584  goto disconnect;
1585  }
1586 
1587  due.QuadPart = 0;
1588 
1589  if (!SetWaitableTimer(timer, &due, 20, NULL, NULL, FALSE))
1590  {
1591  goto disconnect;
1592  }
1593  inputEvent = xfc->x11event;
1594 
1595  while (!freerdp_shall_disconnect_context(instance->context))
1596  {
1597  HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
1598  DWORD nCount = 0;
1599  handles[nCount++] = timer;
1600  handles[nCount++] = inputEvent;
1601 
1602  /*
1603  * win8 and server 2k12 seem to have some timing issue/race condition
1604  * when a initial sync request is send to sync the keyboard indicators
1605  * sending the sync event twice fixed this problem
1606  */
1607  if (freerdp_focus_required(instance))
1608  {
1609  xf_keyboard_focus_in(xfc);
1610  xf_keyboard_focus_in(xfc);
1611  }
1612 
1613  {
1614  DWORD tmp =
1615  freerdp_get_event_handles(context, &handles[nCount], ARRAYSIZE(handles) - nCount);
1616 
1617  if (tmp == 0)
1618  {
1619  WLog_ERR(TAG, "freerdp_get_event_handles failed");
1620  break;
1621  }
1622 
1623  nCount += tmp;
1624  }
1625 
1626  if (xfc->window)
1627  xf_floatbar_hide_and_show(xfc->window->floatbar);
1628 
1629  waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
1630 
1631  if (waitStatus == WAIT_FAILED)
1632  break;
1633 
1634  {
1635  if (!freerdp_check_event_handles(context))
1636  {
1637  if (client_auto_reconnect_ex(instance, handle_window_events))
1638  continue;
1639  else
1640  {
1641  /*
1642  * Indicate an unsuccessful connection attempt if reconnect
1643  * did not succeed and no other error was specified.
1644  */
1645  const UINT32 error = freerdp_get_last_error(instance->context);
1646 
1647  if (freerdp_error_info(instance) == 0)
1648  exit_code = xf_map_error_to_exit_code(error);
1649  }
1650 
1651  if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
1652  WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
1653 
1654  break;
1655  }
1656  }
1657 
1658  if (!handle_window_events(instance))
1659  break;
1660 
1661  if ((waitStatus != WAIT_TIMEOUT) && (waitStatus == WAIT_OBJECT_0))
1662  {
1663  timerEvent.now = GetTickCount64();
1664  PubSub_OnTimer(context->pubSub, context, &timerEvent);
1665  }
1666  }
1667 
1668  if (!exit_code)
1669  {
1670  exit_code = freerdp_error_info(instance);
1671 
1672  if (exit_code == XF_EXIT_DISCONNECT &&
1673  freerdp_get_disconnect_ultimatum(context) == Disconnect_Ultimatum_user_requested)
1674  {
1675  /* This situation might be limited to Windows XP. */
1676  WLog_INFO(TAG, "Error info says user did not initiate but disconnect ultimatum says "
1677  "they did; treat this as a user logoff");
1678  exit_code = XF_EXIT_LOGOFF;
1679  }
1680  }
1681 
1682 disconnect:
1683 
1684  if (timer)
1685  (void)CloseHandle(timer);
1686 
1687  freerdp_disconnect(instance);
1688 end:
1689  ExitThread(exit_code);
1690  return exit_code;
1691 }
1692 
1693 int xf_exit_code_from_disconnect_reason(DWORD reason)
1694 {
1695  if (reason == 0 ||
1696  (reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS))
1697  return reason;
1698  /* License error set */
1699  else if (reason >= 0x100 && reason <= 0x10A)
1700  reason -= 0x100 + XF_EXIT_LICENSE_INTERNAL;
1701  /* RDP protocol error set */
1702  else if (reason >= 0x10c9 && reason <= 0x1193)
1703  reason = XF_EXIT_RDP;
1704  /* There's no need to test protocol-independent codes: they match */
1705  else if (!(reason <= 0xC))
1706  reason = XF_EXIT_UNKNOWN;
1707 
1708  return reason;
1709 }
1710 
1711 static void xf_TerminateEventHandler(void* context, const TerminateEventArgs* e)
1712 {
1713  rdpContext* ctx = (rdpContext*)context;
1714  WINPR_UNUSED(e);
1715  freerdp_abort_connect_context(ctx);
1716 }
1717 
1718 #ifdef WITH_XRENDER
1719 static void xf_ZoomingChangeEventHandler(void* context, const ZoomingChangeEventArgs* e)
1720 {
1721  int w = 0;
1722  int h = 0;
1723  rdpSettings* settings = NULL;
1724  xfContext* xfc = (xfContext*)context;
1725 
1726  WINPR_ASSERT(xfc);
1727 
1728  settings = xfc->common.context.settings;
1729  WINPR_ASSERT(settings);
1730 
1731  w = xfc->scaledWidth + e->dx;
1732  h = xfc->scaledHeight + e->dy;
1733 
1734  if (e->dx == 0 && e->dy == 0)
1735  return;
1736 
1737  if (w < 10)
1738  w = 10;
1739 
1740  if (h < 10)
1741  h = 10;
1742 
1743  if (w == xfc->scaledWidth && h == xfc->scaledHeight)
1744  return;
1745 
1746  xfc->scaledWidth = w;
1747  xfc->scaledHeight = h;
1748  xf_draw_screen(xfc, 0, 0, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
1749  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
1750 }
1751 
1752 static void xf_PanningChangeEventHandler(void* context, const PanningChangeEventArgs* e)
1753 {
1754  xfContext* xfc = (xfContext*)context;
1755  rdpSettings* settings = NULL;
1756 
1757  WINPR_ASSERT(xfc);
1758  WINPR_ASSERT(e);
1759 
1760  settings = xfc->common.context.settings;
1761  WINPR_ASSERT(settings);
1762 
1763  if (e->dx == 0 && e->dy == 0)
1764  return;
1765 
1766  xfc->offset_x += e->dx;
1767  xfc->offset_y += e->dy;
1768  xf_draw_screen(xfc, 0, 0, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
1769  freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight));
1770 }
1771 #endif
1772 
1777 static BOOL xfreerdp_client_global_init(void)
1778 {
1779  (void)setlocale(LC_ALL, "");
1780 
1781  if (freerdp_handle_signals() != 0)
1782  return FALSE;
1783 
1784  return TRUE;
1785 }
1786 
1787 static void xfreerdp_client_global_uninit(void)
1788 {
1789 }
1790 
1791 static int xfreerdp_client_start(rdpContext* context)
1792 {
1793  xfContext* xfc = (xfContext*)context;
1794  rdpSettings* settings = context->settings;
1795 
1796  if (!freerdp_settings_get_string(settings, FreeRDP_ServerHostname))
1797  {
1798  WLog_ERR(TAG, "error: server hostname was not specified with /v:<server>[:port]");
1799  return -1;
1800  }
1801 
1802  if (!(xfc->common.thread = CreateThread(NULL, 0, xf_client_thread, context->instance, 0, NULL)))
1803  {
1804  WLog_ERR(TAG, "failed to create client thread");
1805  return -1;
1806  }
1807 
1808  return 0;
1809 }
1810 
1811 static Atom get_supported_atom(xfContext* xfc, const char* atomName)
1812 {
1813  const Atom atom = Logging_XInternAtom(xfc->log, xfc->display, atomName, False);
1814 
1815  for (unsigned long i = 0; i < xfc->supportedAtomCount; i++)
1816  {
1817  if (xfc->supportedAtoms[i] == atom)
1818  return atom;
1819  }
1820 
1821  return None;
1822 }
1823 
1824 void xf_teardown_x11(xfContext* xfc)
1825 {
1826  WINPR_ASSERT(xfc);
1827 
1828  if (xfc->display)
1829  {
1830  XCloseDisplay(xfc->display);
1831  xfc->display = NULL;
1832  }
1833 
1834  if (xfc->x11event)
1835  {
1836  (void)CloseHandle(xfc->x11event);
1837  xfc->x11event = NULL;
1838  }
1839 
1840  if (xfc->mutex)
1841  {
1842  (void)CloseHandle(xfc->mutex);
1843  xfc->mutex = NULL;
1844  }
1845 
1846  if (xfc->vscreen.monitors)
1847  {
1848  free(xfc->vscreen.monitors);
1849  xfc->vscreen.monitors = NULL;
1850  }
1851  xfc->vscreen.nmonitors = 0;
1852 
1853  free(xfc->supportedAtoms);
1854  xfc->supportedAtoms = NULL;
1855  xfc->supportedAtomCount = 0;
1856 }
1857 
1858 BOOL xf_setup_x11(xfContext* xfc)
1859 {
1860 
1861  WINPR_ASSERT(xfc);
1862  xfc->UseXThreads = TRUE;
1863 
1864 #if !defined(NDEBUG)
1865  /* uncomment below if debugging to prevent keyboard grap */
1866  xfc->debug = TRUE;
1867 #endif
1868 
1869  if (xfc->UseXThreads)
1870  {
1871  if (!XInitThreads())
1872  {
1873  WLog_WARN(TAG, "XInitThreads() failure");
1874  xfc->UseXThreads = FALSE;
1875  }
1876  }
1877 
1878  xfc->display = XOpenDisplay(NULL);
1879 
1880  if (!xfc->display)
1881  {
1882  WLog_ERR(TAG, "failed to open display: %s", XDisplayName(NULL));
1883  WLog_ERR(TAG, "Please check that the $DISPLAY environment variable is properly set.");
1884  goto fail;
1885  }
1886  if (xfc->debug)
1887  {
1888  WLog_INFO(TAG, "Enabling X11 debug mode.");
1889  XSynchronize(xfc->display, TRUE);
1890  }
1891  def_error_handler = XSetErrorHandler(xf_error_handler_ex);
1892 
1893  xfc->mutex = CreateMutex(NULL, FALSE, NULL);
1894 
1895  if (!xfc->mutex)
1896  {
1897  WLog_ERR(TAG, "Could not create mutex!");
1898  goto fail;
1899  }
1900 
1901  xfc->xfds = ConnectionNumber(xfc->display);
1902  xfc->screen_number = DefaultScreen(xfc->display);
1903  xfc->screen = ScreenOfDisplay(xfc->display, xfc->screen_number);
1904  xfc->big_endian = (ImageByteOrder(xfc->display) == MSBFirst);
1905  xfc->invert = TRUE;
1906  xfc->complex_regions = TRUE;
1907  xfc->_NET_SUPPORTED = Logging_XInternAtom(xfc->log, xfc->display, "_NET_SUPPORTED", True);
1908  xfc->_NET_SUPPORTING_WM_CHECK =
1909  Logging_XInternAtom(xfc->log, xfc->display, "_NET_SUPPORTING_WM_CHECK", True);
1910 
1911  if ((xfc->_NET_SUPPORTED != None) && (xfc->_NET_SUPPORTING_WM_CHECK != None))
1912  {
1913  Atom actual_type = 0;
1914  int actual_format = 0;
1915  unsigned long nitems = 0;
1916  unsigned long after = 0;
1917  unsigned char* data = NULL;
1918  int status = LogTagAndXGetWindowProperty(
1919  TAG, xfc->display, RootWindowOfScreen(xfc->screen), xfc->_NET_SUPPORTED, 0, 1024, False,
1920  XA_ATOM, &actual_type, &actual_format, &nitems, &after, &data);
1921 
1922  if ((status == Success) && (actual_type == XA_ATOM) && (actual_format == 32))
1923  {
1924  xfc->supportedAtomCount = nitems;
1925  xfc->supportedAtoms = calloc(xfc->supportedAtomCount, sizeof(Atom));
1926  WINPR_ASSERT(xfc->supportedAtoms);
1927  memcpy(xfc->supportedAtoms, data, nitems * sizeof(Atom));
1928  }
1929 
1930  if (data)
1931  XFree(data);
1932  }
1933 
1934  xfc->_XWAYLAND_MAY_GRAB_KEYBOARD =
1935  Logging_XInternAtom(xfc->log, xfc->display, "_XWAYLAND_MAY_GRAB_KEYBOARD", False);
1936  xfc->_NET_WM_ICON = Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_ICON", False);
1937  xfc->_MOTIF_WM_HINTS = Logging_XInternAtom(xfc->log, xfc->display, "_MOTIF_WM_HINTS", False);
1938  xfc->_NET_NUMBER_OF_DESKTOPS =
1939  Logging_XInternAtom(xfc->log, xfc->display, "_NET_NUMBER_OF_DESKTOPS", False);
1940  xfc->_NET_CURRENT_DESKTOP =
1941  Logging_XInternAtom(xfc->log, xfc->display, "_NET_CURRENT_DESKTOP", False);
1942  xfc->_NET_WORKAREA = Logging_XInternAtom(xfc->log, xfc->display, "_NET_WORKAREA", False);
1943  xfc->_NET_WM_STATE = get_supported_atom(xfc, "_NET_WM_STATE");
1944  xfc->_NET_WM_STATE_MODAL = get_supported_atom(xfc, "_NET_WM_STATE_MODAL");
1945  xfc->_NET_WM_STATE_STICKY = get_supported_atom(xfc, "_NET_WM_STATE_STICKY");
1946  xfc->_NET_WM_STATE_MAXIMIZED_HORZ =
1947  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
1948  xfc->_NET_WM_STATE_MAXIMIZED_VERT =
1949  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
1950  xfc->_NET_WM_STATE_SHADED = get_supported_atom(xfc, "_NET_WM_STATE_SHADED");
1951  xfc->_NET_WM_STATE_SKIP_TASKBAR = get_supported_atom(xfc, "_NET_WM_STATE_SKIP_TASKBAR");
1952  xfc->_NET_WM_STATE_SKIP_PAGER = get_supported_atom(xfc, "_NET_WM_STATE_SKIP_PAGER");
1953  xfc->_NET_WM_STATE_HIDDEN = get_supported_atom(xfc, "_NET_WM_STATE_HIDDEN");
1954  xfc->_NET_WM_STATE_FULLSCREEN = get_supported_atom(xfc, "_NET_WM_STATE_FULLSCREEN");
1955  xfc->_NET_WM_STATE_ABOVE = get_supported_atom(xfc, "_NET_WM_STATE_ABOVE");
1956  xfc->_NET_WM_STATE_BELOW = get_supported_atom(xfc, "_NET_WM_STATE_BELOW");
1957  xfc->_NET_WM_STATE_DEMANDS_ATTENTION =
1958  get_supported_atom(xfc, "_NET_WM_STATE_DEMANDS_ATTENTION");
1959  xfc->_NET_WM_FULLSCREEN_MONITORS = get_supported_atom(xfc, "_NET_WM_FULLSCREEN_MONITORS");
1960  xfc->_NET_WM_NAME = Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_NAME", False);
1961  xfc->_NET_WM_PID = Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_PID", False);
1962  xfc->_NET_WM_WINDOW_TYPE =
1963  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_WINDOW_TYPE", False);
1964  xfc->_NET_WM_WINDOW_TYPE_NORMAL =
1965  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
1966  xfc->_NET_WM_WINDOW_TYPE_DIALOG =
1967  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
1968  xfc->_NET_WM_WINDOW_TYPE_POPUP =
1969  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_WINDOW_TYPE_POPUP", False);
1970  xfc->_NET_WM_WINDOW_TYPE_POPUP_MENU =
1971  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False);
1972  xfc->_NET_WM_WINDOW_TYPE_UTILITY =
1973  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
1974  xfc->_NET_WM_WINDOW_TYPE_DROPDOWN_MENU =
1975  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False);
1976  xfc->_NET_WM_STATE_SKIP_TASKBAR =
1977  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_STATE_SKIP_TASKBAR", False);
1978  xfc->_NET_WM_STATE_SKIP_PAGER =
1979  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_STATE_SKIP_PAGER", False);
1980  xfc->_NET_WM_MOVERESIZE =
1981  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_MOVERESIZE", False);
1982  xfc->_NET_MOVERESIZE_WINDOW =
1983  Logging_XInternAtom(xfc->log, xfc->display, "_NET_MOVERESIZE_WINDOW", False);
1984  xfc->UTF8_STRING = Logging_XInternAtom(xfc->log, xfc->display, "UTF8_STRING", FALSE);
1985  xfc->WM_PROTOCOLS = Logging_XInternAtom(xfc->log, xfc->display, "WM_PROTOCOLS", False);
1986  xfc->WM_DELETE_WINDOW = Logging_XInternAtom(xfc->log, xfc->display, "WM_DELETE_WINDOW", False);
1987  xfc->WM_STATE = Logging_XInternAtom(xfc->log, xfc->display, "WM_STATE", False);
1988  xfc->x11event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfc->xfds, WINPR_FD_READ);
1989 
1990  xfc->NET_WM_ALLOWED_ACTIONS =
1991  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_ALLOWED_ACTIONS", False);
1992 
1993  xfc->NET_WM_ACTION_CLOSE =
1994  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_ACTION_CLOSE", False);
1995  xfc->NET_WM_ACTION_MINIMIZE =
1996  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_ACTION_MINIMIZE", False);
1997  xfc->NET_WM_ACTION_MOVE =
1998  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_ACTION_MOVE", False);
1999  xfc->NET_WM_ACTION_RESIZE =
2000  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_ACTION_RESIZE", False);
2001  xfc->NET_WM_ACTION_MAXIMIZE_HORZ =
2002  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False);
2003  xfc->NET_WM_ACTION_MAXIMIZE_VERT =
2004  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_ACTION_MAXIMIZE_VERT", False);
2005  xfc->NET_WM_ACTION_FULLSCREEN =
2006  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_ACTION_FULLSCREEN", False);
2007  xfc->NET_WM_ACTION_CHANGE_DESKTOP =
2008  Logging_XInternAtom(xfc->log, xfc->display, "_NET_WM_ACTION_CHANGE_DESKTOP", False);
2009 
2010  if (!xfc->x11event)
2011  {
2012  WLog_ERR(TAG, "Could not create xfds event");
2013  goto fail;
2014  }
2015 
2016  xf_check_extensions(xfc);
2017 
2018  xfc->vscreen.monitors = calloc(16, sizeof(MONITOR_INFO));
2019 
2020  if (!xfc->vscreen.monitors)
2021  goto fail;
2022  return TRUE;
2023 
2024 fail:
2025  xf_teardown_x11(xfc);
2026  return FALSE;
2027 }
2028 
2029 static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
2030 {
2031  xfContext* xfc = (xfContext*)instance->context;
2032  WINPR_ASSERT(context);
2033  WINPR_ASSERT(xfc);
2034  WINPR_ASSERT(!xfc->display);
2035  WINPR_ASSERT(!xfc->mutex);
2036  WINPR_ASSERT(!xfc->x11event);
2037  instance->PreConnect = xf_pre_connect;
2038  instance->PostConnect = xf_post_connect;
2039  instance->PostDisconnect = xf_post_disconnect;
2040  instance->PostFinalDisconnect = xf_post_final_disconnect;
2041  instance->LogonErrorInfo = xf_logon_error_info;
2042  instance->GetAccessToken = client_cli_get_access_token;
2043  PubSub_SubscribeTerminate(context->pubSub, xf_TerminateEventHandler);
2044 #ifdef WITH_XRENDER
2045  PubSub_SubscribeZoomingChange(context->pubSub, xf_ZoomingChangeEventHandler);
2046  PubSub_SubscribePanningChange(context->pubSub, xf_PanningChangeEventHandler);
2047 #endif
2048  xfc->log = WLog_Get(TAG);
2049 
2050  return TRUE;
2051 }
2052 
2053 static void xfreerdp_client_free(freerdp* instance, rdpContext* context)
2054 {
2055  if (!context)
2056  return;
2057 
2058  if (context->pubSub)
2059  {
2060  PubSub_UnsubscribeTerminate(context->pubSub, xf_TerminateEventHandler);
2061 #ifdef WITH_XRENDER
2062  PubSub_UnsubscribeZoomingChange(context->pubSub, xf_ZoomingChangeEventHandler);
2063  PubSub_UnsubscribePanningChange(context->pubSub, xf_PanningChangeEventHandler);
2064 #endif
2065  }
2066 }
2067 
2068 int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
2069 {
2070  pEntryPoints->Version = 1;
2071  pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
2072  pEntryPoints->GlobalInit = xfreerdp_client_global_init;
2073  pEntryPoints->GlobalUninit = xfreerdp_client_global_uninit;
2074  pEntryPoints->ContextSize = sizeof(xfContext);
2075  pEntryPoints->ClientNew = xfreerdp_client_new;
2076  pEntryPoints->ClientFree = xfreerdp_client_free;
2077  pEntryPoints->ClientStart = xfreerdp_client_start;
2078  pEntryPoints->ClientStop = freerdp_client_common_stop;
2079  return 0;
2080 }
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.