19#include <freerdp/config.h>
22#include <freerdp/log.h>
23#include <freerdp/client/rail.h>
24#include <winpr/tchar.h>
25#include <winpr/print.h>
29#define TAG CLIENT_TAG("windows")
31#define GET_X_LPARAM(lParam) ((UINT16)(lParam & 0xFFFF))
32#define GET_Y_LPARAM(lParam) ((UINT16)((lParam >> 16) & 0xFFFF))
59static const WINDOW_STYLE WINDOW_STYLES[] = { { WS_BORDER,
"WS_BORDER", FALSE },
60 { WS_CAPTION,
"WS_CAPTION", FALSE },
61 { WS_CHILD,
"WS_CHILD", FALSE },
62 { WS_CLIPCHILDREN,
"WS_CLIPCHILDREN", FALSE },
63 { WS_CLIPSIBLINGS,
"WS_CLIPSIBLINGS", FALSE },
64 { WS_DISABLED,
"WS_DISABLED", FALSE },
65 { WS_DLGFRAME,
"WS_DLGFRAME", FALSE },
66 { WS_GROUP,
"WS_GROUP", FALSE },
67 { WS_HSCROLL,
"WS_HSCROLL", FALSE },
68 { WS_ICONIC,
"WS_ICONIC", FALSE },
69 { WS_MAXIMIZE,
"WS_MAXIMIZE", FALSE },
70 { WS_MAXIMIZEBOX,
"WS_MAXIMIZEBOX", FALSE },
71 { WS_MINIMIZE,
"WS_MINIMIZE", FALSE },
72 { WS_MINIMIZEBOX,
"WS_MINIMIZEBOX", FALSE },
73 { WS_OVERLAPPED,
"WS_OVERLAPPED", FALSE },
74 { WS_OVERLAPPEDWINDOW,
"WS_OVERLAPPEDWINDOW", TRUE },
75 { WS_POPUP,
"WS_POPUP", FALSE },
76 { WS_POPUPWINDOW,
"WS_POPUPWINDOW", TRUE },
77 { WS_SIZEBOX,
"WS_SIZEBOX", FALSE },
78 { WS_SYSMENU,
"WS_SYSMENU", FALSE },
79 { WS_TABSTOP,
"WS_TABSTOP", FALSE },
80 { WS_THICKFRAME,
"WS_THICKFRAME", FALSE },
81 { WS_VISIBLE,
"WS_VISIBLE", FALSE } };
83static const WINDOW_STYLE EXTENDED_WINDOW_STYLES[] = {
84 { WS_EX_ACCEPTFILES,
"WS_EX_ACCEPTFILES", FALSE },
85 { WS_EX_APPWINDOW,
"WS_EX_APPWINDOW", FALSE },
86 { WS_EX_CLIENTEDGE,
"WS_EX_CLIENTEDGE", FALSE },
87 { WS_EX_COMPOSITED,
"WS_EX_COMPOSITED", FALSE },
88 { WS_EX_CONTEXTHELP,
"WS_EX_CONTEXTHELP", FALSE },
89 { WS_EX_CONTROLPARENT,
"WS_EX_CONTROLPARENT", FALSE },
90 { WS_EX_DLGMODALFRAME,
"WS_EX_DLGMODALFRAME", FALSE },
91 { WS_EX_LAYERED,
"WS_EX_LAYERED", FALSE },
92 { WS_EX_LAYOUTRTL,
"WS_EX_LAYOUTRTL", FALSE },
93 { WS_EX_LEFT,
"WS_EX_LEFT", FALSE },
94 { WS_EX_LEFTSCROLLBAR,
"WS_EX_LEFTSCROLLBAR", FALSE },
95 { WS_EX_LTRREADING,
"WS_EX_LTRREADING", FALSE },
96 { WS_EX_MDICHILD,
"WS_EX_MDICHILD", FALSE },
97 { WS_EX_NOACTIVATE,
"WS_EX_NOACTIVATE", FALSE },
98 { WS_EX_NOINHERITLAYOUT,
"WS_EX_NOINHERITLAYOUT", FALSE },
99 { WS_EX_NOPARENTNOTIFY,
"WS_EX_NOPARENTNOTIFY", FALSE },
100 { WS_EX_OVERLAPPEDWINDOW,
"WS_EX_OVERLAPPEDWINDOW", TRUE },
101 { WS_EX_PALETTEWINDOW,
"WS_EX_PALETTEWINDOW", TRUE },
102 { WS_EX_RIGHT,
"WS_EX_RIGHT", FALSE },
103 { WS_EX_RIGHTSCROLLBAR,
"WS_EX_RIGHTSCROLLBAR", FALSE },
104 { WS_EX_RTLREADING,
"WS_EX_RTLREADING", FALSE },
105 { WS_EX_STATICEDGE,
"WS_EX_STATICEDGE", FALSE },
106 { WS_EX_TOOLWINDOW,
"WS_EX_TOOLWINDOW", FALSE },
107 { WS_EX_TOPMOST,
"WS_EX_TOPMOST", FALSE },
108 { WS_EX_TRANSPARENT,
"WS_EX_TRANSPARENT", FALSE },
109 { WS_EX_WINDOWEDGE,
"WS_EX_WINDOWEDGE", FALSE }
112static void PrintWindowStyles(UINT32 style)
114 WLog_INFO(TAG,
"\tWindow Styles:\t{");
116 for (
size_t i = 0; i < ARRAYSIZE(WINDOW_STYLES); i++)
118 if (style & WINDOW_STYLES[i].style)
120 if (WINDOW_STYLES[i].multi)
122 if ((style & WINDOW_STYLES[i].style) != WINDOW_STYLES[i].style)
126 WLog_INFO(TAG,
"\t\t%s", WINDOW_STYLES[i].name);
131static void PrintExtendedWindowStyles(UINT32 style)
133 WLog_INFO(TAG,
"\tExtended Window Styles:\t{");
135 for (
size_t i = 0; i < ARRAYSIZE(EXTENDED_WINDOW_STYLES); i++)
137 if (style & EXTENDED_WINDOW_STYLES[i].style)
139 if (EXTENDED_WINDOW_STYLES[i].multi)
141 if ((style & EXTENDED_WINDOW_STYLES[i].style) != EXTENDED_WINDOW_STYLES[i].style)
145 WLog_INFO(TAG,
"\t\t%s", EXTENDED_WINDOW_STYLES[i].name);
153 if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW)
154 WLog_INFO(TAG,
"WindowCreate: WindowId: 0x%08X", orderInfo->windowId);
156 WLog_INFO(TAG,
"WindowUpdate: WindowId: 0x%08X", orderInfo->windowId);
160 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_OWNER)
162 WLog_INFO(TAG,
"\tOwnerWindowId: 0x%08X", windowState->ownerWindowId);
165 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_STYLE)
167 WLog_INFO(TAG,
"\tStyle: 0x%08X ExtendedStyle: 0x%08X", windowState->style,
168 windowState->extendedStyle);
169 PrintWindowStyles(windowState->style);
170 PrintExtendedWindowStyles(windowState->extendedStyle);
173 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_SHOW)
175 WLog_INFO(TAG,
"\tShowState: %u", windowState->showState);
178 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE)
180 const WCHAR* str = (
const WCHAR*)windowState->titleInfo.string;
182 ConvertWCharNToUtf8Alloc(str, windowState->titleInfo.length /
sizeof(WCHAR),
nullptr);
183 WLog_INFO(TAG,
"\tTitleInfo: %s (length = %hu)", title, windowState->titleInfo.length);
187 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
189 WLog_INFO(TAG,
"\tClientOffsetX: %d ClientOffsetY: %d", windowState->clientOffsetX,
190 windowState->clientOffsetY);
193 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
195 WLog_INFO(TAG,
"\tClientAreaWidth: %u ClientAreaHeight: %u", windowState->clientAreaWidth,
196 windowState->clientAreaHeight);
199 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT)
201 WLog_INFO(TAG,
"\tRPContent: %u", windowState->RPContent);
204 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT)
206 WLog_INFO(TAG,
"\tRootParentHandle: 0x%08X", windowState->rootParentHandle);
209 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
211 WLog_INFO(TAG,
"\tWindowOffsetX: %d WindowOffsetY: %d", windowState->windowOffsetX,
212 windowState->windowOffsetY);
215 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
217 WLog_INFO(TAG,
"\tWindowClientDeltaX: %d WindowClientDeltaY: %d",
218 windowState->windowClientDeltaX, windowState->windowClientDeltaY);
221 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
223 WLog_INFO(TAG,
"\tWindowWidth: %u WindowHeight: %u", windowState->windowWidth,
224 windowState->windowHeight);
227 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
230 WLog_INFO(TAG,
"\tnumWindowRects: %u", windowState->numWindowRects);
232 for (UINT32 index = 0; index < windowState->numWindowRects; index++)
234 rect = &windowState->windowRects[index];
235 WLog_INFO(TAG,
"\twindowRect[%u]: left: %hu top: %hu right: %hu bottom: %hu", index,
236 rect->left, rect->top, rect->right, rect->bottom);
240 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
242 WLog_INFO(TAG,
"\tvisibileOffsetX: %d visibleOffsetY: %d", windowState->visibleOffsetX,
243 windowState->visibleOffsetY);
246 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
249 WLog_INFO(TAG,
"\tnumVisibilityRects: %u", windowState->numVisibilityRects);
251 for (UINT32 index = 0; index < windowState->numVisibilityRects; index++)
253 rect = &windowState->visibilityRects[index];
254 WLog_INFO(TAG,
"\tvisibilityRect[%u]: left: %hu top: %hu right: %hu bottom: %hu", index,
255 rect->left, rect->top, rect->right, rect->bottom);
264 WLog_INFO(TAG,
"ICON_INFO");
266 WLog_INFO(TAG,
"\tbigIcon: %s",
267 (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ICON_BIG) ?
"true" :
"false");
268 WLog_INFO(TAG,
"\tcacheEntry; 0x%08X", iconInfo->cacheEntry);
269 WLog_INFO(TAG,
"\tcacheId: 0x%08X", iconInfo->cacheId);
270 WLog_INFO(TAG,
"\tbpp: %u", iconInfo->bpp);
271 WLog_INFO(TAG,
"\twidth: %u", iconInfo->width);
272 WLog_INFO(TAG,
"\theight: %u", iconInfo->height);
273 WLog_INFO(TAG,
"\tcbColorTable: %u", iconInfo->cbColorTable);
274 WLog_INFO(TAG,
"\tcbBitsMask: %u", iconInfo->cbBitsMask);
275 WLog_INFO(TAG,
"\tcbBitsColor: %u", iconInfo->cbBitsColor);
276 WLog_INFO(TAG,
"\tcolorTable: %p", (
void*)iconInfo->colorTable);
277 WLog_INFO(TAG,
"\tbitsMask: %p", (
void*)iconInfo->bitsMask);
278 WLog_INFO(TAG,
"\tbitsColor: %p", (
void*)iconInfo->bitsColor);
282LRESULT CALLBACK wf_RailWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
292 wfContext* wfc =
nullptr;
293 rdpInput* input =
nullptr;
294 rdpContext* context =
nullptr;
295 wfRailWindow* railWindow;
296 railWindow = (wfRailWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
299 wfc = railWindow->wfc;
302 context = (rdpContext*)wfc;
305 input = context->input;
314 hDC = BeginPaint(hWnd, &ps);
317 width = ps.rcPaint.right - ps.rcPaint.left + 1;
318 height = ps.rcPaint.bottom - ps.rcPaint.top + 1;
319 BitBlt(hDC, x, y, width, height, wfc->primary->hdc, railWindow->x + x,
320 railWindow->y + y, SRCCOPY);
327 if (!railWindow || !input)
330 xPos = GET_X_LPARAM(lParam) + railWindow->x;
331 yPos = GET_Y_LPARAM(lParam) + railWindow->y;
332 inputFlags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1;
335 input->MouseEvent(input, inputFlags, xPos, yPos);
341 if (!railWindow || !input)
344 xPos = GET_X_LPARAM(lParam) + railWindow->x;
345 yPos = GET_Y_LPARAM(lParam) + railWindow->y;
346 inputFlags = PTR_FLAGS_BUTTON1;
349 input->MouseEvent(input, inputFlags, xPos, yPos);
355 if (!railWindow || !input)
358 xPos = GET_X_LPARAM(lParam) + railWindow->x;
359 yPos = GET_Y_LPARAM(lParam) + railWindow->y;
360 inputFlags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2;
363 input->MouseEvent(input, inputFlags, xPos, yPos);
369 if (!railWindow || !input)
372 xPos = GET_X_LPARAM(lParam) + railWindow->x;
373 yPos = GET_Y_LPARAM(lParam) + railWindow->y;
374 inputFlags = PTR_FLAGS_BUTTON2;
377 input->MouseEvent(input, inputFlags, xPos, yPos);
383 if (!railWindow || !input)
386 xPos = GET_X_LPARAM(lParam) + railWindow->x;
387 yPos = GET_Y_LPARAM(lParam) + railWindow->y;
388 inputFlags = PTR_FLAGS_MOVE;
391 input->MouseEvent(input, inputFlags, xPos, yPos);
407 return DefWindowProc(hWnd, msg, wParam, lParam);
413#define RAIL_DISABLED_WINDOW_STYLES \
414 (WS_BORDER | WS_THICKFRAME | WS_DLGFRAME | WS_CAPTION | WS_OVERLAPPED | WS_VSCROLL | \
415 WS_HSCROLL | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
416#define RAIL_DISABLED_EXTENDED_WINDOW_STYLES \
417 (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE)
419static BOOL wf_rail_window_common(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
422 wfRailWindow* railWindow =
nullptr;
423 wfContext* wfc = (wfContext*)context;
424 RailClientContext* rail = wfc->rail;
425 UINT32 fieldFlags = orderInfo->fieldFlags;
426 PrintRailWindowState(orderInfo, windowState);
428 if (fieldFlags & WINDOW_ORDER_STATE_NEW)
432 WCHAR* titleW =
nullptr;
433 WNDCLASSEX wndClassEx = WINPR_C_ARRAY_INIT;
434 railWindow = (wfRailWindow*)calloc(1,
sizeof(wfRailWindow));
439 railWindow->wfc = wfc;
440 railWindow->dwStyle = windowState->style;
441 railWindow->dwStyle &= ~RAIL_DISABLED_WINDOW_STYLES;
442 railWindow->dwExStyle = windowState->extendedStyle;
443 railWindow->dwExStyle &= ~RAIL_DISABLED_EXTENDED_WINDOW_STYLES;
444 railWindow->x = windowState->windowOffsetX;
445 railWindow->y = windowState->windowOffsetY;
446 railWindow->width = windowState->windowWidth;
447 railWindow->height = windowState->windowHeight;
449 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
451 const WCHAR* str = (
const WCHAR*)windowState->titleInfo.string;
452 char* title =
nullptr;
454 if (windowState->titleInfo.length == 0)
456 if (!(title = _strdup(
"")))
458 WLog_ERR(TAG,
"failed to duplicate empty window title string");
462 else if (!(title = ConvertWCharNToUtf8Alloc(
463 str, windowState->titleInfo.length /
sizeof(WCHAR),
nullptr)))
465 WLog_ERR(TAG,
"failed to convert window title");
469 railWindow->title = title;
473 if (!(railWindow->title = _strdup(
"RdpRailWindow")))
474 WLog_ERR(TAG,
"failed to duplicate default window title string");
477 if (!railWindow->title)
483 titleW = ConvertUtf8ToWCharAlloc(railWindow->title,
nullptr);
484 hInstance = GetModuleHandle(
nullptr);
486 wndClassEx.cbSize =
sizeof(WNDCLASSEX);
487 wndClassEx.style = 0;
488 wndClassEx.lpfnWndProc = wf_RailWndProc;
489 wndClassEx.cbClsExtra = 0;
490 wndClassEx.cbWndExtra = 0;
491 wndClassEx.hIcon =
nullptr;
492 wndClassEx.hCursor =
nullptr;
493 wndClassEx.hbrBackground =
nullptr;
494 wndClassEx.lpszMenuName =
nullptr;
495 wndClassEx.lpszClassName = _T(
"RdpRailWindow");
496 wndClassEx.hInstance = hInstance;
497 wndClassEx.hIconSm =
nullptr;
498 RegisterClassEx(&wndClassEx);
499 railWindow->hWnd = CreateWindowExW(railWindow->dwExStyle,
513 if (!railWindow->hWnd)
516 free(railWindow->title);
518 WLog_ERR(TAG,
"CreateWindowExW failed with error %" PRIu32
"", GetLastError());
522 SetWindowLongPtr(railWindow->hWnd, GWLP_USERDATA, (LONG_PTR)railWindow);
523 rc = HashTable_Insert(wfc->railWindows, (
void*)(UINT_PTR)orderInfo->windowId,
526 UpdateWindow(railWindow->hWnd);
531 railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows,
532 (
void*)(UINT_PTR)orderInfo->windowId);
538 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE))
540 if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
542 railWindow->x = windowState->windowOffsetX;
543 railWindow->y = windowState->windowOffsetY;
546 if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
548 railWindow->width = windowState->windowWidth;
549 railWindow->height = windowState->windowHeight;
552 SetWindowPos(railWindow->hWnd,
nullptr, railWindow->x, railWindow->y, railWindow->width,
553 railWindow->height, 0);
556 if (fieldFlags & WINDOW_ORDER_FIELD_OWNER)
560 if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
562 railWindow->dwStyle = windowState->style;
563 railWindow->dwStyle &= ~RAIL_DISABLED_WINDOW_STYLES;
564 railWindow->dwExStyle = windowState->extendedStyle;
565 railWindow->dwExStyle &= ~RAIL_DISABLED_EXTENDED_WINDOW_STYLES;
566 SetWindowLongPtr(railWindow->hWnd, GWL_STYLE, (LONG)railWindow->dwStyle);
567 SetWindowLongPtr(railWindow->hWnd, GWL_EXSTYLE, (LONG)railWindow->dwExStyle);
570 if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
572 ShowWindow(railWindow->hWnd, windowState->showState);
575 if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
577 const WCHAR* raw = (
const WCHAR*)windowState->titleInfo.string;
578 char* title =
nullptr;
581 if (windowState->titleInfo.length == 0)
583 if (!(title = _strdup(
"")))
585 WLog_ERR(TAG,
"failed to duplicate empty window title string");
589 else if (!(title = ConvertWCharNToUtf8Alloc(
590 raw, windowState->titleInfo.length /
sizeof(WCHAR), &utflen)))
592 WLog_ERR(TAG,
"failed to convert window title");
596 free(railWindow->title);
597 railWindow->title = title;
599 WCHAR* str = ConvertUtf8NToWCharAlloc(title, utflen,
nullptr);
601 SetWindowTextW(railWindow->hWnd, str);
605 if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
609 if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
613 if (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
617 if (fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT)
621 if (fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT)
625 if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
631 if (windowState->numWindowRects > 0)
633 rect = &(windowState->windowRects[0]);
634 hWndRects = CreateRectRgn(rect->left, rect->top, rect->right, rect->bottom);
636 for (UINT32 index = 1; index < windowState->numWindowRects; index++)
638 rect = &(windowState->windowRects[index]);
639 hWndRect = CreateRectRgn(rect->left, rect->top, rect->right, rect->bottom);
640 CombineRgn(hWndRects, hWndRects, hWndRect, RGN_OR);
641 DeleteObject(hWndRect);
644 SetWindowRgn(railWindow->hWnd, hWndRects, TRUE);
645 DeleteObject(hWndRects);
649 if (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
653 if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
657 UpdateWindow(railWindow->hWnd);
661static BOOL wf_rail_window_delete(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo)
663 wfRailWindow* railWindow =
nullptr;
664 wfContext* wfc = (wfContext*)context;
665 RailClientContext* rail = wfc->rail;
666 WLog_DBG(TAG,
"RailWindowDelete");
667 railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows,
668 (
void*)(UINT_PTR)orderInfo->windowId);
673 HashTable_Remove(wfc->railWindows, (
void*)(UINT_PTR)orderInfo->windowId);
674 DestroyWindow(railWindow->hWnd);
679static BOOL wf_rail_window_icon(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
688 ICONINFO iconInfo = WINPR_C_ARRAY_INIT;
690 wfRailWindow* railWindow;
692 wfContext* wfc = (wfContext*)context;
693 RailClientContext* rail = wfc->rail;
694 WLog_DBG(TAG,
"RailWindowIcon");
695 PrintRailIconInfo(orderInfo, windowIcon->iconInfo);
696 railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows,
697 (
void*)(UINT_PTR)orderInfo->windowId);
702 bigIcon = (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ICON_BIG) ? TRUE : FALSE;
703 hDC = GetDC(railWindow->hWnd);
704 iconInfo.fIcon = TRUE;
705 iconInfo.xHotspot = 0;
706 iconInfo.yHotspot = 0;
708 bitmapInfoHeader = &(bitmapInfo.bmiHeader);
709 bpp = windowIcon->iconInfo->bpp;
710 width = windowIcon->iconInfo->width;
711 height = windowIcon->iconInfo->height;
713 bitmapInfoHeader->biWidth = width;
714 bitmapInfoHeader->biHeight = height;
715 bitmapInfoHeader->biPlanes = 1;
716 bitmapInfoHeader->biBitCount = bpp;
717 bitmapInfoHeader->biCompression = 0;
718 bitmapInfoHeader->biSizeImage = height * width * ((bpp + 7) / 8);
719 bitmapInfoHeader->biXPelsPerMeter = width;
720 bitmapInfoHeader->biYPelsPerMeter = height;
721 bitmapInfoHeader->biClrUsed = 0;
722 bitmapInfoHeader->biClrImportant = 0;
723 iconInfo.hbmMask = CreateDIBitmap(hDC, bitmapInfoHeader, CBM_INIT,
724 windowIcon->iconInfo->bitsMask, &bitmapInfo, DIB_RGB_COLORS);
726 CreateDIBitmap(hDC, bitmapInfoHeader, CBM_INIT, windowIcon->iconInfo->bitsColor,
727 &bitmapInfo, DIB_RGB_COLORS);
728 hIcon = CreateIconIndirect(&iconInfo);
734 wParam = (WPARAM)bigIcon ? ICON_BIG : ICON_SMALL;
735 lParam = (LPARAM)hIcon;
736 SendMessage(railWindow->hWnd, WM_SETICON, wParam, lParam);
739 ReleaseDC(
nullptr, hDC);
741 if (windowIcon->iconInfo->cacheEntry != 0xFFFF)
749static BOOL wf_rail_window_cached_icon(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
752 WLog_DBG(TAG,
"RailWindowCachedIcon");
756static void wf_rail_notify_icon_common(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
759 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION)
763 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP)
767 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP)
771 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE)
775 if (orderInfo->fieldFlags & WINDOW_ORDER_ICON)
777 const ICON_INFO* iconInfo = &(notifyIconState->icon);
778 PrintRailIconInfo(orderInfo, iconInfo);
781 if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON)
786static BOOL wf_rail_notify_icon_create(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
789 wfContext* wfc = (wfContext*)context;
790 RailClientContext* rail = wfc->rail;
791 WLog_DBG(TAG,
"RailNotifyIconCreate");
792 wf_rail_notify_icon_common(context, orderInfo, notifyIconState);
796static BOOL wf_rail_notify_icon_update(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
799 wfContext* wfc = (wfContext*)context;
800 RailClientContext* rail = wfc->rail;
801 WLog_DBG(TAG,
"RailNotifyIconUpdate");
802 wf_rail_notify_icon_common(context, orderInfo, notifyIconState);
806static BOOL wf_rail_notify_icon_delete(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo)
808 wfContext* wfc = (wfContext*)context;
809 RailClientContext* rail = wfc->rail;
810 WLog_DBG(TAG,
"RailNotifyIconDelete");
814static BOOL wf_rail_monitored_desktop(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo,
817 wfContext* wfc = (wfContext*)context;
818 RailClientContext* rail = wfc->rail;
819 WLog_DBG(TAG,
"RailMonitorDesktop");
823static BOOL wf_rail_non_monitored_desktop(rdpContext* context,
const WINDOW_ORDER_INFO* orderInfo)
825 wfContext* wfc = (wfContext*)context;
826 RailClientContext* rail = wfc->rail;
827 WLog_DBG(TAG,
"RailNonMonitorDesktop");
831void wf_rail_register_update_callbacks(rdpUpdate* update)
833 rdpWindowUpdate* window = update->window;
834 window->WindowCreate = wf_rail_window_common;
835 window->WindowUpdate = wf_rail_window_common;
836 window->WindowDelete = wf_rail_window_delete;
837 window->WindowIcon = wf_rail_window_icon;
838 window->WindowCachedIcon = wf_rail_window_cached_icon;
839 window->NotifyIconCreate = wf_rail_notify_icon_create;
840 window->NotifyIconUpdate = wf_rail_notify_icon_update;
841 window->NotifyIconDelete = wf_rail_notify_icon_delete;
842 window->MonitoredDesktop = wf_rail_monitored_desktop;
843 window->NonMonitoredDesktop = wf_rail_non_monitored_desktop;
853static UINT wf_rail_server_execute_result(RailClientContext* context,
856 WLog_DBG(TAG,
"RailServerExecuteResult: 0x%08X", execResult->rawResult);
857 return CHANNEL_RC_OK;
865static UINT wf_rail_server_system_param(RailClientContext* context,
868 return CHANNEL_RC_OK;
876static UINT wf_rail_server_handshake(RailClientContext* context,
879 return client_rail_server_start_cmd(context);
887static UINT wf_rail_server_handshake_ex(RailClientContext* context,
890 return client_rail_server_start_cmd(context);
898static UINT wf_rail_server_local_move_size(RailClientContext* context,
901 return CHANNEL_RC_OK;
909static UINT wf_rail_server_min_max_info(RailClientContext* context,
912 return CHANNEL_RC_OK;
920static UINT wf_rail_server_language_bar_info(RailClientContext* context,
923 return CHANNEL_RC_OK;
931static UINT wf_rail_server_get_appid_response(RailClientContext* context,
934 return CHANNEL_RC_OK;
937void wf_rail_invalidate_region(wfContext* wfc,
REGION16* invalidRegion)
941 ULONG_PTR* pKeys =
nullptr;
942 wfRailWindow* railWindow;
945 region16_init(&windowInvalidRegion);
946 size_t count = HashTable_GetKeys(wfc->railWindows, &pKeys);
948 for (
size_t index = 0; index < count; index++)
950 railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows, (
void*)pKeys[index]);
954 windowRect.left = railWindow->x;
955 windowRect.top = railWindow->y;
956 windowRect.right = railWindow->x + railWindow->width;
957 windowRect.bottom = railWindow->y + railWindow->height;
958 region16_clear(&windowInvalidRegion);
959 region16_intersect_rect(&windowInvalidRegion, invalidRegion, &windowRect);
961 if (!region16_is_empty(&windowInvalidRegion))
963 extents = region16_extents(&windowInvalidRegion);
964 updateRect.left = extents->left - railWindow->x;
965 updateRect.top = extents->top - railWindow->y;
966 updateRect.right = extents->right - railWindow->x;
967 updateRect.bottom = extents->bottom - railWindow->y;
968 InvalidateRect(railWindow->hWnd, &updateRect, FALSE);
973 region16_uninit(&windowInvalidRegion);
976BOOL wf_rail_init(wfContext* wfc, RailClientContext* rail)
978 rdpContext* context = (rdpContext*)wfc;
980 rail->custom = (
void*)wfc;
981 rail->ServerExecuteResult = wf_rail_server_execute_result;
982 rail->ServerSystemParam = wf_rail_server_system_param;
983 rail->ServerHandshake = wf_rail_server_handshake;
984 rail->ServerHandshakeEx = wf_rail_server_handshake_ex;
985 rail->ServerLocalMoveSize = wf_rail_server_local_move_size;
986 rail->ServerMinMaxInfo = wf_rail_server_min_max_info;
987 rail->ServerLanguageBarInfo = wf_rail_server_language_bar_info;
988 rail->ServerGetAppIdResponse = wf_rail_server_get_appid_response;
989 wf_rail_register_update_callbacks(context->update);
990 wfc->railWindows = HashTable_New(TRUE);
991 return (wfc->railWindows !=
nullptr);
994void wf_rail_uninit(wfContext* wfc, RailClientContext* rail)
997 rail->custom =
nullptr;
998 HashTable_Free(wfc->railWindows);