From 55ea4caf11434becc375eda717168556b6ecd281 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 24 Oct 2014 18:30:04 -0400 Subject: [PATCH] wfreerdp: partial RemoteApp support --- client/Windows/wf_client.c | 2 +- client/Windows/wf_client.h | 9 +- client/Windows/wf_rail.c | 325 +++++++++++++++++++++++++++++++++++++++++---- client/Windows/wf_rail.h | 18 +++ 4 files changed, 323 insertions(+), 31 deletions(-) diff --git a/client/Windows/wf_client.c b/client/Windows/wf_client.c index 9fb2841..0c7e160 100644 --- a/client/Windows/wf_client.c +++ b/client/Windows/wf_client.c @@ -405,7 +405,7 @@ BOOL wf_post_connect(freerdp* instance) wfc->hwnd = CreateWindowEx((DWORD) NULL, wfc->wndClassName, lpWindowName, dwStyle, 0, 0, 0, 0, wfc->hWndParent, NULL, wfc->hInstance, NULL); - SetWindowLongPtr(wfc->hwnd, GWLP_USERDATA, (LONG_PTR) wfc); + SetWindowLongPtr(wfc->hwnd, GWLP_USERDATA, (LONG_PTR) wfc); } wf_resize_window(wfc); diff --git a/client/Windows/wf_client.h b/client/Windows/wf_client.h index c4fea9c..5ec8f82 100644 --- a/client/Windows/wf_client.h +++ b/client/Windows/wf_client.h @@ -24,6 +24,8 @@ #include +#include + #include #include #include @@ -38,16 +40,17 @@ #include #include +typedef struct wf_context wfContext; + #include "wf_channels.h" #include "wf_floatbar.h" #include "wf_event.h" +#include "wf_cliprdr.h" #ifdef __cplusplus extern "C" { #endif -#include "wf_cliprdr.h" - // System menu constants #define SYSCOMMAND_ID_SMARTSIZING 1000 @@ -140,8 +143,8 @@ struct wf_context FloatBar* floatbar; RailClientContext* rail; + wHashTable* railWindows; }; -typedef struct wf_context wfContext; /** * Client Interface diff --git a/client/Windows/wf_rail.c b/client/Windows/wf_rail.c index 0772435..0867de4 100644 --- a/client/Windows/wf_rail.c +++ b/client/Windows/wf_rail.c @@ -20,6 +20,7 @@ #include "config.h" #endif +#include #include #include "wf_rail.h" @@ -276,110 +277,318 @@ static void PrintRailIconInfo(WINDOW_ORDER_INFO* orderInfo, ICON_INFO* iconInfo) fprintf(stderr, "}\n"); } +LRESULT CALLBACK wf_RailWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HDC hDC; + int x, y; + int width; + int height; + PAINTSTRUCT ps; + wfContext* wfc = NULL; + wfRailWindow* railWindow; + + railWindow = (wfRailWindow*) GetWindowLongPtr(hWnd, GWLP_USERDATA); + + if (railWindow) + wfc = railWindow->wfc; + + switch (msg) + { + case WM_PAINT: + { + if (!wfc) + return 0; + + hDC = BeginPaint(hWnd, &ps); + + x = ps.rcPaint.left; + y = ps.rcPaint.top; + width = ps.rcPaint.right - ps.rcPaint.left + 1; + height = ps.rcPaint.bottom - ps.rcPaint.top + 1; + + BitBlt(hDC, x, y, width, height, wfc->primary->hdc, + railWindow->x + x, railWindow->y + y, SRCCOPY); + + EndPaint(hWnd, &ps); + } + break; + + case WM_CLOSE: + DestroyWindow(hWnd); + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + default: + return DefWindowProc(hWnd, msg, wParam, lParam); + } + + return 0; +} + +#define RAIL_DISABLED_WINDOW_STYLES (WS_BORDER | WS_THICKFRAME | WS_DLGFRAME | WS_CAPTION | WS_OVERLAPPED) +#define RAIL_DISABLED_EXTENDED_WINDOW_STYLES (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE) + static void wf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, WINDOW_STATE_ORDER* windowState) { + wfRailWindow* railWindow = NULL; wfContext* wfc = (wfContext*) context; RailClientContext* rail = wfc->rail; + UINT32 fieldFlags = orderInfo->fieldFlags; PrintRailWindowState(orderInfo, windowState); - if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW) + if (fieldFlags & WINDOW_ORDER_STATE_NEW) { + HANDLE hInstance; + WCHAR* titleW = NULL; + WNDCLASSEX wndClassEx; + + railWindow = (wfRailWindow*) calloc(1, sizeof(wfRailWindow)); + + if (!railWindow) + return; + + railWindow->wfc = wfc; + + railWindow->dwStyle = windowState->style; + railWindow->dwStyle &= ~RAIL_DISABLED_WINDOW_STYLES; + railWindow->dwExStyle = windowState->extendedStyle; + railWindow->dwExStyle &= ~RAIL_DISABLED_EXTENDED_WINDOW_STYLES; + + railWindow->x = windowState->windowOffsetX; + railWindow->y = windowState->windowOffsetY; + railWindow->width = windowState->windowWidth; + railWindow->height = windowState->windowHeight; + + if (fieldFlags & WINDOW_ORDER_FIELD_TITLE) + { + char* title = NULL; + ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, + windowState->titleInfo.length / 2, &title, 0, NULL, NULL); + + railWindow->title = title; + } + else + { + railWindow->title = _strdup("RdpRailWindow"); + } + + ConvertToUnicode(CP_UTF8, 0, railWindow->title, -1, &titleW, 0); + + hInstance = GetModuleHandle(NULL); + + ZeroMemory(&wndClassEx, sizeof(WNDCLASSEX)); + wndClassEx.cbSize = sizeof(WNDCLASSEX); + wndClassEx.style = 0; + wndClassEx.lpfnWndProc = wf_RailWndProc; + wndClassEx.cbClsExtra = 0; + wndClassEx.cbWndExtra = 0; + wndClassEx.hIcon = NULL; + wndClassEx.hCursor = NULL; + wndClassEx.hbrBackground = NULL; + wndClassEx.lpszMenuName = NULL; + wndClassEx.lpszClassName = _T("RdpRailWindow"); + wndClassEx.hInstance = hInstance; + wndClassEx.hIconSm = NULL; + + RegisterClassEx(&wndClassEx); + + railWindow->hWnd = CreateWindowExW( + railWindow->dwExStyle, /* dwExStyle */ + _T("RdpRailWindow"), /* lpClassName */ + titleW, /* lpWindowName */ + railWindow->dwStyle, /* dwStyle */ + railWindow->x, /* x */ + railWindow->y, /* y */ + railWindow->width, /* nWidth */ + railWindow->height, /* nHeight */ + NULL, /* hWndParent */ + NULL, /* hMenu */ + hInstance, /* hInstance */ + NULL /* lpParam */ + ); + + SetWindowLongPtr(railWindow->hWnd, GWLP_USERDATA, (LONG_PTR) railWindow); + + HashTable_Add(wfc->railWindows, (void*) (UINT_PTR) orderInfo->windowId, (void*) railWindow); + + free(titleW); + + UpdateWindow(railWindow->hWnd); + + return; } else { - + railWindow = (wfRailWindow*) HashTable_GetItemValue(wfc->railWindows, + (void*) (UINT_PTR) orderInfo->windowId); } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) - { - - } + if (!railWindow) + return; - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) + if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || + (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)) { - + if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) + { + railWindow->x = windowState->windowOffsetX; + railWindow->y = windowState->windowOffsetY; + } + + if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) + { + railWindow->width = windowState->windowWidth; + railWindow->height = windowState->windowHeight; + } + + SetWindowPos(railWindow->hWnd, NULL, + railWindow->x, + railWindow->y, + railWindow->width, + railWindow->height, + 0); } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_OWNER) + if (fieldFlags & WINDOW_ORDER_FIELD_OWNER) { } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_STYLE) + if (fieldFlags & WINDOW_ORDER_FIELD_STYLE) { - + railWindow->dwStyle = windowState->style; + railWindow->dwStyle &= ~RAIL_DISABLED_WINDOW_STYLES; + railWindow->dwExStyle = windowState->extendedStyle; + railWindow->dwExStyle &= ~RAIL_DISABLED_EXTENDED_WINDOW_STYLES; + + SetWindowLongPtr(railWindow->hWnd, GWL_STYLE, (LONG) railWindow->dwStyle); + SetWindowLongPtr(railWindow->hWnd, GWL_EXSTYLE, (LONG) railWindow->dwExStyle); } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_SHOW) + if (fieldFlags & WINDOW_ORDER_FIELD_SHOW) { - + ShowWindow(railWindow->hWnd, windowState->showState); } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE) + if (fieldFlags & WINDOW_ORDER_FIELD_TITLE) { char* title = NULL; + WCHAR* titleW = NULL; ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, - windowState->titleInfo.length / 2, &title, 0, NULL, NULL); + windowState->titleInfo.length / 2, &title, 0, NULL, NULL); - free(title); + free(railWindow->title); + railWindow->title = title; + + ConvertToUnicode(CP_UTF8, 0, railWindow->title, -1, &titleW, 0); + + SetWindowTextW(railWindow->hWnd, titleW); + + free(titleW); } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) + if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) { } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) + if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) { } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) + if (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) { } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT) + if (fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT) { } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT) + if (fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT) { } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) + if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) { + UINT32 index; + HRGN hWndRect; + HRGN hWndRects; + RECTANGLE_16* rect; + if (windowState->numWindowRects > 0) + { + rect = &(windowState->windowRects[0]); + hWndRects = CreateRectRgn(rect->left, rect->top, rect->right, rect->bottom); + + for (index = 1; index < windowState->numWindowRects; index++) + { + rect = &(windowState->windowRects[index]); + hWndRect = CreateRectRgn(rect->left, rect->top, rect->right, rect->bottom); + CombineRgn(hWndRects, hWndRects, hWndRect, RGN_OR); + DeleteObject(hWndRect); + } + + SetWindowRgn(railWindow->hWnd, hWndRects, TRUE); + DeleteObject(hWndRects); + } } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) + if (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) { } - if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) + if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) { } + + UpdateWindow(railWindow->hWnd); } static void wf_rail_window_delete(rdpContext* context, WINDOW_ORDER_INFO* orderInfo) { + wfRailWindow* railWindow = NULL; wfContext* wfc = (wfContext*) context; RailClientContext* rail = wfc->rail; fprintf(stderr, "RailWindowDelete\n"); + + railWindow = (wfRailWindow*) HashTable_GetItemValue(wfc->railWindows, + (void*) (UINT_PTR) orderInfo->windowId); + + if (!railWindow) + return; + + HashTable_Remove(wfc->railWindows, (void*) (UINT_PTR) orderInfo->windowId); + + DestroyWindow(railWindow->hWnd); + + free(railWindow); } static void wf_rail_window_icon(rdpContext* context, WINDOW_ORDER_INFO* orderInfo, WINDOW_ICON_ORDER* windowIcon) { + HDC hDC; + int bpp; + int width; + int height; + HICON hIcon; BOOL bigIcon; - ICON_INFO* iconInfo; + ICONINFO iconInfo; + BITMAPINFO bitmapInfo; + wfRailWindow* railWindow; + BITMAPINFOHEADER* bitmapInfoHeader; wfContext* wfc = (wfContext*) context; RailClientContext* rail = wfc->rail; @@ -387,11 +596,65 @@ static void wf_rail_window_icon(rdpContext* context, WINDOW_ORDER_INFO* orderInf PrintRailIconInfo(orderInfo, windowIcon->iconInfo); - iconInfo = windowIcon->iconInfo; + railWindow = (wfRailWindow*) HashTable_GetItemValue(wfc->railWindows, + (void*) (UINT_PTR) orderInfo->windowId); + + if (!railWindow) + return; bigIcon = (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ICON_BIG) ? TRUE : FALSE; - if (iconInfo->cacheEntry != 0xFFFF) + hDC = GetDC(railWindow->hWnd); + + iconInfo.fIcon = TRUE; + iconInfo.xHotspot = 0; + iconInfo.yHotspot = 0; + + ZeroMemory(&bitmapInfo, sizeof(BITMAPINFO)); + bitmapInfoHeader = &(bitmapInfo.bmiHeader); + + bpp = windowIcon->iconInfo->bpp; + width = windowIcon->iconInfo->width; + height = windowIcon->iconInfo->height; + + bitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER); + bitmapInfoHeader->biWidth = width; + bitmapInfoHeader->biHeight = height; + bitmapInfoHeader->biPlanes = 1; + bitmapInfoHeader->biBitCount = bpp; + bitmapInfoHeader->biCompression = 0; + bitmapInfoHeader->biSizeImage = height * width * ((bpp + 7) / 8); + bitmapInfoHeader->biXPelsPerMeter = width; + bitmapInfoHeader->biYPelsPerMeter = height; + bitmapInfoHeader->biClrUsed = 0; + bitmapInfoHeader->biClrImportant = 0; + + iconInfo.hbmMask = CreateDIBitmap(hDC, + bitmapInfoHeader, CBM_INIT, + windowIcon->iconInfo->bitsMask, + &bitmapInfo, DIB_RGB_COLORS); + + iconInfo.hbmColor = CreateDIBitmap(hDC, + bitmapInfoHeader, CBM_INIT, + windowIcon->iconInfo->bitsColor, + &bitmapInfo, DIB_RGB_COLORS); + + hIcon = CreateIconIndirect(&iconInfo); + + if (hIcon) + { + WPARAM wParam; + LPARAM lParam; + + wParam = (WPARAM) bigIcon ? ICON_BIG : ICON_SMALL; + lParam = (LPARAM) hIcon; + + SendMessage(railWindow->hWnd, WM_SETICON, wParam, lParam); + } + + ReleaseDC(NULL, hDC); + + if (windowIcon->iconInfo->cacheEntry != 0xFFFF) { /* icon should be cached */ } @@ -602,6 +865,8 @@ static int wf_rail_server_get_appid_response(RailClientContext* context, RAIL_GE void wf_rail_init(wfContext* wfc, RailClientContext* rail) { + rdpContext* context = (rdpContext*) wfc; + wfc->rail = rail; rail->custom = (void*) wfc; @@ -613,10 +878,16 @@ void wf_rail_init(wfContext* wfc, RailClientContext* rail) rail->ServerMinMaxInfo = wf_rail_server_min_max_info; rail->ServerLanguageBarInfo = wf_rail_server_language_bar_info; rail->ServerGetAppIdResponse = wf_rail_server_get_appid_response; + + wf_rail_register_update_callbacks(context->update); + + wfc->railWindows = HashTable_New(TRUE); } void wf_rail_uninit(wfContext* wfc, RailClientContext* rail) { wfc->rail = NULL; rail->custom = NULL; + + HashTable_Free(wfc->railWindows); } diff --git a/client/Windows/wf_rail.h b/client/Windows/wf_rail.h index a17617a..3945831 100644 --- a/client/Windows/wf_rail.h +++ b/client/Windows/wf_rail.h @@ -19,10 +19,28 @@ #ifndef __WF_RAIL_H #define __WF_RAIL_H +typedef struct wf_rail_window wfRailWindow; + #include "wf_client.h" #include +struct wf_rail_window +{ + wfContext* wfc; + + HWND hWnd; + + DWORD dwStyle; + DWORD dwExStyle; + + int x; + int y; + int width; + int height; + char* title; +}; + void wf_rail_init(wfContext* wfc, RailClientContext* rail); void wf_rail_uninit(wfContext* wfc, RailClientContext* rail); -- 2.7.4