20#include <freerdp/config.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>
37#include <freerdp/log.h>
38#define TAG CLIENT_TAG("x11")
40static const char* error_code2str(UINT32 code)
47 EVCASE(RAIL_EXEC_S_OK);
48 EVCASE(RAIL_EXEC_E_HOOK_NOT_LOADED);
49 EVCASE(RAIL_EXEC_E_DECODE_FAILED);
50 EVCASE(RAIL_EXEC_E_NOT_IN_ALLOWLIST);
51 EVCASE(RAIL_EXEC_E_FILE_NOT_FOUND);
52 EVCASE(RAIL_EXEC_E_FAIL);
53 EVCASE(RAIL_EXEC_E_SESSION_LOCKED);
55 return "RAIL_EXEC_E_UNKNOWN";
60static const char* movetype2str(UINT32 code)
69 EVCASE(RAIL_WMSZ_LEFT);
70 EVCASE(RAIL_WMSZ_RIGHT);
71 EVCASE(RAIL_WMSZ_TOP);
72 EVCASE(RAIL_WMSZ_TOPLEFT);
73 EVCASE(RAIL_WMSZ_TOPRIGHT);
74 EVCASE(RAIL_WMSZ_BOTTOM);
75 EVCASE(RAIL_WMSZ_BOTTOMLEFT);
76 EVCASE(RAIL_WMSZ_BOTTOMRIGHT);
77 EVCASE(RAIL_WMSZ_MOVE);
78 EVCASE(RAIL_WMSZ_KEYMOVE);
79 EVCASE(RAIL_WMSZ_KEYSIZE);
81 return "RAIL_WMSZ_INVALID";
91typedef struct xf_rail_icon xfRailIcon;
93struct xf_rail_icon_cache
97 UINT32 numCacheEntries;
105} rail_paint_fn_arg_t;
107BOOL xf_rail_enable_remoteapp_mode(xfContext* xfc)
110 if (!xfc->remote_app)
112 rdpGdi* gdi = xfc->common.context.gdi;
115 const BOOL old = gdi->suppressOutput;
116 gdi->suppressOutput = TRUE;
117 xfc->remote_app = TRUE;
118 xfc->drawable = xf_CreateDummyWindow(xfc);
119 xf_DestroyDesktopWindow(xfc, xfc->window);
120 xfc->window =
nullptr;
122 gdi->suppressOutput = old;
127BOOL xf_rail_disable_remoteapp_mode(xfContext* xfc)
132 rdpGdi* gdi = xfc->common.context.gdi;
135 const BOOL old = gdi->suppressOutput;
136 gdi->suppressOutput = TRUE;
138 xfc->remote_app = FALSE;
139 xf_DestroyDummyWindow(xfc, xfc->drawable);
140 xf_destroy_window(xfc);
141 xf_create_window(xfc);
142 xf_create_image(xfc);
144 gdi->suppressOutput = old;
149BOOL xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled)
152 xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, xwindow);
158 xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle);
160 WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
161 activate.windowId = (UINT32)appWindow->windowId;
162 xf_rail_return_window(appWindow);
164 activate.enabled = enabled;
165 const UINT rc = xfc->rail->ClientActivate(xfc->rail, &activate);
166 return rc == CHANNEL_RC_OK;
169BOOL xf_rail_send_client_system_command(xfContext* xfc, UINT64 windowId, UINT16 command)
172 WINPR_ASSERT(xfc->rail);
173 WINPR_ASSERT(xfc->rail->ClientSystemCommand);
174 if (windowId > UINT32_MAX)
178 const UINT rc = xfc->rail->ClientSystemCommand(xfc->rail, &syscommand);
179 return rc == CHANNEL_RC_OK;
188BOOL xf_rail_adjust_position(xfContext* xfc, xfAppWindow* appWindow)
193 WINPR_ASSERT(appWindow);
194 if (!appWindow->is_mapped || appWindow->local_move.state != LMS_NOT_ACTIVE)
198 if (appWindow->x != appWindow->windowOffsetX || appWindow->y != appWindow->windowOffsetY ||
199 appWindow->width != (INT64)appWindow->windowWidth ||
200 appWindow->height != (INT64)appWindow->windowHeight)
202 WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
203 windowMove.windowId = (UINT32)appWindow->windowId;
208 const INT16 left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginLeft);
209 const INT16 right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginRight);
210 const INT16 top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginTop);
211 const INT16 bottom = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginBottom);
212 windowMove.left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x - left);
213 windowMove.top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->y - top);
214 windowMove.right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x + appWindow->width + right);
216 WINPR_ASSERTING_INT_CAST(INT16, appWindow->y + appWindow->height + bottom);
217 const UINT rc = xfc->rail->ClientWindowMove(xfc->rail, &windowMove);
218 return rc == CHANNEL_RC_OK;
223BOOL xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
229 unsigned int mask = 0;
230 Window root_window = 0;
231 Window child_window = 0;
234 WINPR_ASSERT(appWindow);
236 if ((appWindow->local_move.direction == NET_WM_MOVERESIZE_MOVE_KEYBOARD) ||
237 (appWindow->local_move.direction == NET_WM_MOVERESIZE_SIZE_KEYBOARD))
244 WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
245 windowMove.windowId = (UINT32)appWindow->windowId;
251 const INT16 left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginLeft);
252 const INT16 right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginRight);
253 const INT16 top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginTop);
254 const INT16 bottom = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginBottom);
255 const INT16 w = WINPR_ASSERTING_INT_CAST(INT16, appWindow->width + right);
256 const INT16 h = WINPR_ASSERTING_INT_CAST(INT16, appWindow->height + bottom);
257 windowMove.left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x - left);
258 windowMove.top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->y - top);
259 windowMove.right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x + w);
261 windowMove.bottom = WINPR_ASSERTING_INT_CAST(INT16, appWindow->y + h);
262 const UINT rc = xfc->rail->ClientWindowMove(xfc->rail, &windowMove);
263 if (rc != CHANNEL_RC_OK)
270 XQueryPointer(xfc->display, appWindow->handle, &root_window, &child_window, &x, &y, &child_x,
274 if ((appWindow->local_move.direction != NET_WM_MOVERESIZE_MOVE_KEYBOARD) &&
275 (appWindow->local_move.direction != NET_WM_MOVERESIZE_SIZE_KEYBOARD))
277 if (!freerdp_client_send_button_event(&xfc->common, FALSE, PTR_FLAGS_BUTTON1, x, y))
286 appWindow->windowOffsetX = appWindow->x;
287 appWindow->windowOffsetY = appWindow->y;
288 appWindow->windowWidth = WINPR_ASSERTING_INT_CAST(uint32_t, appWindow->width);
289 appWindow->windowHeight = WINPR_ASSERTING_INT_CAST(uint32_t, appWindow->height);
290 appWindow->local_move.state = LMS_TERMINATING;
294BOOL xf_rail_paint_surface(xfContext* xfc, UINT64 windowId,
const RECTANGLE_16* rect)
296 xfAppWindow* appWindow = xf_rail_get_window(xfc, windowId);
304 .left = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->x, 0)),
305 .top = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->y, 0)),
306 .right = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->x + appWindow->width, 0)),
307 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->y + appWindow->height, 0))
310 REGION16 windowInvalidRegion = WINPR_C_ARRAY_INIT;
311 region16_init(&windowInvalidRegion);
312 if (!region16_union_rect(&windowInvalidRegion, &windowInvalidRegion, &windowRect))
314 if (!region16_intersect_rect(&windowInvalidRegion, &windowInvalidRegion, rect))
317 if (!region16_is_empty(&windowInvalidRegion))
319 const RECTANGLE_16* extents = region16_extents(&windowInvalidRegion);
322 .left = WINPR_ASSERTING_INT_CAST(UINT16, extents->left - appWindow->x),
323 .top = WINPR_ASSERTING_INT_CAST(UINT16, extents->top - appWindow->y),
324 .right = WINPR_ASSERTING_INT_CAST(UINT16, extents->right - appWindow->x),
325 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, extents->bottom - appWindow->y)
328 xf_UpdateWindowArea(xfc, appWindow, updateRect.left, updateRect.top,
329 updateRect.right - updateRect.left, updateRect.bottom - updateRect.top);
331 region16_uninit(&windowInvalidRegion);
332 xf_rail_return_window(appWindow);
336static BOOL rail_paint_fn(
const void* pvkey, WINPR_ATTR_UNUSED
void* value,
void* pvarg)
338 rail_paint_fn_arg_t* arg = pvarg;
342 const UINT64 key = *(
const UINT64*)pvkey;
343 return xf_rail_paint_surface(arg->xfc, key, arg->rect);
346BOOL xf_rail_paint(xfContext* xfc,
const RECTANGLE_16* rect)
348 rail_paint_fn_arg_t arg = { .xfc = xfc, .rect = rect };
353 if (!xfc->railWindows)
356 return HashTable_Foreach(xfc->railWindows, rail_paint_fn, &arg);
359#define window_state_log_style(log, windowState) \
360 window_state_log_style_int((log), (windowState), __FILE__, __func__, __LINE__)
361static void window_state_log_style_int(wLog* log,
const WINDOW_STATE_ORDER* windowState,
362 const char* file,
const char* fkt,
size_t line)
364 const DWORD log_level = WLOG_DEBUG;
367 WINPR_ASSERT(windowState);
368 if (WLog_IsLevelActive(log, log_level))
370 char buffer1[128] = WINPR_C_ARRAY_INIT;
371 char buffer2[128] = WINPR_C_ARRAY_INIT;
373 window_styles_to_string(windowState->style, buffer1,
sizeof(buffer1));
374 window_styles_ex_to_string(windowState->extendedStyle, buffer2,
sizeof(buffer2));
375 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"windowStyle={%s, %s}", buffer1,
382static BOOL xf_rail_window_common(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
386 xfContext* xfc = (xfContext*)context;
389 WINPR_ASSERT(orderInfo);
390 WINPR_ASSERT(windowState);
392 UINT32 fieldFlags = orderInfo->fieldFlags;
393 BOOL position_or_size_updated = FALSE;
394 xfAppWindow* appWindow = xf_rail_get_window(xfc, orderInfo->windowId);
396 if (fieldFlags & WINDOW_ORDER_STATE_NEW)
399 appWindow = xf_rail_add_window(xfc, orderInfo->windowId, windowState->windowOffsetX,
400 windowState->windowOffsetY, windowState->windowWidth,
401 windowState->windowHeight, 0xFFFFFFFF);
406 appWindow->dwStyle = windowState->style;
407 appWindow->dwExStyle = windowState->extendedStyle;
408 window_state_log_style(xfc->log, windowState);
411 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
418 char* title =
nullptr;
420 cnv.b = windowState->titleInfo.string;
421 if (windowState->titleInfo.length == 0)
423 if (!(title = _strdup(
"")))
425 WLog_ERR(TAG,
"failed to duplicate empty window title string");
429 else if (!(title = ConvertWCharNToUtf8Alloc(
430 cnv.wc, windowState->titleInfo.length /
sizeof(WCHAR),
nullptr)))
432 WLog_ERR(TAG,
"failed to convert window title");
436 appWindow->title = title;
440 if (!(appWindow->title = _strdup(
"RdpRailWindow")))
441 WLog_ERR(TAG,
"failed to duplicate default window title string");
444 if (!appWindow->title)
447 xf_AppWindowInit(xfc, appWindow);
454 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
455 (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) ||
456 (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) ||
457 (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) ||
458 (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) ||
459 (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) ||
460 (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY))
462 position_or_size_updated = TRUE;
467 if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
469 appWindow->windowOffsetX = windowState->windowOffsetX;
470 appWindow->windowOffsetY = windowState->windowOffsetY;
473 if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
475 appWindow->windowWidth = windowState->windowWidth;
476 appWindow->windowHeight = windowState->windowHeight;
479 if (fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_X)
481 appWindow->resizeMarginLeft = windowState->resizeMarginLeft;
482 appWindow->resizeMarginRight = windowState->resizeMarginRight;
485 if (fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_Y)
487 appWindow->resizeMarginTop = windowState->resizeMarginTop;
488 appWindow->resizeMarginBottom = windowState->resizeMarginBottom;
491 if (fieldFlags & WINDOW_ORDER_FIELD_OWNER)
493 appWindow->ownerWindowId = windowState->ownerWindowId;
496 if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
498 appWindow->dwStyle = windowState->style;
499 appWindow->dwExStyle = windowState->extendedStyle;
500 window_state_log_style(xfc->log, windowState);
503 if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
505 appWindow->showState = windowState->showState;
508 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
510 char* title =
nullptr;
517 cnv.b = windowState->titleInfo.string;
518 if (windowState->titleInfo.length == 0)
520 if (!(title = _strdup(
"")))
522 WLog_ERR(TAG,
"failed to duplicate empty window title string");
526 else if (!(title = ConvertWCharNToUtf8Alloc(
527 cnv.wc, windowState->titleInfo.length /
sizeof(WCHAR),
nullptr)))
529 WLog_ERR(TAG,
"failed to convert window title");
533 free(appWindow->title);
534 appWindow->title = title;
537 if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
539 appWindow->clientOffsetX = windowState->clientOffsetX;
540 appWindow->clientOffsetY = windowState->clientOffsetY;
543 if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
545 appWindow->clientAreaWidth = windowState->clientAreaWidth;
546 appWindow->clientAreaHeight = windowState->clientAreaHeight;
549 if (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
551 appWindow->windowClientDeltaX = windowState->windowClientDeltaX;
552 appWindow->windowClientDeltaY = windowState->windowClientDeltaY;
555 if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
557 if (appWindow->windowRects)
559 free(appWindow->windowRects);
560 appWindow->windowRects =
nullptr;
563 appWindow->numWindowRects = windowState->numWindowRects;
565 if (appWindow->numWindowRects)
567 appWindow->windowRects =
570 if (!appWindow->windowRects)
573 CopyMemory(appWindow->windowRects, windowState->windowRects,
578 if (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
580 appWindow->visibleOffsetX = windowState->visibleOffsetX;
581 appWindow->visibleOffsetY = windowState->visibleOffsetY;
584 if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
586 if (appWindow->visibilityRects)
588 free(appWindow->visibilityRects);
589 appWindow->visibilityRects =
nullptr;
592 appWindow->numVisibilityRects = windowState->numVisibilityRects;
594 if (appWindow->numVisibilityRects)
596 appWindow->visibilityRects =
599 if (!appWindow->visibilityRects)
602 CopyMemory(appWindow->visibilityRects, windowState->visibilityRects,
609 if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
613 if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
615 xf_ShowWindow(xfc, appWindow, WINPR_ASSERTING_INT_CAST(UINT8, appWindow->showState));
618 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
620 if (appWindow->title)
621 xf_SetWindowText(xfc, appWindow, appWindow->title);
624 if (position_or_size_updated)
626 const INT32 visibilityRectsOffsetX =
627 (appWindow->visibleOffsetX -
628 (appWindow->clientOffsetX - appWindow->windowClientDeltaX));
629 const INT32 visibilityRectsOffsetY =
630 (appWindow->visibleOffsetY -
631 (appWindow->clientOffsetY - appWindow->windowClientDeltaY));
638 if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED)
641 if (appWindow->x == (INT64)appWindow->windowOffsetX &&
642 appWindow->y == (INT64)appWindow->windowOffsetY &&
643 appWindow->width == (INT64)appWindow->windowWidth &&
644 appWindow->height == (INT64)appWindow->windowHeight)
646 xf_UpdateWindowArea(xfc, appWindow, 0, 0,
647 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowWidth),
648 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowHeight));
652 xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX, appWindow->windowOffsetY,
653 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowWidth),
654 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowHeight));
657 xf_SetWindowVisibilityRects(
658 xfc, appWindow, WINPR_ASSERTING_INT_CAST(uint32_t, visibilityRectsOffsetX),
659 WINPR_ASSERTING_INT_CAST(uint32_t, visibilityRectsOffsetY),
660 appWindow->visibilityRects,
661 WINPR_ASSERTING_INT_CAST(
int, appWindow->numVisibilityRects));
664 if (appWindow->rail_state == WINDOW_SHOW_MAXIMIZED)
666 xf_SendClientEvent(xfc, appWindow->handle, xfc->NET_WM_STATE, 4, NET_WM_STATE_ADD,
667 xfc->NET_WM_STATE_MAXIMIZED_VERT, xfc->NET_WM_STATE_MAXIMIZED_HORZ,
672 if (fieldFlags & (WINDOW_ORDER_STATE_NEW | WINDOW_ORDER_FIELD_STYLE))
673 xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle);
682 xf_rail_return_window(appWindow);
686static BOOL xf_rail_window_delete(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo)
688 xfContext* xfc = (xfContext*)context;
690 return xf_rail_del_window(xfc, orderInfo->windowId);
693static xfRailIconCache* RailIconCache_New(rdpSettings* settings)
695 xfRailIconCache* cache = calloc(1,
sizeof(xfRailIconCache));
701 cache->numCacheEntries =
703 cache->entries = calloc(1ull * cache->numCaches * cache->numCacheEntries,
sizeof(xfRailIcon));
707 WLog_ERR(TAG,
"failed to allocate icon cache %" PRIu32
" x %" PRIu32
" entries",
708 cache->numCaches, cache->numCacheEntries);
716static void RailIconCache_Free(xfRailIconCache* cache)
721 for (UINT32 i = 0; i < cache->numCaches * cache->numCacheEntries; i++)
723 xfRailIcon* cur = &cache->entries[i];
727 free(cache->scratch.data);
728 free(cache->entries);
732static xfRailIcon* RailIconCache_Lookup(xfRailIconCache* cache, UINT8 cacheId, UINT16 cacheEntry)
745 return &cache->scratch;
747 if (cacheId >= cache->numCaches)
750 if (cacheEntry >= cache->numCacheEntries)
753 return &cache->entries[cache->numCacheEntries * cacheId + cacheEntry];
766static BOOL convert_rail_icon(
const ICON_INFO* iconInfo, xfRailIcon* railIcon)
768 WINPR_ASSERT(iconInfo);
769 WINPR_ASSERT(railIcon);
771 BYTE* nextPixel =
nullptr;
772 long* pixels =
nullptr;
773 BYTE* argbPixels = calloc(1ull * iconInfo->width * iconInfo->height, 4);
778 if (!freerdp_image_copy_from_icon_data(
779 argbPixels, PIXEL_FORMAT_ARGB32, 0, 0, 0,
780 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->width),
781 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->height), iconInfo->bitsColor,
782 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->cbBitsColor), iconInfo->bitsMask,
783 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->cbBitsMask), iconInfo->colorTable,
784 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->cbColorTable), iconInfo->bpp))
788 const UINT32 nelements = 2 + iconInfo->width * iconInfo->height;
789 pixels = realloc(railIcon->data, nelements *
sizeof(
long));
794 railIcon->data = pixels;
796 railIcon->length = WINPR_ASSERTING_INT_CAST(
int, nelements);
797 pixels[0] = iconInfo->width;
798 pixels[1] = iconInfo->height;
799 nextPixel = argbPixels;
801 for (UINT32 i = 2; i < nelements; i++)
803 pixels[i] = FreeRDPReadColor(nextPixel, PIXEL_FORMAT_BGRA32);
815static void xf_rail_set_window_icon(xfContext* xfc, xfAppWindow* railWindow, xfRailIcon* icon,
820 LogDynAndXChangeProperty(xfc->log, xfc->display, railWindow->handle, xfc->NET_WM_ICON,
821 XA_CARDINAL, 32, replace ? PropModeReplace : PropModeAppend,
822 (unsigned char*)icon->data, icon->length);
823 LogDynAndXFlush(xfc->log, xfc->display);
826static BOOL xf_rail_window_icon(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
830 xfContext* xfc = (xfContext*)context;
831 BOOL replaceIcon = 0;
832 xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId);
837 WINPR_ASSERT(windowIcon);
838 WINPR_ASSERT(windowIcon->iconInfo);
839 xfRailIcon* icon = RailIconCache_Lookup(
840 xfc->railIconCache, WINPR_ASSERTING_INT_CAST(UINT8, windowIcon->iconInfo->cacheId),
841 WINPR_ASSERTING_INT_CAST(UINT16, windowIcon->iconInfo->cacheEntry));
845 WLog_Print(xfc->log, WLOG_WARN,
"failed to get icon from cache %02X:%04X",
846 windowIcon->iconInfo->cacheId, windowIcon->iconInfo->cacheEntry);
848 else if (!convert_rail_icon(windowIcon->iconInfo, icon))
850 WLog_Print(xfc->log, WLOG_WARN,
"failed to convert icon for window %08X",
851 orderInfo->windowId);
855 replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW);
856 xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon);
859 xf_rail_return_window(railWindow);
863static BOOL xf_rail_window_cached_icon(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
867 xfContext* xfc = (xfContext*)context;
868 WINPR_ASSERT(orderInfo);
870 BOOL replaceIcon = 0;
871 xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId);
876 WINPR_ASSERT(windowCachedIcon);
878 xfRailIcon* icon = RailIconCache_Lookup(
879 xfc->railIconCache, WINPR_ASSERTING_INT_CAST(UINT8, windowCachedIcon->cachedIcon.cacheId),
880 WINPR_ASSERTING_INT_CAST(UINT16, windowCachedIcon->cachedIcon.cacheEntry));
884 WLog_Print(xfc->log, WLOG_WARN,
"failed to get icon from cache %02X:%04X",
885 windowCachedIcon->cachedIcon.cacheId, windowCachedIcon->cachedIcon.cacheEntry);
889 replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW);
890 xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon);
893 xf_rail_return_window(railWindow);
898xf_rail_notify_icon_common(WINPR_ATTR_UNUSED rdpContext* context,
902 WLog_ERR(
"TODO",
"TODO: implement");
903 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION)
907 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP)
911 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP)
915 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE)
919 if (orderInfo->fieldFlags & WINDOW_ORDER_ICON)
923 if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON)
930static BOOL xf_rail_notify_icon_create(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
933 return xf_rail_notify_icon_common(context, orderInfo, notifyIconState);
936static BOOL xf_rail_notify_icon_update(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
939 return xf_rail_notify_icon_common(context, orderInfo, notifyIconState);
942static BOOL xf_rail_notify_icon_delete(WINPR_ATTR_UNUSED rdpContext* context,
945 WLog_ERR(
"TODO",
"TODO: implement");
950xf_rail_monitored_desktop(WINPR_ATTR_UNUSED rdpContext* context,
954 const UINT32 mask = WINDOW_ORDER_TYPE_DESKTOP | WINDOW_ORDER_FIELD_DESKTOP_HOOKED |
955 WINDOW_ORDER_FIELD_DESKTOP_ARC_BEGAN |
956 WINDOW_ORDER_FIELD_DESKTOP_ARC_COMPLETED |
957 WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND | WINDOW_ORDER_FIELD_DESKTOP_ZORDER;
958 xfContext* xfc = (xfContext*)context;
960 if (!context || !orderInfo || !monitoredDesktop)
963 if ((orderInfo->fieldFlags & WINDOW_ORDER_TYPE_DESKTOP) == 0)
965 WLog_Print(xfc->log, WLOG_WARN,
"WINDOW_ORDER_TYPE_DESKTOP flag missing!");
969 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ARC_BEGAN) &&
970 (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_HOOKED))
973 WLog_Print(xfc->log, WLOG_WARN,
974 "TODO: implement WINDOW_ORDER_FIELD_DESKTOP_ARC_BEGAN && "
975 "WINDOW_ORDER_FIELD_DESKTOP_HOOKED");
977 else if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_HOOKED)
979 WLog_Print(xfc->log, WLOG_WARN,
"TODO: implement WINDOW_ORDER_FIELD_DESKTOP_HOOKED");
981 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ARC_COMPLETED)
983 WLog_DBG(TAG,
"WINDOW_ORDER_FIELD_DESKTOP_ARC_COMPLETED -> switch to RAILS mode");
984 xf_rail_enable_remoteapp_mode(xfc);
986 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND)
988 WLog_Print(xfc->log, WLOG_WARN,
"TODO: implement WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND");
990 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER)
992 WLog_Print(xfc->log, WLOG_WARN,
"TODO: implement WINDOW_ORDER_FIELD_DESKTOP_ZORDER");
994 if (orderInfo->fieldFlags & ~mask)
996 WLog_Print(xfc->log, WLOG_WARN,
"unknown flags 0x%08" PRIx32
"!", orderInfo->fieldFlags);
1001static BOOL xf_rail_non_monitored_desktop(rdpContext* context,
1004 xfContext* xfc = (xfContext*)context;
1005 const UINT32 mask = WINDOW_ORDER_TYPE_DESKTOP | WINDOW_ORDER_FIELD_DESKTOP_NONE;
1007 if (!context || !orderInfo)
1010 if ((orderInfo->fieldFlags & WINDOW_ORDER_TYPE_DESKTOP) == 0)
1012 WLog_Print(xfc->log, WLOG_WARN,
"TODO: implement WINDOW_ORDER_TYPE_DESKTOP");
1015 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_NONE)
1017 WLog_Print(xfc->log, WLOG_WARN,
"TODO: implement WINDOW_ORDER_FIELD_DESKTOP_NONE");
1019 if (orderInfo->fieldFlags & ~mask)
1021 WLog_Print(xfc->log, WLOG_WARN,
"unknown flags 0x%08" PRIx32
"!", orderInfo->fieldFlags);
1024 xf_rail_disable_remoteapp_mode(xfc);
1028static void xf_rail_register_update_callbacks(rdpUpdate* update)
1030 WINPR_ASSERT(update);
1032 rdpWindowUpdate* window = update->window;
1033 WINPR_ASSERT(window);
1035 window->WindowCreate = xf_rail_window_common;
1036 window->WindowUpdate = xf_rail_window_common;
1037 window->WindowDelete = xf_rail_window_delete;
1038 window->WindowIcon = xf_rail_window_icon;
1039 window->WindowCachedIcon = xf_rail_window_cached_icon;
1040 window->NotifyIconCreate = xf_rail_notify_icon_create;
1041 window->NotifyIconUpdate = xf_rail_notify_icon_update;
1042 window->NotifyIconDelete = xf_rail_notify_icon_delete;
1043 window->MonitoredDesktop = xf_rail_monitored_desktop;
1044 window->NonMonitoredDesktop = xf_rail_non_monitored_desktop;
1054static UINT xf_rail_server_execute_result(RailClientContext* context,
1057 WINPR_ASSERT(context);
1058 WINPR_ASSERT(execResult);
1060 xfContext* xfc = (xfContext*)context->custom;
1063 if (execResult->execResult != RAIL_EXEC_S_OK)
1065 WLog_ERR(TAG,
"RAIL exec error: execResult=%s [0x%08" PRIx32
"] NtError=0x%X\n",
1066 error_code2str(execResult->execResult), execResult->execResult,
1067 execResult->rawResult);
1068 freerdp_abort_connect_context(&xfc->common.context);
1071 return CHANNEL_RC_OK;
1079static UINT xf_rail_server_system_param(WINPR_ATTR_UNUSED RailClientContext* context,
1083 WLog_ERR(
"TODO",
"TODO: implement");
1084 return CHANNEL_RC_OK;
1092static UINT xf_rail_server_handshake(RailClientContext* context,
1095 return client_rail_server_start_cmd(context);
1104xf_rail_server_handshake_ex(RailClientContext* context,
1107 return client_rail_server_start_cmd(context);
1115static UINT xf_rail_server_local_move_size(RailClientContext* context,
1121 Window child_window = 0;
1122 WINPR_ASSERT(context);
1123 WINPR_ASSERT(localMoveSize);
1125 xfContext* xfc = (xfContext*)context->custom;
1126 xfAppWindow* appWindow = xf_rail_get_window(xfc, localMoveSize->windowId);
1129 return ERROR_INTERNAL_ERROR;
1131 WLog_Print(xfc->log, WLOG_TRACE,
"%s [0x%08" PRIx32
"]",
1132 movetype2str(localMoveSize->moveSizeType), localMoveSize->moveSizeType);
1133 switch (localMoveSize->moveSizeType)
1135 case RAIL_WMSZ_LEFT:
1136 direction = NET_WM_MOVERESIZE_SIZE_LEFT;
1137 x = localMoveSize->posX;
1138 y = localMoveSize->posY;
1141 case RAIL_WMSZ_RIGHT:
1142 direction = NET_WM_MOVERESIZE_SIZE_RIGHT;
1143 x = localMoveSize->posX;
1144 y = localMoveSize->posY;
1148 direction = NET_WM_MOVERESIZE_SIZE_TOP;
1149 x = localMoveSize->posX;
1150 y = localMoveSize->posY;
1153 case RAIL_WMSZ_TOPLEFT:
1154 direction = NET_WM_MOVERESIZE_SIZE_TOPLEFT;
1155 x = localMoveSize->posX;
1156 y = localMoveSize->posY;
1159 case RAIL_WMSZ_TOPRIGHT:
1160 direction = NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
1161 x = localMoveSize->posX;
1162 y = localMoveSize->posY;
1165 case RAIL_WMSZ_BOTTOM:
1166 direction = NET_WM_MOVERESIZE_SIZE_BOTTOM;
1167 x = localMoveSize->posX;
1168 y = localMoveSize->posY;
1171 case RAIL_WMSZ_BOTTOMLEFT:
1172 direction = NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
1173 x = localMoveSize->posX;
1174 y = localMoveSize->posY;
1177 case RAIL_WMSZ_BOTTOMRIGHT:
1178 direction = NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
1179 x = localMoveSize->posX;
1180 y = localMoveSize->posY;
1183 case RAIL_WMSZ_MOVE:
1184 direction = NET_WM_MOVERESIZE_MOVE;
1185 XTranslateCoordinates(xfc->display, appWindow->handle, RootWindowOfScreen(xfc->screen),
1186 localMoveSize->posX, localMoveSize->posY, &x, &y, &child_window);
1189 case RAIL_WMSZ_KEYMOVE:
1190 direction = NET_WM_MOVERESIZE_MOVE_KEYBOARD;
1191 x = localMoveSize->posX;
1192 y = localMoveSize->posY;
1196 case RAIL_WMSZ_KEYSIZE:
1197 direction = NET_WM_MOVERESIZE_SIZE_KEYBOARD;
1198 x = localMoveSize->posX;
1199 y = localMoveSize->posY;
1206 if (localMoveSize->isMoveSizeStart)
1207 xf_StartLocalMoveSize(xfc, appWindow, direction, x, y);
1209 xf_EndLocalMoveSize(xfc, appWindow);
1211 xf_rail_return_window(appWindow);
1212 return CHANNEL_RC_OK;
1220static UINT xf_rail_server_min_max_info(RailClientContext* context,
1223 WINPR_ASSERT(context);
1224 WINPR_ASSERT(minMaxInfo);
1226 xfContext* xfc = (xfContext*)context->custom;
1227 xfAppWindow* appWindow = xf_rail_get_window(xfc, minMaxInfo->windowId);
1231 xf_SetWindowMinMaxInfo(xfc, appWindow, minMaxInfo->maxWidth, minMaxInfo->maxHeight,
1232 minMaxInfo->maxPosX, minMaxInfo->maxPosY, minMaxInfo->minTrackWidth,
1233 minMaxInfo->minTrackHeight, minMaxInfo->maxTrackWidth,
1234 minMaxInfo->maxTrackHeight);
1236 xf_rail_return_window(appWindow);
1238 return CHANNEL_RC_OK;
1247xf_rail_server_language_bar_info(WINPR_ATTR_UNUSED RailClientContext* context,
1250 WLog_ERR(
"TODO",
"TODO: implement");
1251 return CHANNEL_RC_OK;
1260xf_rail_server_get_appid_response(WINPR_ATTR_UNUSED RailClientContext* context,
1263 WLog_ERR(
"TODO",
"TODO: implement");
1264 return CHANNEL_RC_OK;
1267static BOOL rail_window_key_equals(
const void* key1,
const void* key2)
1269 const UINT64* k1 = (
const UINT64*)key1;
1270 const UINT64* k2 = (
const UINT64*)key2;
1278static UINT32 rail_window_key_hash(
const void* key)
1280 const UINT64* k1 = (
const UINT64*)key;
1284static void rail_window_free(
void* value)
1286 xfAppWindow* appWindow = (xfAppWindow*)value;
1291 xf_DestroyWindow(appWindow->xfc, appWindow);
1294int xf_rail_init(xfContext* xfc, RailClientContext* rail)
1296 rdpContext* context = (rdpContext*)xfc;
1302 xf_rail_register_update_callbacks(context->update);
1303 rail->custom = (
void*)xfc;
1304 rail->ServerExecuteResult = xf_rail_server_execute_result;
1305 rail->ServerSystemParam = xf_rail_server_system_param;
1306 rail->ServerHandshake = xf_rail_server_handshake;
1307 rail->ServerHandshakeEx = xf_rail_server_handshake_ex;
1308 rail->ServerLocalMoveSize = xf_rail_server_local_move_size;
1309 rail->ServerMinMaxInfo = xf_rail_server_min_max_info;
1310 rail->ServerLanguageBarInfo = xf_rail_server_language_bar_info;
1311 rail->ServerGetAppIdResponse = xf_rail_server_get_appid_response;
1312 xfc->railWindows = HashTable_New(TRUE);
1314 if (!xfc->railWindows)
1317 if (!HashTable_SetHashFunction(xfc->railWindows, rail_window_key_hash))
1320 wObject* obj = HashTable_KeyObject(xfc->railWindows);
1324 wObject* obj = HashTable_ValueObject(xfc->railWindows);
1327 xfc->railIconCache = RailIconCache_New(xfc->common.context.settings);
1329 if (!xfc->railIconCache)
1335 HashTable_Free(xfc->railWindows);
1339int xf_rail_uninit(xfContext* xfc, RailClientContext* rail)
1345 xfc->rail->custom =
nullptr;
1346 xfc->rail =
nullptr;
1349 if (xfc->railWindows)
1351 HashTable_Free(xfc->railWindows);
1352 xfc->railWindows =
nullptr;
1355 if (xfc->railIconCache)
1357 RailIconCache_Free(xfc->railIconCache);
1358 xfc->railIconCache =
nullptr;
1364xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64
id, INT32 x, INT32 y, UINT32 width,
1365 UINT32 height, UINT32 surfaceId)
1370 xfAppWindow* appWindow = (xfAppWindow*)calloc(1,
sizeof(xfAppWindow));
1375 appWindow->xfc = xfc;
1376 appWindow->windowId = id;
1377 appWindow->surfaceId = surfaceId;
1380 appWindow->width = WINPR_ASSERTING_INT_CAST(
int, width);
1381 appWindow->height = WINPR_ASSERTING_INT_CAST(
int, height);
1383 xf_AppWindowsLock(xfc);
1384 if (!xf_AppWindowCreate(xfc, appWindow))
1387 if (!HashTable_Insert(xfc->railWindows, &appWindow->windowId, (
void*)appWindow))
1391 rail_window_free(appWindow);
1392 xf_AppWindowsUnlock(xfc);
1396BOOL xf_rail_del_window(xfContext* xfc, UINT64
id)
1401 if (!xfc->railWindows)
1404 return HashTable_Remove(xfc->railWindows, &
id);
1407void xf_rail_return_windowFrom(xfAppWindow* window,
const char* file,
const char* fkt,
size_t line)
1412 xfAppWindowsUnlockFrom(window->xfc, file, fkt, line);
WINPR_ATTR_NODISCARD 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.
OBJECT_FREE_FN fnObjectFree
OBJECT_EQUALS_FN fnObjectEquals