RemoteApp Support

1. Remove all uses of "localWindowOffsetCorr" variables, they added an extra layer of complexity and they are not actually needed to handle coordination of window position/size between
the local coordinate system and the remote one. This logic was causing issues in the case where the window was moved off the left side of the screen.

2. Update the xf_setWindowVisibilityRects function to offset the visibility rects as necessary when the window is hanging off the left side of the screen.

3. Stop sending mouse events when doing keyboard moves/sizes(as desired), and stop sending two mouse events for non-keyboard moves/sizes

4. Move location of new UTF8_STRING variable from previous commit

5. Refresh window and window shape for any window position/size updates, this helps keep the local and server windows in sync and works around some race conditions
This commit is contained in:
bjcollins 2015-10-15 18:41:55 -05:00
parent cc676c4468
commit 8e27b6d05e
5 changed files with 66 additions and 89 deletions

View File

@ -1865,11 +1865,12 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
xfc->_NET_WM_STATE_SKIP_PAGER = XInternAtom(xfc->display, "_NET_WM_STATE_SKIP_PAGER", False);
xfc->_NET_WM_MOVERESIZE = XInternAtom(xfc->display, "_NET_WM_MOVERESIZE", False);
xfc->_NET_MOVERESIZE_WINDOW = XInternAtom(xfc->display, "_NET_MOVERESIZE_WINDOW", False);
xfc->UTF8_STRING = XInternAtom(xfc->display, "UTF8_STRING", FALSE);
xfc->WM_PROTOCOLS = XInternAtom(xfc->display, "WM_PROTOCOLS", False);
xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False);
xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False);
xfc->UTF8_STRING = XInternAtom(xfc->display, "UTF8_STRING", FALSE);
xfc->xfds = ConnectionNumber(xfc->display);
xfc->screen_number = DefaultScreen(xfc->display);
xfc->screen = ScreenOfDisplay(xfc->display, xfc->screen_number);

View File

@ -278,7 +278,8 @@ BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window win
xf_event_adjust_coordinates(xfc, &x, &y);
input->MouseEvent(input, PTR_FLAGS_MOVE, x, y);
if (!app || xf_AppWindowFromX11Window(xfc,window)->local_move.direction != RAIL_WMSZ_KEYSIZE)
input->MouseEvent(input, PTR_FLAGS_MOVE, x, y);
if (xfc->fullscreen && !app)
{

View File

@ -119,25 +119,17 @@ void xf_rail_adjust_position(xfContext* xfc, xfAppWindow* appWindow)
return;
/* If current window position disagrees with RDP window position, send update to RDP server */
if (appWindow->x != (appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX) ||
appWindow->y != (appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY) ||
if (appWindow->x != appWindow->windowOffsetX ||
appWindow->y != appWindow->windowOffsetY ||
appWindow->width != appWindow->windowWidth ||
appWindow->height != appWindow->windowHeight)
{
/*
* windowOffset corresponds to the window location on the rail server
* but our local window is based uses a local offset since the windowOffset
* can be negative and but X does not support negative values. Not using an
* offset can result in blank areas for a maximized window
*/
windowMove.windowId = appWindow->windowId;
/*
* Calculate new size/position for the rail window(new values for windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server
* New position is based on: Current local rail window offset +
* Local offset correction(current correction value to translate the local window offset to the server rail window offset)
*/
windowMove.left = appWindow->x + appWindow->localWindowOffsetCorrX;
windowMove.top = appWindow->y + appWindow->localWindowOffsetCorrY;
windowMove.left = appWindow->x;
windowMove.top = appWindow->y;
windowMove.right = windowMove.left + appWindow->width;
windowMove.bottom = windowMove.top + appWindow->height;
@ -163,12 +155,10 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
/*
* Calculate new size/position for the rail window(new values for windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server
* New position is based on: Current local rail window offset +
* Local offset correction(current correction value to translate the local window offset to the server rail window offset)
*
*/
windowMove.left = appWindow->x + appWindow->localWindowOffsetCorrX;
windowMove.top = appWindow->y + appWindow->localWindowOffsetCorrY;
windowMove.left = appWindow->x;
windowMove.top = appWindow->y;
windowMove.right = windowMove.left + appWindow->width; /* In the update to RDP the position is one past the window */
windowMove.bottom = windowMove.top + appWindow->height;
@ -180,8 +170,6 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
XQueryPointer(xfc->display, appWindow->handle,
&root_window, &child_window, &x, &y, &child_x, &child_y, &mask);
input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y);
/* only send the mouse coordinates if not a keyboard move or size */
if ((appWindow->local_move.direction != _NET_WM_MOVERESIZE_MOVE_KEYBOARD) &&
(appWindow->local_move.direction != _NET_WM_MOVERESIZE_SIZE_KEYBOARD))
@ -194,8 +182,8 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow)
* we can start to receive GDI orders for the new window dimensions before we
* receive the RAIL ORDER for the new window size. This avoids that race condition.
*/
appWindow->windowOffsetX = windowMove.left;
appWindow->windowOffsetY = windowMove.top;
appWindow->windowOffsetX = appWindow->x;
appWindow->windowOffsetY = appWindow->y;
appWindow->windowWidth = appWindow->width;
appWindow->windowHeight = appWindow->height;
appWindow->local_move.state = LMS_TERMINATING;
@ -277,6 +265,7 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI
xfAppWindow* appWindow = NULL;
xfContext* xfc = (xfContext*) context;
UINT32 fieldFlags = orderInfo->fieldFlags;
BOOL position_or_size_updated = FALSE;
if (fieldFlags & WINDOW_ORDER_STATE_NEW)
{
@ -296,9 +285,6 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI
appWindow->width = appWindow->windowWidth = windowState->windowWidth;
appWindow->height = appWindow->windowHeight = windowState->windowHeight;
appWindow->localWindowOffsetCorrX = 0;
appWindow->localWindowOffsetCorrY = 0;
/* Ensure window always gets a window title */
if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
{
@ -332,37 +318,31 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI
if (!appWindow)
return FALSE;
/* Keep track of any position/size update so that we can force a refresh of the window */
if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
(fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) ||
(fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) ||
(fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) ||
(fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) ||
(fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) ||
(fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY))
{
position_or_size_updated = TRUE;
}
/* Update Parameters */
if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
(fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE))
if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
{
if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
{
appWindow->windowOffsetX = windowState->windowOffsetX;
appWindow->windowOffsetY = windowState->windowOffsetY;
appWindow->windowOffsetX = windowState->windowOffsetX;
appWindow->windowOffsetY = windowState->windowOffsetY;
}
/*
* The rail server can give negative window coordinates when updating windowOffsetX and windowOffsetY,
* but we can only send unsigned integers to the rail server. Therefore, we maintain a local offset.
*/
if (appWindow->windowOffsetX < 0)
appWindow->localWindowOffsetCorrX = 0 - appWindow->windowOffsetX;
else
appWindow->localWindowOffsetCorrX = 0;
if (appWindow->windowOffsetY < 0)
appWindow->localWindowOffsetCorrY = 0 - appWindow->windowOffsetY;
else
appWindow->localWindowOffsetCorrY = 0;
}
if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
{
appWindow->windowWidth = windowState->windowWidth;
appWindow->windowHeight = windowState->windowHeight;
}
if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
{
appWindow->windowWidth = windowState->windowWidth;
appWindow->windowHeight = windowState->windowHeight;
}
if (fieldFlags & WINDOW_ORDER_FIELD_OWNER)
@ -478,42 +458,43 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI
xf_SetWindowText(xfc, appWindow, appWindow->title);
}
if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) ||
(fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE))
if (position_or_size_updated)
{
UINT32 visibilityRectsOffsetX = (appWindow->visibleOffsetX - (appWindow->clientOffsetX - appWindow->windowClientDeltaX));
UINT32 visibilityRectsOffsetY = (appWindow->visibleOffsetY - (appWindow->clientOffsetY - appWindow->windowClientDeltaY));
/*
* The rail server like to set the window to a small size when it is minimized even though it is hidden
* in some cases this can cause the window not to restore back to its original size. Therefore we don't
* update our local window when that rail window state is minimized
*/
if (appWindow->rail_state == WINDOW_SHOW_MINIMIZED)
return TRUE;
if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED)
{
/* Do nothing if window is already in the correct position */
if (appWindow->x == (appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX) &&
appWindow->y == (appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY) &&
/* Redraw window area if already in the correct position */
if (appWindow->x == appWindow->windowOffsetX &&
appWindow->y == appWindow->windowOffsetY &&
appWindow->width == appWindow->windowWidth &&
appWindow->height == appWindow->windowHeight)
{
xf_UpdateWindowArea(xfc, appWindow, 0, 0, appWindow->windowWidth, appWindow->windowHeight);
}
else
{
xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX, appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY,
appWindow->windowWidth, appWindow->windowHeight);
{
xf_UpdateWindowArea(xfc, appWindow, 0, 0, appWindow->windowWidth, appWindow->windowHeight);
}
else
{
xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX, appWindow->windowOffsetY,
appWindow->windowWidth, appWindow->windowHeight);
}
xf_SetWindowVisibilityRects(xfc, appWindow, visibilityRectsOffsetX, visibilityRectsOffsetY, appWindow->visibilityRects, appWindow->numVisibilityRects);
}
}
if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
/* We should only be using the visibility rects for shaping the window */
/*if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
{
/* We should only be using the visibility rects for shaping the window */
//xf_SetWindowRects(xfc, appWindow, appWindow->windowRects, appWindow->numWindowRects);
}
xf_SetWindowRects(xfc, appWindow, appWindow->windowRects, appWindow->numWindowRects);
}*/
if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
{
xf_SetWindowVisibilityRects(xfc, appWindow, appWindow->visibilityRects, appWindow->numVisibilityRects);
}
return TRUE;
}

View File

@ -927,7 +927,7 @@ void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rec
}
void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects)
void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX, UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects)
{
int i;
XRectangle* xrects;
@ -946,7 +946,7 @@ void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANG
xrects[i].height = rects[i].bottom - rects[i].top;
}
XShapeCombineRectangles(xfc->display, appWindow->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0);
XShapeCombineRectangles(xfc->display, appWindow->handle, ShapeBounding, rectsOffsetX, rectsOffsetY, xrects, nrects, ShapeSet, 0);
free(xrects);
#endif
@ -955,20 +955,14 @@ void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANG
void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height)
{
int ax, ay;
UINT32 translatedWindowOffsetX;
UINT32 translatedWindowOffsetY;
/* Translate the server rail window offset to a local offset */
translatedWindowOffsetX = (appWindow->windowOffsetX - appWindow->localWindowOffsetCorrX);
translatedWindowOffsetY = (appWindow->windowOffsetY - appWindow->localWindowOffsetCorrY);
ax = x + appWindow->windowOffsetX;
ay = y + appWindow->windowOffsetY;
ax = x + translatedWindowOffsetX;
ay = y + translatedWindowOffsetY;
if (ax + width > translatedWindowOffsetX + appWindow->width)
width = (translatedWindowOffsetX + appWindow->width - 1) - ax;
if (ay + height > translatedWindowOffsetY + appWindow->height)
height = (translatedWindowOffsetY + appWindow->height - 1) - ay;
if (ax + width > appWindow->windowOffsetX + appWindow->windowWidth)
width = (appWindow->windowOffsetX + appWindow->windowWidth - 1) - ax;
if (ay + height > appWindow->windowOffsetY + appWindow->windowHeight)
height = (appWindow->windowOffsetY + appWindow->windowHeight - 1) - ay;
xf_lock_x11(xfc, TRUE);

View File

@ -160,7 +160,7 @@ void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int wid
void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state);
//void xf_SetWindowIcon(xfContext* xfc, xfAppWindow* appWindow, rdpIcon* icon);
void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects);
void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects);
void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX, UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects);
void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UINT32 ex_style);
void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height);
void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow);