25 #include <freerdp/config.h>
28 #include <winpr/assert.h>
29 #include <winpr/sspicli.h>
34 #include <X11/Xutil.h>
35 #include <X11/Xatom.h>
38 #include <X11/extensions/Xrender.h>
42 #include <X11/extensions/XInput.h>
43 #include <X11/extensions/XInput2.h>
47 #include <X11/Xcursor/Xcursor.h>
51 #include <X11/extensions/Xinerama.h>
54 #include <X11/XKBlib.h>
65 #include <sys/types.h>
66 #include <sys/select.h>
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>
77 #include <freerdp/utils/signal.h>
78 #include <freerdp/utils/passphrase.h>
79 #include <freerdp/client/cliprdr.h>
80 #include <freerdp/client/channels.h>
82 #include <freerdp/client/file.h>
83 #include <freerdp/client/cmdline.h>
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>
92 #if defined(CHANNEL_TSMF_CLIENT)
97 #include "xf_cliprdr.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"
108 #include <freerdp/log.h>
109 #define TAG CLIENT_TAG("x11")
111 #define MIN_PIXEL_DIFF 0.001
113 struct xf_exit_code_map_t
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 }
149 static BOOL xf_setup_x11(xfContext* xfc);
150 static void xf_teardown_x11(xfContext* xfc);
152 static int xf_map_error_to_exit_code(DWORD error)
154 for (
size_t x = 0; x < ARRAYSIZE(xf_exit_code_map); x++)
156 const struct xf_exit_code_map_t* cur = &xf_exit_code_map[x];
157 if (cur->error == error)
161 return XF_EXIT_CONN_FAILED;
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);
170 static void xf_draw_screen_scaled(xfContext* xfc,
int x,
int y,
int w,
int h)
172 XTransform transform = { 0 };
173 Picture windowPicture = 0;
174 Picture primaryPicture = 0;
175 XRenderPictureAttributes pa;
176 XRenderPictFormat* picFormat = NULL;
179 const char* filter = NULL;
182 rdpSettings* settings = xfc->common.context.settings;
183 WINPR_ASSERT(settings);
185 if (xfc->scaledWidth <= 0 || xfc->scaledHeight <= 0)
187 WLog_ERR(TAG,
"the current window dimensions are invalid");
194 WLog_ERR(TAG,
"the window dimensions are invalid");
198 const double xScalingFactor = 1.0 *
200 (double)xfc->scaledWidth;
201 const double yScalingFactor = 1.0 *
203 (double)xfc->scaledHeight;
204 XSetFillStyle(xfc->display, xfc->gc, FillSolid);
205 XSetForeground(xfc->display, xfc->gc, 0);
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);
215 if (XSubtractRegion(reg1, reg2, reg1) && !XEmptyRegion(reg1))
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);
223 XDestroyRegion(reg1);
224 XDestroyRegion(reg2);
226 picFormat = XRenderFindVisualFormat(xfc->display, xfc->visual);
227 pa.subwindow_mode = IncludeInferiors;
229 XRenderCreatePicture(xfc->display, xfc->primary, picFormat, CPSubwindowMode, &pa);
231 XRenderCreatePicture(xfc->display, xfc->window->handle, picFormat, CPSubwindowMode, &pa);
234 filter = FilterBilinear;
235 if (fabs(xScalingFactor - yScalingFactor) < MIN_PIXEL_DIFF)
237 const double inverseX = 1.0 / xScalingFactor;
238 const double inverseRoundedX = round(inverseX);
239 const double absInverse = fabs(inverseX - inverseRoundedX);
241 if (absInverse < MIN_PIXEL_DIFF)
242 filter = FilterNearest;
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);
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);
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);
273 BOOL xf_picture_transform_required(xfContext* xfc)
275 rdpSettings* settings = NULL;
279 settings = xfc->common.context.settings;
280 WINPR_ASSERT(settings);
282 if ((xfc->offset_x != 0) || (xfc->offset_y != 0) ||
293 void xf_draw_screen_(xfContext* xfc,
int x,
int y,
int w,
int h,
const char* fkt,
const char* file,
298 WLog_DBG(TAG,
"called from [%s] xfc=%p", fkt, xfc);
302 if (w == 0 || h == 0)
304 WLog_WARN(TAG,
"invalid width and/or height specified: w=%d h=%d", w, h);
310 WLog_WARN(TAG,
"invalid xfc->window=%p", xfc->window);
316 if (xf_picture_transform_required(xfc))
318 xf_draw_screen_scaled(xfc, x, y, w, h);
323 XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y);
326 static BOOL xf_desktop_resize(rdpContext* context)
328 rdpSettings* settings = NULL;
329 xfContext* xfc = (xfContext*)context;
333 settings = context->settings;
334 WINPR_ASSERT(settings);
338 BOOL same = (xfc->primary == xfc->drawing) ? TRUE : FALSE;
339 XFreePixmap(xfc->display, xfc->primary);
341 WINPR_ASSERT(xfc->depth != 0);
342 if (!(xfc->primary = XCreatePixmap(
343 xfc->display, xfc->drawable,
349 xfc->drawing = xfc->primary;
362 if (!xfc->fullscreen)
364 xf_ResizeDesktopWindow(xfc, xfc->window,
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,
392 static BOOL xf_paint(xfContext* xfc,
const GDI_RGN* region)
395 WINPR_ASSERT(region);
401 .right = region->x + region->w,
402 .bottom = region->y + region->h };
403 xf_rail_paint(xfc, &rect);
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);
414 static BOOL xf_end_paint(rdpContext* context)
416 xfContext* xfc = (xfContext*)context;
417 rdpGdi* gdi = context->gdi;
419 if (gdi->suppressOutput)
422 HGDI_DC hdc = gdi->primary->hdc;
424 if (!xfc->complex_regions)
426 const GDI_RGN* rgn = hdc->hwnd->invalid;
430 if (!xf_paint(xfc, rgn))
436 const INT32 ninvalid = hdc->hwnd->ninvalid;
437 const GDI_RGN* cinvalid = hdc->hwnd->cinvalid;
439 if (hdc->hwnd->ninvalid < 1)
444 for (INT32 i = 0; i < ninvalid; i++)
446 const GDI_RGN* rgn = &cinvalid[i];
447 if (!xf_paint(xfc, rgn))
451 XFlush(xfc->display);
455 hdc->hwnd->invalid->null = TRUE;
456 hdc->hwnd->ninvalid = 0;
460 static BOOL xf_sw_desktop_resize(rdpContext* context)
462 rdpGdi* gdi = context->gdi;
463 xfContext* xfc = (xfContext*)context;
464 rdpSettings* settings = context->settings;
476 xfc->image->data = NULL;
477 XDestroyImage(xfc->image);
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)))
488 xfc->image->byte_order = LSBFirst;
489 xfc->image->bitmap_bit_order = LSBFirst;
490 ret = xf_desktop_resize(context);
496 static BOOL xf_process_x_events(freerdp* instance)
499 int pending_status = 1;
500 xfContext* xfc = (xfContext*)instance->context;
502 while (pending_status)
505 pending_status = XPending(xfc->display);
509 XEvent xevent = { 0 };
511 XNextEvent(xfc->display, &xevent);
512 status = xf_event_process(instance, &xevent);
522 static char* xf_window_get_title(rdpSettings* settings)
525 char* windowTitle = NULL;
527 const char* prefix =
"FreeRDP:";
536 return _strdup(title);
540 size = strnlen(name, MAX_PATH) + 16;
541 windowTitle = calloc(size,
sizeof(
char));
547 (void)sprintf_s(windowTitle, size,
"%s %s", prefix, name);
549 (
void)sprintf_s(windowTitle, size,
"%s %s:%" PRIu32, prefix, name,
555 BOOL xf_create_window(xfContext* xfc)
557 XGCValues gcv = { 0 };
558 XEvent xevent = { 0 };
559 char* windowTitle = NULL;
562 rdpSettings* settings = xfc->common.context.settings;
563 WINPR_ASSERT(settings);
568 const XSetWindowAttributes empty = { 0 };
569 xfc->attribs = empty;
574 xfc->depth = DefaultDepthOfScreen(xfc->screen);
576 XVisualInfo vinfo = { 0 };
577 if (XMatchVisualInfo(xfc->display, xfc->screen_number, xfc->depth, TrueColor, &vinfo))
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);
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, ...)");
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);
600 if (vinfo.red_mask & 0xFF)
605 if (!xfc->remote_app)
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;
612 xfc->attribs.bit_gravity = NorthWestGravity;
613 xfc->attribs.win_gravity = NorthWestGravity;
614 xfc->attribs_mask = CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
615 CWBorderPixel | CWWinGravity | CWBitGravity;
621 windowTitle = xf_window_get_title(settings);
636 xfc->scaledWidth = width;
637 xfc->scaledHeight = height;
641 xfc->window = xf_CreateDesktopWindow(xfc, windowTitle, width, height);
645 xf_SetWindowFullscreen(xfc, xfc->window, xfc->fullscreen);
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;
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;
658 xfc->attribs.bit_gravity = NorthWestGravity;
659 xfc->attribs.win_gravity = NorthWestGravity;
660 xfc->attribs_mask = CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
661 CWBorderPixel | CWWinGravity | CWBitGravity;
663 xfc->drawable = xf_CreateDummyWindow(xfc);
667 xfc->gc = XCreateGC(xfc->display, xfc->drawable, GCGraphicsExposures, &gcv);
669 WINPR_ASSERT(xfc->depth != 0);
672 XCreatePixmap(xfc->display, xfc->drawable,
676 xfc->drawing = xfc->primary;
678 if (!xfc->bitmap_mono)
679 xfc->bitmap_mono = XCreatePixmap(xfc->display, xfc->drawable, 8, 8, 1);
682 xfc->gc_mono = XCreateGC(xfc->display, xfc->bitmap_mono, GCGraphicsExposures, &gcv);
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,
690 XFlush(xfc->display);
695 BOOL xf_create_image(xfContext* xfc)
700 const rdpSettings* settings = xfc->common.context.settings;
701 rdpGdi* cgdi = xfc->common.context.gdi;
704 WINPR_ASSERT(xfc->depth != 0);
705 xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0,
706 (
char*)cgdi->primary_buffer,
709 xfc->scanline_pad, cgdi->stride);
710 xfc->image->byte_order = LSBFirst;
711 xfc->image->bitmap_bit_order = LSBFirst;
716 static void xf_window_free(xfContext* xfc)
720 xf_DestroyDesktopWindow(xfc, xfc->window);
724 #if defined(CHANNEL_TSMF_CLIENT)
727 xf_tsmf_uninit(xfc, NULL);
728 xfc->xv_context = NULL;
734 xfc->image->data = NULL;
735 XDestroyImage(xfc->image);
739 if (xfc->bitmap_mono)
741 XFreePixmap(xfc->display, xfc->bitmap_mono);
742 xfc->bitmap_mono = 0;
747 XFreeGC(xfc->display, xfc->gc_mono);
753 XFreePixmap(xfc->display, xfc->primary);
759 XFreeGC(xfc->display, xfc->gc);
764 void xf_toggle_fullscreen(xfContext* xfc)
766 WindowStateChangeEventArgs e = { 0 };
767 rdpContext* context = (rdpContext*)xfc;
768 rdpSettings* settings = context->settings;
777 xfc->fullscreen = (xfc->fullscreen) ? FALSE : TRUE;
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);
786 void xf_minimize(xfContext* xfc)
788 WindowStateChangeEventArgs e = { 0 };
789 rdpContext* context = (rdpContext*)xfc;
790 WINPR_ASSERT(context);
799 xf_SetWindowMinimized(xfc, xfc->window);
801 e.state = xfc->fullscreen ? FREERDP_WINDOW_STATE_FULLSCREEN : 0;
802 PubSub_OnWindowStateChange(context->pubSub, context, &e);
805 void xf_lock_x11_(xfContext* xfc,
const char* fkt)
808 if (!xfc->UseXThreads)
809 (void)WaitForSingleObject(xfc->mutex, INFINITE);
811 XLockDisplay(xfc->display);
814 #ifdef WITH_DEBUG_X11
815 WLog_VRB(TAG,
"[%" PRIu32
"] from %s", xfc->locked, fkt);
819 void xf_unlock_x11_(xfContext* xfc,
const char* fkt)
821 if (xfc->locked == 0)
822 WLog_WARN(TAG,
"X11: trying to unlock although not locked!");
826 #ifdef WITH_DEBUG_X11
827 WLog_VRB(TAG,
"[%" PRIu32
"] from %s", xfc->locked, fkt);
830 if (!xfc->UseXThreads)
831 (void)ReleaseMutex(xfc->mutex);
833 XUnlockDisplay(xfc->display);
836 static BOOL xf_get_pixmap_info(xfContext* xfc)
839 XPixmapFormatValues* pfs = NULL;
841 WINPR_ASSERT(xfc->display);
842 pfs = XListPixmapFormats(xfc->display, &pf_count);
846 WLog_ERR(TAG,
"XListPixmapFormats failed");
850 WINPR_ASSERT(xfc->depth != 0);
851 for (
int i = 0; i < pf_count; i++)
853 const XPixmapFormatValues* pf = &pfs[i];
855 if (pf->depth == xfc->depth)
857 xfc->scanline_pad = pf->scanline_pad;
863 if ((xfc->visual == NULL) || (xfc->scanline_pad == 0))
869 static int xf_error_handler(Display* d, XErrorEvent* ev)
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);
877 const BOOL do_abort = TRUE;
882 if (def_error_handler)
883 return def_error_handler(d, ev);
888 static int xf_error_handler_ex(Display* d, XErrorEvent* ev)
896 XUngrabKeyboard(d, CurrentTime);
897 XUngrabPointer(d, CurrentTime);
898 return xf_error_handler(d, ev);
901 static BOOL xf_play_sound(rdpContext* context,
const PLAY_SOUND_UPDATE* play_sound)
903 xfContext* xfc = (xfContext*)context;
904 WINPR_UNUSED(play_sound);
905 XkbBell(xfc->display, None, 100, 0);
909 static void xf_check_extensions(xfContext* context)
914 int xkb_major = XkbMajorVersion;
915 int xkb_minor = XkbMinorVersion;
917 if (XkbLibraryVersion(&xkb_major, &xkb_minor) &&
918 XkbQueryExtension(context->display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major,
921 context->xkbAvailable = TRUE;
926 int xrender_event_base = 0;
927 int xrender_error_base = 0;
929 if (XRenderQueryExtension(context->display, &xrender_event_base, &xrender_error_base))
931 context->xrenderAvailable = TRUE;
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);
944 static void xf_get_x11_button_map(xfContext* xfc,
unsigned char* x11_map)
950 XDevice* ptr_dev = NULL;
951 XExtensionVersion* version = NULL;
952 XDeviceInfo* devices1 = NULL;
953 XIDeviceInfo* devices2 = NULL;
956 if (XQueryExtension(xfc->display,
"XInputExtension", &opcode, &event, &error))
958 WLog_DBG(TAG,
"Searching for XInput pointer device");
961 version = XGetExtensionVersion(xfc->display, INAME);
963 if (version->major_version >= 2)
966 devices2 = XIQueryDevice(xfc->display, XIAllDevices, &num_devices);
970 for (
int i = 0; i < num_devices; ++i)
972 if ((devices2[i].use == XISlavePointer) &&
973 (strncmp(devices2[i].name, TEST_PTR_STR, TEST_PTR_LEN) != 0))
975 ptr_dev = XOpenDevice(xfc->display, devices2[i].deviceid);
981 XIFreeDeviceInfo(devices2);
987 devices1 = XListInputDevices(xfc->display, &num_devices);
991 for (
int i = 0; i < num_devices; ++i)
993 if ((devices1[i].use == IsXExtensionPointer) &&
994 (strncmp(devices1[i].name, TEST_PTR_STR, TEST_PTR_LEN) != 0))
996 ptr_dev = XOpenDevice(xfc->display, devices1[i].id);
1002 XFreeDeviceList(devices1);
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);
1018 WLog_DBG(TAG,
"No pointer device found!");
1024 WLog_DBG(TAG,
"Get global pointer mapping (no XInput)");
1025 XGetPointerMapping(xfc->display, x11_map, NUM_BUTTONS_MAPPED);
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 },
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 }
1046 static UINT16 get_flags_for_button(
size_t button)
1048 for (
size_t x = 0; x < ARRAYSIZE(xf_button_flags); x++)
1052 if (map->button == button)
1059 static void xf_button_map_init(xfContext* xfc)
1066 unsigned char x11_map[112] = { 0 };
1069 WINPR_ASSERT(xfc->common.context.settings);
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;
1086 xf_get_x11_button_map(xfc, x11_map);
1092 for (
size_t physical = 0; physical < ARRAYSIZE(x11_map); ++physical)
1094 const unsigned char logical = x11_map[physical];
1095 const UINT16 flags = get_flags_for_button(logical);
1097 if ((logical != 0) && (flags != 0))
1099 if (pos >= NUM_BUTTONS_MAPPED)
1101 WLog_ERR(TAG,
"Failed to map mouse button to RDP button, no space");
1106 map->button = logical;
1107 map->flags = get_flags_for_button(physical + Button1);
1124 static BOOL xf_pre_connect(freerdp* instance)
1126 rdpChannels* channels = NULL;
1127 rdpSettings* settings = NULL;
1128 rdpContext* context = NULL;
1129 xfContext* xfc = NULL;
1130 UINT32 maxWidth = 0;
1131 UINT32 maxHeight = 0;
1133 WINPR_ASSERT(instance);
1135 context = instance->context;
1136 xfc = (xfContext*)instance->context;
1137 WINPR_ASSERT(context);
1139 settings = context->settings;
1140 WINPR_ASSERT(settings);
1147 if (!xf_setup_x11(xfc))
1151 channels = context->channels;
1152 WINPR_ASSERT(channels);
1158 PubSub_SubscribeChannelConnected(context->pubSub, xf_OnChannelConnectedEventHandler);
1159 PubSub_SubscribeChannelDisconnected(context->pubSub, xf_OnChannelDisconnectedEventHandler);
1165 char login_name[MAX_PATH] = { 0 };
1166 ULONG size =
sizeof(login_name) - 1;
1168 if (GetUserNameExA(NameSamCompatible, login_name, &size))
1173 WLog_INFO(TAG,
"No user name set. - Using login name: %s",
1183 WLog_INFO(TAG,
"auth-only, but no password set. Please provide one.");
1187 WLog_INFO(TAG,
"Authentication only. Don't connect to X.");
1192 if (!xf_keyboard_init(xfc))
1194 if (!xf_detect_monitors(xfc, &maxWidth, &maxHeight))
1218 settings, FreeRDP_DesktopWidth,
1222 settings, FreeRDP_DesktopHeight,
1233 xf_button_map_init(xfc);
1237 static BOOL xf_inject_keypress(rdpContext* context,
const char* buffer,
size_t size)
1239 WCHAR wbuffer[64] = { 0 };
1240 const SSIZE_T len = ConvertUtf8NToWChar(buffer, size, wbuffer, ARRAYSIZE(wbuffer));
1244 rdpInput* input = context->input;
1245 WINPR_ASSERT(input);
1247 for (SSIZE_T x = 0; x < len; x++)
1249 const WCHAR code = wbuffer[x];
1250 freerdp_input_send_unicode_keyboard_event(input, 0, code);
1252 freerdp_input_send_unicode_keyboard_event(input, KBD_FLAGS_RELEASE, code);
1258 static BOOL xf_process_pipe(rdpContext* context,
const char* pipe)
1260 int fd = open(pipe, O_NONBLOCK | O_RDONLY);
1263 char ebuffer[256] = { 0 };
1264 WLog_ERR(TAG,
"pipe '%s' open returned %s [%d]", pipe,
1265 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1268 while (!freerdp_shall_disconnect_context(context))
1270 char buffer[64] = { 0 };
1271 ssize_t rd = read(fd, buffer,
sizeof(buffer) - 1);
1274 char ebuffer[256] = { 0 };
1275 if ((errno == EAGAIN) || (errno == 0))
1282 WLog_ERR(TAG,
"pipe '%s' read returned %s [%d]", pipe,
1283 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1288 char ebuffer[256] = { 0 };
1289 WLog_ERR(TAG,
"pipe '%s' read returned %s [%d]", pipe,
1290 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1295 if (!xf_inject_keypress(context, buffer, rd))
1303 static void cleanup_pipe(
int signum,
const char* signame,
void* context)
1305 const char* pipe = context;
1311 static DWORD WINAPI xf_handle_pipe(
void* arg)
1313 xfContext* xfc = arg;
1316 rdpContext* context = &xfc->common.context;
1317 WINPR_ASSERT(context);
1319 rdpSettings* settings = context->settings;
1320 WINPR_ASSERT(settings);
1325 const int rc = mkfifo(pipe, S_IWUSR | S_IRUSR);
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);
1334 void* ctx = WINPR_CAST_CONST_PTR_AWAY(pipe,
void*);
1335 freerdp_add_signal_cleanup_handler(ctx, cleanup_pipe);
1337 xf_process_pipe(context, pipe);
1339 freerdp_del_signal_cleanup_handler(ctx, cleanup_pipe);
1350 static BOOL xf_post_connect(freerdp* instance)
1352 ResizeWindowEventArgs e = { 0 };
1354 WINPR_ASSERT(instance);
1355 xfContext* xfc = (xfContext*)instance->context;
1356 rdpContext* context = instance->context;
1357 WINPR_ASSERT(context);
1359 rdpSettings* settings = context->settings;
1360 WINPR_ASSERT(settings);
1362 rdpUpdate* update = context->update;
1363 WINPR_ASSERT(update);
1366 xfc->remote_app = TRUE;
1368 if (!xf_create_window(xfc))
1371 if (!xf_get_pixmap_info(xfc))
1374 if (!gdi_init(instance, xf_get_local_color_format(xfc, TRUE)))
1377 if (!xf_create_image(xfc))
1380 if (!xf_register_pointer(context->graphics))
1390 if (!xfc->xrenderAvailable)
1394 WLog_ERR(TAG,
"XRender not available: disabling smart-sizing");
1401 WLog_ERR(TAG,
"XRender not available: disabling local multi-touch gestures");
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;
1413 const BOOL serverIsWindowsPlatform =
1416 !(xfc->clipboard = xf_clipboard_new(xfc, !serverIsWindowsPlatform)))
1419 if (!(xfc->xfDisp = xf_disp_new(xfc)))
1425 xfc->pipethread = CreateThread(NULL, 0, xf_handle_pipe, xfc, 0, NULL);
1426 if (!xfc->pipethread)
1430 EventArgsInit(&e,
"xfreerdp");
1433 PubSub_OnResizeWindow(context->pubSub, xfc, &e);
1437 static void xf_post_disconnect(freerdp* instance)
1439 xfContext* xfc = NULL;
1440 rdpContext* context = NULL;
1442 if (!instance || !instance->context)
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);
1453 if (xfc->pipethread)
1455 (void)WaitForSingleObject(xfc->pipethread, INFINITE);
1456 (void)CloseHandle(xfc->pipethread);
1457 xfc->pipethread = NULL;
1461 xf_clipboard_free(xfc->clipboard);
1462 xfc->clipboard = NULL;
1467 xf_disp_free(xfc->xfDisp);
1471 if ((xfc->window != NULL) && (xfc->drawable == xfc->window->handle))
1474 xf_DestroyDummyWindow(xfc, xfc->drawable);
1476 xf_window_free(xfc);
1479 static void xf_post_final_disconnect(freerdp* instance)
1481 xfContext* xfc = NULL;
1482 rdpContext* context = NULL;
1484 if (!instance || !instance->context)
1487 context = instance->context;
1488 xfc = (xfContext*)context;
1490 xf_keyboard_free(xfc);
1491 xf_teardown_x11(xfc);
1494 static int xf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
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)
1502 xf_rail_disable_remoteapp_mode(xfc);
1507 static BOOL handle_window_events(freerdp* instance)
1509 if (!xf_process_x_events(instance))
1511 WLog_DBG(TAG,
"Closed from X11");
1526 static DWORD WINAPI xf_client_thread(LPVOID param)
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 };
1535 EventArgsInit(&timerEvent,
"xfreerdp");
1536 freerdp* instance = (freerdp*)param;
1537 WINPR_ASSERT(instance);
1539 const BOOL status = freerdp_connect(instance);
1540 rdpContext* context = instance->context;
1541 WINPR_ASSERT(context);
1542 xfContext* xfc = (xfContext*)instance->context;
1545 rdpSettings* settings = context->settings;
1546 WINPR_ASSERT(settings);
1550 UINT32 error = freerdp_get_last_error(instance->context);
1551 exit_code = xf_map_error_to_exit_code(error);
1554 exit_code = XF_EXIT_SUCCESS;
1562 WLog_ERR(TAG,
"Authentication only, exit status %" PRId32
"", !status);
1568 WLog_ERR(TAG,
"Freerdp connect error exit status %" PRId32
"", !status);
1569 exit_code = freerdp_error_info(instance);
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;
1579 timer = CreateWaitableTimerA(NULL, FALSE,
"mainloop-periodic-timer");
1583 WLog_ERR(TAG,
"failed to create timer");
1589 if (!SetWaitableTimer(timer, &due, 20, NULL, NULL, FALSE))
1593 inputEvent = xfc->x11event;
1595 while (!freerdp_shall_disconnect_context(instance->context))
1597 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
1599 handles[nCount++] = timer;
1600 handles[nCount++] = inputEvent;
1607 if (freerdp_focus_required(instance))
1609 xf_keyboard_focus_in(xfc);
1610 xf_keyboard_focus_in(xfc);
1615 freerdp_get_event_handles(context, &handles[nCount], ARRAYSIZE(handles) - nCount);
1619 WLog_ERR(TAG,
"freerdp_get_event_handles failed");
1627 xf_floatbar_hide_and_show(xfc->window->floatbar);
1629 waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
1631 if (waitStatus == WAIT_FAILED)
1635 if (!freerdp_check_event_handles(context))
1637 if (client_auto_reconnect_ex(instance, handle_window_events))
1645 const UINT32 error = freerdp_get_last_error(instance->context);
1647 if (freerdp_error_info(instance) == 0)
1648 exit_code = xf_map_error_to_exit_code(error);
1651 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
1652 WLog_ERR(TAG,
"Failed to check FreeRDP file descriptor");
1658 if (!handle_window_events(instance))
1661 if ((waitStatus != WAIT_TIMEOUT) && (waitStatus == WAIT_OBJECT_0))
1663 timerEvent.now = GetTickCount64();
1664 PubSub_OnTimer(context->pubSub, context, &timerEvent);
1670 exit_code = freerdp_error_info(instance);
1672 if (exit_code == XF_EXIT_DISCONNECT &&
1673 freerdp_get_disconnect_ultimatum(context) == Disconnect_Ultimatum_user_requested)
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;
1685 (void)CloseHandle(timer);
1687 freerdp_disconnect(instance);
1689 ExitThread(exit_code);
1693 int xf_exit_code_from_disconnect_reason(DWORD reason)
1696 (reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS))
1699 else if (reason >= 0x100 && reason <= 0x10A)
1700 reason -= 0x100 + XF_EXIT_LICENSE_INTERNAL;
1702 else if (reason >= 0x10c9 && reason <= 0x1193)
1703 reason = XF_EXIT_RDP;
1705 else if (!(reason <= 0xC))
1706 reason = XF_EXIT_UNKNOWN;
1711 static void xf_TerminateEventHandler(
void* context,
const TerminateEventArgs* e)
1713 rdpContext* ctx = (rdpContext*)context;
1715 freerdp_abort_connect_context(ctx);
1719 static void xf_ZoomingChangeEventHandler(
void* context,
const ZoomingChangeEventArgs* e)
1723 rdpSettings* settings = NULL;
1724 xfContext* xfc = (xfContext*)context;
1728 settings = xfc->common.context.settings;
1729 WINPR_ASSERT(settings);
1731 w = xfc->scaledWidth + e->dx;
1732 h = xfc->scaledHeight + e->dy;
1734 if (e->dx == 0 && e->dy == 0)
1743 if (w == xfc->scaledWidth && h == xfc->scaledHeight)
1746 xfc->scaledWidth = w;
1747 xfc->scaledHeight = h;
1752 static void xf_PanningChangeEventHandler(
void* context,
const PanningChangeEventArgs* e)
1754 xfContext* xfc = (xfContext*)context;
1755 rdpSettings* settings = NULL;
1760 settings = xfc->common.context.settings;
1761 WINPR_ASSERT(settings);
1763 if (e->dx == 0 && e->dy == 0)
1766 xfc->offset_x += e->dx;
1767 xfc->offset_y += e->dy;
1777 static BOOL xfreerdp_client_global_init(
void)
1779 (void)setlocale(LC_ALL,
"");
1781 if (freerdp_handle_signals() != 0)
1787 static void xfreerdp_client_global_uninit(
void)
1791 static int xfreerdp_client_start(rdpContext* context)
1793 xfContext* xfc = (xfContext*)context;
1794 rdpSettings* settings = context->settings;
1798 WLog_ERR(TAG,
"error: server hostname was not specified with /v:<server>[:port]");
1802 if (!(xfc->common.thread = CreateThread(NULL, 0, xf_client_thread, context->instance, 0, NULL)))
1804 WLog_ERR(TAG,
"failed to create client thread");
1811 static Atom get_supported_atom(xfContext* xfc,
const char* atomName)
1813 const Atom atom = Logging_XInternAtom(xfc->log, xfc->display, atomName, False);
1815 for (
unsigned long i = 0; i < xfc->supportedAtomCount; i++)
1817 if (xfc->supportedAtoms[i] == atom)
1824 void xf_teardown_x11(xfContext* xfc)
1830 XCloseDisplay(xfc->display);
1831 xfc->display = NULL;
1836 (void)CloseHandle(xfc->x11event);
1837 xfc->x11event = NULL;
1842 (void)CloseHandle(xfc->mutex);
1846 if (xfc->vscreen.monitors)
1848 free(xfc->vscreen.monitors);
1849 xfc->vscreen.monitors = NULL;
1851 xfc->vscreen.nmonitors = 0;
1853 free(xfc->supportedAtoms);
1854 xfc->supportedAtoms = NULL;
1855 xfc->supportedAtomCount = 0;
1858 BOOL xf_setup_x11(xfContext* xfc)
1862 xfc->UseXThreads = TRUE;
1864 #if !defined(NDEBUG)
1869 if (xfc->UseXThreads)
1871 if (!XInitThreads())
1873 WLog_WARN(TAG,
"XInitThreads() failure");
1874 xfc->UseXThreads = FALSE;
1878 xfc->display = XOpenDisplay(NULL);
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.");
1888 WLog_INFO(TAG,
"Enabling X11 debug mode.");
1889 XSynchronize(xfc->display, TRUE);
1891 def_error_handler = XSetErrorHandler(xf_error_handler_ex);
1893 xfc->mutex = CreateMutex(NULL, FALSE, NULL);
1897 WLog_ERR(TAG,
"Could not create mutex!");
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);
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);
1911 if ((xfc->_NET_SUPPORTED != None) && (xfc->_NET_SUPPORTING_WM_CHECK != None))
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);
1922 if ((status == Success) && (actual_type == XA_ATOM) && (actual_format == 32))
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));
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);
1990 xfc->NET_WM_ALLOWED_ACTIONS =
1991 Logging_XInternAtom(xfc->log, xfc->display,
"_NET_WM_ALLOWED_ACTIONS", False);
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);
2012 WLog_ERR(TAG,
"Could not create xfds event");
2016 xf_check_extensions(xfc);
2018 xfc->vscreen.monitors = calloc(16,
sizeof(MONITOR_INFO));
2020 if (!xfc->vscreen.monitors)
2025 xf_teardown_x11(xfc);
2029 static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
2031 xfContext* xfc = (xfContext*)instance->context;
2032 WINPR_ASSERT(context);
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);
2045 PubSub_SubscribeZoomingChange(context->pubSub, xf_ZoomingChangeEventHandler);
2046 PubSub_SubscribePanningChange(context->pubSub, xf_PanningChangeEventHandler);
2048 xfc->log = WLog_Get(TAG);
2053 static void xfreerdp_client_free(freerdp* instance, rdpContext* context)
2058 if (context->pubSub)
2060 PubSub_UnsubscribeTerminate(context->pubSub, xf_TerminateEventHandler);
2062 PubSub_UnsubscribeZoomingChange(context->pubSub, xf_ZoomingChangeEventHandler);
2063 PubSub_UnsubscribePanningChange(context->pubSub, xf_PanningChangeEventHandler);
2068 int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
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;
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.