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_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" };
49static 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"
62typedef struct xf_rail_icon xfRailIcon;
64struct xf_rail_icon_cache
68 UINT32 numCacheEntries;
78void xf_rail_enable_remoteapp_mode(xfContext* xfc)
83 rdpGdi* gdi = xfc->common.context.gdi;
86 const BOOL old = gdi->suppressOutput;
87 gdi->suppressOutput = TRUE;
88 xfc->remote_app = TRUE;
89 xfc->drawable = xf_CreateDummyWindow(xfc);
90 xf_DestroyDesktopWindow(xfc, xfc->window);
93 gdi->suppressOutput = old;
97void xf_rail_disable_remoteapp_mode(xfContext* xfc)
102 rdpGdi* gdi = xfc->common.context.gdi;
105 const BOOL old = gdi->suppressOutput;
106 gdi->suppressOutput = TRUE;
108 xfc->remote_app = FALSE;
109 xf_DestroyDummyWindow(xfc, xfc->drawable);
110 xf_destroy_window(xfc);
111 xf_create_window(xfc);
112 xf_create_image(xfc);
114 gdi->suppressOutput = old;
118void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled)
121 xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, xwindow);
127 xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle);
129 WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
130 activate.windowId = (UINT32)appWindow->windowId;
131 activate.enabled = enabled;
132 xfc->rail->ClientActivate(xfc->rail, &activate);
135BOOL xf_rail_send_client_system_command(xfContext* xfc, UINT64 windowId, UINT16 command)
138 WINPR_ASSERT(xfc->rail);
139 WINPR_ASSERT(xfc->rail->ClientSystemCommand);
140 if (windowId > UINT32_MAX)
144 const UINT rc = xfc->rail->ClientSystemCommand(xfc->rail, &syscommand);
145 return rc == CHANNEL_RC_OK;
154void xf_rail_adjust_position(xfContext* xfc, xfAppWindow* appWindow)
159 WINPR_ASSERT(appWindow);
160 if (!appWindow->is_mapped || appWindow->local_move.state != LMS_NOT_ACTIVE)
164 if (appWindow->x != appWindow->windowOffsetX || appWindow->y != appWindow->windowOffsetY ||
165 appWindow->width != (INT64)appWindow->windowWidth ||
166 appWindow->height != (INT64)appWindow->windowHeight)
168 WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
169 windowMove.windowId = (UINT32)appWindow->windowId;
174 const INT16 left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginLeft);
175 const INT16 right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginRight);
176 const INT16 top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginTop);
177 const INT16 bottom = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginBottom);
178 windowMove.left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x - left);
179 windowMove.top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->y - top);
180 windowMove.right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x + appWindow->width + right);
182 WINPR_ASSERTING_INT_CAST(INT16, appWindow->y + appWindow->height + bottom);
183 xfc->rail->ClientWindowMove(xfc->rail, &windowMove);
187void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
193 unsigned int mask = 0;
194 Window root_window = 0;
195 Window child_window = 0;
198 WINPR_ASSERT(appWindow);
200 if ((appWindow->local_move.direction == NET_WM_MOVERESIZE_MOVE_KEYBOARD) ||
201 (appWindow->local_move.direction == NET_WM_MOVERESIZE_SIZE_KEYBOARD))
208 WINPR_ASSERT(appWindow->windowId <= UINT32_MAX);
209 windowMove.windowId = (UINT32)appWindow->windowId;
215 const INT16 left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginLeft);
216 const INT16 right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginRight);
217 const INT16 top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginTop);
218 const INT16 bottom = WINPR_ASSERTING_INT_CAST(INT16, appWindow->resizeMarginBottom);
219 const INT16 w = WINPR_ASSERTING_INT_CAST(INT16, appWindow->width + right);
220 const INT16 h = WINPR_ASSERTING_INT_CAST(INT16, appWindow->height + bottom);
221 windowMove.left = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x - left);
222 windowMove.top = WINPR_ASSERTING_INT_CAST(INT16, appWindow->y - top);
223 windowMove.right = WINPR_ASSERTING_INT_CAST(INT16, appWindow->x + w);
225 windowMove.bottom = WINPR_ASSERTING_INT_CAST(INT16, appWindow->y + h);
226 xfc->rail->ClientWindowMove(xfc->rail, &windowMove);
232 XQueryPointer(xfc->display, appWindow->handle, &root_window, &child_window, &x, &y, &child_x,
236 if ((appWindow->local_move.direction != NET_WM_MOVERESIZE_MOVE_KEYBOARD) &&
237 (appWindow->local_move.direction != NET_WM_MOVERESIZE_SIZE_KEYBOARD))
239 freerdp_client_send_button_event(&xfc->common, FALSE, PTR_FLAGS_BUTTON1, x, y);
247 appWindow->windowOffsetX = appWindow->x;
248 appWindow->windowOffsetY = appWindow->y;
249 appWindow->windowWidth = WINPR_ASSERTING_INT_CAST(uint32_t, appWindow->width);
250 appWindow->windowHeight = WINPR_ASSERTING_INT_CAST(uint32_t, appWindow->height);
251 appWindow->local_move.state = LMS_TERMINATING;
254BOOL xf_rail_paint_surface(xfContext* xfc, UINT64 windowId,
const RECTANGLE_16* rect)
256 xfAppWindow* appWindow = xf_rail_get_window(xfc, windowId);
264 .left = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->x, 0)),
265 .top = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->y, 0)),
266 .right = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->x + appWindow->width, 0)),
267 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, MAX(appWindow->y + appWindow->height, 0))
270 REGION16 windowInvalidRegion = { 0 };
271 region16_init(&windowInvalidRegion);
272 region16_union_rect(&windowInvalidRegion, &windowInvalidRegion, &windowRect);
273 region16_intersect_rect(&windowInvalidRegion, &windowInvalidRegion, rect);
275 if (!region16_is_empty(&windowInvalidRegion))
277 const RECTANGLE_16* extents = region16_extents(&windowInvalidRegion);
280 .left = WINPR_ASSERTING_INT_CAST(UINT16, extents->left - appWindow->x),
281 .top = WINPR_ASSERTING_INT_CAST(UINT16, extents->top - appWindow->y),
282 .right = WINPR_ASSERTING_INT_CAST(UINT16, extents->right - appWindow->x),
283 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, extents->bottom - appWindow->y)
286 xf_UpdateWindowArea(xfc, appWindow, updateRect.left, updateRect.top,
287 updateRect.right - updateRect.left, updateRect.bottom - updateRect.top);
289 region16_uninit(&windowInvalidRegion);
293static BOOL rail_paint_fn(
const void* pvkey, WINPR_ATTR_UNUSED
void* value,
void* pvarg)
295 rail_paint_fn_arg_t* arg = pvarg;
299 const UINT64 key = *(
const UINT64*)pvkey;
300 return xf_rail_paint_surface(arg->xfc, key, arg->rect);
303BOOL xf_rail_paint(xfContext* xfc,
const RECTANGLE_16* rect)
305 rail_paint_fn_arg_t arg = { .xfc = xfc, .rect = rect };
310 if (!xfc->railWindows)
313 return HashTable_Foreach(xfc->railWindows, rail_paint_fn, &arg);
316#define window_state_log_style(log, windowState) \
317 window_state_log_style_int((log), (windowState), __FILE__, __func__, __LINE__)
318static void window_state_log_style_int(wLog* log,
const WINDOW_STATE_ORDER* windowState,
319 const char* file,
const char* fkt,
size_t line)
321 const DWORD log_level = WLOG_DEBUG;
324 WINPR_ASSERT(windowState);
325 if (WLog_IsLevelActive(log, log_level))
327 char buffer1[128] = { 0 };
328 char buffer2[128] = { 0 };
330 window_styles_to_string(windowState->style, buffer1,
sizeof(buffer1));
331 window_styles_ex_to_string(windowState->extendedStyle, buffer2,
sizeof(buffer2));
332 WLog_PrintTextMessage(log, log_level, line, file, fkt,
"windowStyle={%s, %s}", buffer1,
339static BOOL xf_rail_window_common(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
342 xfAppWindow* appWindow = NULL;
343 xfContext* xfc = (xfContext*)context;
346 WINPR_ASSERT(orderInfo);
347 WINPR_ASSERT(windowState);
349 UINT32 fieldFlags = orderInfo->fieldFlags;
350 BOOL position_or_size_updated = FALSE;
351 appWindow = xf_rail_get_window(xfc, orderInfo->windowId);
353 if (fieldFlags & WINDOW_ORDER_STATE_NEW)
356 appWindow = xf_rail_add_window(xfc, orderInfo->windowId, windowState->windowOffsetX,
357 windowState->windowOffsetY, windowState->windowWidth,
358 windowState->windowHeight, 0xFFFFFFFF);
363 appWindow->dwStyle = windowState->style;
364 appWindow->dwExStyle = windowState->extendedStyle;
365 window_state_log_style(xfc->log, windowState);
368 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
377 cnv.b = windowState->titleInfo.string;
378 if (windowState->titleInfo.length == 0)
380 if (!(title = _strdup(
"")))
382 WLog_ERR(TAG,
"failed to duplicate empty window title string");
386 else if (!(title = ConvertWCharNToUtf8Alloc(
387 cnv.wc, windowState->titleInfo.length /
sizeof(WCHAR), NULL)))
389 WLog_ERR(TAG,
"failed to convert window title");
393 appWindow->title = title;
397 if (!(appWindow->title = _strdup(
"RdpRailWindow")))
398 WLog_ERR(TAG,
"failed to duplicate default window title string");
401 if (!appWindow->title)
407 xf_AppWindowInit(xfc, appWindow);
414 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
415 (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) ||
416 (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) ||
417 (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) ||
418 (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) ||
419 (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) ||
420 (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY))
422 position_or_size_updated = TRUE;
427 if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
429 appWindow->windowOffsetX = windowState->windowOffsetX;
430 appWindow->windowOffsetY = windowState->windowOffsetY;
433 if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
435 appWindow->windowWidth = windowState->windowWidth;
436 appWindow->windowHeight = windowState->windowHeight;
439 if (fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_X)
441 appWindow->resizeMarginLeft = windowState->resizeMarginLeft;
442 appWindow->resizeMarginRight = windowState->resizeMarginRight;
445 if (fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_Y)
447 appWindow->resizeMarginTop = windowState->resizeMarginTop;
448 appWindow->resizeMarginBottom = windowState->resizeMarginBottom;
451 if (fieldFlags & WINDOW_ORDER_FIELD_OWNER)
453 appWindow->ownerWindowId = windowState->ownerWindowId;
456 if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
458 appWindow->dwStyle = windowState->style;
459 appWindow->dwExStyle = windowState->extendedStyle;
460 window_state_log_style(xfc->log, windowState);
463 if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
465 appWindow->showState = windowState->showState;
468 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
477 cnv.b = windowState->titleInfo.string;
478 if (windowState->titleInfo.length == 0)
480 if (!(title = _strdup(
"")))
482 WLog_ERR(TAG,
"failed to duplicate empty window title string");
486 else if (!(title = ConvertWCharNToUtf8Alloc(
487 cnv.wc, windowState->titleInfo.length /
sizeof(WCHAR), NULL)))
489 WLog_ERR(TAG,
"failed to convert window title");
493 free(appWindow->title);
494 appWindow->title = title;
497 if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
499 appWindow->clientOffsetX = windowState->clientOffsetX;
500 appWindow->clientOffsetY = windowState->clientOffsetY;
503 if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
505 appWindow->clientAreaWidth = windowState->clientAreaWidth;
506 appWindow->clientAreaHeight = windowState->clientAreaHeight;
509 if (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
511 appWindow->windowClientDeltaX = windowState->windowClientDeltaX;
512 appWindow->windowClientDeltaY = windowState->windowClientDeltaY;
515 if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
517 if (appWindow->windowRects)
519 free(appWindow->windowRects);
520 appWindow->windowRects = NULL;
523 appWindow->numWindowRects = windowState->numWindowRects;
525 if (appWindow->numWindowRects)
527 appWindow->windowRects =
530 if (!appWindow->windowRects)
533 CopyMemory(appWindow->windowRects, windowState->windowRects,
538 if (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
540 appWindow->visibleOffsetX = windowState->visibleOffsetX;
541 appWindow->visibleOffsetY = windowState->visibleOffsetY;
544 if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
546 if (appWindow->visibilityRects)
548 free(appWindow->visibilityRects);
549 appWindow->visibilityRects = NULL;
552 appWindow->numVisibilityRects = windowState->numVisibilityRects;
554 if (appWindow->numVisibilityRects)
556 appWindow->visibilityRects =
559 if (!appWindow->visibilityRects)
562 CopyMemory(appWindow->visibilityRects, windowState->visibilityRects,
569 if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
573 if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
575 xf_ShowWindow(xfc, appWindow, WINPR_ASSERTING_INT_CAST(UINT8, appWindow->showState));
578 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
580 if (appWindow->title)
581 xf_SetWindowText(xfc, appWindow, appWindow->title);
584 if (position_or_size_updated)
586 const INT32 visibilityRectsOffsetX =
587 (appWindow->visibleOffsetX -
588 (appWindow->clientOffsetX - appWindow->windowClientDeltaX));
589 const INT32 visibilityRectsOffsetY =
590 (appWindow->visibleOffsetY -
591 (appWindow->clientOffsetY - appWindow->windowClientDeltaY));
598 if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED)
601 if (appWindow->x == (INT64)appWindow->windowOffsetX &&
602 appWindow->y == (INT64)appWindow->windowOffsetY &&
603 appWindow->width == (INT64)appWindow->windowWidth &&
604 appWindow->height == (INT64)appWindow->windowHeight)
606 xf_UpdateWindowArea(xfc, appWindow, 0, 0,
607 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowWidth),
608 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowHeight));
612 xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX, appWindow->windowOffsetY,
613 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowWidth),
614 WINPR_ASSERTING_INT_CAST(
int, appWindow->windowHeight));
617 xf_SetWindowVisibilityRects(
618 xfc, appWindow, WINPR_ASSERTING_INT_CAST(uint32_t, visibilityRectsOffsetX),
619 WINPR_ASSERTING_INT_CAST(uint32_t, visibilityRectsOffsetY),
620 appWindow->visibilityRects,
621 WINPR_ASSERTING_INT_CAST(
int, appWindow->numVisibilityRects));
624 if (appWindow->rail_state == WINDOW_SHOW_MAXIMIZED)
626 xf_SendClientEvent(xfc, appWindow->handle, xfc->NET_WM_STATE, 4, NET_WM_STATE_ADD,
627 xfc->NET_WM_STATE_MAXIMIZED_VERT, xfc->NET_WM_STATE_MAXIMIZED_HORZ,
632 if (fieldFlags & (WINDOW_ORDER_STATE_NEW | WINDOW_ORDER_FIELD_STYLE))
633 xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle);
643static BOOL xf_rail_window_delete(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo)
645 xfContext* xfc = (xfContext*)context;
647 return xf_rail_del_window(xfc, orderInfo->windowId);
650static xfRailIconCache* RailIconCache_New(rdpSettings* settings)
652 xfRailIconCache* cache = calloc(1,
sizeof(xfRailIconCache));
658 cache->numCacheEntries =
660 cache->entries = calloc(1ull * cache->numCaches * cache->numCacheEntries,
sizeof(xfRailIcon));
664 WLog_ERR(TAG,
"failed to allocate icon cache %" PRIu32
" x %" PRIu32
" entries",
665 cache->numCaches, cache->numCacheEntries);
673static void RailIconCache_Free(xfRailIconCache* cache)
678 for (UINT32 i = 0; i < cache->numCaches * cache->numCacheEntries; i++)
680 xfRailIcon* cur = &cache->entries[i];
684 free(cache->scratch.data);
685 free(cache->entries);
689static xfRailIcon* RailIconCache_Lookup(xfRailIconCache* cache, UINT8 cacheId, UINT16 cacheEntry)
702 return &cache->scratch;
704 if (cacheId >= cache->numCaches)
707 if (cacheEntry >= cache->numCacheEntries)
710 return &cache->entries[cache->numCacheEntries * cacheId + cacheEntry];
723static BOOL convert_rail_icon(
const ICON_INFO* iconInfo, xfRailIcon* railIcon)
725 WINPR_ASSERT(iconInfo);
726 WINPR_ASSERT(railIcon);
728 BYTE* nextPixel = NULL;
730 BYTE* argbPixels = calloc(1ull * iconInfo->width * iconInfo->height, 4);
735 if (!freerdp_image_copy_from_icon_data(
736 argbPixels, PIXEL_FORMAT_ARGB32, 0, 0, 0,
737 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->width),
738 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->height), iconInfo->bitsColor,
739 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->cbBitsColor), iconInfo->bitsMask,
740 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->cbBitsMask), iconInfo->colorTable,
741 WINPR_ASSERTING_INT_CAST(UINT16, iconInfo->cbColorTable), iconInfo->bpp))
744 const UINT32 nelements = 2 + iconInfo->width * iconInfo->height;
745 pixels = realloc(railIcon->data, nelements *
sizeof(
long));
750 railIcon->data = pixels;
752 railIcon->length = WINPR_ASSERTING_INT_CAST(
int, nelements);
753 pixels[0] = iconInfo->width;
754 pixels[1] = iconInfo->height;
755 nextPixel = argbPixels;
757 for (UINT32 i = 2; i < nelements; i++)
759 pixels[i] = FreeRDPReadColor(nextPixel, PIXEL_FORMAT_BGRA32);
770static void xf_rail_set_window_icon(xfContext* xfc, xfAppWindow* railWindow, xfRailIcon* icon,
775 LogDynAndXChangeProperty(xfc->log, xfc->display, railWindow->handle, xfc->NET_WM_ICON,
776 XA_CARDINAL, 32, replace ? PropModeReplace : PropModeAppend,
777 (unsigned char*)icon->data, icon->length);
778 LogDynAndXFlush(xfc->log, xfc->display);
781static BOOL xf_rail_window_icon(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
784 xfContext* xfc = (xfContext*)context;
785 BOOL replaceIcon = 0;
786 xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId);
791 WINPR_ASSERT(windowIcon);
792 WINPR_ASSERT(windowIcon->iconInfo);
793 xfRailIcon* icon = RailIconCache_Lookup(
794 xfc->railIconCache, WINPR_ASSERTING_INT_CAST(UINT8, windowIcon->iconInfo->cacheId),
795 WINPR_ASSERTING_INT_CAST(UINT16, windowIcon->iconInfo->cacheEntry));
799 WLog_Print(xfc->log, WLOG_WARN,
"failed to get icon from cache %02X:%04X",
800 windowIcon->iconInfo->cacheId, windowIcon->iconInfo->cacheEntry);
804 if (!convert_rail_icon(windowIcon->iconInfo, icon))
806 WLog_Print(xfc->log, WLOG_WARN,
"failed to convert icon for window %08X",
807 orderInfo->windowId);
811 replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW);
812 xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon);
816static BOOL xf_rail_window_cached_icon(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
819 xfContext* xfc = (xfContext*)context;
820 WINPR_ASSERT(orderInfo);
822 BOOL replaceIcon = 0;
823 xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId);
828 WINPR_ASSERT(windowCachedIcon);
830 xfRailIcon* icon = RailIconCache_Lookup(
831 xfc->railIconCache, WINPR_ASSERTING_INT_CAST(UINT8, windowCachedIcon->cachedIcon.cacheId),
832 WINPR_ASSERTING_INT_CAST(UINT16, windowCachedIcon->cachedIcon.cacheEntry));
836 WLog_Print(xfc->log, WLOG_WARN,
"failed to get icon from cache %02X:%04X",
837 windowCachedIcon->cachedIcon.cacheId, windowCachedIcon->cachedIcon.cacheEntry);
841 replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW);
842 xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon);
847xf_rail_notify_icon_common(WINPR_ATTR_UNUSED rdpContext* context,
851 WLog_ERR(
"TODO",
"TODO: implement");
852 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION)
856 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP)
860 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP)
864 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE)
868 if (orderInfo->fieldFlags & WINDOW_ORDER_ICON)
872 if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON)
879static BOOL xf_rail_notify_icon_create(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
882 return xf_rail_notify_icon_common(context, orderInfo, notifyIconState);
885static BOOL xf_rail_notify_icon_update(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
888 return xf_rail_notify_icon_common(context, orderInfo, notifyIconState);
891static BOOL xf_rail_notify_icon_delete(WINPR_ATTR_UNUSED rdpContext* context,
894 WLog_ERR(
"TODO",
"TODO: implement");
899xf_rail_monitored_desktop(WINPR_ATTR_UNUSED rdpContext* context,
903 const UINT32 mask = WINDOW_ORDER_TYPE_DESKTOP | WINDOW_ORDER_FIELD_DESKTOP_HOOKED |
904 WINDOW_ORDER_FIELD_DESKTOP_ARC_BEGAN |
905 WINDOW_ORDER_FIELD_DESKTOP_ARC_COMPLETED |
906 WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND | WINDOW_ORDER_FIELD_DESKTOP_ZORDER;
907 xfContext* xfc = (xfContext*)context;
909 if (!context || !orderInfo || !monitoredDesktop)
912 if ((orderInfo->fieldFlags & WINDOW_ORDER_TYPE_DESKTOP) == 0)
914 WLog_Print(xfc->log, WLOG_WARN,
"WINDOW_ORDER_TYPE_DESKTOP flag missing!");
918 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ARC_BEGAN) &&
919 (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_HOOKED))
922 WLog_Print(xfc->log, WLOG_WARN,
923 "TODO: implement WINDOW_ORDER_FIELD_DESKTOP_ARC_BEGAN && "
924 "WINDOW_ORDER_FIELD_DESKTOP_HOOKED");
926 else if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_HOOKED)
928 WLog_Print(xfc->log, WLOG_WARN,
"TODO: implement WINDOW_ORDER_FIELD_DESKTOP_HOOKED");
930 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ARC_COMPLETED)
932 WLog_DBG(TAG,
"WINDOW_ORDER_FIELD_DESKTOP_ARC_COMPLETED -> switch to RAILS mode");
933 xf_rail_enable_remoteapp_mode(xfc);
935 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND)
937 WLog_Print(xfc->log, WLOG_WARN,
"TODO: implement WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND");
939 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER)
941 WLog_Print(xfc->log, WLOG_WARN,
"TODO: implement WINDOW_ORDER_FIELD_DESKTOP_ZORDER");
943 if (orderInfo->fieldFlags & ~mask)
945 WLog_Print(xfc->log, WLOG_WARN,
"unknown flags 0x%08" PRIx32
"!", orderInfo->fieldFlags);
950static BOOL xf_rail_non_monitored_desktop(rdpContext* context,
953 xfContext* xfc = (xfContext*)context;
954 const UINT32 mask = WINDOW_ORDER_TYPE_DESKTOP | WINDOW_ORDER_FIELD_DESKTOP_NONE;
956 if (!context || !orderInfo)
959 if ((orderInfo->fieldFlags & WINDOW_ORDER_TYPE_DESKTOP) == 0)
961 WLog_Print(xfc->log, WLOG_WARN,
"TODO: implement WINDOW_ORDER_TYPE_DESKTOP");
964 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_NONE)
966 WLog_Print(xfc->log, WLOG_WARN,
"TODO: implement WINDOW_ORDER_FIELD_DESKTOP_NONE");
968 if (orderInfo->fieldFlags & ~mask)
970 WLog_Print(xfc->log, WLOG_WARN,
"unknown flags 0x%08" PRIx32
"!", orderInfo->fieldFlags);
973 xf_rail_disable_remoteapp_mode(xfc);
977static void xf_rail_register_update_callbacks(rdpUpdate* update)
979 WINPR_ASSERT(update);
981 rdpWindowUpdate* window = update->window;
982 WINPR_ASSERT(window);
984 window->WindowCreate = xf_rail_window_common;
985 window->WindowUpdate = xf_rail_window_common;
986 window->WindowDelete = xf_rail_window_delete;
987 window->WindowIcon = xf_rail_window_icon;
988 window->WindowCachedIcon = xf_rail_window_cached_icon;
989 window->NotifyIconCreate = xf_rail_notify_icon_create;
990 window->NotifyIconUpdate = xf_rail_notify_icon_update;
991 window->NotifyIconDelete = xf_rail_notify_icon_delete;
992 window->MonitoredDesktop = xf_rail_monitored_desktop;
993 window->NonMonitoredDesktop = xf_rail_non_monitored_desktop;
1003static UINT xf_rail_server_execute_result(RailClientContext* context,
1006 WINPR_ASSERT(context);
1007 WINPR_ASSERT(execResult);
1009 xfContext* xfc = (xfContext*)context->custom;
1012 if (execResult->execResult != RAIL_EXEC_S_OK)
1014 WLog_ERR(TAG,
"RAIL exec error: execResult=%s NtError=0x%X\n",
1015 error_code_names[execResult->execResult], execResult->rawResult);
1016 freerdp_abort_connect_context(&xfc->common.context);
1019 return CHANNEL_RC_OK;
1027static UINT xf_rail_server_system_param(WINPR_ATTR_UNUSED RailClientContext* context,
1031 WLog_ERR(
"TODO",
"TODO: implement");
1032 return CHANNEL_RC_OK;
1040static UINT xf_rail_server_handshake(RailClientContext* context,
1043 return client_rail_server_start_cmd(context);
1052xf_rail_server_handshake_ex(RailClientContext* context,
1055 return client_rail_server_start_cmd(context);
1063static UINT xf_rail_server_local_move_size(RailClientContext* context,
1069 Window child_window = 0;
1070 WINPR_ASSERT(context);
1071 WINPR_ASSERT(localMoveSize);
1073 xfContext* xfc = (xfContext*)context->custom;
1074 xfAppWindow* appWindow = xf_rail_get_window(xfc, localMoveSize->windowId);
1077 return ERROR_INTERNAL_ERROR;
1079 switch (localMoveSize->moveSizeType)
1081 case RAIL_WMSZ_LEFT:
1082 direction = NET_WM_MOVERESIZE_SIZE_LEFT;
1083 x = localMoveSize->posX;
1084 y = localMoveSize->posY;
1087 case RAIL_WMSZ_RIGHT:
1088 direction = NET_WM_MOVERESIZE_SIZE_RIGHT;
1089 x = localMoveSize->posX;
1090 y = localMoveSize->posY;
1094 direction = NET_WM_MOVERESIZE_SIZE_TOP;
1095 x = localMoveSize->posX;
1096 y = localMoveSize->posY;
1099 case RAIL_WMSZ_TOPLEFT:
1100 direction = NET_WM_MOVERESIZE_SIZE_TOPLEFT;
1101 x = localMoveSize->posX;
1102 y = localMoveSize->posY;
1105 case RAIL_WMSZ_TOPRIGHT:
1106 direction = NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
1107 x = localMoveSize->posX;
1108 y = localMoveSize->posY;
1111 case RAIL_WMSZ_BOTTOM:
1112 direction = NET_WM_MOVERESIZE_SIZE_BOTTOM;
1113 x = localMoveSize->posX;
1114 y = localMoveSize->posY;
1117 case RAIL_WMSZ_BOTTOMLEFT:
1118 direction = NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
1119 x = localMoveSize->posX;
1120 y = localMoveSize->posY;
1123 case RAIL_WMSZ_BOTTOMRIGHT:
1124 direction = NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
1125 x = localMoveSize->posX;
1126 y = localMoveSize->posY;
1129 case RAIL_WMSZ_MOVE:
1130 direction = NET_WM_MOVERESIZE_MOVE;
1131 XTranslateCoordinates(xfc->display, appWindow->handle, RootWindowOfScreen(xfc->screen),
1132 localMoveSize->posX, localMoveSize->posY, &x, &y, &child_window);
1135 case RAIL_WMSZ_KEYMOVE:
1136 direction = NET_WM_MOVERESIZE_MOVE_KEYBOARD;
1137 x = localMoveSize->posX;
1138 y = localMoveSize->posY;
1140 return CHANNEL_RC_OK;
1142 case RAIL_WMSZ_KEYSIZE:
1143 direction = NET_WM_MOVERESIZE_SIZE_KEYBOARD;
1144 x = localMoveSize->posX;
1145 y = localMoveSize->posY;
1147 return CHANNEL_RC_OK;
1152 if (localMoveSize->isMoveSizeStart)
1153 xf_StartLocalMoveSize(xfc, appWindow, direction, x, y);
1155 xf_EndLocalMoveSize(xfc, appWindow);
1157 return CHANNEL_RC_OK;
1165static UINT xf_rail_server_min_max_info(RailClientContext* context,
1168 WINPR_ASSERT(context);
1169 WINPR_ASSERT(minMaxInfo);
1171 xfContext* xfc = (xfContext*)context->custom;
1172 xfAppWindow* appWindow = xf_rail_get_window(xfc, minMaxInfo->windowId);
1176 xf_SetWindowMinMaxInfo(xfc, appWindow, minMaxInfo->maxWidth, minMaxInfo->maxHeight,
1177 minMaxInfo->maxPosX, minMaxInfo->maxPosY, minMaxInfo->minTrackWidth,
1178 minMaxInfo->minTrackHeight, minMaxInfo->maxTrackWidth,
1179 minMaxInfo->maxTrackHeight);
1182 return CHANNEL_RC_OK;
1191xf_rail_server_language_bar_info(WINPR_ATTR_UNUSED RailClientContext* context,
1194 WLog_ERR(
"TODO",
"TODO: implement");
1195 return CHANNEL_RC_OK;
1204xf_rail_server_get_appid_response(WINPR_ATTR_UNUSED RailClientContext* context,
1207 WLog_ERR(
"TODO",
"TODO: implement");
1208 return CHANNEL_RC_OK;
1211static BOOL rail_window_key_equals(
const void* key1,
const void* key2)
1213 const UINT64* k1 = (
const UINT64*)key1;
1214 const UINT64* k2 = (
const UINT64*)key2;
1222static UINT32 rail_window_key_hash(
const void* key)
1224 const UINT64* k1 = (
const UINT64*)key;
1228static void rail_window_free(
void* value)
1230 xfAppWindow* appWindow = (xfAppWindow*)value;
1235 xf_DestroyWindow(appWindow->xfc, appWindow);
1238int xf_rail_init(xfContext* xfc, RailClientContext* rail)
1240 rdpContext* context = (rdpContext*)xfc;
1246 xf_rail_register_update_callbacks(context->update);
1247 rail->custom = (
void*)xfc;
1248 rail->ServerExecuteResult = xf_rail_server_execute_result;
1249 rail->ServerSystemParam = xf_rail_server_system_param;
1250 rail->ServerHandshake = xf_rail_server_handshake;
1251 rail->ServerHandshakeEx = xf_rail_server_handshake_ex;
1252 rail->ServerLocalMoveSize = xf_rail_server_local_move_size;
1253 rail->ServerMinMaxInfo = xf_rail_server_min_max_info;
1254 rail->ServerLanguageBarInfo = xf_rail_server_language_bar_info;
1255 rail->ServerGetAppIdResponse = xf_rail_server_get_appid_response;
1256 xfc->railWindows = HashTable_New(TRUE);
1258 if (!xfc->railWindows)
1261 if (!HashTable_SetHashFunction(xfc->railWindows, rail_window_key_hash))
1264 wObject* obj = HashTable_KeyObject(xfc->railWindows);
1265 obj->fnObjectEquals = rail_window_key_equals;
1268 wObject* obj = HashTable_ValueObject(xfc->railWindows);
1269 obj->fnObjectFree = rail_window_free;
1271 xfc->railIconCache = RailIconCache_New(xfc->common.context.settings);
1273 if (!xfc->railIconCache)
1279 HashTable_Free(xfc->railWindows);
1283int xf_rail_uninit(xfContext* xfc, RailClientContext* rail)
1289 xfc->rail->custom = NULL;
1293 if (xfc->railWindows)
1295 HashTable_Free(xfc->railWindows);
1296 xfc->railWindows = NULL;
1299 if (xfc->railIconCache)
1301 RailIconCache_Free(xfc->railIconCache);
1302 xfc->railIconCache = NULL;
1308xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64
id, INT32 x, INT32 y, UINT32 width,
1309 UINT32 height, UINT32 surfaceId)
1314 xfAppWindow* appWindow = (xfAppWindow*)calloc(1,
sizeof(xfAppWindow));
1319 appWindow->xfc = xfc;
1320 appWindow->windowId = id;
1321 appWindow->surfaceId = surfaceId;
1324 appWindow->width = WINPR_ASSERTING_INT_CAST(
int, width);
1325 appWindow->height = WINPR_ASSERTING_INT_CAST(
int, height);
1327 if (!xf_AppWindowCreate(xfc, appWindow))
1329 if (!HashTable_Insert(xfc->railWindows, &appWindow->windowId, (
void*)appWindow))
1333 rail_window_free(appWindow);
1337BOOL xf_rail_del_window(xfContext* xfc, UINT64
id)
1342 if (!xfc->railWindows)
1345 return HashTable_Remove(xfc->railWindows, &
id);
1348xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64
id)
1353 if (!xfc->railWindows)
1356 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.