20 #include <freerdp/config.h>
23 #include <X11/Xatom.h>
24 #include <X11/Xutil.h>
26 #include <winpr/cast.h>
27 #include <winpr/assert.h>
28 #include <winpr/wlog.h>
29 #include <winpr/print.h>
31 #include <freerdp/client/rail.h>
33 #include "xf_window.h"
37 #include <freerdp/log.h>
38 #define TAG CLIENT_TAG("x11")
40 static const char* error_code_names[] = {
"RAIL_EXEC_S_OK",
41 "RAIL_EXEC_E_HOOK_NOT_LOADED",
42 "RAIL_EXEC_E_DECODE_FAILED",
43 "RAIL_EXEC_E_NOT_IN_ALLOWLIST",
44 "RAIL_EXEC_E_FILE_NOT_FOUND",
46 "RAIL_EXEC_E_SESSION_LOCKED" };
48 #ifdef WITH_DEBUG_RAIL
49 static const char* movetype_names[] = {
50 "(invalid)",
"RAIL_WMSZ_LEFT",
"RAIL_WMSZ_RIGHT",
51 "RAIL_WMSZ_TOP",
"RAIL_WMSZ_TOPLEFT",
"RAIL_WMSZ_TOPRIGHT",
52 "RAIL_WMSZ_BOTTOM",
"RAIL_WMSZ_BOTTOMLEFT",
"RAIL_WMSZ_BOTTOMRIGHT",
53 "RAIL_WMSZ_MOVE",
"RAIL_WMSZ_KEYMOVE",
"RAIL_WMSZ_KEYSIZE"
62 typedef struct xf_rail_icon xfRailIcon;
64 struct xf_rail_icon_cache
68 UINT32 numCacheEntries;
76 } rail_paint_fn_arg_t;
78 void xf_rail_enable_remoteapp_mode(xfContext* xfc)
82 xfc->remote_app = TRUE;
83 xfc->drawable = xf_CreateDummyWindow(xfc);
84 xf_DestroyDesktopWindow(xfc, xfc->window);
89 void xf_rail_disable_remoteapp_mode(xfContext* xfc)
93 xfc->remote_app = FALSE;
94 xf_DestroyDummyWindow(xfc, xfc->drawable);
95 xf_create_window(xfc);
100 void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled)
103 xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, xwindow);
109 xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle);
111 WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
112 activate.windowId = (UINT32)appWindow->windowId;
113 activate.enabled = enabled;
114 xfc->rail->ClientActivate(xfc->rail, &activate);
117 BOOL xf_rail_send_client_system_command(xfContext* xfc, UINT64 windowId, UINT16 command)
120 WINPR_ASSERT(xfc->rail);
121 WINPR_ASSERT(xfc->rail->ClientSystemCommand);
122 if (windowId > UINT32_MAX)
126 const UINT rc = xfc->rail->ClientSystemCommand(xfc->rail, &syscommand);
127 return rc == CHANNEL_RC_OK;
136 void xf_rail_adjust_position(xfContext* xfc, xfAppWindow* appWindow)
140 if (!appWindow->is_mapped || appWindow->local_move.state != LMS_NOT_ACTIVE)
144 if (appWindow->x != appWindow->windowOffsetX || appWindow->y != appWindow->windowOffsetY ||
145 appWindow->width != (INT64)appWindow->windowWidth ||
146 appWindow->height != (INT64)appWindow->windowHeight)
148 WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
149 windowMove.windowId = (UINT32)appWindow->windowId;
154 const INT16 left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginLeft);
155 const INT16 right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginRight);
156 const INT16 top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginTop);
157 const INT16 bottom = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginBottom);
158 windowMove.left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x - left);
159 windowMove.top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->y - top);
160 windowMove.right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x + appWindow->width + right);
162 WINPR_ASSERTING_INT_CAST(INT16, appWindow->y + appWindow->height + bottom);
163 xfc->rail->ClientWindowMove(xfc->rail, &windowMove);
167 void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
173 unsigned int mask = 0;
174 Window root_window = 0;
175 Window child_window = 0;
176 rdpInput* input = NULL;
180 input = xfc->common.context.input;
183 if ((appWindow->local_move.direction == _NET_WM_MOVERESIZE_MOVE_KEYBOARD) ||
184 (appWindow->local_move.direction == _NET_WM_MOVERESIZE_SIZE_KEYBOARD))
191 WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
192 windowMove.windowId = (UINT32)appWindow->windowId;
198 const INT16 left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginLeft);
199 const INT16 right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginRight);
200 const INT16 top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginTop);
201 const INT16 bottom = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginBottom);
202 const INT16 w = WINPR_ASSERTING_INT_CAST(INT16, appWindow->width + right);
203 const INT16 h = WINPR_ASSERTING_INT_CAST(INT16, appWindow->height + bottom);
204 windowMove.left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x - left);
205 windowMove.top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->y - top);
206 windowMove.right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x + w);
208 windowMove.bottom = WINPR_ASSERTING_INT_CAST(INT16, appWindow->y + h);
209 xfc->rail->ClientWindowMove(xfc->rail, &windowMove);
215 XQueryPointer(xfc->display, appWindow->handle, &root_window, &child_window, &x, &y, &child_x,
219 if ((appWindow->local_move.direction != _NET_WM_MOVERESIZE_MOVE_KEYBOARD) &&
220 (appWindow->local_move.direction != _NET_WM_MOVERESIZE_SIZE_KEYBOARD))
222 freerdp_client_send_button_event(&xfc->common, FALSE, PTR_FLAGS_BUTTON1, x, y);
230 appWindow->windowOffsetX = appWindow->x;
231 appWindow->windowOffsetY = appWindow->y;
232 appWindow->windowWidth = WINPR_ASSERTING_INT_CAST(uint32_t, appWindow->width);
233 appWindow->windowHeight = WINPR_ASSERTING_INT_CAST(uint32_t, appWindow->height);
234 appWindow->local_move.state = LMS_TERMINATING;
237 BOOL xf_rail_paint_surface(xfContext* xfc, UINT64 windowId,
const RECTANGLE_16* rect)
239 xfAppWindow* appWindow = xf_rail_get_window(xfc, windowId);
247 .left = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->x, 0)),
248 .top = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->y, 0)),
249 .right = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->x + appWindow->width, 0)),
250 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->y + appWindow->height, 0))
253 REGION16 windowInvalidRegion = { 0 };
254 region16_init(&windowInvalidRegion);
255 region16_union_rect(&windowInvalidRegion, &windowInvalidRegion, &windowRect);
256 region16_intersect_rect(&windowInvalidRegion, &windowInvalidRegion, rect);
258 if (!region16_is_empty(&windowInvalidRegion))
260 const RECTANGLE_16* extents = region16_extents(&windowInvalidRegion);
263 .left = WINPR_ASSERTING_INT_CAST(UINT16, extents->left - appWindow->x),
264 .top = WINPR_ASSERTING_INT_CAST(UINT16, extents->top - appWindow->y),
265 .right = WINPR_ASSERTING_INT_CAST(UINT16, extents->right - appWindow->x),
266 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, extents->bottom - appWindow->y)
269 xf_UpdateWindowArea(xfc, appWindow, updateRect.left, updateRect.top,
270 updateRect.right - updateRect.left, updateRect.bottom - updateRect.top);
272 region16_uninit(&windowInvalidRegion);
276 static BOOL rail_paint_fn(
const void* pvkey,
void* value,
void* pvarg)
278 rail_paint_fn_arg_t* arg = pvarg;
282 const UINT64 key = *(
const UINT64*)pvkey;
283 return xf_rail_paint_surface(arg->xfc, key, arg->rect);
286 BOOL xf_rail_paint(xfContext* xfc,
const RECTANGLE_16* rect)
288 rail_paint_fn_arg_t arg = { .xfc = xfc, .rect = rect };
293 if (!xfc->railWindows)
296 return HashTable_Foreach(xfc->railWindows, rail_paint_fn, &arg);
299 #define window_state_log_style(log, windowState) \
300 window_state_log_style_int((log), (windowState), __FILE__, __func__, __LINE__)
301 static void window_state_log_style_int(wLog* log,
const WINDOW_STATE_ORDER* windowState,
302 const char* file,
const char* fkt,
size_t line)
304 const DWORD log_level = WLOG_DEBUG;
307 WINPR_ASSERT(windowState);
308 if (WLog_IsLevelActive(log, log_level))
310 char buffer1[128] = { 0 };
311 char buffer2[128] = { 0 };
313 window_styles_to_string(windowState->style, buffer1,
sizeof(buffer1));
314 window_styles_ex_to_string(windowState->extendedStyle, buffer2,
sizeof(buffer2));
315 WLog_PrintMessage(log, WLOG_MESSAGE_TEXT, log_level, line, file, fkt,
316 "windowStyle={%s, %s}", buffer1, buffer2);
322 static BOOL xf_rail_window_common(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
325 xfAppWindow* appWindow = NULL;
326 xfContext* xfc = (xfContext*)context;
327 UINT32 fieldFlags = orderInfo->fieldFlags;
328 BOOL position_or_size_updated = FALSE;
329 appWindow = xf_rail_get_window(xfc, orderInfo->windowId);
331 if (fieldFlags & WINDOW_ORDER_STATE_NEW)
335 xf_rail_add_window(xfc, orderInfo->windowId,
336 WINPR_ASSERTING_INT_CAST(uint32_t, windowState->windowOffsetX),
337 WINPR_ASSERTING_INT_CAST(uint32_t, windowState->windowOffsetY),
338 windowState->windowWidth, windowState->windowHeight, 0xFFFFFFFF);
343 appWindow->dwStyle = windowState->style;
344 appWindow->dwExStyle = windowState->extendedStyle;
345 window_state_log_style(xfc->log, windowState);
348 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
357 cnv.b = windowState->titleInfo.string;
358 if (windowState->titleInfo.length == 0)
360 if (!(title = _strdup(
"")))
362 WLog_ERR(TAG,
"failed to duplicate empty window title string");
366 else if (!(title = ConvertWCharNToUtf8Alloc(
367 cnv.wc, windowState->titleInfo.length /
sizeof(WCHAR), NULL)))
369 WLog_ERR(TAG,
"failed to convert window title");
373 appWindow->title = title;
377 if (!(appWindow->title = _strdup(
"RdpRailWindow")))
378 WLog_ERR(TAG,
"failed to duplicate default window title string");
381 if (!appWindow->title)
387 xf_AppWindowInit(xfc, appWindow);
394 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
395 (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) ||
396 (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) ||
397 (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) ||
398 (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) ||
399 (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) ||
400 (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY))
402 position_or_size_updated = TRUE;
407 if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
409 appWindow->windowOffsetX = windowState->windowOffsetX;
410 appWindow->windowOffsetY = windowState->windowOffsetY;
413 if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
415 appWindow->windowWidth = windowState->windowWidth;
416 appWindow->windowHeight = windowState->windowHeight;
419 if (fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_X)
421 appWindow->resizeMarginLeft = windowState->resizeMarginLeft;
422 appWindow->resizeMarginRight = windowState->resizeMarginRight;
425 if (fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_Y)
427 appWindow->resizeMarginTop = windowState->resizeMarginTop;
428 appWindow->resizeMarginBottom = windowState->resizeMarginBottom;
431 if (fieldFlags & WINDOW_ORDER_FIELD_OWNER)
433 appWindow->ownerWindowId = windowState->ownerWindowId;
436 if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
438 appWindow->dwStyle = windowState->style;
439 appWindow->dwExStyle = windowState->extendedStyle;
440 window_state_log_style(xfc->log, windowState);
443 if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
445 appWindow->showState = windowState->showState;
448 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
457 cnv.b = windowState->titleInfo.string;
458 if (windowState->titleInfo.length == 0)
460 if (!(title = _strdup(
"")))
462 WLog_ERR(TAG,
"failed to duplicate empty window title string");
466 else if (!(title = ConvertWCharNToUtf8Alloc(
467 cnv.wc, windowState->titleInfo.length /
sizeof(WCHAR), NULL)))
469 WLog_ERR(TAG,
"failed to convert window title");
473 free(appWindow->title);
474 appWindow->title = title;
477 if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
479 appWindow->clientOffsetX = windowState->clientOffsetX;
480 appWindow->clientOffsetY = windowState->clientOffsetY;
483 if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
485 appWindow->clientAreaWidth = windowState->clientAreaWidth;
486 appWindow->clientAreaHeight = windowState->clientAreaHeight;
489 if (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
491 appWindow->windowClientDeltaX = windowState->windowClientDeltaX;
492 appWindow->windowClientDeltaY = windowState->windowClientDeltaY;
495 if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
497 if (appWindow->windowRects)
499 free(appWindow->windowRects);
500 appWindow->windowRects = NULL;
503 appWindow->numWindowRects = windowState->numWindowRects;
505 if (appWindow->numWindowRects)
507 appWindow->windowRects =
510 if (!appWindow->windowRects)
513 CopyMemory(appWindow->windowRects, windowState->windowRects,
518 if (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
520 appWindow->visibleOffsetX = windowState->visibleOffsetX;
521 appWindow->visibleOffsetY = windowState->visibleOffsetY;
524 if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
526 if (appWindow->visibilityRects)
528 free(appWindow->visibilityRects);
529 appWindow->visibilityRects = NULL;
532 appWindow->numVisibilityRects = windowState->numVisibilityRects;
534 if (appWindow->numVisibilityRects)
536 appWindow->visibilityRects =
539 if (!appWindow->visibilityRects)
542 CopyMemory(appWindow->visibilityRects, windowState->visibilityRects,
549 if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
553 if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
555 xf_ShowWindow(xfc, appWindow, WINPR_ASSERTING_INT_CAST(UINT8, appWindow->showState));
558 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
560 if (appWindow->title)
561 xf_SetWindowText(xfc, appWindow, appWindow->title);
564 if (position_or_size_updated)
566 const INT32 visibilityRectsOffsetX =
567 (appWindow->visibleOffsetX -
568 (appWindow->clientOffsetX - appWindow->windowClientDeltaX));
569 const INT32 visibilityRectsOffsetY =
570 (appWindow->visibleOffsetY -
571 (appWindow->clientOffsetY - appWindow->windowClientDeltaY));
578 if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED)
581 if (appWindow->x == (INT64)appWindow->windowOffsetX &&
582 appWindow->y == (INT64)appWindow->windowOffsetY &&
583 appWindow->width == (INT64)appWindow->windowWidth &&
584 appWindow->height == (INT64)appWindow->windowHeight)
586 xf_UpdateWindowArea(xfc, appWindow, 0, 0,
587 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowWidth),
588 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowHeight));
592 xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX, appWindow->windowOffsetY,
593 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowWidth),
594 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowHeight));
597 xf_SetWindowVisibilityRects(
598 xfc, appWindow, WINPR_ASSERTING_INT_CAST(uint32_t, visibilityRectsOffsetX),
599 WINPR_ASSERTING_INT_CAST(uint32_t, visibilityRectsOffsetY),
600 appWindow->visibilityRects,
601 WINPR_ASSERTING_INT_CAST(
int, appWindow->numVisibilityRects));
604 if (appWindow->rail_state == WINDOW_SHOW_MAXIMIZED)
606 xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_ADD,
607 xfc->_NET_WM_STATE_MAXIMIZED_VERT, xfc->_NET_WM_STATE_MAXIMIZED_HORZ,
612 if (fieldFlags & (WINDOW_ORDER_STATE_NEW | WINDOW_ORDER_FIELD_STYLE))
613 xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle);
623 static BOOL xf_rail_window_delete(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo)
625 xfContext* xfc = (xfContext*)context;
626 return xf_rail_del_window(xfc, orderInfo->windowId);
629 static xfRailIconCache* RailIconCache_New(rdpSettings* settings)
631 xfRailIconCache* cache = NULL;
632 cache = calloc(1,
sizeof(xfRailIconCache));
638 cache->numCacheEntries =
640 cache->entries = calloc(1ull * cache->numCaches * cache->numCacheEntries,
sizeof(xfRailIcon));
644 WLog_ERR(TAG,
"failed to allocate icon cache %" PRIu32
" x %" PRIu32
" entries",
645 cache->numCaches, cache->numCacheEntries);
653 static void RailIconCache_Free(xfRailIconCache* cache)
657 for (UINT32 i = 0; i < cache->numCaches * cache->numCacheEntries; i++)
659 free(cache->entries[i].data);
662 free(cache->scratch.data);
663 free(cache->entries);
668 static xfRailIcon* RailIconCache_Lookup(xfRailIconCache* cache, UINT8 cacheId, UINT16 cacheEntry)
680 return &cache->scratch;
682 if (cacheId >= cache->numCaches)
685 if (cacheEntry >= cache->numCacheEntries)
688 return &cache->entries[cache->numCacheEntries * cacheId + cacheEntry];
701 static BOOL convert_rail_icon(
const ICON_INFO* iconInfo, xfRailIcon* railIcon)
703 BYTE* argbPixels = NULL;
704 BYTE* nextPixel = NULL;
706 argbPixels = calloc(1ull * iconInfo->width * iconInfo->height, 4);
711 if (!freerdp_image_copy_from_icon_data(
712 argbPixels, PIXEL_FORMAT_ARGB32, 0, 0, 0,
713 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->width),
714 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->height), iconInfo->bitsColor,
715 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->cbBitsColor), iconInfo->bitsMask,
716 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->cbBitsMask), iconInfo->colorTable,
717 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->cbColorTable), iconInfo->bpp))
720 const UINT32 nelements = 2 + iconInfo->width * iconInfo->height;
721 pixels = realloc(railIcon->data, nelements *
sizeof(
long));
726 railIcon->data = pixels;
728 railIcon->length = WINPR_ASSERTING_INT_CAST(
int, nelements);
729 pixels[0] = iconInfo->width;
730 pixels[1] = iconInfo->height;
731 nextPixel = argbPixels;
733 for (UINT32 i = 2; i < nelements; i++)
735 pixels[i] = FreeRDPReadColor(nextPixel, PIXEL_FORMAT_BGRA32);
746 static void xf_rail_set_window_icon(xfContext* xfc, xfAppWindow* railWindow, xfRailIcon* icon,
751 LogTagAndXChangeProperty(TAG, xfc->display, railWindow->handle, xfc->_NET_WM_ICON, XA_CARDINAL,
752 32, replace ? PropModeReplace : PropModeAppend,
753 (
unsigned char*)icon->data, icon->length);
754 XFlush(xfc->display);
757 static BOOL xf_rail_window_icon(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
760 xfContext* xfc = (xfContext*)context;
761 BOOL replaceIcon = 0;
762 xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId);
767 WINPR_ASSERT(windowIcon);
768 WINPR_ASSERT(windowIcon->iconInfo);
769 xfRailIcon* icon = RailIconCache_Lookup(
770 xfc->railIconCache, WINPR_ASSERTING_INT_CAST(UINT8, windowIcon->iconInfo->cacheId),
771 WINPR_ASSERTING_INT_CAST(UINT16, windowIcon->iconInfo->cacheEntry));
775 WLog_WARN(TAG,
"failed to get icon from cache %02X:%04X", windowIcon->iconInfo->cacheId,
776 windowIcon->iconInfo->cacheEntry);
780 if (!convert_rail_icon(windowIcon->iconInfo, icon))
782 WLog_WARN(TAG,
"failed to convert icon for window %08X", orderInfo->windowId);
786 replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW);
787 xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon);
791 static BOOL xf_rail_window_cached_icon(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
794 xfContext* xfc = (xfContext*)context;
795 xfAppWindow* railWindow = NULL;
796 xfRailIcon* icon = NULL;
797 BOOL replaceIcon = 0;
798 railWindow = xf_rail_get_window(xfc, orderInfo->windowId);
803 icon = RailIconCache_Lookup(
804 xfc->railIconCache, WINPR_ASSERTING_INT_CAST(UINT8, windowCachedIcon->cachedIcon.cacheId),
805 WINPR_ASSERTING_INT_CAST(UINT16, windowCachedIcon->cachedIcon.cacheEntry));
809 WLog_WARN(TAG,
"failed to get icon from cache %02X:%04X",
810 windowCachedIcon->cachedIcon.cacheId, windowCachedIcon->cachedIcon.cacheEntry);
814 replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW);
815 xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon);
819 static BOOL xf_rail_notify_icon_common(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
822 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION)
826 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP)
830 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP)
834 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE)
838 if (orderInfo->fieldFlags & WINDOW_ORDER_ICON)
842 if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON)
849 static BOOL xf_rail_notify_icon_create(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
852 return xf_rail_notify_icon_common(context, orderInfo, notifyIconState);
855 static BOOL xf_rail_notify_icon_update(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
858 return xf_rail_notify_icon_common(context, orderInfo, notifyIconState);
861 static BOOL xf_rail_notify_icon_delete(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo)
866 static BOOL xf_rail_monitored_desktop(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
872 static BOOL xf_rail_non_monitored_desktop(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo)
874 xfContext* xfc = (xfContext*)context;
875 xf_rail_disable_remoteapp_mode(xfc);
879 static void xf_rail_register_update_callbacks(rdpUpdate* update)
881 rdpWindowUpdate* window = update->window;
882 window->WindowCreate = xf_rail_window_common;
883 window->WindowUpdate = xf_rail_window_common;
884 window->WindowDelete = xf_rail_window_delete;
885 window->WindowIcon = xf_rail_window_icon;
886 window->WindowCachedIcon = xf_rail_window_cached_icon;
887 window->NotifyIconCreate = xf_rail_notify_icon_create;
888 window->NotifyIconUpdate = xf_rail_notify_icon_update;
889 window->NotifyIconDelete = xf_rail_notify_icon_delete;
890 window->MonitoredDesktop = xf_rail_monitored_desktop;
891 window->NonMonitoredDesktop = xf_rail_non_monitored_desktop;
901 static UINT xf_rail_server_execute_result(RailClientContext* context,
904 xfContext* xfc = NULL;
906 WINPR_ASSERT(context);
907 WINPR_ASSERT(execResult);
909 xfc = (xfContext*)context->custom;
912 if (execResult->execResult != RAIL_EXEC_S_OK)
914 WLog_ERR(TAG,
"RAIL exec error: execResult=%s NtError=0x%X\n",
915 error_code_names[execResult->execResult], execResult->rawResult);
916 freerdp_abort_connect_context(&xfc->common.context);
920 xf_rail_enable_remoteapp_mode(xfc);
923 return CHANNEL_RC_OK;
931 static UINT xf_rail_server_system_param(RailClientContext* context,
935 return CHANNEL_RC_OK;
943 static UINT xf_rail_server_handshake(RailClientContext* context,
946 return client_rail_server_start_cmd(context);
954 static UINT xf_rail_server_handshake_ex(RailClientContext* context,
957 return client_rail_server_start_cmd(context);
965 static UINT xf_rail_server_local_move_size(RailClientContext* context,
971 Window child_window = 0;
972 xfContext* xfc = (xfContext*)context->custom;
973 xfAppWindow* appWindow = xf_rail_get_window(xfc, localMoveSize->windowId);
976 return ERROR_INTERNAL_ERROR;
978 switch (localMoveSize->moveSizeType)
981 direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
982 x = localMoveSize->posX;
983 y = localMoveSize->posY;
986 case RAIL_WMSZ_RIGHT:
987 direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
988 x = localMoveSize->posX;
989 y = localMoveSize->posY;
993 direction = _NET_WM_MOVERESIZE_SIZE_TOP;
994 x = localMoveSize->posX;
995 y = localMoveSize->posY;
998 case RAIL_WMSZ_TOPLEFT:
999 direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
1000 x = localMoveSize->posX;
1001 y = localMoveSize->posY;
1004 case RAIL_WMSZ_TOPRIGHT:
1005 direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
1006 x = localMoveSize->posX;
1007 y = localMoveSize->posY;
1010 case RAIL_WMSZ_BOTTOM:
1011 direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
1012 x = localMoveSize->posX;
1013 y = localMoveSize->posY;
1016 case RAIL_WMSZ_BOTTOMLEFT:
1017 direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
1018 x = localMoveSize->posX;
1019 y = localMoveSize->posY;
1022 case RAIL_WMSZ_BOTTOMRIGHT:
1023 direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
1024 x = localMoveSize->posX;
1025 y = localMoveSize->posY;
1028 case RAIL_WMSZ_MOVE:
1029 direction = _NET_WM_MOVERESIZE_MOVE;
1030 XTranslateCoordinates(xfc->display, appWindow->handle, RootWindowOfScreen(xfc->screen),
1031 localMoveSize->posX, localMoveSize->posY, &x, &y, &child_window);
1034 case RAIL_WMSZ_KEYMOVE:
1035 direction = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
1036 x = localMoveSize->posX;
1037 y = localMoveSize->posY;
1039 return CHANNEL_RC_OK;
1041 case RAIL_WMSZ_KEYSIZE:
1042 direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
1043 x = localMoveSize->posX;
1044 y = localMoveSize->posY;
1046 return CHANNEL_RC_OK;
1051 if (localMoveSize->isMoveSizeStart)
1052 xf_StartLocalMoveSize(xfc, appWindow, direction, x, y);
1054 xf_EndLocalMoveSize(xfc, appWindow);
1056 return CHANNEL_RC_OK;
1064 static UINT xf_rail_server_min_max_info(RailClientContext* context,
1067 xfContext* xfc = (xfContext*)context->custom;
1068 xfAppWindow* appWindow = xf_rail_get_window(xfc, minMaxInfo->windowId);
1072 xf_SetWindowMinMaxInfo(xfc, appWindow, minMaxInfo->maxWidth, minMaxInfo->maxHeight,
1073 minMaxInfo->maxPosX, minMaxInfo->maxPosY, minMaxInfo->minTrackWidth,
1074 minMaxInfo->minTrackHeight, minMaxInfo->maxTrackWidth,
1075 minMaxInfo->maxTrackHeight);
1078 return CHANNEL_RC_OK;
1086 static UINT xf_rail_server_language_bar_info(RailClientContext* context,
1089 return CHANNEL_RC_OK;
1097 static UINT xf_rail_server_get_appid_response(RailClientContext* context,
1100 return CHANNEL_RC_OK;
1103 static BOOL rail_window_key_equals(
const void* key1,
const void* key2)
1105 const UINT64* k1 = (
const UINT64*)key1;
1106 const UINT64* k2 = (
const UINT64*)key2;
1114 static UINT32 rail_window_key_hash(
const void* key)
1116 const UINT64* k1 = (
const UINT64*)key;
1120 static void rail_window_free(
void* value)
1122 xfAppWindow* appWindow = (xfAppWindow*)value;
1127 xf_DestroyWindow(appWindow->xfc, appWindow);
1130 int xf_rail_init(xfContext* xfc, RailClientContext* rail)
1132 rdpContext* context = (rdpContext*)xfc;
1138 xf_rail_register_update_callbacks(context->update);
1139 rail->custom = (
void*)xfc;
1140 rail->ServerExecuteResult = xf_rail_server_execute_result;
1141 rail->ServerSystemParam = xf_rail_server_system_param;
1142 rail->ServerHandshake = xf_rail_server_handshake;
1143 rail->ServerHandshakeEx = xf_rail_server_handshake_ex;
1144 rail->ServerLocalMoveSize = xf_rail_server_local_move_size;
1145 rail->ServerMinMaxInfo = xf_rail_server_min_max_info;
1146 rail->ServerLanguageBarInfo = xf_rail_server_language_bar_info;
1147 rail->ServerGetAppIdResponse = xf_rail_server_get_appid_response;
1148 xfc->railWindows = HashTable_New(TRUE);
1150 if (!xfc->railWindows)
1153 if (!HashTable_SetHashFunction(xfc->railWindows, rail_window_key_hash))
1156 wObject* obj = HashTable_KeyObject(xfc->railWindows);
1157 obj->fnObjectEquals = rail_window_key_equals;
1160 wObject* obj = HashTable_ValueObject(xfc->railWindows);
1161 obj->fnObjectFree = rail_window_free;
1163 xfc->railIconCache = RailIconCache_New(xfc->common.context.settings);
1165 if (!xfc->railIconCache)
1171 HashTable_Free(xfc->railWindows);
1175 int xf_rail_uninit(xfContext* xfc, RailClientContext* rail)
1181 xfc->rail->custom = NULL;
1185 if (xfc->railWindows)
1187 HashTable_Free(xfc->railWindows);
1188 xfc->railWindows = NULL;
1191 if (xfc->railIconCache)
1193 RailIconCache_Free(xfc->railIconCache);
1194 xfc->railIconCache = NULL;
1200 xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64
id, UINT32 x, UINT32 y, UINT32 width,
1201 UINT32 height, UINT32 surfaceId)
1203 xfAppWindow* appWindow = NULL;
1208 appWindow = (xfAppWindow*)calloc(1,
sizeof(xfAppWindow));
1213 appWindow->xfc = xfc;
1214 appWindow->windowId = id;
1215 appWindow->surfaceId = surfaceId;
1216 appWindow->x = WINPR_ASSERTING_INT_CAST(
int, x);
1217 appWindow->y = WINPR_ASSERTING_INT_CAST(
int, y);
1218 appWindow->width = WINPR_ASSERTING_INT_CAST(
int, width);
1219 appWindow->height = WINPR_ASSERTING_INT_CAST(
int, height);
1221 if (!xf_AppWindowCreate(xfc, appWindow))
1223 if (!HashTable_Insert(xfc->railWindows, &appWindow->windowId, (
void*)appWindow))
1227 rail_window_free(appWindow);
1231 BOOL xf_rail_del_window(xfContext* xfc, UINT64
id)
1236 if (!xfc->railWindows)
1239 return HashTable_Remove(xfc->railWindows, &
id);
1242 xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64
id)
1247 if (!xfc->railWindows)
1250 return HashTable_GetItemValue(xfc->railWindows, &
id);
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
This struct contains function pointer to initialize/free objects.