29#include <sys/select.h> 
   30#include <sys/signal.h> 
   36#include <winpr/assert.h> 
   37#include <winpr/cast.h> 
   38#include <winpr/path.h> 
   39#include <winpr/synch.h> 
   40#include <winpr/image.h> 
   41#include <winpr/sysinfo.h> 
   43#include <freerdp/log.h> 
   44#include <freerdp/codec/color.h> 
   45#include <freerdp/codec/region.h> 
   47#include "x11_shadow.h" 
   49#define TAG SERVER_TAG("shadow.x11") 
   53static UINT32 x11_shadow_enum_monitors(
MONITOR_DEF* monitors, UINT32 maxMonitors);
 
   57#include <security/pam_appl.h> 
   64} SHADOW_PAM_AUTH_DATA;
 
   71  SHADOW_PAM_AUTH_DATA appdata;
 
   72} SHADOW_PAM_AUTH_INFO;
 
   74static int x11_shadow_pam_conv(
int num_msg, 
const struct pam_message** msg,
 
   75                               struct pam_response** resp, 
void* appdata_ptr)
 
   77  int pam_status = PAM_CONV_ERR;
 
   78  SHADOW_PAM_AUTH_DATA* appdata = NULL;
 
   79  struct pam_response* response = NULL;
 
   80  WINPR_ASSERT(num_msg >= 0);
 
   81  appdata = (SHADOW_PAM_AUTH_DATA*)appdata_ptr;
 
   82  WINPR_ASSERT(appdata);
 
   84  if (!(response = (
struct pam_response*)calloc((
size_t)num_msg, 
sizeof(
struct pam_response))))
 
   87  for (
int index = 0; index < num_msg; index++)
 
   89    switch (msg[index]->msg_style)
 
   91      case PAM_PROMPT_ECHO_ON:
 
   92        response[index].resp = _strdup(appdata->user);
 
   94        if (!response[index].resp)
 
   97        response[index].resp_retcode = PAM_SUCCESS;
 
  100      case PAM_PROMPT_ECHO_OFF:
 
  101        response[index].resp = _strdup(appdata->password);
 
  103        if (!response[index].resp)
 
  106        response[index].resp_retcode = PAM_SUCCESS;
 
  110        pam_status = PAM_CONV_ERR;
 
  119  for (
int index = 0; index < num_msg; ++index)
 
  121    if (response[index].resp)
 
  123      memset(response[index].resp, 0, strlen(response[index].resp));
 
  124      free(response[index].resp);
 
  128  memset(response, 0, 
sizeof(
struct pam_response) * (
size_t)num_msg);
 
  134static BOOL x11_shadow_pam_get_service_name(SHADOW_PAM_AUTH_INFO* info)
 
  136  const char* base = 
"/etc/pam.d";
 
  137  const char* hints[] = { 
"lightdm", 
"gdm", 
"xdm", 
"login", 
"sshd" };
 
  139  for (
size_t x = 0; x < ARRAYSIZE(hints); x++)
 
  141    char path[MAX_PATH] = { 0 };
 
  142    const char* hint = hints[x];
 
  144    (void)_snprintf(path, 
sizeof(path), 
"%s/%s", base, hint);
 
  145    if (winpr_PathFileExists(path))
 
  148      info->service_name = _strdup(hint);
 
  149      return info->service_name != NULL;
 
  152  WLog_WARN(TAG, 
"Could not determine PAM service name");
 
  156static int x11_shadow_pam_authenticate(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
 
  157                                       const char* user, 
const char* domain, 
const char* password)
 
  160  SHADOW_PAM_AUTH_INFO info = { 0 };
 
  161  WINPR_UNUSED(subsystem);
 
  162  WINPR_UNUSED(client);
 
  164  if (!x11_shadow_pam_get_service_name(&info))
 
  167  info.appdata.user = user;
 
  168  info.appdata.domain = domain;
 
  169  info.appdata.password = password;
 
  170  info.pamc.conv = &x11_shadow_pam_conv;
 
  171  info.pamc.appdata_ptr = &info.appdata;
 
  172  pam_status = pam_start(info.service_name, 0, &info.pamc, &info.handle);
 
  174  if (pam_status != PAM_SUCCESS)
 
  176    WLog_ERR(TAG, 
"pam_start failure: %s", pam_strerror(info.handle, pam_status));
 
  180  pam_status = pam_authenticate(info.handle, 0);
 
  182  if (pam_status != PAM_SUCCESS)
 
  184    WLog_ERR(TAG, 
"pam_authenticate failure: %s", pam_strerror(info.handle, pam_status));
 
  188  pam_status = pam_acct_mgmt(info.handle, 0);
 
  190  if (pam_status != PAM_SUCCESS)
 
  192    WLog_ERR(TAG, 
"pam_acct_mgmt failure: %s", pam_strerror(info.handle, pam_status));
 
  201static BOOL x11_shadow_input_synchronize_event(WINPR_ATTR_UNUSED rdpShadowSubsystem* subsystem,
 
  202                                               WINPR_ATTR_UNUSED rdpShadowClient* client,
 
  203                                               WINPR_ATTR_UNUSED UINT32 flags)
 
  206  WLog_WARN(TAG, 
"not implemented");
 
  210static BOOL x11_shadow_input_keyboard_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
 
  211                                            UINT16 flags, UINT8 code)
 
  214  x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
 
  218  BOOL extended = FALSE;
 
  220  if (!client || !subsystem)
 
  223  if (flags & KBD_FLAGS_EXTENDED)
 
  230  vkcode = GetVirtualKeyCodeFromVirtualScanCode(scancode, WINPR_KBD_TYPE_IBM_ENHANCED);
 
  235  keycode = GetKeycodeFromVirtualKeyCode(vkcode, WINPR_KEYCODE_TYPE_XKB);
 
  239    XLockDisplay(x11->display);
 
  240    XTestGrabControl(x11->display, True);
 
  242    if (flags & KBD_FLAGS_RELEASE)
 
  243      XTestFakeKeyEvent(x11->display, keycode, False, CurrentTime);
 
  245      XTestFakeKeyEvent(x11->display, keycode, True, CurrentTime);
 
  247    XTestGrabControl(x11->display, False);
 
  248    XFlush(x11->display);
 
  249    XUnlockDisplay(x11->display);
 
  252  WLog_WARN(TAG, 
"KeyboardEvent not supported by backend, ignoring");
 
  257static BOOL x11_shadow_input_unicode_keyboard_event(WINPR_ATTR_UNUSED rdpShadowSubsystem* subsystem,
 
  258                                                    WINPR_ATTR_UNUSED rdpShadowClient* client,
 
  259                                                    WINPR_ATTR_UNUSED UINT16 flags,
 
  260                                                    WINPR_ATTR_UNUSED UINT16 code)
 
  263  WLog_WARN(TAG, 
"not implemented");
 
  267static BOOL x11_shadow_input_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
 
  268                                         UINT16 flags, UINT16 x, UINT16 y)
 
  271  x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
 
  272  unsigned int button = 0;
 
  274  rdpShadowServer* server = NULL;
 
  275  rdpShadowSurface* surface = NULL;
 
  277  if (!subsystem || !client)
 
  280  server = subsystem->server;
 
  285  surface = server->surface;
 
  290  x11->lastMouseClient = client;
 
  293  XLockDisplay(x11->display);
 
  294  XTestGrabControl(x11->display, True);
 
  296  if (flags & PTR_FLAGS_WHEEL)
 
  298    BOOL negative = FALSE;
 
  300    if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
 
  303    button = (negative) ? 5 : 4;
 
  304    XTestFakeButtonEvent(x11->display, button, True, (
unsigned long)CurrentTime);
 
  305    XTestFakeButtonEvent(x11->display, button, False, (
unsigned long)CurrentTime);
 
  307  else if (flags & PTR_FLAGS_HWHEEL)
 
  309    BOOL negative = FALSE;
 
  311    if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
 
  314    button = (negative) ? 7 : 6;
 
  315    XTestFakeButtonEvent(x11->display, button, True, (
unsigned long)CurrentTime);
 
  316    XTestFakeButtonEvent(x11->display, button, False, (
unsigned long)CurrentTime);
 
  320    if (flags & PTR_FLAGS_MOVE)
 
  321      XTestFakeMotionEvent(x11->display, 0, x, y, CurrentTime);
 
  323    if (flags & PTR_FLAGS_BUTTON1)
 
  325    else if (flags & PTR_FLAGS_BUTTON2)
 
  327    else if (flags & PTR_FLAGS_BUTTON3)
 
  330    if (flags & PTR_FLAGS_DOWN)
 
  334      XTestFakeButtonEvent(x11->display, button, down, CurrentTime);
 
  337  XTestGrabControl(x11->display, False);
 
  338  XFlush(x11->display);
 
  339  XUnlockDisplay(x11->display);
 
  341  WLog_WARN(TAG, 
"MouseEvent not supported by backend, ignoring");
 
  346static BOOL x11_shadow_input_rel_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
 
  347                                             UINT16 flags, INT16 xDelta, INT16 yDelta)
 
  350  x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
 
  353  unsigned int button = 0;
 
  356  if (!subsystem || !client)
 
  359  rdpShadowServer* server = subsystem->server;
 
  364  rdpShadowSurface* surface = server->surface;
 
  369  x11->lastMouseClient = client;
 
  371  XLockDisplay(x11->display);
 
  372  XTestGrabControl(x11->display, True);
 
  374  if (flags & PTR_FLAGS_MOVE)
 
  375    XTestFakeRelativeMotionEvent(x11->display, xDelta, yDelta, 0);
 
  377  if (flags & PTR_FLAGS_BUTTON1)
 
  379  else if (flags & PTR_FLAGS_BUTTON2)
 
  381  else if (flags & PTR_FLAGS_BUTTON3)
 
  383  else if (flags & PTR_XFLAGS_BUTTON1)
 
  385  else if (flags & PTR_XFLAGS_BUTTON2)
 
  388  if (flags & PTR_FLAGS_DOWN)
 
  392    XTestFakeButtonEvent(x11->display, button, down, CurrentTime);
 
  394  XTestGrabControl(x11->display, False);
 
  395  XFlush(x11->display);
 
  396  XUnlockDisplay(x11->display);
 
  398  WLog_WARN(TAG, 
"RelMouseEvent not supported by backend, ignoring");
 
  403static BOOL x11_shadow_input_extended_mouse_event(rdpShadowSubsystem* subsystem,
 
  404                                                  rdpShadowClient* client, UINT16 flags, UINT16 x,
 
  408  x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
 
  411  rdpShadowServer* server = NULL;
 
  412  rdpShadowSurface* surface = NULL;
 
  414  if (!subsystem || !client)
 
  417  server = subsystem->server;
 
  422  surface = server->surface;
 
  427  x11->lastMouseClient = client;
 
  430  XLockDisplay(x11->display);
 
  431  XTestGrabControl(x11->display, True);
 
  432  XTestFakeMotionEvent(x11->display, 0, x, y, CurrentTime);
 
  434  if (flags & PTR_XFLAGS_BUTTON1)
 
  436  else if (flags & PTR_XFLAGS_BUTTON2)
 
  439  if (flags & PTR_XFLAGS_DOWN)
 
  443    XTestFakeButtonEvent(x11->display, button, down, CurrentTime);
 
  445  XTestGrabControl(x11->display, False);
 
  446  XFlush(x11->display);
 
  447  XUnlockDisplay(x11->display);
 
  449  WLog_WARN(TAG, 
"ExtendedMouseEvent not supported by backend, ignoring");
 
  454static void x11_shadow_message_free(UINT32 
id, SHADOW_MSG_OUT* msg)
 
  458    case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
 
  462    case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
 
  469      WLog_ERR(TAG, 
"Unknown message id: %" PRIu32 
"", 
id);
 
  475static int x11_shadow_pointer_position_update(x11ShadowSubsystem* subsystem)
 
  477  UINT32 msgId = SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID;
 
  478  rdpShadowServer* server = NULL;
 
  482  if (!subsystem || !subsystem->common.server || !subsystem->common.server->clients)
 
  485  templateMsg.xPos = subsystem->common.pointerX;
 
  486  templateMsg.yPos = subsystem->common.pointerY;
 
  487  templateMsg.common.Free = x11_shadow_message_free;
 
  488  server = subsystem->common.server;
 
  489  ArrayList_Lock(server->clients);
 
  491  for (
size_t index = 0; index < ArrayList_Count(server->clients); index++)
 
  494    rdpShadowClient* client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
 
  497    if (client == subsystem->lastMouseClient)
 
  500    msg = malloc(
sizeof(templateMsg));
 
  508    memcpy(msg, &templateMsg, 
sizeof(templateMsg));
 
  510    if (shadow_client_post_msg(client, NULL, msgId, (SHADOW_MSG_OUT*)msg, NULL))
 
  514  ArrayList_Unlock(server->clients);
 
  518static int x11_shadow_pointer_alpha_update(x11ShadowSubsystem* subsystem)
 
  521  UINT32 msgId = SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID;
 
  528  msg->xHot = subsystem->cursorHotX;
 
  529  msg->yHot = subsystem->cursorHotY;
 
  530  msg->width = subsystem->cursorWidth;
 
  531  msg->height = subsystem->cursorHeight;
 
  533  if (shadow_subsystem_pointer_convert_alpha_pointer_data_to_format(
 
  534          subsystem->cursorPixels, subsystem->format, TRUE, msg->width, msg->height, msg) < 0)
 
  540  msg->common.Free = x11_shadow_message_free;
 
  541  return shadow_client_boardcast_msg(subsystem->common.server, NULL, msgId, (SHADOW_MSG_OUT*)msg,
 
  547static int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
 
  552  rdpShadowServer* server = NULL;
 
  553  rdpShadowSurface* surface = NULL;
 
  554  server = subsystem->common.server;
 
  555  surface = server->surface;
 
  560    UINT32* pDstPixel = NULL;
 
  561    XFixesCursorImage* ci = NULL;
 
  562    XLockDisplay(subsystem->display);
 
  563    ci = XFixesGetCursorImage(subsystem->display);
 
  564    XUnlockDisplay(subsystem->display);
 
  572    if (ci->width > subsystem->cursorMaxWidth)
 
  575    if (ci->height > subsystem->cursorMaxHeight)
 
  578    subsystem->cursorHotX = ci->xhot;
 
  579    subsystem->cursorHotY = ci->yhot;
 
  580    subsystem->cursorWidth = ci->width;
 
  581    subsystem->cursorHeight = ci->height;
 
  582    subsystem->cursorId = ci->cursor_serial;
 
  583    n = ci->width * ci->height;
 
  584    pDstPixel = (UINT32*)subsystem->cursorPixels;
 
  586    for (
int k = 0; k < n; k++)
 
  589      *pDstPixel++ = (UINT32)ci->pixels[k];
 
  593    x11_shadow_pointer_alpha_update(subsystem);
 
  605    XLockDisplay(subsystem->display);
 
  607    if (!XQueryPointer(subsystem->display, subsystem->root_window, &root, &child, &root_x,
 
  608                       &root_y, &win_x, &win_y, &mask))
 
  610      XUnlockDisplay(subsystem->display);
 
  614    XUnlockDisplay(subsystem->display);
 
  626  if ((x != (INT64)subsystem->common.pointerX) || (y != (INT64)subsystem->common.pointerY))
 
  628    subsystem->common.pointerX = (UINT32)MAX(0, x);
 
  629    subsystem->common.pointerY = (UINT32)MAX(0, y);
 
  630    x11_shadow_pointer_position_update(subsystem);
 
  636static int x11_shadow_handle_xevent(x11ShadowSubsystem* subsystem, XEvent* xevent)
 
  638  if (xevent->type == MotionNotify)
 
  643  else if (xevent->type == subsystem->xfixes_cursor_notify_event)
 
  645    x11_shadow_query_cursor(subsystem, TRUE);
 
  656#if defined(USE_SHADOW_BLEND_CURSOR) 
  657static int x11_shadow_blend_cursor(x11ShadowSubsystem* subsystem)
 
  662  rdpShadowSurface* surface = subsystem->common.server->surface;
 
  665  UINT32 nWidth = subsystem->cursorWidth;
 
  666  UINT32 nHeight = subsystem->cursorHeight;
 
  667  INT64 nXDst = subsystem->common.pointerX - subsystem->cursorHotX;
 
  668  INT64 nYDst = subsystem->common.pointerY - subsystem->cursorHotY;
 
  670  if (nXDst >= surface->width)
 
  680    nXSrc = (UINT32)nXDst;
 
  685  if (nYDst >= surface->height)
 
  692    if (nYDst >= nHeight)
 
  695    nYSrc = (UINT32)nYDst;
 
  700  if ((nXDst + nWidth) > surface->width)
 
  701    nWidth = (nXDst > surface->width) ? 0 : (UINT32)(surface->width - nXDst);
 
  703  if ((nYDst + nHeight) > surface->height)
 
  704    nHeight = (nYDst > surface->height) ? 0 : (UINT32)(surface->height - nYDst);
 
  706  const BYTE* pSrcData = subsystem->cursorPixels;
 
  707  const UINT32 nSrcStep = subsystem->cursorWidth * 4;
 
  708  BYTE* pDstData = surface->data;
 
  709  const UINT32 nDstStep = surface->scanline;
 
  711  for (
size_t y = 0; y < nHeight; y++)
 
  713    const BYTE* pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (4ULL * nXSrc)];
 
  714    BYTE* pDstPixel = &pDstData[((WINPR_ASSERTING_INT_CAST(uint32_t, nYDst) + y) * nDstStep) +
 
  715                                (4ULL * WINPR_ASSERTING_INT_CAST(uint32_t, nXDst))];
 
  717    for (
size_t x = 0; x < nWidth; x++)
 
  719      const BYTE B = *pSrcPixel++;
 
  720      const BYTE G = *pSrcPixel++;
 
  721      const BYTE R = *pSrcPixel++;
 
  722      const BYTE A = *pSrcPixel++;
 
  732        pDstPixel[0] = B + (pDstPixel[0] * (0xFF - A) + (0xFF / 2)) / 0xFF;
 
  733        pDstPixel[1] = G + (pDstPixel[1] * (0xFF - A) + (0xFF / 2)) / 0xFF;
 
  734        pDstPixel[2] = R + (pDstPixel[2] * (0xFF - A) + (0xFF / 2)) / 0xFF;
 
  746static BOOL x11_shadow_check_resize(x11ShadowSubsystem* subsystem)
 
  748  XWindowAttributes attr;
 
  749  XLockDisplay(subsystem->display);
 
  750  XGetWindowAttributes(subsystem->display, subsystem->root_window, &attr);
 
  751  XUnlockDisplay(subsystem->display);
 
  753  if (attr.width != (INT64)subsystem->width || attr.height != (INT64)subsystem->height)
 
  755    MONITOR_DEF* virtualScreen = &(subsystem->common.virtualScreen);
 
  758    subsystem->common.numMonitors = x11_shadow_enum_monitors(subsystem->common.monitors, 16);
 
  759    if (!shadow_screen_resize(subsystem->common.server->screen))
 
  762    WINPR_ASSERT(attr.width > 0);
 
  763    WINPR_ASSERT(attr.height > 0);
 
  765    subsystem->width = (UINT32)attr.width;
 
  766    subsystem->height = (UINT32)attr.height;
 
  768    virtualScreen->left = 0;
 
  769    virtualScreen->top = 0;
 
  770    virtualScreen->right = attr.width - 1;
 
  771    virtualScreen->bottom = attr.height - 1;
 
  772    virtualScreen->flags = 1;
 
  779static int x11_shadow_error_handler_for_capture(Display* display, XErrorEvent* event)
 
  782  XGetErrorText(display, event->error_code, (
char*)&msg, 
sizeof(msg));
 
  783  WLog_ERR(TAG, 
"X11 error: %s Error code: %x, request code: %x, minor code: %x", msg,
 
  784           event->error_code, event->request_code, event->minor_code);
 
  787  if (event->error_code != BadMatch)
 
  795static int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
 
  804  XImage* image = NULL;
 
  805  rdpShadowServer* server = NULL;
 
  806  rdpShadowSurface* surface = NULL;
 
  810  server = subsystem->common.server;
 
  811  surface = server->surface;
 
  812  count = ArrayList_Count(server->clients);
 
  817  EnterCriticalSection(&surface->lock);
 
  818  surfaceRect.left = 0;
 
  821  surfaceRect.right = WINPR_ASSERTING_INT_CAST(UINT16, surface->width);
 
  822  surfaceRect.bottom = WINPR_ASSERTING_INT_CAST(UINT16, surface->height);
 
  823  LeaveCriticalSection(&surface->lock);
 
  825  XLockDisplay(subsystem->display);
 
  830  XSetErrorHandler(x11_shadow_error_handler_for_capture);
 
  831#if defined(WITH_XDAMAGE) 
  832  if (subsystem->use_xshm)
 
  834    image = subsystem->fb_image;
 
  835    XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap,
 
  836              subsystem->xshm_gc, 0, 0, subsystem->width, subsystem->height, 0, 0);
 
  838    EnterCriticalSection(&surface->lock);
 
  839    status = shadow_capture_compare_with_format(
 
  840        surface->data, surface->format, surface->scanline, surface->width, surface->height,
 
  841        (BYTE*)&(image->data[surface->width * 4ull]), subsystem->format,
 
  842        WINPR_ASSERTING_INT_CAST(UINT32, image->bytes_per_line), &invalidRect);
 
  843    LeaveCriticalSection(&surface->lock);
 
  848    EnterCriticalSection(&surface->lock);
 
  849    image = XGetImage(subsystem->display, subsystem->root_window, surface->x, surface->y,
 
  850                      surface->width, surface->height, AllPlanes, ZPixmap);
 
  854      status = shadow_capture_compare_with_format(
 
  855          surface->data, surface->format, surface->scanline, surface->width, surface->height,
 
  856          (BYTE*)image->data, subsystem->format,
 
  857          WINPR_ASSERTING_INT_CAST(UINT32, image->bytes_per_line), &invalidRect);
 
  859    LeaveCriticalSection(&surface->lock);
 
  871  XSetErrorHandler(NULL);
 
  872  XSync(subsystem->display, False);
 
  873  XUnlockDisplay(subsystem->display);
 
  878    EnterCriticalSection(&surface->lock);
 
  879    region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
 
  880    region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
 
  881    empty = region16_is_empty(&(surface->invalidRegion));
 
  882    LeaveCriticalSection(&surface->lock);
 
  887      EnterCriticalSection(&surface->lock);
 
  888      extents = region16_extents(&(surface->invalidRegion));
 
  891      width = extents->right - extents->left;
 
  892      height = extents->bottom - extents->top;
 
  894      WINPR_ASSERT(image->bytes_per_line >= 0);
 
  895      WINPR_ASSERT(width >= 0);
 
  896      WINPR_ASSERT(height >= 0);
 
  897      success = freerdp_image_copy_no_overlap(
 
  898          surface->data, surface->format, surface->scanline,
 
  899          WINPR_ASSERTING_INT_CAST(uint32_t, x), WINPR_ASSERTING_INT_CAST(uint32_t, y),
 
  900          WINPR_ASSERTING_INT_CAST(uint32_t, width),
 
  901          WINPR_ASSERTING_INT_CAST(uint32_t, height), (BYTE*)image->data, subsystem->format,
 
  902          WINPR_ASSERTING_INT_CAST(uint32_t, image->bytes_per_line),
 
  903          WINPR_ASSERTING_INT_CAST(UINT32, x), WINPR_ASSERTING_INT_CAST(UINT32, y), NULL,
 
  905      LeaveCriticalSection(&surface->lock);
 
  909#if defined(USE_SHADOW_BLEND_CURSOR) 
  910      if (x11_shadow_blend_cursor(subsystem) < 0)
 
  913      count = ArrayList_Count(server->clients);
 
  914      shadow_subsystem_frame_update(&subsystem->common);
 
  918        rdpShadowClient* client = NULL;
 
  919        client = (rdpShadowClient*)ArrayList_GetItem(server->clients, 0);
 
  922          subsystem->common.captureFrameRate =
 
  923              shadow_encoder_preferred_fps(client->encoder);
 
  926      EnterCriticalSection(&surface->lock);
 
  927      region16_clear(&(surface->invalidRegion));
 
  928      LeaveCriticalSection(&surface->lock);
 
  934  if (!subsystem->use_xshm && image)
 
  935    XDestroyImage(image);
 
  939    XSetErrorHandler(NULL);
 
  940    XSync(subsystem->display, False);
 
  941    XUnlockDisplay(subsystem->display);
 
  947static int x11_shadow_subsystem_process_message(x11ShadowSubsystem* subsystem, wMessage* message)
 
  951    case SHADOW_MSG_IN_REFRESH_REQUEST_ID:
 
  952      shadow_subsystem_frame_update((rdpShadowSubsystem*)subsystem);
 
  956      WLog_ERR(TAG, 
"Unknown message id: %" PRIu32 
"", message->id);
 
  961    message->Free(message);
 
  966static DWORD WINAPI x11_shadow_subsystem_thread(LPVOID arg)
 
  968  x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)arg;
 
  972  DWORD dwInterval = 0;
 
  973  UINT64 frameTime = 0;
 
  977  MsgPipe = subsystem->common.MsgPipe;
 
  979  events[nCount++] = subsystem->common.event;
 
  980  events[nCount++] = MessageQueue_Event(MsgPipe->In);
 
  981  subsystem->common.captureFrameRate = 16;
 
  982  dwInterval = 1000 / subsystem->common.captureFrameRate;
 
  983  frameTime = GetTickCount64() + dwInterval;
 
  987    const UINT64 cTime = GetTickCount64();
 
  988    const DWORD dwTimeout =
 
  989        (DWORD)((cTime > frameTime) ? 0 : MIN(UINT32_MAX, frameTime - cTime));
 
  990    status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout);
 
  992    if (WaitForSingleObject(MessageQueue_Event(MsgPipe->In), 0) == WAIT_OBJECT_0)
 
  994      if (MessageQueue_Peek(MsgPipe->In, &message, TRUE))
 
  996        if (message.id == WMQ_QUIT)
 
  999        x11_shadow_subsystem_process_message(subsystem, &message);
 
 1003    if (WaitForSingleObject(subsystem->common.event, 0) == WAIT_OBJECT_0)
 
 1005      XLockDisplay(subsystem->display);
 
 1007      if (XEventsQueued(subsystem->display, QueuedAlready))
 
 1009        XNextEvent(subsystem->display, &xevent);
 
 1010        x11_shadow_handle_xevent(subsystem, &xevent);
 
 1013      XUnlockDisplay(subsystem->display);
 
 1016    if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
 
 1018      x11_shadow_check_resize(subsystem);
 
 1019      x11_shadow_screen_grab(subsystem);
 
 1020      x11_shadow_query_cursor(subsystem, FALSE);
 
 1021      dwInterval = 1000 / subsystem->common.captureFrameRate;
 
 1022      frameTime += dwInterval;
 
 1030static int x11_shadow_subsystem_base_init(x11ShadowSubsystem* subsystem)
 
 1032  if (subsystem->display)
 
 1036  if (!getenv(
"DISPLAY"))
 
 1039    setenv(
"DISPLAY", 
":0", 1);
 
 1042  if (!XInitThreads())
 
 1045  subsystem->display = XOpenDisplay(NULL);
 
 1047  if (!subsystem->display)
 
 1049    WLog_ERR(TAG, 
"failed to open display: %s", XDisplayName(NULL));
 
 1053  subsystem->xfds = ConnectionNumber(subsystem->display);
 
 1054  subsystem->number = DefaultScreen(subsystem->display);
 
 1055  subsystem->screen = ScreenOfDisplay(subsystem->display, subsystem->number);
 
 1056  subsystem->depth = WINPR_ASSERTING_INT_CAST(UINT32, DefaultDepthOfScreen(subsystem->screen));
 
 1057  subsystem->width = WINPR_ASSERTING_INT_CAST(UINT32, WidthOfScreen(subsystem->screen));
 
 1058  subsystem->height = WINPR_ASSERTING_INT_CAST(UINT32, HeightOfScreen(subsystem->screen));
 
 1059  subsystem->root_window = RootWindow(subsystem->display, subsystem->number);
 
 1063static int x11_shadow_xfixes_init(x11ShadowSubsystem* subsystem)
 
 1066  int xfixes_event = 0;
 
 1067  int xfixes_error = 0;
 
 1071  if (!XFixesQueryExtension(subsystem->display, &xfixes_event, &xfixes_error))
 
 1074  if (!XFixesQueryVersion(subsystem->display, &major, &minor))
 
 1077  subsystem->xfixes_cursor_notify_event = xfixes_event + XFixesCursorNotify;
 
 1078  XFixesSelectCursorInput(subsystem->display, subsystem->root_window,
 
 1079                          XFixesDisplayCursorNotifyMask);
 
 1086static int x11_shadow_xinerama_init(x11ShadowSubsystem* subsystem)
 
 1089  int xinerama_event = 0;
 
 1090  int xinerama_error = 0;
 
 1092  const int rc = x11_shadow_subsystem_base_init(subsystem);
 
 1096  if (!XineramaQueryExtension(subsystem->display, &xinerama_event, &xinerama_error))
 
 1099#if defined(WITH_XDAMAGE) 
 1102  if (!XDamageQueryVersion(subsystem->display, &major, &minor))
 
 1106  if (!XineramaIsActive(subsystem->display))
 
 1115static int x11_shadow_xdamage_init(x11ShadowSubsystem* subsystem)
 
 1120  int damage_event = 0;
 
 1121  int damage_error = 0;
 
 1123  if (!subsystem->use_xfixes)
 
 1126  if (!XDamageQueryExtension(subsystem->display, &damage_event, &damage_error))
 
 1129  if (!XDamageQueryVersion(subsystem->display, &major, &minor))
 
 1135  subsystem->xdamage_notify_event = damage_event + XDamageNotify;
 
 1136  subsystem->xdamage =
 
 1137      XDamageCreate(subsystem->display, subsystem->root_window, XDamageReportDeltaRectangles);
 
 1139  if (!subsystem->xdamage)
 
 1143  subsystem->xdamage_region = XFixesCreateRegion(subsystem->display, NULL, 0);
 
 1145  if (!subsystem->xdamage_region)
 
 1155static int x11_shadow_xshm_init(x11ShadowSubsystem* subsystem)
 
 1162  if (!XShmQueryExtension(subsystem->display))
 
 1165  if (!XShmQueryVersion(subsystem->display, &major, &minor, &pixmaps))
 
 1171  subsystem->fb_shm_info.shmid = -1;
 
 1172  subsystem->fb_shm_info.shmaddr = (
char*)-1;
 
 1173  subsystem->fb_shm_info.readOnly = False;
 
 1174  subsystem->fb_image =
 
 1175      XShmCreateImage(subsystem->display, subsystem->visual, subsystem->depth, ZPixmap, NULL,
 
 1176                      &(subsystem->fb_shm_info), subsystem->width, subsystem->height);
 
 1178  if (!subsystem->fb_image)
 
 1180    WLog_ERR(TAG, 
"XShmCreateImage failed");
 
 1184  subsystem->fb_shm_info.shmid =
 
 1186             1ull * WINPR_ASSERTING_INT_CAST(uint32_t, subsystem->fb_image->bytes_per_line) *
 
 1187                 WINPR_ASSERTING_INT_CAST(uint32_t, subsystem->fb_image->height),
 
 1190  if (subsystem->fb_shm_info.shmid == -1)
 
 1192    WLog_ERR(TAG, 
"shmget failed");
 
 1196  subsystem->fb_shm_info.shmaddr = shmat(subsystem->fb_shm_info.shmid, 0, 0);
 
 1197  subsystem->fb_image->data = subsystem->fb_shm_info.shmaddr;
 
 1199  if (subsystem->fb_shm_info.shmaddr == ((
char*)-1))
 
 1201    WLog_ERR(TAG, 
"shmat failed");
 
 1205  if (!XShmAttach(subsystem->display, &(subsystem->fb_shm_info)))
 
 1208  XSync(subsystem->display, False);
 
 1209  shmctl(subsystem->fb_shm_info.shmid, IPC_RMID, 0);
 
 1210  subsystem->fb_pixmap = XShmCreatePixmap(
 
 1211      subsystem->display, subsystem->root_window, subsystem->fb_image->data,
 
 1212      &(subsystem->fb_shm_info), WINPR_ASSERTING_INT_CAST(uint32_t, subsystem->fb_image->width),
 
 1213      WINPR_ASSERTING_INT_CAST(uint32_t, subsystem->fb_image->height),
 
 1214      WINPR_ASSERTING_INT_CAST(uint32_t, subsystem->fb_image->depth));
 
 1215  XSync(subsystem->display, False);
 
 1217  if (!subsystem->fb_pixmap)
 
 1220  values.subwindow_mode = IncludeInferiors;
 
 1221  values.graphics_exposures = False;
 
 1222#if defined(WITH_XDAMAGE) 
 1223  subsystem->xshm_gc = XCreateGC(subsystem->display, subsystem->root_window,
 
 1224                                 GCSubwindowMode | GCGraphicsExposures, &values);
 
 1225  XSetFunction(subsystem->display, subsystem->xshm_gc, GXcopy);
 
 1227  XSync(subsystem->display, False);
 
 1231UINT32 x11_shadow_enum_monitors(
MONITOR_DEF* monitors, UINT32 maxMonitors)
 
 1233  Display* display = NULL;
 
 1234  int displayWidth = 0;
 
 1235  int displayHeight = 0;
 
 1236  int numMonitors = 0;
 
 1239  if (!getenv(
"DISPLAY"))
 
 1242    setenv(
"DISPLAY", 
":0", 1);
 
 1245  display = XOpenDisplay(NULL);
 
 1249    WLog_ERR(TAG, 
"failed to open display: %s", XDisplayName(NULL));
 
 1253  displayWidth = WidthOfScreen(DefaultScreenOfDisplay(display));
 
 1254  displayHeight = HeightOfScreen(DefaultScreenOfDisplay(display));
 
 1257#if defined(WITH_XDAMAGE) 
 1261    int xinerama_event = 0;
 
 1262    int xinerama_error = 0;
 
 1263    XineramaScreenInfo* screens = NULL;
 
 1265    const Bool xinerama = XineramaQueryExtension(display, &xinerama_event, &xinerama_error);
 
 1267#if defined(WITH_XDAMAGE) 
 1268        XDamageQueryVersion(display, &major, &minor);
 
 1273    if (xinerama && damage && XineramaIsActive(display))
 
 1275      screens = XineramaQueryScreens(display, &numMonitors);
 
 1277      if (numMonitors > (INT64)maxMonitors)
 
 1278        numMonitors = (int)maxMonitors;
 
 1280      if (screens && (numMonitors > 0))
 
 1282        for (
int index = 0; index < numMonitors; index++)
 
 1285          const XineramaScreenInfo* screen = &screens[index];
 
 1287          monitor->left = screen->x_org;
 
 1288          monitor->top = screen->y_org;
 
 1289          monitor->right = monitor->left + screen->width - 1;
 
 1290          monitor->bottom = monitor->top + screen->height - 1;
 
 1291          monitor->flags = (index == 0) ? 1 : 0;
 
 1299  XCloseDisplay(display);
 
 1301  if (numMonitors < 1)
 
 1308    monitor->right = displayWidth - 1;
 
 1309    monitor->bottom = displayHeight - 1;
 
 1314  return WINPR_ASSERTING_INT_CAST(uint32_t, numMonitors);
 
 1317static int x11_shadow_subsystem_init(rdpShadowSubsystem* sub)
 
 1321  int nextensions = 0;
 
 1322  char** extensions = NULL;
 
 1323  XVisualInfo* vi = NULL;
 
 1324  XVisualInfo* vis = NULL;
 
 1325  XVisualInfo 
template = { 0 };
 
 1326  XPixmapFormatValues* pf = NULL;
 
 1327  XPixmapFormatValues* pfs = NULL;
 
 1329  x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
 
 1334  subsystem->common.numMonitors = x11_shadow_enum_monitors(subsystem->common.monitors, 16);
 
 1335  const int rc = x11_shadow_subsystem_base_init(subsystem);
 
 1339  subsystem->format = (ImageByteOrder(subsystem->display) == LSBFirst) ? PIXEL_FORMAT_BGRA32
 
 1340                                                                       : PIXEL_FORMAT_ARGB32;
 
 1342  if ((subsystem->depth != 24) && (subsystem->depth != 32))
 
 1344    WLog_ERR(TAG, 
"unsupported X11 server color depth: %" PRIu32, subsystem->depth);
 
 1348  extensions = XListExtensions(subsystem->display, &nextensions);
 
 1350  if (!extensions || (nextensions < 0))
 
 1353  for (
int i = 0; i < nextensions; i++)
 
 1355    if (strcmp(extensions[i], 
"Composite") == 0)
 
 1356      subsystem->composite = TRUE;
 
 1359  XFreeExtensionList(extensions);
 
 1361  if (subsystem->composite)
 
 1362    subsystem->use_xdamage = FALSE;
 
 1364  pfs = XListPixmapFormats(subsystem->display, &pf_count);
 
 1368    WLog_ERR(TAG, 
"XListPixmapFormats failed");
 
 1372  for (
int i = 0; i < pf_count; i++)
 
 1376    if (pf->depth == (INT64)subsystem->depth)
 
 1378      subsystem->bpp = WINPR_ASSERTING_INT_CAST(uint32_t, pf->bits_per_pixel);
 
 1379      subsystem->scanline_pad = WINPR_ASSERTING_INT_CAST(uint32_t, pf->scanline_pad);
 
 1385  template.class = TrueColor;
 
 1386  template.screen = subsystem->number;
 
 1387  vis = XGetVisualInfo(subsystem->display, VisualClassMask | VisualScreenMask, &
template,
 
 1392    WLog_ERR(TAG, 
"XGetVisualInfo failed");
 
 1396  for (
int i = 0; i < vi_count; i++)
 
 1400    if (vi->depth == (INT64)subsystem->depth)
 
 1402      subsystem->visual = vi->visual;
 
 1408  XSelectInput(subsystem->display, subsystem->root_window, SubstructureNotifyMask);
 
 1409  subsystem->cursorMaxWidth = 256;
 
 1410  subsystem->cursorMaxHeight = 256;
 
 1411  subsystem->cursorPixels =
 
 1412      winpr_aligned_malloc(4ULL * subsystem->cursorMaxWidth * subsystem->cursorMaxHeight, 16);
 
 1414  if (!subsystem->cursorPixels)
 
 1417  x11_shadow_query_cursor(subsystem, TRUE);
 
 1419  if (subsystem->use_xfixes)
 
 1421    if (x11_shadow_xfixes_init(subsystem) < 0)
 
 1422      subsystem->use_xfixes = FALSE;
 
 1425  if (subsystem->use_xinerama)
 
 1427    if (x11_shadow_xinerama_init(subsystem) < 0)
 
 1428      subsystem->use_xinerama = FALSE;
 
 1431  if (subsystem->use_xshm)
 
 1433    if (x11_shadow_xshm_init(subsystem) < 0)
 
 1434      subsystem->use_xshm = FALSE;
 
 1437  if (subsystem->use_xdamage)
 
 1439    if (x11_shadow_xdamage_init(subsystem) < 0)
 
 1440      subsystem->use_xdamage = FALSE;
 
 1443  if (!(subsystem->common.event =
 
 1444            CreateFileDescriptorEvent(NULL, FALSE, FALSE, subsystem->xfds, WINPR_FD_READ)))
 
 1448    MONITOR_DEF* virtualScreen = &(subsystem->common.virtualScreen);
 
 1449    virtualScreen->left = 0;
 
 1450    virtualScreen->top = 0;
 
 1451    WINPR_ASSERT(subsystem->width <= INT32_MAX);
 
 1452    WINPR_ASSERT(subsystem->height <= INT32_MAX);
 
 1453    virtualScreen->right = (INT32)subsystem->width - 1;
 
 1454    virtualScreen->bottom = (INT32)subsystem->height - 1;
 
 1455    virtualScreen->flags = 1;
 
 1457              "X11 Extensions: XFixes: %" PRId32 
" Xinerama: %" PRId32 
" XDamage: %" PRId32
 
 1458              " XShm: %" PRId32 
"",
 
 1459              subsystem->use_xfixes, subsystem->use_xinerama, subsystem->use_xdamage,
 
 1460              subsystem->use_xshm);
 
 1466static int x11_shadow_subsystem_uninit(rdpShadowSubsystem* sub)
 
 1468  x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
 
 1473  if (subsystem->display)
 
 1475    XCloseDisplay(subsystem->display);
 
 1476    subsystem->display = NULL;
 
 1479  if (subsystem->common.event)
 
 1481    (void)CloseHandle(subsystem->common.event);
 
 1482    subsystem->common.event = NULL;
 
 1485  if (subsystem->cursorPixels)
 
 1487    winpr_aligned_free(subsystem->cursorPixels);
 
 1488    subsystem->cursorPixels = NULL;
 
 1494static int x11_shadow_subsystem_start(rdpShadowSubsystem* sub)
 
 1496  x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
 
 1501  if (!(subsystem->thread =
 
 1502            CreateThread(NULL, 0, x11_shadow_subsystem_thread, (
void*)subsystem, 0, NULL)))
 
 1504    WLog_ERR(TAG, 
"Failed to create thread");
 
 1511static int x11_shadow_subsystem_stop(rdpShadowSubsystem* sub)
 
 1513  x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
 
 1518  if (subsystem->thread)
 
 1520    if (MessageQueue_PostQuit(subsystem->common.MsgPipe->In, 0))
 
 1521      (
void)WaitForSingleObject(subsystem->thread, INFINITE);
 
 1523    (void)CloseHandle(subsystem->thread);
 
 1524    subsystem->thread = NULL;
 
 1530static rdpShadowSubsystem* x11_shadow_subsystem_new(
void)
 
 1532  x11ShadowSubsystem* subsystem = NULL;
 
 1533  subsystem = (x11ShadowSubsystem*)calloc(1, 
sizeof(x11ShadowSubsystem));
 
 1539  subsystem->common.Authenticate = x11_shadow_pam_authenticate;
 
 1541  subsystem->common.SynchronizeEvent = x11_shadow_input_synchronize_event;
 
 1542  subsystem->common.KeyboardEvent = x11_shadow_input_keyboard_event;
 
 1543  subsystem->common.UnicodeKeyboardEvent = x11_shadow_input_unicode_keyboard_event;
 
 1544  subsystem->common.MouseEvent = x11_shadow_input_mouse_event;
 
 1545  subsystem->common.RelMouseEvent = x11_shadow_input_rel_mouse_event;
 
 1546  subsystem->common.ExtendedMouseEvent = x11_shadow_input_extended_mouse_event;
 
 1547  subsystem->composite = FALSE;
 
 1548  subsystem->use_xshm = FALSE; 
 
 1549  subsystem->use_xfixes = TRUE;
 
 1550  subsystem->use_xdamage = FALSE;
 
 1551  subsystem->use_xinerama = TRUE;
 
 1552  return (rdpShadowSubsystem*)subsystem;
 
 1555static void x11_shadow_subsystem_free(rdpShadowSubsystem* subsystem)
 
 1560  x11_shadow_subsystem_uninit(subsystem);
 
 1564FREERDP_ENTRY_POINT(FREERDP_API 
const char* ShadowSubsystemName(
void))
 
 1569FREERDP_ENTRY_POINT(FREERDP_API 
int ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints))
 
 1574  pEntryPoints->New = x11_shadow_subsystem_new;
 
 1575  pEntryPoints->Free = x11_shadow_subsystem_free;
 
 1576  pEntryPoints->Init = x11_shadow_subsystem_init;
 
 1577  pEntryPoints->Uninit = x11_shadow_subsystem_uninit;
 
 1578  pEntryPoints->Start = x11_shadow_subsystem_start;
 
 1579  pEntryPoints->Stop = x11_shadow_subsystem_stop;
 
 1580  pEntryPoints->EnumMonitors = x11_shadow_enum_monitors;