Blame client/X11/xf_rail.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * X11 RAIL
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <X11/Xlib.h>
Packit 1fb8d4
#include <X11/Xatom.h>
Packit 1fb8d4
#include <X11/Xutil.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/wlog.h>
Packit 1fb8d4
#include <winpr/print.h>
Packit 1fb8d4
Packit 1fb8d4
#include "xf_window.h"
Packit 1fb8d4
#include "xf_rail.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG CLIENT_TAG("x11")
Packit 1fb8d4
Packit Service 5a9772
static const char* error_code_names[] = { "RAIL_EXEC_S_OK",
Packit Service 5a9772
	                                      "RAIL_EXEC_E_HOOK_NOT_LOADED",
Packit Service 5a9772
	                                      "RAIL_EXEC_E_DECODE_FAILED",
Packit Service 5a9772
	                                      "RAIL_EXEC_E_NOT_IN_ALLOWLIST",
Packit Service 5a9772
	                                      "RAIL_EXEC_E_FILE_NOT_FOUND",
Packit Service 5a9772
	                                      "RAIL_EXEC_E_FAIL",
Packit Service 5a9772
	                                      "RAIL_EXEC_E_SESSION_LOCKED" };
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_DEBUG_RAIL
Packit Service 5a9772
static const char* movetype_names[] = {
Packit Service 5a9772
	"(invalid)",        "RAIL_WMSZ_LEFT",       "RAIL_WMSZ_RIGHT",
Packit Service 5a9772
	"RAIL_WMSZ_TOP",    "RAIL_WMSZ_TOPLEFT",    "RAIL_WMSZ_TOPRIGHT",
Packit Service 5a9772
	"RAIL_WMSZ_BOTTOM", "RAIL_WMSZ_BOTTOMLEFT", "RAIL_WMSZ_BOTTOMRIGHT",
Packit Service 5a9772
	"RAIL_WMSZ_MOVE",   "RAIL_WMSZ_KEYMOVE",    "RAIL_WMSZ_KEYSIZE"
Packit 1fb8d4
};
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
struct xf_rail_icon
Packit 1fb8d4
{
Packit 1fb8d4
	long* data;
Packit 1fb8d4
	int length;
Packit 1fb8d4
};
Packit 1fb8d4
typedef struct xf_rail_icon xfRailIcon;
Packit 1fb8d4
Packit 1fb8d4
struct xf_rail_icon_cache
Packit 1fb8d4
{
Packit 1fb8d4
	xfRailIcon* entries;
Packit 1fb8d4
	UINT32 numCaches;
Packit 1fb8d4
	UINT32 numCacheEntries;
Packit 1fb8d4
	xfRailIcon scratch;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
void xf_rail_enable_remoteapp_mode(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!xfc->remote_app)
Packit 1fb8d4
	{
Packit 1fb8d4
		xfc->remote_app = TRUE;
Packit 1fb8d4
		xfc->drawable = xf_CreateDummyWindow(xfc);
Packit 1fb8d4
		xf_DestroyDesktopWindow(xfc, xfc->window);
Packit 1fb8d4
		xfc->window = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_rail_disable_remoteapp_mode(xfContext* xfc)
Packit 1fb8d4
{
Packit 1fb8d4
	if (xfc->remote_app)
Packit 1fb8d4
	{
Packit 1fb8d4
		xfc->remote_app = FALSE;
Packit 1fb8d4
		xf_DestroyDummyWindow(xfc, xfc->drawable);
Packit 1fb8d4
		xf_create_window(xfc);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled)
Packit 1fb8d4
{
Packit 1fb8d4
	xfAppWindow* appWindow;
Packit 1fb8d4
	RAIL_ACTIVATE_ORDER activate;
Packit 1fb8d4
	appWindow = xf_AppWindowFromX11Window(xfc, xwindow);
Packit 1fb8d4
Packit 1fb8d4
	if (!appWindow)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	if (enabled)
Packit 1fb8d4
		xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle);
Packit 1fb8d4
	else
Packit 1fb8d4
		xf_SetWindowStyle(xfc, appWindow, 0, 0);
Packit 1fb8d4
Packit 1fb8d4
	activate.windowId = appWindow->windowId;
Packit 1fb8d4
	activate.enabled = enabled;
Packit 1fb8d4
	xfc->rail->ClientActivate(xfc->rail, &activate);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
void xf_rail_send_client_system_command(xfContext* xfc, UINT32 windowId, UINT16 command)
Packit 1fb8d4
{
Packit 1fb8d4
	RAIL_SYSCOMMAND_ORDER syscommand;
Packit 1fb8d4
	syscommand.windowId = windowId;
Packit 1fb8d4
	syscommand.command = command;
Packit 1fb8d4
	xfc->rail->ClientSystemCommand(xfc->rail, &syscommand);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * The position of the X window can become out of sync with the RDP window
Packit 1fb8d4
 * if the X window is moved locally by the window manager.  In this event
Packit 1fb8d4
 * send an update to the RDP server informing it of the new window position
Packit 1fb8d4
 * and size.
Packit 1fb8d4
 */
Packit 1fb8d4
void xf_rail_adjust_position(xfContext* xfc, xfAppWindow* appWindow)
Packit 1fb8d4
{
Packit 1fb8d4
	RAIL_WINDOW_MOVE_ORDER windowMove;
Packit 1fb8d4
Packit 1fb8d4
	if (!appWindow->is_mapped || appWindow->local_move.state != LMS_NOT_ACTIVE)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	/* If current window position disagrees with RDP window position, send update to RDP server */
Packit Service 5a9772
	if (appWindow->x != appWindow->windowOffsetX || appWindow->y != appWindow->windowOffsetY ||
Packit Service 5a9772
	    appWindow->width != (INT64)appWindow->windowWidth ||
Packit Service 5a9772
	    appWindow->height != (INT64)appWindow->windowHeight)
Packit 1fb8d4
	{
Packit 1fb8d4
		windowMove.windowId = appWindow->windowId;
Packit 1fb8d4
		/*
Packit Service 5a9772
		 * Calculate new size/position for the rail window(new values for
Packit Service 5a9772
		 * windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server
Packit 1fb8d4
		 */
Packit 1fb8d4
		windowMove.left = appWindow->x;
Packit 1fb8d4
		windowMove.top = appWindow->y;
Packit 1fb8d4
		windowMove.right = windowMove.left + appWindow->width;
Packit 1fb8d4
		windowMove.bottom = windowMove.top + appWindow->height;
Packit 1fb8d4
		xfc->rail->ClientWindowMove(xfc->rail, &windowMove);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
Packit 1fb8d4
{
Packit 1fb8d4
	int x, y;
Packit 1fb8d4
	int child_x;
Packit 1fb8d4
	int child_y;
Packit 1fb8d4
	unsigned int mask;
Packit 1fb8d4
	Window root_window;
Packit 1fb8d4
	Window child_window;
Packit 1fb8d4
	RAIL_WINDOW_MOVE_ORDER windowMove;
Packit 1fb8d4
	rdpInput* input = xfc->context.input;
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * For keyboard moves send and explicit update to RDP server
Packit 1fb8d4
	 */
Packit 1fb8d4
	windowMove.windowId = appWindow->windowId;
Packit 1fb8d4
	/*
Packit Service 5a9772
	 * Calculate new size/position for the rail window(new values for
Packit Service 5a9772
	 * windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server
Packit 1fb8d4
	 *
Packit 1fb8d4
	 */
Packit 1fb8d4
	windowMove.left = appWindow->x;
Packit 1fb8d4
	windowMove.top = appWindow->y;
Packit Service 5a9772
	windowMove.right =
Packit Service 5a9772
	    windowMove.left +
Packit Service 5a9772
	    appWindow->width; /* In the update to RDP the position is one past the window */
Packit 1fb8d4
	windowMove.bottom = windowMove.top + appWindow->height;
Packit 1fb8d4
	xfc->rail->ClientWindowMove(xfc->rail, &windowMove);
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * Simulate button up at new position to end the local move (per RDP spec)
Packit 1fb8d4
	 */
Packit Service 5a9772
	XQueryPointer(xfc->display, appWindow->handle, &root_window, &child_window, &x, &y, &child_x,
Packit Service 5a9772
	              &child_y, &mask);
Packit 1fb8d4
Packit 1fb8d4
	/* only send the mouse coordinates if not a keyboard move or size */
Packit 1fb8d4
	if ((appWindow->local_move.direction != _NET_WM_MOVERESIZE_MOVE_KEYBOARD) &&
Packit 1fb8d4
	    (appWindow->local_move.direction != _NET_WM_MOVERESIZE_SIZE_KEYBOARD))
Packit 1fb8d4
	{
Packit 1fb8d4
		input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * Proactively update the RAIL window dimensions.  There is a race condition where
Packit 1fb8d4
	 * we can start to receive GDI orders for the new window dimensions before we
Packit 1fb8d4
	 * receive the RAIL ORDER for the new window size.  This avoids that race condition.
Packit 1fb8d4
	 */
Packit 1fb8d4
	appWindow->windowOffsetX = appWindow->x;
Packit 1fb8d4
	appWindow->windowOffsetY = appWindow->y;
Packit 1fb8d4
	appWindow->windowWidth = appWindow->width;
Packit 1fb8d4
	appWindow->windowHeight = appWindow->height;
Packit 1fb8d4
	appWindow->local_move.state = LMS_TERMINATING;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void xf_rail_invalidate_region(xfContext* xfc, REGION16* invalidRegion)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit Service 5a9772
	int count = 0;
Packit 1fb8d4
	RECTANGLE_16 updateRect;
Packit 1fb8d4
	RECTANGLE_16 windowRect;
Packit 1fb8d4
	ULONG_PTR* pKeys = NULL;
Packit 1fb8d4
	xfAppWindow* appWindow;
Packit 1fb8d4
	const RECTANGLE_16* extents;
Packit 1fb8d4
	REGION16 windowInvalidRegion;
Packit 1fb8d4
	region16_init(&windowInvalidRegion);
Packit Service 5a9772
	if (xfc->railWindows)
Packit Service 5a9772
		count = HashTable_GetKeys(xfc->railWindows, &pKeys);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < count; index++)
Packit 1fb8d4
	{
Packit Service 5a9772
		appWindow = xf_rail_get_window(xfc, *(UINT64*)pKeys[index]);
Packit 1fb8d4
Packit 1fb8d4
		if (appWindow)
Packit 1fb8d4
		{
Packit 1fb8d4
			windowRect.left = MAX(appWindow->x, 0);
Packit 1fb8d4
			windowRect.top = MAX(appWindow->y, 0);
Packit 1fb8d4
			windowRect.right = MAX(appWindow->x + appWindow->width, 0);
Packit 1fb8d4
			windowRect.bottom = MAX(appWindow->y + appWindow->height, 0);
Packit 1fb8d4
			region16_clear(&windowInvalidRegion);
Packit 1fb8d4
			region16_intersect_rect(&windowInvalidRegion, invalidRegion, &windowRect);
Packit 1fb8d4
Packit 1fb8d4
			if (!region16_is_empty(&windowInvalidRegion))
Packit 1fb8d4
			{
Packit 1fb8d4
				extents = region16_extents(&windowInvalidRegion);
Packit 1fb8d4
				updateRect.left = extents->left - appWindow->x;
Packit 1fb8d4
				updateRect.top = extents->top - appWindow->y;
Packit 1fb8d4
				updateRect.right = extents->right - appWindow->x;
Packit 1fb8d4
				updateRect.bottom = extents->bottom - appWindow->y;
Packit 1fb8d4
				xf_UpdateWindowArea(xfc, appWindow, updateRect.left, updateRect.top,
Packit 1fb8d4
				                    updateRect.right - updateRect.left,
Packit 1fb8d4
				                    updateRect.bottom - updateRect.top);
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(pKeys);
Packit 1fb8d4
	region16_uninit(&windowInvalidRegion);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
void xf_rail_paint(xfContext* xfc, INT32 uleft, INT32 utop, UINT32 uright, UINT32 ubottom)
Packit 1fb8d4
{
Packit 1fb8d4
	REGION16 invalidRegion;
Packit 1fb8d4
	RECTANGLE_16 invalidRect;
Packit 1fb8d4
	invalidRect.left = uleft;
Packit 1fb8d4
	invalidRect.top = utop;
Packit 1fb8d4
	invalidRect.right = uright;
Packit 1fb8d4
	invalidRect.bottom = ubottom;
Packit 1fb8d4
	region16_init(&invalidRegion);
Packit 1fb8d4
	region16_union_rect(&invalidRegion, &invalidRegion, &invalidRect);
Packit 1fb8d4
	xf_rail_invalidate_region(xfc, &invalidRegion);
Packit 1fb8d4
	region16_uninit(&invalidRegion);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* RemoteApp Core Protocol Extension */
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
Packit Service 5a9772
                                  const WINDOW_STATE_ORDER* windowState)
Packit 1fb8d4
{
Packit 1fb8d4
	xfAppWindow* appWindow = NULL;
Packit Service 5a9772
	xfContext* xfc = (xfContext*)context;
Packit 1fb8d4
	UINT32 fieldFlags = orderInfo->fieldFlags;
Packit 1fb8d4
	BOOL position_or_size_updated = FALSE;
Packit Service 5a9772
	appWindow = xf_rail_get_window(xfc, orderInfo->windowId);
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_STATE_NEW)
Packit 1fb8d4
	{
Packit Service 5a9772
		if (!appWindow)
Packit Service 5a9772
			appWindow = xf_rail_add_window(xfc, orderInfo->windowId, windowState->windowOffsetX,
Packit Service 5a9772
			                               windowState->windowOffsetY, windowState->windowWidth,
Packit Service 5a9772
			                               windowState->windowHeight, 0xFFFFFFFF);
Packit 1fb8d4
Packit 1fb8d4
		if (!appWindow)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		appWindow->dwStyle = windowState->style;
Packit 1fb8d4
		appWindow->dwExStyle = windowState->extendedStyle;
Packit 1fb8d4
Packit 1fb8d4
		/* Ensure window always gets a window title */
Packit 1fb8d4
		if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
Packit 1fb8d4
		{
Packit 1fb8d4
			char* title = NULL;
Packit 1fb8d4
Packit 1fb8d4
			if (windowState->titleInfo.length == 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!(title = _strdup("")))
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_ERR(TAG, "failed to duplicate empty window title string");
Packit 1fb8d4
					/* error handled below */
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit Service 5a9772
			else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)windowState->titleInfo.string,
Packit Service 5a9772
			                            windowState->titleInfo.length / 2, &title, 0, NULL,
Packit Service 5a9772
			                            NULL) < 1)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "failed to convert window title");
Packit 1fb8d4
				/* error handled below */
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			appWindow->title = title;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!(appWindow->title = _strdup("RdpRailWindow")))
Packit 1fb8d4
				WLog_ERR(TAG, "failed to duplicate default window title string");
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!appWindow->title)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(appWindow);
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		xf_AppWindowInit(xfc, appWindow);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!appWindow)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* Keep track of any position/size update so that we can force a refresh of the window */
Packit 1fb8d4
	if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
Packit Service 5a9772
	    (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) ||
Packit 1fb8d4
	    (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) ||
Packit 1fb8d4
	    (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) ||
Packit 1fb8d4
	    (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) ||
Packit 1fb8d4
	    (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) ||
Packit 1fb8d4
	    (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY))
Packit 1fb8d4
	{
Packit 1fb8d4
		position_or_size_updated = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Update Parameters */
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
Packit 1fb8d4
	{
Packit 1fb8d4
		appWindow->windowOffsetX = windowState->windowOffsetX;
Packit 1fb8d4
		appWindow->windowOffsetY = windowState->windowOffsetY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
Packit 1fb8d4
	{
Packit 1fb8d4
		appWindow->windowWidth = windowState->windowWidth;
Packit 1fb8d4
		appWindow->windowHeight = windowState->windowHeight;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_OWNER)
Packit 1fb8d4
	{
Packit 1fb8d4
		appWindow->ownerWindowId = windowState->ownerWindowId;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
Packit 1fb8d4
	{
Packit 1fb8d4
		appWindow->dwStyle = windowState->style;
Packit 1fb8d4
		appWindow->dwExStyle = windowState->extendedStyle;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
Packit 1fb8d4
	{
Packit 1fb8d4
		appWindow->showState = windowState->showState;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
Packit 1fb8d4
	{
Packit 1fb8d4
		char* title = NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (windowState->titleInfo.length == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!(title = _strdup("")))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "failed to duplicate empty window title string");
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit Service 5a9772
		else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)windowState->titleInfo.string,
Packit 1fb8d4
		                            windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "failed to convert window title");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		free(appWindow->title);
Packit 1fb8d4
		appWindow->title = title;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
Packit 1fb8d4
	{
Packit 1fb8d4
		appWindow->clientOffsetX = windowState->clientOffsetX;
Packit 1fb8d4
		appWindow->clientOffsetY = windowState->clientOffsetY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
Packit 1fb8d4
	{
Packit 1fb8d4
		appWindow->clientAreaWidth = windowState->clientAreaWidth;
Packit 1fb8d4
		appWindow->clientAreaHeight = windowState->clientAreaHeight;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
Packit 1fb8d4
	{
Packit 1fb8d4
		appWindow->windowClientDeltaX = windowState->windowClientDeltaX;
Packit 1fb8d4
		appWindow->windowClientDeltaY = windowState->windowClientDeltaY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (appWindow->windowRects)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(appWindow->windowRects);
Packit 1fb8d4
			appWindow->windowRects = NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		appWindow->numWindowRects = windowState->numWindowRects;
Packit 1fb8d4
Packit 1fb8d4
		if (appWindow->numWindowRects)
Packit 1fb8d4
		{
Packit Service 5a9772
			appWindow->windowRects =
Packit Service 5a9772
			    (RECTANGLE_16*)calloc(appWindow->numWindowRects, sizeof(RECTANGLE_16));
Packit 1fb8d4
Packit 1fb8d4
			if (!appWindow->windowRects)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			CopyMemory(appWindow->windowRects, windowState->windowRects,
Packit 1fb8d4
			           appWindow->numWindowRects * sizeof(RECTANGLE_16));
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
Packit 1fb8d4
	{
Packit 1fb8d4
		appWindow->visibleOffsetX = windowState->visibleOffsetX;
Packit 1fb8d4
		appWindow->visibleOffsetY = windowState->visibleOffsetY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (appWindow->visibilityRects)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(appWindow->visibilityRects);
Packit 1fb8d4
			appWindow->visibilityRects = NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		appWindow->numVisibilityRects = windowState->numVisibilityRects;
Packit 1fb8d4
Packit 1fb8d4
		if (appWindow->numVisibilityRects)
Packit 1fb8d4
		{
Packit Service 5a9772
			appWindow->visibilityRects =
Packit Service 5a9772
			    (RECTANGLE_16*)calloc(appWindow->numVisibilityRects, sizeof(RECTANGLE_16));
Packit 1fb8d4
Packit 1fb8d4
			if (!appWindow->visibilityRects)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			CopyMemory(appWindow->visibilityRects, windowState->visibilityRects,
Packit 1fb8d4
			           appWindow->numVisibilityRects * sizeof(RECTANGLE_16));
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Update Window */
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
Packit 1fb8d4
	{
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
Packit 1fb8d4
	{
Packit 1fb8d4
		xf_ShowWindow(xfc, appWindow, appWindow->showState);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (appWindow->title)
Packit 1fb8d4
			xf_SetWindowText(xfc, appWindow, appWindow->title);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (position_or_size_updated)
Packit 1fb8d4
	{
Packit Service 5a9772
		UINT32 visibilityRectsOffsetX =
Packit Service 5a9772
		    (appWindow->visibleOffsetX -
Packit Service 5a9772
		     (appWindow->clientOffsetX - appWindow->windowClientDeltaX));
Packit Service 5a9772
		UINT32 visibilityRectsOffsetY =
Packit Service 5a9772
		    (appWindow->visibleOffsetY -
Packit Service 5a9772
		     (appWindow->clientOffsetY - appWindow->windowClientDeltaY));
Packit 1fb8d4
Packit 1fb8d4
		/*
Packit Service 5a9772
		 * The rail server like to set the window to a small size when it is minimized even though
Packit Service 5a9772
		 * it is hidden in some cases this can cause the window not to restore back to its original
Packit Service 5a9772
		 * size. Therefore we don't update our local window when that rail window state is minimized
Packit 1fb8d4
		 */
Packit 1fb8d4
		if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Redraw window area if already in the correct position */
Packit Service 5a9772
			if (appWindow->x == (INT64)appWindow->windowOffsetX &&
Packit Service 5a9772
			    appWindow->y == (INT64)appWindow->windowOffsetY &&
Packit Service 5a9772
			    appWindow->width == (INT64)appWindow->windowWidth &&
Packit Service 5a9772
			    appWindow->height == (INT64)appWindow->windowHeight)
Packit 1fb8d4
			{
Packit 1fb8d4
				xf_UpdateWindowArea(xfc, appWindow, 0, 0, appWindow->windowWidth,
Packit 1fb8d4
				                    appWindow->windowHeight);
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit Service 5a9772
				xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX, appWindow->windowOffsetY,
Packit 1fb8d4
				              appWindow->windowWidth, appWindow->windowHeight);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			xf_SetWindowVisibilityRects(xfc, appWindow, visibilityRectsOffsetX,
Packit 1fb8d4
			                            visibilityRectsOffsetY, appWindow->visibilityRects,
Packit 1fb8d4
			                            appWindow->numVisibilityRects);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* We should only be using the visibility rects for shaping the window */
Packit 1fb8d4
	/*if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
Packit 1fb8d4
	{
Packit Service 5a9772
	    xf_SetWindowRects(xfc, appWindow, appWindow->windowRects, appWindow->numWindowRects);
Packit 1fb8d4
	}*/
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_rail_window_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
Packit 1fb8d4
{
Packit Service 5a9772
	xfContext* xfc = (xfContext*)context;
Packit Service 5a9772
	return xf_rail_del_window(xfc, orderInfo->windowId);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static xfRailIconCache* RailIconCache_New(rdpSettings* settings)
Packit 1fb8d4
{
Packit 1fb8d4
	xfRailIconCache* cache;
Packit 1fb8d4
	cache = calloc(1, sizeof(xfRailIconCache));
Packit 1fb8d4
Packit 1fb8d4
	if (!cache)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	cache->numCaches = settings->RemoteAppNumIconCaches;
Packit 1fb8d4
	cache->numCacheEntries = settings->RemoteAppNumIconCacheEntries;
Packit Service 5a9772
	cache->entries = calloc(cache->numCaches * cache->numCacheEntries, sizeof(xfRailIcon));
Packit 1fb8d4
Packit 1fb8d4
	if (!cache->entries)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "failed to allocate icon cache %d x %d entries", cache->numCaches,
Packit Service 5a9772
		         cache->numCacheEntries);
Packit 1fb8d4
		free(cache);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return cache;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void RailIconCache_Free(xfRailIconCache* cache)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i;
Packit 1fb8d4
Packit 1fb8d4
	if (cache)
Packit 1fb8d4
	{
Packit 1fb8d4
		for (i = 0; i < cache->numCaches * cache->numCacheEntries; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(cache->entries[i].data);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		free(cache->scratch.data);
Packit 1fb8d4
		free(cache->entries);
Packit 1fb8d4
		free(cache);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static xfRailIcon* RailIconCache_Lookup(xfRailIconCache* cache, UINT8 cacheId, UINT16 cacheEntry)
Packit 1fb8d4
{
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * MS-RDPERP 2.2.1.2.3 Icon Info (TS_ICON_INFO)
Packit 1fb8d4
	 *
Packit 1fb8d4
	 * CacheId (1 byte):
Packit 1fb8d4
	 *     If the value is 0xFFFF, the icon SHOULD NOT be cached.
Packit 1fb8d4
	 *
Packit 1fb8d4
	 * Yes, the spec says "0xFFFF" in the 2018-03-16 revision,
Packit 1fb8d4
	 * but the actual protocol field is 1-byte wide.
Packit 1fb8d4
	 */
Packit 1fb8d4
	if (cacheId == 0xFF)
Packit 1fb8d4
		return &cache->scratch;
Packit 1fb8d4
Packit 1fb8d4
	if (cacheId >= cache->numCaches)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (cacheEntry >= cache->numCacheEntries)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	return &cache->entries[cache->numCacheEntries * cacheId + cacheEntry];
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/*
Packit 1fb8d4
 * _NET_WM_ICON format is defined as "array of CARDINAL" values which for
Packit 1fb8d4
 * Xlib must be represented with an array of C's "long" values. Note that
Packit 1fb8d4
 * "long" != "INT32" on 64-bit systems. Therefore we can't simply cast
Packit 1fb8d4
 * the bitmap data as (unsigned char*), we have to copy all the pixels.
Packit 1fb8d4
 *
Packit 1fb8d4
 * The first two values are width and height followed by actual color data
Packit 1fb8d4
 * in ARGB format (e.g., 0xFFFF0000L is opaque red), pixels are in normal,
Packit 1fb8d4
 * left-to-right top-down order.
Packit 1fb8d4
 */
Packit 1fb8d4
static BOOL convert_rail_icon(ICON_INFO* iconInfo, xfRailIcon* railIcon)
Packit 1fb8d4
{
Packit Service 5a9772
	BYTE* argbPixels = NULL;
Packit 1fb8d4
	BYTE* nextPixel;
Packit 1fb8d4
	long* pixels;
Packit 1fb8d4
	int i;
Packit 1fb8d4
	int nelements;
Packit 1fb8d4
	argbPixels = calloc(iconInfo->width * iconInfo->height, 4);
Packit 1fb8d4
Packit 1fb8d4
	if (!argbPixels)
Packit 1fb8d4
		goto error;
Packit 1fb8d4
Packit Service 5a9772
	if (!freerdp_image_copy_from_icon_data(
Packit Service 5a9772
	        argbPixels, PIXEL_FORMAT_ARGB32, 0, 0, 0, iconInfo->width, iconInfo->height,
Packit Service 5a9772
	        iconInfo->bitsColor, iconInfo->cbBitsColor, iconInfo->bitsMask, iconInfo->cbBitsMask,
Packit Service 5a9772
	        iconInfo->colorTable, iconInfo->cbColorTable, iconInfo->bpp))
Packit 1fb8d4
		goto error;
Packit 1fb8d4
Packit 1fb8d4
	nelements = 2 + iconInfo->width * iconInfo->height;
Packit 1fb8d4
	pixels = realloc(railIcon->data, nelements * sizeof(long));
Packit 1fb8d4
Packit 1fb8d4
	if (!pixels)
Packit 1fb8d4
		goto error;
Packit 1fb8d4
Packit 1fb8d4
	railIcon->data = pixels;
Packit 1fb8d4
	railIcon->length = nelements;
Packit 1fb8d4
	pixels[0] = iconInfo->width;
Packit 1fb8d4
	pixels[1] = iconInfo->height;
Packit 1fb8d4
	nextPixel = argbPixels;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 2; i < nelements; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		pixels[i] = ReadColor(nextPixel, PIXEL_FORMAT_BGRA32);
Packit 1fb8d4
		nextPixel += 4;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(argbPixels);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
error:
Packit 1fb8d4
	free(argbPixels);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void xf_rail_set_window_icon(xfContext* xfc, xfAppWindow* railWindow, xfRailIcon* icon,
Packit 1fb8d4
                                    BOOL replace)
Packit 1fb8d4
{
Packit Service 5a9772
	XChangeProperty(xfc->display, railWindow->handle, xfc->_NET_WM_ICON, XA_CARDINAL, 32,
Packit Service 5a9772
	                replace ? PropModeReplace : PropModeAppend, (unsigned char*)icon->data,
Packit Service 5a9772
	                icon->length);
Packit 1fb8d4
	XFlush(xfc->display);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_rail_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
Packit Service 5a9772
                                const WINDOW_ICON_ORDER* windowIcon)
Packit 1fb8d4
{
Packit Service 5a9772
	xfContext* xfc = (xfContext*)context;
Packit 1fb8d4
	xfAppWindow* railWindow;
Packit 1fb8d4
	xfRailIcon* icon;
Packit 1fb8d4
	BOOL replaceIcon;
Packit Service 5a9772
	railWindow = xf_rail_get_window(xfc, orderInfo->windowId);
Packit 1fb8d4
Packit 1fb8d4
	if (!railWindow)
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit Service 5a9772
	icon = RailIconCache_Lookup(xfc->railIconCache, windowIcon->iconInfo->cacheId,
Packit 1fb8d4
	                            windowIcon->iconInfo->cacheEntry);
Packit 1fb8d4
Packit 1fb8d4
	if (!icon)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_WARN(TAG, "failed to get icon from cache %02X:%04X", windowIcon->iconInfo->cacheId,
Packit 1fb8d4
		          windowIcon->iconInfo->cacheEntry);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!convert_rail_icon(windowIcon->iconInfo, icon))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_WARN(TAG, "failed to convert icon for window %08X", orderInfo->windowId);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW);
Packit 1fb8d4
	xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
Packit Service 5a9772
                                       const WINDOW_CACHED_ICON_ORDER* windowCachedIcon)
Packit 1fb8d4
{
Packit Service 5a9772
	xfContext* xfc = (xfContext*)context;
Packit 1fb8d4
	xfAppWindow* railWindow;
Packit 1fb8d4
	xfRailIcon* icon;
Packit 1fb8d4
	BOOL replaceIcon;
Packit Service 5a9772
	railWindow = xf_rail_get_window(xfc, orderInfo->windowId);
Packit 1fb8d4
Packit 1fb8d4
	if (!railWindow)
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit Service 5a9772
	icon = RailIconCache_Lookup(xfc->railIconCache, windowCachedIcon->cachedIcon.cacheId,
Packit 1fb8d4
	                            windowCachedIcon->cachedIcon.cacheEntry);
Packit 1fb8d4
Packit 1fb8d4
	if (!icon)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_WARN(TAG, "failed to get icon from cache %02X:%04X",
Packit Service 5a9772
		          windowCachedIcon->cachedIcon.cacheId, windowCachedIcon->cachedIcon.cacheEntry);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW);
Packit 1fb8d4
	xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_rail_notify_icon_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
Packit Service 5a9772
                                       const NOTIFY_ICON_STATE_ORDER* notifyIconState)
Packit 1fb8d4
{
Packit 1fb8d4
	if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION)
Packit 1fb8d4
	{
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP)
Packit 1fb8d4
	{
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP)
Packit 1fb8d4
	{
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE)
Packit 1fb8d4
	{
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (orderInfo->fieldFlags & WINDOW_ORDER_ICON)
Packit 1fb8d4
	{
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON)
Packit 1fb8d4
	{
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_rail_notify_icon_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
Packit Service 5a9772
                                       const NOTIFY_ICON_STATE_ORDER* notifyIconState)
Packit 1fb8d4
{
Packit 1fb8d4
	return xf_rail_notify_icon_common(context, orderInfo, notifyIconState);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_rail_notify_icon_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
Packit Service 5a9772
                                       const NOTIFY_ICON_STATE_ORDER* notifyIconState)
Packit 1fb8d4
{
Packit 1fb8d4
	return xf_rail_notify_icon_common(context, orderInfo, notifyIconState);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_rail_notify_icon_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
Packit 1fb8d4
{
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_rail_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
Packit Service 5a9772
                                      const MONITORED_DESKTOP_ORDER* monitoredDesktop)
Packit 1fb8d4
{
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL xf_rail_non_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
Packit 1fb8d4
{
Packit Service 5a9772
	xfContext* xfc = (xfContext*)context;
Packit 1fb8d4
	xf_rail_disable_remoteapp_mode(xfc);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void xf_rail_register_update_callbacks(rdpUpdate* update)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpWindowUpdate* window = update->window;
Packit 1fb8d4
	window->WindowCreate = xf_rail_window_common;
Packit 1fb8d4
	window->WindowUpdate = xf_rail_window_common;
Packit 1fb8d4
	window->WindowDelete = xf_rail_window_delete;
Packit 1fb8d4
	window->WindowIcon = xf_rail_window_icon;
Packit 1fb8d4
	window->WindowCachedIcon = xf_rail_window_cached_icon;
Packit 1fb8d4
	window->NotifyIconCreate = xf_rail_notify_icon_create;
Packit 1fb8d4
	window->NotifyIconUpdate = xf_rail_notify_icon_update;
Packit 1fb8d4
	window->NotifyIconDelete = xf_rail_notify_icon_delete;
Packit 1fb8d4
	window->MonitoredDesktop = xf_rail_monitored_desktop;
Packit 1fb8d4
	window->NonMonitoredDesktop = xf_rail_non_monitored_desktop;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/* RemoteApp Virtual Channel Extension */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT xf_rail_server_execute_result(RailClientContext* context,
Packit Service 5a9772
                                          const RAIL_EXEC_RESULT_ORDER* execResult)
Packit 1fb8d4
{
Packit Service 5a9772
	xfContext* xfc = (xfContext*)context->custom;
Packit 1fb8d4
Packit 1fb8d4
	if (execResult->execResult != RAIL_EXEC_S_OK)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "RAIL exec error: execResult=%s NtError=0x%X\n",
Packit 1fb8d4
		         error_code_names[execResult->execResult], execResult->rawResult);
Packit 1fb8d4
		freerdp_abort_connect(xfc->context.instance);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		xf_rail_enable_remoteapp_mode(xfc);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT xf_rail_server_system_param(RailClientContext* context,
Packit 1fb8d4
                                        const RAIL_SYSPARAM_ORDER* sysparam)
Packit 1fb8d4
{
Packit Service 5a9772
	// TODO: Actually apply param
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static UINT xf_rail_server_start_cmd(RailClientContext* context)
Packit 1fb8d4
{
Packit Service 5a9772
	UINT status;
Packit Service 5a9772
	RAIL_EXEC_ORDER exec = { 0 };
Packit Service 5a9772
	RAIL_SYSPARAM_ORDER sysparam = { 0 };
Packit Service 5a9772
	RAIL_CLIENT_STATUS_ORDER clientStatus = { 0 };
Packit Service 5a9772
	xfContext* xfc = (xfContext*)context->custom;
Packit 1fb8d4
	rdpSettings* settings = xfc->context.settings;
Packit Service 5a9772
	clientStatus.flags = TS_RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE;
Packit Service 5a9772
Packit Service 5a9772
	if (settings->AutoReconnectionEnabled)
Packit Service 5a9772
		clientStatus.flags |= TS_RAIL_CLIENTSTATUS_AUTORECONNECT;
Packit Service 5a9772
Packit Service 5a9772
	clientStatus.flags |= TS_RAIL_CLIENTSTATUS_ZORDER_SYNC;
Packit Service 5a9772
	clientStatus.flags |= TS_RAIL_CLIENTSTATUS_WINDOW_RESIZE_MARGIN_SUPPORTED;
Packit Service 5a9772
	clientStatus.flags |= TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED;
Packit Service 5a9772
	clientStatus.flags |= TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED;
Packit Service 5a9772
	clientStatus.flags |= TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED;
Packit Service 5a9772
	status = context->ClientInformation(context, &clientStatus);
Packit Service 5a9772
Packit Service 5a9772
	if (status != CHANNEL_RC_OK)
Packit Service 5a9772
		return status;
Packit 1fb8d4
Packit 1fb8d4
	if (settings->RemoteAppLanguageBarSupported)
Packit 1fb8d4
	{
Packit 1fb8d4
		RAIL_LANGBAR_INFO_ORDER langBarInfo;
Packit 1fb8d4
		langBarInfo.languageBarStatus = 0x00000008; /* TF_SFT_HIDDEN */
Packit Service 5a9772
		status = context->ClientLanguageBarInfo(context, &langBarInfo);
Packit Service 5a9772
Packit Service 5a9772
		/* We want the language bar, but the server might not support it. */
Packit Service 5a9772
		switch (status)
Packit Service 5a9772
		{
Packit Service 5a9772
			case CHANNEL_RC_OK:
Packit Service 5a9772
			case ERROR_BAD_CONFIGURATION:
Packit Service 5a9772
				break;
Packit Service 5a9772
			default:
Packit Service 5a9772
				return status;
Packit Service 5a9772
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	sysparam.params = 0;
Packit 1fb8d4
	sysparam.params |= SPI_MASK_SET_HIGH_CONTRAST;
Packit 1fb8d4
	sysparam.highContrast.colorScheme.string = NULL;
Packit 1fb8d4
	sysparam.highContrast.colorScheme.length = 0;
Packit 1fb8d4
	sysparam.highContrast.flags = 0x7E;
Packit 1fb8d4
	sysparam.params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP;
Packit 1fb8d4
	sysparam.mouseButtonSwap = FALSE;
Packit 1fb8d4
	sysparam.params |= SPI_MASK_SET_KEYBOARD_PREF;
Packit 1fb8d4
	sysparam.keyboardPref = FALSE;
Packit 1fb8d4
	sysparam.params |= SPI_MASK_SET_DRAG_FULL_WINDOWS;
Packit 1fb8d4
	sysparam.dragFullWindows = FALSE;
Packit 1fb8d4
	sysparam.params |= SPI_MASK_SET_KEYBOARD_CUES;
Packit 1fb8d4
	sysparam.keyboardCues = FALSE;
Packit 1fb8d4
	sysparam.params |= SPI_MASK_SET_WORK_AREA;
Packit 1fb8d4
	sysparam.workArea.left = 0;
Packit 1fb8d4
	sysparam.workArea.top = 0;
Packit 1fb8d4
	sysparam.workArea.right = settings->DesktopWidth;
Packit 1fb8d4
	sysparam.workArea.bottom = settings->DesktopHeight;
Packit 1fb8d4
	sysparam.dragFullWindows = FALSE;
Packit Service 5a9772
	status = context->ClientSystemParam(context, &sysparam);
Packit Service 5a9772
Packit Service 5a9772
	if (status != CHANNEL_RC_OK)
Packit Service 5a9772
		return status;
Packit Service 5a9772
Packit 1fb8d4
	exec.RemoteApplicationProgram = settings->RemoteApplicationProgram;
Packit 1fb8d4
	exec.RemoteApplicationWorkingDir = settings->ShellWorkingDirectory;
Packit 1fb8d4
	exec.RemoteApplicationArguments = settings->RemoteApplicationCmdLine;
Packit Service 5a9772
	return context->ClientExecute(context, &exec);
Packit Service 5a9772
}
Packit Service 5a9772
/**
Packit Service 5a9772
 * Function description
Packit Service 5a9772
 *
Packit Service 5a9772
 * @return 0 on success, otherwise a Win32 error code
Packit Service 5a9772
 */
Packit Service 5a9772
static UINT xf_rail_server_handshake(RailClientContext* context,
Packit Service 5a9772
                                     const RAIL_HANDSHAKE_ORDER* handshake)
Packit Service 5a9772
{
Packit Service 5a9772
	return xf_rail_server_start_cmd(context);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT xf_rail_server_handshake_ex(RailClientContext* context,
Packit 1fb8d4
                                        const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
Packit 1fb8d4
{
Packit Service 5a9772
	return xf_rail_server_start_cmd(context);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT xf_rail_server_local_move_size(RailClientContext* context,
Packit Service 5a9772
                                           const RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
Packit 1fb8d4
{
Packit 1fb8d4
	int x = 0, y = 0;
Packit 1fb8d4
	int direction = 0;
Packit 1fb8d4
	Window child_window;
Packit Service 5a9772
	xfContext* xfc = (xfContext*)context->custom;
Packit Service 5a9772
	xfAppWindow* appWindow = xf_rail_get_window(xfc, localMoveSize->windowId);
Packit 1fb8d4
Packit 1fb8d4
	if (!appWindow)
Packit 1fb8d4
		return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
Packit 1fb8d4
	switch (localMoveSize->moveSizeType)
Packit 1fb8d4
	{
Packit 1fb8d4
		case RAIL_WMSZ_LEFT:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
Packit 1fb8d4
			x = localMoveSize->posX;
Packit 1fb8d4
			y = localMoveSize->posY;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RAIL_WMSZ_RIGHT:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
Packit 1fb8d4
			x = localMoveSize->posX;
Packit 1fb8d4
			y = localMoveSize->posY;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RAIL_WMSZ_TOP:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_SIZE_TOP;
Packit 1fb8d4
			x = localMoveSize->posX;
Packit 1fb8d4
			y = localMoveSize->posY;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RAIL_WMSZ_TOPLEFT:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
Packit 1fb8d4
			x = localMoveSize->posX;
Packit 1fb8d4
			y = localMoveSize->posY;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RAIL_WMSZ_TOPRIGHT:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
Packit 1fb8d4
			x = localMoveSize->posX;
Packit 1fb8d4
			y = localMoveSize->posY;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RAIL_WMSZ_BOTTOM:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
Packit 1fb8d4
			x = localMoveSize->posX;
Packit 1fb8d4
			y = localMoveSize->posY;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RAIL_WMSZ_BOTTOMLEFT:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
Packit 1fb8d4
			x = localMoveSize->posX;
Packit 1fb8d4
			y = localMoveSize->posY;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RAIL_WMSZ_BOTTOMRIGHT:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
Packit 1fb8d4
			x = localMoveSize->posX;
Packit 1fb8d4
			y = localMoveSize->posY;
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RAIL_WMSZ_MOVE:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_MOVE;
Packit Service 5a9772
			XTranslateCoordinates(xfc->display, appWindow->handle, RootWindowOfScreen(xfc->screen),
Packit 1fb8d4
			                      localMoveSize->posX, localMoveSize->posY, &x, &y, &child_window);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case RAIL_WMSZ_KEYMOVE:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
Packit 1fb8d4
			x = localMoveSize->posX;
Packit 1fb8d4
			y = localMoveSize->posY;
Packit 1fb8d4
			/* FIXME: local keyboard moves not working */
Packit 1fb8d4
			return CHANNEL_RC_OK;
Packit 1fb8d4
Packit 1fb8d4
		case RAIL_WMSZ_KEYSIZE:
Packit 1fb8d4
			direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
Packit 1fb8d4
			x = localMoveSize->posX;
Packit 1fb8d4
			y = localMoveSize->posY;
Packit 1fb8d4
			/* FIXME: local keyboard moves not working */
Packit 1fb8d4
			return CHANNEL_RC_OK;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (localMoveSize->isMoveSizeStart)
Packit 1fb8d4
		xf_StartLocalMoveSize(xfc, appWindow, direction, x, y);
Packit 1fb8d4
	else
Packit 1fb8d4
		xf_EndLocalMoveSize(xfc, appWindow);
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT xf_rail_server_min_max_info(RailClientContext* context,
Packit 1fb8d4
                                        const RAIL_MINMAXINFO_ORDER* minMaxInfo)
Packit 1fb8d4
{
Packit Service 5a9772
	xfContext* xfc = (xfContext*)context->custom;
Packit Service 5a9772
	xfAppWindow* appWindow = xf_rail_get_window(xfc, minMaxInfo->windowId);
Packit 1fb8d4
Packit 1fb8d4
	if (appWindow)
Packit 1fb8d4
	{
Packit Service 5a9772
		xf_SetWindowMinMaxInfo(xfc, appWindow, minMaxInfo->maxWidth, minMaxInfo->maxHeight,
Packit Service 5a9772
		                       minMaxInfo->maxPosX, minMaxInfo->maxPosY, minMaxInfo->minTrackWidth,
Packit Service 5a9772
		                       minMaxInfo->minTrackHeight, minMaxInfo->maxTrackWidth,
Packit Service 5a9772
		                       minMaxInfo->maxTrackHeight);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT xf_rail_server_language_bar_info(RailClientContext* context,
Packit Service 5a9772
                                             const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
Packit 1fb8d4
{
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
static UINT xf_rail_server_get_appid_response(RailClientContext* context,
Packit Service 5a9772
                                              const RAIL_GET_APPID_RESP_ORDER* getAppIdResp)
Packit 1fb8d4
{
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL rail_window_key_equals(void* key1, void* key2)
Packit Service 5a9772
{
Packit Service 5a9772
	const UINT64* k1 = (const UINT64*)key1;
Packit Service 5a9772
	const UINT64* k2 = (const UINT64*)key2;
Packit Service 5a9772
Packit Service 5a9772
	if (!k1 || !k2)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	return *k1 == *k2;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT32 rail_window_key_hash(void* key)
Packit Service 5a9772
{
Packit Service 5a9772
	const UINT64* k1 = (const UINT64*)key;
Packit Service 5a9772
	return (UINT32)*k1;
Packit Service 5a9772
}
Packit Service 5a9772
Packit 1fb8d4
static void rail_window_free(void* value)
Packit 1fb8d4
{
Packit Service 5a9772
	xfAppWindow* appWindow = (xfAppWindow*)value;
Packit 1fb8d4
Packit 1fb8d4
	if (!appWindow)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	xf_DestroyWindow(appWindow->xfc, appWindow);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int xf_rail_init(xfContext* xfc, RailClientContext* rail)
Packit 1fb8d4
{
Packit Service 5a9772
	rdpContext* context = (rdpContext*)xfc;
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc || !rail)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	xfc->rail = rail;
Packit 1fb8d4
	xf_rail_register_update_callbacks(context->update);
Packit Service 5a9772
	rail->custom = (void*)xfc;
Packit 1fb8d4
	rail->ServerExecuteResult = xf_rail_server_execute_result;
Packit 1fb8d4
	rail->ServerSystemParam = xf_rail_server_system_param;
Packit 1fb8d4
	rail->ServerHandshake = xf_rail_server_handshake;
Packit 1fb8d4
	rail->ServerHandshakeEx = xf_rail_server_handshake_ex;
Packit 1fb8d4
	rail->ServerLocalMoveSize = xf_rail_server_local_move_size;
Packit 1fb8d4
	rail->ServerMinMaxInfo = xf_rail_server_min_max_info;
Packit 1fb8d4
	rail->ServerLanguageBarInfo = xf_rail_server_language_bar_info;
Packit 1fb8d4
	rail->ServerGetAppIdResponse = xf_rail_server_get_appid_response;
Packit 1fb8d4
	xfc->railWindows = HashTable_New(TRUE);
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc->railWindows)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit Service 5a9772
	xfc->railWindows->keyCompare = rail_window_key_equals;
Packit Service 5a9772
	xfc->railWindows->hash = rail_window_key_hash;
Packit 1fb8d4
	xfc->railWindows->valueFree = rail_window_free;
Packit 1fb8d4
	xfc->railIconCache = RailIconCache_New(xfc->context.settings);
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc->railIconCache)
Packit 1fb8d4
	{
Packit 1fb8d4
		HashTable_Free(xfc->railWindows);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int xf_rail_uninit(xfContext* xfc, RailClientContext* rail)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_UNUSED(rail);
Packit Service 5a9772
Packit 1fb8d4
	if (xfc->rail)
Packit 1fb8d4
	{
Packit 1fb8d4
		xfc->rail->custom = NULL;
Packit 1fb8d4
		xfc->rail = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (xfc->railWindows)
Packit 1fb8d4
	{
Packit 1fb8d4
		HashTable_Free(xfc->railWindows);
Packit 1fb8d4
		xfc->railWindows = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (xfc->railIconCache)
Packit 1fb8d4
	{
Packit 1fb8d4
		RailIconCache_Free(xfc->railIconCache);
Packit 1fb8d4
		xfc->railIconCache = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit Service 5a9772
Packit Service 5a9772
xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, UINT32 x, UINT32 y, UINT32 width,
Packit Service 5a9772
                                UINT32 height, UINT32 surfaceId)
Packit Service 5a9772
{
Packit Service 5a9772
	xfAppWindow* appWindow;
Packit Service 5a9772
Packit Service 5a9772
	if (!xfc)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	appWindow = (xfAppWindow*)calloc(1, sizeof(xfAppWindow));
Packit Service 5a9772
Packit Service 5a9772
	if (!appWindow)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	appWindow->xfc = xfc;
Packit Service 5a9772
	appWindow->windowId = id;
Packit Service 5a9772
	appWindow->surfaceId = surfaceId;
Packit Service 5a9772
	appWindow->x = x;
Packit Service 5a9772
	appWindow->y = y;
Packit Service 5a9772
	appWindow->width = width;
Packit Service 5a9772
	appWindow->height = height;
Packit Service 5a9772
	xf_AppWindowCreate(xfc, appWindow);
Packit Service 5a9772
	HashTable_Add(xfc->railWindows, &appWindow->windowId, (void*)appWindow);
Packit Service 5a9772
	return appWindow;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
BOOL xf_rail_del_window(xfContext* xfc, UINT64 id)
Packit Service 5a9772
{
Packit Service 5a9772
	if (!xfc)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (!xfc->railWindows)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	return HashTable_Remove(xfc->railWindows, &id;;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64 id)
Packit Service 5a9772
{
Packit Service 5a9772
	if (!xfc)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	if (!xfc->railWindows)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	return HashTable_GetItemValue(xfc->railWindows, &id;;
Packit Service 5a9772
}