1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 *
4 * Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
5 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
6 * Copyright 2017 Thincast Technologies GmbH
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include <sys/ipc.h>
28 #include <sys/shm.h>
29 #include <sys/select.h>
30 #include <sys/signal.h>
31
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34
35 #include <winpr/crt.h>
36 #include <winpr/path.h>
37 #include <winpr/synch.h>
38 #include <winpr/image.h>
39 #include <winpr/sysinfo.h>
40
41 #include <freerdp/log.h>
42 #include <freerdp/codec/color.h>
43 #include <freerdp/codec/region.h>
44
45 #include "x11_shadow.h"
46
47 #define TAG SERVER_TAG("shadow.x11")
48
49 static UINT32 x11_shadow_enum_monitors(MONITOR_DEF* monitors, UINT32 maxMonitors);
50
51 #ifdef WITH_PAM
52
53 #include <security/pam_appl.h>
54
55 struct _SHADOW_PAM_AUTH_DATA
56 {
57 const char* user;
58 const char* domain;
59 const char* password;
60 };
61 typedef struct _SHADOW_PAM_AUTH_DATA SHADOW_PAM_AUTH_DATA;
62
63 struct _SHADOW_PAM_AUTH_INFO
64 {
65 char* service_name;
66 pam_handle_t* handle;
67 struct pam_conv pamc;
68 SHADOW_PAM_AUTH_DATA appdata;
69 };
70 typedef struct _SHADOW_PAM_AUTH_INFO SHADOW_PAM_AUTH_INFO;
71
x11_shadow_pam_conv(int num_msg,const struct pam_message ** msg,struct pam_response ** resp,void * appdata_ptr)72 static int x11_shadow_pam_conv(int num_msg, const struct pam_message** msg,
73 struct pam_response** resp, void* appdata_ptr)
74 {
75 int index;
76 int pam_status = PAM_CONV_ERR;
77 SHADOW_PAM_AUTH_DATA* appdata;
78 struct pam_response* response;
79 appdata = (SHADOW_PAM_AUTH_DATA*)appdata_ptr;
80
81 if (!(response = (struct pam_response*)calloc(num_msg, sizeof(struct pam_response))))
82 return PAM_BUF_ERR;
83
84 for (index = 0; index < num_msg; index++)
85 {
86 switch (msg[index]->msg_style)
87 {
88 case PAM_PROMPT_ECHO_ON:
89 response[index].resp = _strdup(appdata->user);
90
91 if (!response[index].resp)
92 goto out_fail;
93
94 response[index].resp_retcode = PAM_SUCCESS;
95 break;
96
97 case PAM_PROMPT_ECHO_OFF:
98 response[index].resp = _strdup(appdata->password);
99
100 if (!response[index].resp)
101 goto out_fail;
102
103 response[index].resp_retcode = PAM_SUCCESS;
104 break;
105
106 default:
107 pam_status = PAM_CONV_ERR;
108 goto out_fail;
109 }
110 }
111
112 *resp = response;
113 return PAM_SUCCESS;
114 out_fail:
115
116 for (index = 0; index < num_msg; ++index)
117 {
118 if (response[index].resp)
119 {
120 memset(response[index].resp, 0, strlen(response[index].resp));
121 free(response[index].resp);
122 }
123 }
124
125 memset(response, 0, sizeof(struct pam_response) * num_msg);
126 free(response);
127 *resp = NULL;
128 return pam_status;
129 }
130
x11_shadow_pam_get_service_name(SHADOW_PAM_AUTH_INFO * info)131 static BOOL x11_shadow_pam_get_service_name(SHADOW_PAM_AUTH_INFO* info)
132 {
133 size_t x;
134 const char* base = "/etc/pam.d";
135 const char* hints[] = { "lightdm", "gdm", "xdm", "login", "sshd" };
136
137 for (x = 0; x < ARRAYSIZE(hints); x++)
138 {
139 char path[MAX_PATH];
140 const char* hint = hints[x];
141
142 _snprintf(path, sizeof(path), "%s/%s", base, hint);
143 if (winpr_PathFileExists(path))
144 {
145
146 info->service_name = _strdup(hint);
147 return info->service_name != NULL;
148 }
149 }
150 WLog_WARN(TAG, "Could not determine PAM service name");
151 return FALSE;
152 }
153
x11_shadow_pam_authenticate(rdpShadowSubsystem * subsystem,rdpShadowClient * client,const char * user,const char * domain,const char * password)154 static int x11_shadow_pam_authenticate(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
155 const char* user, const char* domain, const char* password)
156 {
157 int pam_status;
158 SHADOW_PAM_AUTH_INFO info = { 0 };
159 WINPR_UNUSED(subsystem);
160 WINPR_UNUSED(client);
161
162 if (!x11_shadow_pam_get_service_name(&info))
163 return -1;
164
165 info.appdata.user = user;
166 info.appdata.domain = domain;
167 info.appdata.password = password;
168 info.pamc.conv = &x11_shadow_pam_conv;
169 info.pamc.appdata_ptr = &info.appdata;
170 pam_status = pam_start(info.service_name, 0, &info.pamc, &info.handle);
171
172 if (pam_status != PAM_SUCCESS)
173 {
174 WLog_ERR(TAG, "pam_start failure: %s", pam_strerror(info.handle, pam_status));
175 return -1;
176 }
177
178 pam_status = pam_authenticate(info.handle, 0);
179
180 if (pam_status != PAM_SUCCESS)
181 {
182 WLog_ERR(TAG, "pam_authenticate failure: %s", pam_strerror(info.handle, pam_status));
183 return -1;
184 }
185
186 pam_status = pam_acct_mgmt(info.handle, 0);
187
188 if (pam_status != PAM_SUCCESS)
189 {
190 WLog_ERR(TAG, "pam_acct_mgmt failure: %s", pam_strerror(info.handle, pam_status));
191 return -1;
192 }
193
194 return 1;
195 }
196
197 #endif
198
x11_shadow_input_synchronize_event(rdpShadowSubsystem * subsystem,rdpShadowClient * client,UINT32 flags)199 static BOOL x11_shadow_input_synchronize_event(rdpShadowSubsystem* subsystem,
200 rdpShadowClient* client, UINT32 flags)
201 {
202 /* TODO: Implement */
203 WLog_WARN(TAG, "%s not implemented", __FUNCTION__);
204 return TRUE;
205 }
206
x11_shadow_input_keyboard_event(rdpShadowSubsystem * subsystem,rdpShadowClient * client,UINT16 flags,UINT16 code)207 static BOOL x11_shadow_input_keyboard_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
208 UINT16 flags, UINT16 code)
209 {
210 #ifdef WITH_XTEST
211 x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
212 DWORD vkcode;
213 DWORD keycode;
214 BOOL extended = FALSE;
215
216 if (!client || !subsystem)
217 return FALSE;
218
219 if (flags & KBD_FLAGS_EXTENDED)
220 extended = TRUE;
221
222 if (extended)
223 code |= KBDEXT;
224
225 vkcode = GetVirtualKeyCodeFromVirtualScanCode(code, 4);
226
227 if (extended)
228 vkcode |= KBDEXT;
229
230 keycode = GetKeycodeFromVirtualKeyCode(vkcode, KEYCODE_TYPE_EVDEV);
231
232 if (keycode != 0)
233 {
234 XLockDisplay(x11->display);
235 XTestGrabControl(x11->display, True);
236
237 if (flags & KBD_FLAGS_DOWN)
238 XTestFakeKeyEvent(x11->display, keycode, True, CurrentTime);
239 else if (flags & KBD_FLAGS_RELEASE)
240 XTestFakeKeyEvent(x11->display, keycode, False, CurrentTime);
241
242 XTestGrabControl(x11->display, False);
243 XFlush(x11->display);
244 XUnlockDisplay(x11->display);
245 }
246
247 #endif
248 return TRUE;
249 }
250
x11_shadow_input_unicode_keyboard_event(rdpShadowSubsystem * subsystem,rdpShadowClient * client,UINT16 flags,UINT16 code)251 static BOOL x11_shadow_input_unicode_keyboard_event(rdpShadowSubsystem* subsystem,
252 rdpShadowClient* client, UINT16 flags,
253 UINT16 code)
254 {
255 /* TODO: Implement */
256 WLog_WARN(TAG, "%s not implemented", __FUNCTION__);
257 return TRUE;
258 }
259
x11_shadow_input_mouse_event(rdpShadowSubsystem * subsystem,rdpShadowClient * client,UINT16 flags,UINT16 x,UINT16 y)260 static BOOL x11_shadow_input_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
261 UINT16 flags, UINT16 x, UINT16 y)
262 {
263 #ifdef WITH_XTEST
264 x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
265 int button = 0;
266 BOOL down = FALSE;
267 rdpShadowServer* server;
268 rdpShadowSurface* surface;
269
270 if (!subsystem || !client)
271 return FALSE;
272
273 server = subsystem->server;
274
275 if (!server)
276 return FALSE;
277
278 surface = server->surface;
279
280 if (!surface)
281 return FALSE;
282
283 x11->lastMouseClient = client;
284 x += surface->x;
285 y += surface->y;
286 XLockDisplay(x11->display);
287 XTestGrabControl(x11->display, True);
288
289 if (flags & PTR_FLAGS_WHEEL)
290 {
291 BOOL negative = FALSE;
292
293 if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
294 negative = TRUE;
295
296 button = (negative) ? 5 : 4;
297 XTestFakeButtonEvent(x11->display, button, True, CurrentTime);
298 XTestFakeButtonEvent(x11->display, button, False, CurrentTime);
299 }
300 else
301 {
302 if (flags & PTR_FLAGS_MOVE)
303 XTestFakeMotionEvent(x11->display, 0, x, y, CurrentTime);
304
305 if (flags & PTR_FLAGS_BUTTON1)
306 button = 1;
307 else if (flags & PTR_FLAGS_BUTTON2)
308 button = 3;
309 else if (flags & PTR_FLAGS_BUTTON3)
310 button = 2;
311
312 if (flags & PTR_FLAGS_DOWN)
313 down = TRUE;
314
315 if (button)
316 XTestFakeButtonEvent(x11->display, button, down, CurrentTime);
317 }
318
319 XTestGrabControl(x11->display, False);
320 XFlush(x11->display);
321 XUnlockDisplay(x11->display);
322 #endif
323 return TRUE;
324 }
325
x11_shadow_input_extended_mouse_event(rdpShadowSubsystem * subsystem,rdpShadowClient * client,UINT16 flags,UINT16 x,UINT16 y)326 static BOOL x11_shadow_input_extended_mouse_event(rdpShadowSubsystem* subsystem,
327 rdpShadowClient* client, UINT16 flags, UINT16 x,
328 UINT16 y)
329 {
330 #ifdef WITH_XTEST
331 x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
332 int button = 0;
333 BOOL down = FALSE;
334 rdpShadowServer* server;
335 rdpShadowSurface* surface;
336
337 if (!subsystem || !client)
338 return FALSE;
339
340 server = subsystem->server;
341
342 if (!server)
343 return FALSE;
344
345 surface = server->surface;
346
347 if (!surface)
348 return FALSE;
349
350 x11->lastMouseClient = client;
351 x += surface->x;
352 y += surface->y;
353 XLockDisplay(x11->display);
354 XTestGrabControl(x11->display, True);
355 XTestFakeMotionEvent(x11->display, 0, x, y, CurrentTime);
356
357 if (flags & PTR_XFLAGS_BUTTON1)
358 button = 8;
359 else if (flags & PTR_XFLAGS_BUTTON2)
360 button = 9;
361
362 if (flags & PTR_XFLAGS_DOWN)
363 down = TRUE;
364
365 if (button)
366 XTestFakeButtonEvent(x11->display, button, down, CurrentTime);
367
368 XTestGrabControl(x11->display, False);
369 XFlush(x11->display);
370 XUnlockDisplay(x11->display);
371 #endif
372 return TRUE;
373 }
374
x11_shadow_message_free(UINT32 id,SHADOW_MSG_OUT * msg)375 static void x11_shadow_message_free(UINT32 id, SHADOW_MSG_OUT* msg)
376 {
377 switch (id)
378 {
379 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
380 free(msg);
381 break;
382
383 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
384 free(((SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)msg)->xorMaskData);
385 free(((SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)msg)->andMaskData);
386 free(msg);
387 break;
388
389 default:
390 WLog_ERR(TAG, "Unknown message id: %" PRIu32 "", id);
391 free(msg);
392 break;
393 }
394 }
395
x11_shadow_pointer_position_update(x11ShadowSubsystem * subsystem)396 static int x11_shadow_pointer_position_update(x11ShadowSubsystem* subsystem)
397 {
398 UINT32 msgId = SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID;
399 rdpShadowServer* server;
400 SHADOW_MSG_OUT_POINTER_POSITION_UPDATE templateMsg;
401 int count = 0;
402 int index = 0;
403
404 if (!subsystem || !subsystem->common.server || !subsystem->common.server->clients)
405 return -1;
406
407 templateMsg.xPos = subsystem->common.pointerX;
408 templateMsg.yPos = subsystem->common.pointerY;
409 templateMsg.common.Free = x11_shadow_message_free;
410 server = subsystem->common.server;
411 ArrayList_Lock(server->clients);
412
413 for (index = 0; index < ArrayList_Count(server->clients); index++)
414 {
415 SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg;
416 rdpShadowClient* client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
417
418 /* Skip the client which send us the latest mouse event */
419 if (client == subsystem->lastMouseClient)
420 continue;
421
422 msg = malloc(sizeof(templateMsg));
423
424 if (!msg)
425 {
426 count = -1;
427 break;
428 }
429
430 memcpy(msg, &templateMsg, sizeof(templateMsg));
431
432 if (shadow_client_post_msg(client, NULL, msgId, (SHADOW_MSG_OUT*)msg, NULL))
433 count++;
434 }
435
436 ArrayList_Unlock(server->clients);
437 return count;
438 }
439
x11_shadow_pointer_alpha_update(x11ShadowSubsystem * subsystem)440 static int x11_shadow_pointer_alpha_update(x11ShadowSubsystem* subsystem)
441 {
442 SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg;
443 UINT32 msgId = SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID;
444 msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)calloc(1,
445 sizeof(SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE));
446
447 if (!msg)
448 return -1;
449
450 msg->xHot = subsystem->cursorHotX;
451 msg->yHot = subsystem->cursorHotY;
452 msg->width = subsystem->cursorWidth;
453 msg->height = subsystem->cursorHeight;
454
455 if (shadow_subsystem_pointer_convert_alpha_pointer_data(subsystem->cursorPixels, TRUE,
456 msg->width, msg->height, msg) < 0)
457 {
458 free(msg);
459 return -1;
460 }
461
462 msg->common.Free = x11_shadow_message_free;
463 return shadow_client_boardcast_msg(subsystem->common.server, NULL, msgId, (SHADOW_MSG_OUT*)msg,
464 NULL)
465 ? 1
466 : -1;
467 }
468
x11_shadow_query_cursor(x11ShadowSubsystem * subsystem,BOOL getImage)469 static int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
470 {
471 int x = 0, y = 0, n, k;
472 rdpShadowServer* server;
473 rdpShadowSurface* surface;
474 server = subsystem->common.server;
475 surface = server->surface;
476
477 if (getImage)
478 {
479 #ifdef WITH_XFIXES
480 UINT32* pDstPixel;
481 XFixesCursorImage* ci;
482 XLockDisplay(subsystem->display);
483 ci = XFixesGetCursorImage(subsystem->display);
484 XUnlockDisplay(subsystem->display);
485
486 if (!ci)
487 return -1;
488
489 x = ci->x;
490 y = ci->y;
491
492 if (ci->width > subsystem->cursorMaxWidth)
493 return -1;
494
495 if (ci->height > subsystem->cursorMaxHeight)
496 return -1;
497
498 subsystem->cursorHotX = ci->xhot;
499 subsystem->cursorHotY = ci->yhot;
500 subsystem->cursorWidth = ci->width;
501 subsystem->cursorHeight = ci->height;
502 subsystem->cursorId = ci->cursor_serial;
503 n = ci->width * ci->height;
504 pDstPixel = (UINT32*)subsystem->cursorPixels;
505
506 for (k = 0; k < n; k++)
507 {
508 /* XFixesCursorImage.pixels is in *unsigned long*, which may be 8 bytes */
509 *pDstPixel++ = (UINT32)ci->pixels[k];
510 }
511
512 XFree(ci);
513 x11_shadow_pointer_alpha_update(subsystem);
514 #endif
515 }
516 else
517 {
518 UINT32 mask;
519 int win_x, win_y;
520 int root_x, root_y;
521 Window root, child;
522 XLockDisplay(subsystem->display);
523
524 if (!XQueryPointer(subsystem->display, subsystem->root_window, &root, &child, &root_x,
525 &root_y, &win_x, &win_y, &mask))
526 {
527 XUnlockDisplay(subsystem->display);
528 return -1;
529 }
530
531 XUnlockDisplay(subsystem->display);
532 x = root_x;
533 y = root_y;
534 }
535
536 /* Convert to offset based on current surface */
537 if (surface)
538 {
539 x -= surface->x;
540 y -= surface->y;
541 }
542
543 if ((x != (INT64)subsystem->common.pointerX) || (y != (INT64)subsystem->common.pointerY))
544 {
545 subsystem->common.pointerX = x;
546 subsystem->common.pointerY = y;
547 x11_shadow_pointer_position_update(subsystem);
548 }
549
550 return 1;
551 }
552
x11_shadow_handle_xevent(x11ShadowSubsystem * subsystem,XEvent * xevent)553 static int x11_shadow_handle_xevent(x11ShadowSubsystem* subsystem, XEvent* xevent)
554 {
555 if (xevent->type == MotionNotify)
556 {
557 }
558
559 #ifdef WITH_XFIXES
560 else if (xevent->type == subsystem->xfixes_cursor_notify_event)
561 {
562 x11_shadow_query_cursor(subsystem, TRUE);
563 }
564
565 #endif
566 else
567 {
568 }
569
570 return 1;
571 }
572
x11_shadow_validate_region(x11ShadowSubsystem * subsystem,int x,int y,int width,int height)573 static void x11_shadow_validate_region(x11ShadowSubsystem* subsystem, int x, int y, int width,
574 int height)
575 {
576 XRectangle region;
577
578 if (!subsystem->use_xfixes || !subsystem->use_xdamage)
579 return;
580
581 region.x = x;
582 region.y = y;
583 region.width = width;
584 region.height = height;
585 #ifdef WITH_XFIXES
586 XLockDisplay(subsystem->display);
587 XFixesSetRegion(subsystem->display, subsystem->xdamage_region, ®ion, 1);
588 XDamageSubtract(subsystem->display, subsystem->xdamage, subsystem->xdamage_region, None);
589 XUnlockDisplay(subsystem->display);
590 #endif
591 }
592
x11_shadow_blend_cursor(x11ShadowSubsystem * subsystem)593 static int x11_shadow_blend_cursor(x11ShadowSubsystem* subsystem)
594 {
595 int x, y;
596 int nXSrc;
597 int nYSrc;
598 int nXDst;
599 int nYDst;
600 int nWidth;
601 int nHeight;
602 int nSrcStep;
603 int nDstStep;
604 BYTE* pSrcData;
605 BYTE* pDstData;
606 BYTE A, R, G, B;
607 rdpShadowSurface* surface;
608
609 if (!subsystem)
610 return -1;
611
612 surface = subsystem->common.server->surface;
613 nXSrc = 0;
614 nYSrc = 0;
615 nWidth = subsystem->cursorWidth;
616 nHeight = subsystem->cursorHeight;
617 nXDst = subsystem->common.pointerX - subsystem->cursorHotX;
618 nYDst = subsystem->common.pointerY - subsystem->cursorHotY;
619
620 if (nXDst >= surface->width)
621 return 1;
622
623 if (nXDst < 0)
624 {
625 nXDst *= -1;
626
627 if (nXDst >= nWidth)
628 return 1;
629
630 nXSrc = nXDst;
631 nWidth -= nXDst;
632 nXDst = 0;
633 }
634
635 if (nYDst >= surface->height)
636 return 1;
637
638 if (nYDst < 0)
639 {
640 nYDst *= -1;
641
642 if (nYDst >= nHeight)
643 return 1;
644
645 nYSrc = nYDst;
646 nHeight -= nYDst;
647 nYDst = 0;
648 }
649
650 if ((nXDst + nWidth) > surface->width)
651 nWidth = surface->width - nXDst;
652
653 if ((nYDst + nHeight) > surface->height)
654 nHeight = surface->height - nYDst;
655
656 pSrcData = subsystem->cursorPixels;
657 nSrcStep = subsystem->cursorWidth * 4;
658 pDstData = surface->data;
659 nDstStep = surface->scanline;
660
661 for (y = 0; y < nHeight; y++)
662 {
663 const BYTE* pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * 4)];
664 BYTE* pDstPixel = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)];
665
666 for (x = 0; x < nWidth; x++)
667 {
668 B = *pSrcPixel++;
669 G = *pSrcPixel++;
670 R = *pSrcPixel++;
671 A = *pSrcPixel++;
672
673 if (A == 0xFF)
674 {
675 pDstPixel[0] = B;
676 pDstPixel[1] = G;
677 pDstPixel[2] = R;
678 }
679 else
680 {
681 pDstPixel[0] = B + (pDstPixel[0] * (0xFF - A) + (0xFF / 2)) / 0xFF;
682 pDstPixel[1] = G + (pDstPixel[1] * (0xFF - A) + (0xFF / 2)) / 0xFF;
683 pDstPixel[2] = R + (pDstPixel[2] * (0xFF - A) + (0xFF / 2)) / 0xFF;
684 }
685
686 pDstPixel[3] = 0xFF;
687 pDstPixel += 4;
688 }
689 }
690
691 return 1;
692 }
693
x11_shadow_check_resize(x11ShadowSubsystem * subsystem)694 static BOOL x11_shadow_check_resize(x11ShadowSubsystem* subsystem)
695 {
696 MONITOR_DEF* virtualScreen;
697 XWindowAttributes attr;
698 XLockDisplay(subsystem->display);
699 XGetWindowAttributes(subsystem->display, subsystem->root_window, &attr);
700 XUnlockDisplay(subsystem->display);
701
702 if (attr.width != (INT64)subsystem->width || attr.height != (INT64)subsystem->height)
703 {
704 /* Screen size changed. Refresh monitor definitions and trigger screen resize */
705 subsystem->common.numMonitors = x11_shadow_enum_monitors(subsystem->common.monitors, 16);
706 shadow_screen_resize(subsystem->common.server->screen);
707 subsystem->width = attr.width;
708 subsystem->height = attr.height;
709 virtualScreen = &(subsystem->common.virtualScreen);
710 virtualScreen->left = 0;
711 virtualScreen->top = 0;
712 virtualScreen->right = subsystem->width;
713 virtualScreen->bottom = subsystem->height;
714 virtualScreen->flags = 1;
715 return TRUE;
716 }
717
718 return FALSE;
719 }
720
x11_shadow_error_handler_for_capture(Display * display,XErrorEvent * event)721 static int x11_shadow_error_handler_for_capture(Display* display, XErrorEvent* event)
722 {
723 char msg[256];
724 XGetErrorText(display, event->error_code, (char*)&msg, sizeof(msg));
725 WLog_ERR(TAG, "X11 error: %s Error code: %x, request code: %x, minor code: %x", msg,
726 event->error_code, event->request_code, event->minor_code);
727
728 /* Ignore BAD MATCH error during image capture. Abort in other case */
729 if (event->error_code != BadMatch)
730 {
731 abort();
732 }
733
734 return 0;
735 }
736
x11_shadow_screen_grab(x11ShadowSubsystem * subsystem)737 static int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
738 {
739 int rc = 0;
740 int count;
741 int status;
742 int x, y;
743 int width, height;
744 XImage* image;
745 rdpShadowServer* server;
746 rdpShadowSurface* surface;
747 RECTANGLE_16 invalidRect;
748 RECTANGLE_16 surfaceRect;
749 const RECTANGLE_16* extents;
750 server = subsystem->common.server;
751 surface = server->surface;
752 count = ArrayList_Count(server->clients);
753
754 if (count < 1)
755 return 1;
756
757 EnterCriticalSection(&surface->lock);
758 surfaceRect.left = 0;
759 surfaceRect.top = 0;
760 surfaceRect.right = surface->width;
761 surfaceRect.bottom = surface->height;
762 LeaveCriticalSection(&surface->lock);
763
764 XLockDisplay(subsystem->display);
765 /*
766 * Ignore BadMatch error during image capture. The screen size may be
767 * changed outside. We will resize to correct resolution at next frame
768 */
769 XSetErrorHandler(x11_shadow_error_handler_for_capture);
770
771 if (subsystem->use_xshm)
772 {
773 image = subsystem->fb_image;
774 XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap,
775 subsystem->xshm_gc, 0, 0, subsystem->width, subsystem->height, 0, 0);
776
777 EnterCriticalSection(&surface->lock);
778 status = shadow_capture_compare(surface->data, surface->scanline, surface->width,
779 surface->height, (BYTE*)&(image->data[surface->width * 4]),
780 image->bytes_per_line, &invalidRect);
781 LeaveCriticalSection(&surface->lock);
782 }
783 else
784 {
785 EnterCriticalSection(&surface->lock);
786 image = XGetImage(subsystem->display, subsystem->root_window, surface->x, surface->y,
787 surface->width, surface->height, AllPlanes, ZPixmap);
788
789 if (image)
790 {
791 status = shadow_capture_compare(surface->data, surface->scanline, surface->width,
792 surface->height, (BYTE*)image->data,
793 image->bytes_per_line, &invalidRect);
794 }
795 LeaveCriticalSection(&surface->lock);
796 if (!image)
797 {
798 /*
799 * BadMatch error happened. The size may have been changed again.
800 * Give up this frame and we will resize again in next frame
801 */
802 goto fail_capture;
803 }
804 }
805
806 /* Restore the default error handler */
807 XSetErrorHandler(NULL);
808 XSync(subsystem->display, False);
809 XUnlockDisplay(subsystem->display);
810
811 if (status)
812 {
813 BOOL empty;
814 EnterCriticalSection(&surface->lock);
815 region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
816 region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
817 empty = region16_is_empty(&(surface->invalidRegion));
818 LeaveCriticalSection(&surface->lock);
819
820 if (!empty)
821 {
822 BOOL success;
823 EnterCriticalSection(&surface->lock);
824 extents = region16_extents(&(surface->invalidRegion));
825 x = extents->left;
826 y = extents->top;
827 width = extents->right - extents->left;
828 height = extents->bottom - extents->top;
829 success = freerdp_image_copy(surface->data, surface->format, surface->scanline, x, y,
830 width, height, (BYTE*)image->data, PIXEL_FORMAT_BGRX32,
831 image->bytes_per_line, x, y, NULL, FREERDP_FLIP_NONE);
832 LeaveCriticalSection(&surface->lock);
833 if (!success)
834 goto fail_capture;
835
836 // x11_shadow_blend_cursor(subsystem);
837 count = ArrayList_Count(server->clients);
838 shadow_subsystem_frame_update(&subsystem->common);
839
840 if (count == 1)
841 {
842 rdpShadowClient* client;
843 client = (rdpShadowClient*)ArrayList_GetItem(server->clients, 0);
844
845 if (client)
846 subsystem->common.captureFrameRate =
847 shadow_encoder_preferred_fps(client->encoder);
848 }
849
850 EnterCriticalSection(&surface->lock);
851 region16_clear(&(surface->invalidRegion));
852 LeaveCriticalSection(&surface->lock);
853 }
854 }
855
856 rc = 1;
857 fail_capture:
858 if (!subsystem->use_xshm && image)
859 XDestroyImage(image);
860
861 if (rc != 1)
862 {
863 XSetErrorHandler(NULL);
864 XSync(subsystem->display, False);
865 XUnlockDisplay(subsystem->display);
866 }
867
868 return rc;
869 }
870
x11_shadow_subsystem_process_message(x11ShadowSubsystem * subsystem,wMessage * message)871 static int x11_shadow_subsystem_process_message(x11ShadowSubsystem* subsystem, wMessage* message)
872 {
873 switch (message->id)
874 {
875 case SHADOW_MSG_IN_REFRESH_REQUEST_ID:
876 shadow_subsystem_frame_update((rdpShadowSubsystem*)subsystem);
877 break;
878
879 default:
880 WLog_ERR(TAG, "Unknown message id: %" PRIu32 "", message->id);
881 break;
882 }
883
884 if (message->Free)
885 message->Free(message);
886
887 return 1;
888 }
889
x11_shadow_subsystem_thread(LPVOID arg)890 static DWORD WINAPI x11_shadow_subsystem_thread(LPVOID arg)
891 {
892 x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)arg;
893 XEvent xevent;
894 DWORD status;
895 DWORD nCount;
896 UINT64 cTime;
897 DWORD dwTimeout;
898 DWORD dwInterval;
899 UINT64 frameTime;
900 HANDLE events[32];
901 wMessage message;
902 wMessagePipe* MsgPipe;
903 MsgPipe = subsystem->common.MsgPipe;
904 nCount = 0;
905 events[nCount++] = subsystem->common.event;
906 events[nCount++] = MessageQueue_Event(MsgPipe->In);
907 subsystem->common.captureFrameRate = 16;
908 dwInterval = 1000 / subsystem->common.captureFrameRate;
909 frameTime = GetTickCount64() + dwInterval;
910
911 while (1)
912 {
913 cTime = GetTickCount64();
914 dwTimeout = (cTime > frameTime) ? 0 : frameTime - cTime;
915 status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout);
916
917 if (WaitForSingleObject(MessageQueue_Event(MsgPipe->In), 0) == WAIT_OBJECT_0)
918 {
919 if (MessageQueue_Peek(MsgPipe->In, &message, TRUE))
920 {
921 if (message.id == WMQ_QUIT)
922 break;
923
924 x11_shadow_subsystem_process_message(subsystem, &message);
925 }
926 }
927
928 if (WaitForSingleObject(subsystem->common.event, 0) == WAIT_OBJECT_0)
929 {
930 XLockDisplay(subsystem->display);
931
932 if (XEventsQueued(subsystem->display, QueuedAlready))
933 {
934 XNextEvent(subsystem->display, &xevent);
935 x11_shadow_handle_xevent(subsystem, &xevent);
936 }
937
938 XUnlockDisplay(subsystem->display);
939 }
940
941 if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
942 {
943 x11_shadow_check_resize(subsystem);
944 x11_shadow_screen_grab(subsystem);
945 x11_shadow_query_cursor(subsystem, FALSE);
946 dwInterval = 1000 / subsystem->common.captureFrameRate;
947 frameTime += dwInterval;
948 }
949 }
950
951 ExitThread(0);
952 return 0;
953 }
954
x11_shadow_subsystem_base_init(x11ShadowSubsystem * subsystem)955 static int x11_shadow_subsystem_base_init(x11ShadowSubsystem* subsystem)
956 {
957 if (subsystem->display)
958 return 1; /* initialize once */
959
960 if (!getenv("DISPLAY"))
961 setenv("DISPLAY", ":0", 1);
962
963 if (!XInitThreads())
964 return -1;
965
966 subsystem->display = XOpenDisplay(NULL);
967
968 if (!subsystem->display)
969 {
970 WLog_ERR(TAG, "failed to open display: %s", XDisplayName(NULL));
971 return -1;
972 }
973
974 subsystem->xfds = ConnectionNumber(subsystem->display);
975 subsystem->number = DefaultScreen(subsystem->display);
976 subsystem->screen = ScreenOfDisplay(subsystem->display, subsystem->number);
977 subsystem->depth = DefaultDepthOfScreen(subsystem->screen);
978 subsystem->width = WidthOfScreen(subsystem->screen);
979 subsystem->height = HeightOfScreen(subsystem->screen);
980 subsystem->root_window = RootWindow(subsystem->display, subsystem->number);
981 return 1;
982 }
983
x11_shadow_xfixes_init(x11ShadowSubsystem * subsystem)984 static int x11_shadow_xfixes_init(x11ShadowSubsystem* subsystem)
985 {
986 #ifdef WITH_XFIXES
987 int xfixes_event;
988 int xfixes_error;
989 int major, minor;
990
991 if (!XFixesQueryExtension(subsystem->display, &xfixes_event, &xfixes_error))
992 return -1;
993
994 if (!XFixesQueryVersion(subsystem->display, &major, &minor))
995 return -1;
996
997 subsystem->xfixes_cursor_notify_event = xfixes_event + XFixesCursorNotify;
998 XFixesSelectCursorInput(subsystem->display, subsystem->root_window,
999 XFixesDisplayCursorNotifyMask);
1000 return 1;
1001 #else
1002 return -1;
1003 #endif
1004 }
1005
x11_shadow_xinerama_init(x11ShadowSubsystem * subsystem)1006 static int x11_shadow_xinerama_init(x11ShadowSubsystem* subsystem)
1007 {
1008 #ifdef WITH_XINERAMA
1009 int major, minor;
1010 int xinerama_event;
1011 int xinerama_error;
1012 x11_shadow_subsystem_base_init(subsystem);
1013
1014 if (!XineramaQueryExtension(subsystem->display, &xinerama_event, &xinerama_error))
1015 return -1;
1016
1017 if (!XDamageQueryVersion(subsystem->display, &major, &minor))
1018 return -1;
1019
1020 if (!XineramaIsActive(subsystem->display))
1021 return -1;
1022
1023 return 1;
1024 #else
1025 return -1;
1026 #endif
1027 }
1028
x11_shadow_xdamage_init(x11ShadowSubsystem * subsystem)1029 static int x11_shadow_xdamage_init(x11ShadowSubsystem* subsystem)
1030 {
1031 #ifdef WITH_XDAMAGE
1032 int major, minor;
1033 int damage_event;
1034 int damage_error;
1035
1036 if (!subsystem->use_xfixes)
1037 return -1;
1038
1039 if (!XDamageQueryExtension(subsystem->display, &damage_event, &damage_error))
1040 return -1;
1041
1042 if (!XDamageQueryVersion(subsystem->display, &major, &minor))
1043 return -1;
1044
1045 if (major < 1)
1046 return -1;
1047
1048 subsystem->xdamage_notify_event = damage_event + XDamageNotify;
1049 subsystem->xdamage =
1050 XDamageCreate(subsystem->display, subsystem->root_window, XDamageReportDeltaRectangles);
1051
1052 if (!subsystem->xdamage)
1053 return -1;
1054
1055 #ifdef WITH_XFIXES
1056 subsystem->xdamage_region = XFixesCreateRegion(subsystem->display, NULL, 0);
1057
1058 if (!subsystem->xdamage_region)
1059 return -1;
1060
1061 #endif
1062 return 1;
1063 #else
1064 return -1;
1065 #endif
1066 }
1067
x11_shadow_xshm_init(x11ShadowSubsystem * subsystem)1068 static int x11_shadow_xshm_init(x11ShadowSubsystem* subsystem)
1069 {
1070 Bool pixmaps;
1071 int major, minor;
1072 XGCValues values;
1073
1074 if (!XShmQueryExtension(subsystem->display))
1075 return -1;
1076
1077 if (!XShmQueryVersion(subsystem->display, &major, &minor, &pixmaps))
1078 return -1;
1079
1080 if (!pixmaps)
1081 return -1;
1082
1083 subsystem->fb_shm_info.shmid = -1;
1084 subsystem->fb_shm_info.shmaddr = (char*)-1;
1085 subsystem->fb_shm_info.readOnly = False;
1086 subsystem->fb_image =
1087 XShmCreateImage(subsystem->display, subsystem->visual, subsystem->depth, ZPixmap, NULL,
1088 &(subsystem->fb_shm_info), subsystem->width, subsystem->height);
1089
1090 if (!subsystem->fb_image)
1091 {
1092 WLog_ERR(TAG, "XShmCreateImage failed");
1093 return -1;
1094 }
1095
1096 subsystem->fb_shm_info.shmid =
1097 shmget(IPC_PRIVATE, subsystem->fb_image->bytes_per_line * subsystem->fb_image->height,
1098 IPC_CREAT | 0600);
1099
1100 if (subsystem->fb_shm_info.shmid == -1)
1101 {
1102 WLog_ERR(TAG, "shmget failed");
1103 return -1;
1104 }
1105
1106 subsystem->fb_shm_info.shmaddr = shmat(subsystem->fb_shm_info.shmid, 0, 0);
1107 subsystem->fb_image->data = subsystem->fb_shm_info.shmaddr;
1108
1109 if (subsystem->fb_shm_info.shmaddr == ((char*)-1))
1110 {
1111 WLog_ERR(TAG, "shmat failed");
1112 return -1;
1113 }
1114
1115 if (!XShmAttach(subsystem->display, &(subsystem->fb_shm_info)))
1116 return -1;
1117
1118 XSync(subsystem->display, False);
1119 shmctl(subsystem->fb_shm_info.shmid, IPC_RMID, 0);
1120 subsystem->fb_pixmap =
1121 XShmCreatePixmap(subsystem->display, subsystem->root_window, subsystem->fb_image->data,
1122 &(subsystem->fb_shm_info), subsystem->fb_image->width,
1123 subsystem->fb_image->height, subsystem->fb_image->depth);
1124 XSync(subsystem->display, False);
1125
1126 if (!subsystem->fb_pixmap)
1127 return -1;
1128
1129 values.subwindow_mode = IncludeInferiors;
1130 values.graphics_exposures = False;
1131 subsystem->xshm_gc = XCreateGC(subsystem->display, subsystem->root_window,
1132 GCSubwindowMode | GCGraphicsExposures, &values);
1133 XSetFunction(subsystem->display, subsystem->xshm_gc, GXcopy);
1134 XSync(subsystem->display, False);
1135 return 1;
1136 }
1137
x11_shadow_enum_monitors(MONITOR_DEF * monitors,UINT32 maxMonitors)1138 UINT32 x11_shadow_enum_monitors(MONITOR_DEF* monitors, UINT32 maxMonitors)
1139 {
1140 int index;
1141 Display* display;
1142 int displayWidth;
1143 int displayHeight;
1144 int numMonitors = 0;
1145 MONITOR_DEF* monitor;
1146
1147 if (!getenv("DISPLAY"))
1148 setenv("DISPLAY", ":0", 1);
1149
1150 display = XOpenDisplay(NULL);
1151
1152 if (!display)
1153 {
1154 WLog_ERR(TAG, "failed to open display: %s", XDisplayName(NULL));
1155 return -1;
1156 }
1157
1158 displayWidth = WidthOfScreen(DefaultScreenOfDisplay(display));
1159 displayHeight = HeightOfScreen(DefaultScreenOfDisplay(display));
1160 #ifdef WITH_XINERAMA
1161 {
1162 int major, minor;
1163 int xinerama_event;
1164 int xinerama_error;
1165 XineramaScreenInfo* screen;
1166 XineramaScreenInfo* screens;
1167
1168 if (XineramaQueryExtension(display, &xinerama_event, &xinerama_error) &&
1169 XDamageQueryVersion(display, &major, &minor) && XineramaIsActive(display))
1170 {
1171 screens = XineramaQueryScreens(display, &numMonitors);
1172
1173 if (numMonitors > (INT64)maxMonitors)
1174 numMonitors = (int)maxMonitors;
1175
1176 if (screens && (numMonitors > 0))
1177 {
1178 for (index = 0; index < numMonitors; index++)
1179 {
1180 screen = &screens[index];
1181 monitor = &monitors[index];
1182 monitor->left = screen->x_org;
1183 monitor->top = screen->y_org;
1184 monitor->right = monitor->left + screen->width;
1185 monitor->bottom = monitor->top + screen->height;
1186 monitor->flags = (index == 0) ? 1 : 0;
1187 }
1188 }
1189
1190 XFree(screens);
1191 }
1192 }
1193 #endif
1194 XCloseDisplay(display);
1195
1196 if (numMonitors < 1)
1197 {
1198 index = 0;
1199 numMonitors = 1;
1200 monitor = &monitors[index];
1201 monitor->left = 0;
1202 monitor->top = 0;
1203 monitor->right = displayWidth;
1204 monitor->bottom = displayHeight;
1205 monitor->flags = 1;
1206 }
1207
1208 errno = 0;
1209 return numMonitors;
1210 }
1211
x11_shadow_subsystem_init(rdpShadowSubsystem * sub)1212 static int x11_shadow_subsystem_init(rdpShadowSubsystem* sub)
1213 {
1214 int i;
1215 int pf_count;
1216 int vi_count;
1217 int nextensions;
1218 char** extensions;
1219 XVisualInfo* vi;
1220 XVisualInfo* vis;
1221 XVisualInfo template;
1222 XPixmapFormatValues* pf;
1223 XPixmapFormatValues* pfs;
1224 MONITOR_DEF* virtualScreen;
1225 x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
1226
1227 if (!subsystem)
1228 return -1;
1229
1230 subsystem->common.numMonitors = x11_shadow_enum_monitors(subsystem->common.monitors, 16);
1231 x11_shadow_subsystem_base_init(subsystem);
1232
1233 if ((subsystem->depth != 24) && (subsystem->depth != 32))
1234 {
1235 WLog_ERR(TAG, "unsupported X11 server color depth: %d", subsystem->depth);
1236 return -1;
1237 }
1238
1239 extensions = XListExtensions(subsystem->display, &nextensions);
1240
1241 if (!extensions || (nextensions < 0))
1242 return -1;
1243
1244 for (i = 0; i < nextensions; i++)
1245 {
1246 if (strcmp(extensions[i], "Composite") == 0)
1247 subsystem->composite = TRUE;
1248 }
1249
1250 XFreeExtensionList(extensions);
1251
1252 if (subsystem->composite)
1253 subsystem->use_xdamage = FALSE;
1254
1255 pfs = XListPixmapFormats(subsystem->display, &pf_count);
1256
1257 if (!pfs)
1258 {
1259 WLog_ERR(TAG, "XListPixmapFormats failed");
1260 return -1;
1261 }
1262
1263 for (i = 0; i < pf_count; i++)
1264 {
1265 pf = pfs + i;
1266
1267 if (pf->depth == (INT64)subsystem->depth)
1268 {
1269 subsystem->bpp = pf->bits_per_pixel;
1270 subsystem->scanline_pad = pf->scanline_pad;
1271 break;
1272 }
1273 }
1274
1275 XFree(pfs);
1276 ZeroMemory(&template, sizeof(template));
1277 template.class = TrueColor;
1278 template.screen = subsystem->number;
1279 vis = XGetVisualInfo(subsystem->display, VisualClassMask | VisualScreenMask, &template,
1280 &vi_count);
1281
1282 if (!vis)
1283 {
1284 WLog_ERR(TAG, "XGetVisualInfo failed");
1285 return -1;
1286 }
1287
1288 for (i = 0; i < vi_count; i++)
1289 {
1290 vi = vis + i;
1291
1292 if (vi->depth == (INT64)subsystem->depth)
1293 {
1294 subsystem->visual = vi->visual;
1295 break;
1296 }
1297 }
1298
1299 XFree(vis);
1300 XSelectInput(subsystem->display, subsystem->root_window, SubstructureNotifyMask);
1301 subsystem->cursorMaxWidth = 256;
1302 subsystem->cursorMaxHeight = 256;
1303 subsystem->cursorPixels =
1304 _aligned_malloc(subsystem->cursorMaxWidth * subsystem->cursorMaxHeight * 4, 16);
1305
1306 if (!subsystem->cursorPixels)
1307 return -1;
1308
1309 x11_shadow_query_cursor(subsystem, TRUE);
1310
1311 if (subsystem->use_xfixes)
1312 {
1313 if (x11_shadow_xfixes_init(subsystem) < 0)
1314 subsystem->use_xfixes = FALSE;
1315 }
1316
1317 if (subsystem->use_xinerama)
1318 {
1319 if (x11_shadow_xinerama_init(subsystem) < 0)
1320 subsystem->use_xinerama = FALSE;
1321 }
1322
1323 if (subsystem->use_xshm)
1324 {
1325 if (x11_shadow_xshm_init(subsystem) < 0)
1326 subsystem->use_xshm = FALSE;
1327 }
1328
1329 if (subsystem->use_xdamage)
1330 {
1331 if (x11_shadow_xdamage_init(subsystem) < 0)
1332 subsystem->use_xdamage = FALSE;
1333 }
1334
1335 if (!(subsystem->common.event =
1336 CreateFileDescriptorEvent(NULL, FALSE, FALSE, subsystem->xfds, WINPR_FD_READ)))
1337 return -1;
1338
1339 virtualScreen = &(subsystem->common.virtualScreen);
1340 virtualScreen->left = 0;
1341 virtualScreen->top = 0;
1342 virtualScreen->right = subsystem->width;
1343 virtualScreen->bottom = subsystem->height;
1344 virtualScreen->flags = 1;
1345 WLog_INFO(TAG,
1346 "X11 Extensions: XFixes: %" PRId32 " Xinerama: %" PRId32 " XDamage: %" PRId32
1347 " XShm: %" PRId32 "",
1348 subsystem->use_xfixes, subsystem->use_xinerama, subsystem->use_xdamage,
1349 subsystem->use_xshm);
1350 return 1;
1351 }
1352
x11_shadow_subsystem_uninit(rdpShadowSubsystem * sub)1353 static int x11_shadow_subsystem_uninit(rdpShadowSubsystem* sub)
1354 {
1355 x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
1356
1357 if (!subsystem)
1358 return -1;
1359
1360 if (subsystem->display)
1361 {
1362 XCloseDisplay(subsystem->display);
1363 subsystem->display = NULL;
1364 }
1365
1366 if (subsystem->common.event)
1367 {
1368 CloseHandle(subsystem->common.event);
1369 subsystem->common.event = NULL;
1370 }
1371
1372 if (subsystem->cursorPixels)
1373 {
1374 _aligned_free(subsystem->cursorPixels);
1375 subsystem->cursorPixels = NULL;
1376 }
1377
1378 return 1;
1379 }
1380
x11_shadow_subsystem_start(rdpShadowSubsystem * sub)1381 static int x11_shadow_subsystem_start(rdpShadowSubsystem* sub)
1382 {
1383 x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
1384
1385 if (!subsystem)
1386 return -1;
1387
1388 if (!(subsystem->thread =
1389 CreateThread(NULL, 0, x11_shadow_subsystem_thread, (void*)subsystem, 0, NULL)))
1390 {
1391 WLog_ERR(TAG, "Failed to create thread");
1392 return -1;
1393 }
1394
1395 return 1;
1396 }
1397
x11_shadow_subsystem_stop(rdpShadowSubsystem * sub)1398 static int x11_shadow_subsystem_stop(rdpShadowSubsystem* sub)
1399 {
1400 x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
1401
1402 if (!subsystem)
1403 return -1;
1404
1405 if (subsystem->thread)
1406 {
1407 if (MessageQueue_PostQuit(subsystem->common.MsgPipe->In, 0))
1408 WaitForSingleObject(subsystem->thread, INFINITE);
1409
1410 CloseHandle(subsystem->thread);
1411 subsystem->thread = NULL;
1412 }
1413
1414 return 1;
1415 }
1416
x11_shadow_subsystem_new(void)1417 static rdpShadowSubsystem* x11_shadow_subsystem_new(void)
1418 {
1419 x11ShadowSubsystem* subsystem;
1420 subsystem = (x11ShadowSubsystem*)calloc(1, sizeof(x11ShadowSubsystem));
1421
1422 if (!subsystem)
1423 return NULL;
1424
1425 #ifdef WITH_PAM
1426 subsystem->common.Authenticate = x11_shadow_pam_authenticate;
1427 #endif
1428 subsystem->common.SynchronizeEvent = x11_shadow_input_synchronize_event;
1429 subsystem->common.KeyboardEvent = x11_shadow_input_keyboard_event;
1430 subsystem->common.UnicodeKeyboardEvent = x11_shadow_input_unicode_keyboard_event;
1431 subsystem->common.MouseEvent = x11_shadow_input_mouse_event;
1432 subsystem->common.ExtendedMouseEvent = x11_shadow_input_extended_mouse_event;
1433 subsystem->composite = FALSE;
1434 subsystem->use_xshm = FALSE; /* temporarily disabled */
1435 subsystem->use_xfixes = TRUE;
1436 subsystem->use_xdamage = FALSE;
1437 subsystem->use_xinerama = TRUE;
1438 return (rdpShadowSubsystem*)subsystem;
1439 }
1440
x11_shadow_subsystem_free(rdpShadowSubsystem * subsystem)1441 static void x11_shadow_subsystem_free(rdpShadowSubsystem* subsystem)
1442 {
1443 if (!subsystem)
1444 return;
1445
1446 x11_shadow_subsystem_uninit(subsystem);
1447 free(subsystem);
1448 }
1449
X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS * pEntryPoints)1450 FREERDP_API int X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
1451 {
1452 if (!pEntryPoints)
1453 return -1;
1454
1455 pEntryPoints->New = x11_shadow_subsystem_new;
1456 pEntryPoints->Free = x11_shadow_subsystem_free;
1457 pEntryPoints->Init = x11_shadow_subsystem_init;
1458 pEntryPoints->Uninit = x11_shadow_subsystem_uninit;
1459 pEntryPoints->Start = x11_shadow_subsystem_start;
1460 pEntryPoints->Stop = x11_shadow_subsystem_stop;
1461 pEntryPoints->EnumMonitors = x11_shadow_enum_monitors;
1462 return 1;
1463 }
1464