Multiple RAIL fixes/improvements

1. Linked Window Manager Maximize/Minimize and Restore operations to those from the Server Rail Window so that they are in sync

2. Enable things like "CTRL-ALT-DELETE" and "WindowsKey-L" to show the full desktop window again since the desktop is not actively monitored since
this was still trying to draw to the rail window without updating the size of the window to accomodate the full workspace area.

3. Changed local window coordinates to be based on the visibileOffsetX/Y- while moving server window based on WindowOffsetX/Y. I have seen various issues regarding this when trying to use a maximized window where this is a disconnect between local window coordinates and remote window coordinates. This change clears these things up.

4. Commented the XShapeCombineRectangles calls - this can cause issues where the entire window is not visible and it does not currently play well with the changes from #3. The gain here is greater than the loss.

5. Draw the initial workspace correctly when running across multiple monitors. The correct size was always used, but the window was only starting on the current monitor and thus could draw the window off of the viewable area.

Known Issues:

Although the changes for #2 worked well in the stable branch that I developed from - the desktop window shown once the rail windows are destroyed does not respond to input unless I minimize/restore the window. Once the window starts responding to input - you can hit cancel to close the desktop window and return to your rail windows again(or launch task manager, etc.). This is still a big step in the right direction as xfreerdp is now correctly acting when the rail server stops Actively Monitoring the desktop.

XShapeCombineRectangles needs to be revisited, most windows applications will give you a rectangular window anyways.
This commit is contained in:
Brent Collins 2012-08-03 17:35:17 -05:00
parent 26e5f8587e
commit 0b7db6232f
11 changed files with 360 additions and 37 deletions

View File

@ -366,8 +366,18 @@ static boolean xf_event_FocusIn(xfInfo* xfi, XEvent* event, boolean app)
XGrabKeyboard(xfi->display, xfi->window->handle, true, GrabModeAsync, GrabModeAsync, CurrentTime);
if (app)
{
xf_rail_send_activate(xfi, event->xany.window, true);
rdpWindow* window;
rdpRail* rail = ((rdpContext*) xfi->context)->rail;
window = window_list_get_by_extra_id(rail->list, (void*) event->xany.window);
//Update the server with any window changes that occured while the window was not focused.
if (window != NULL)
xf_rail_adjust_position(xfi, window);
}
xf_kbd_focus_in(xfi);
if (app != true)
@ -506,7 +516,11 @@ static boolean xf_event_ConfigureNotify(xfInfo* xfi, XEvent* event, boolean app)
(uint32) xfw->handle, xfw->left, xfw->top, xfw->right, xfw->bottom,
xfw->width, xfw->height, event->xconfigure.send_event);
if (app && ! event->xconfigure.send_event)
//additonal checks for not in a local move and not ignoring configure to send position update to server,
//also should the window not be focused then do not send to server yet(ie. resizing using window decoration).
//The server will be updated when the window gets refocused.
if (app && (!event->xconfigure.send_event || xfi->window->local_move.state == LMS_NOT_ACTIVE)
&& !xfw->rail_ignore_configure && xfi->focused)
xf_rail_adjust_position(xfi, window);
}
@ -539,7 +553,10 @@ static boolean xf_event_MapNotify(xfInfo* xfi, XEvent* event, boolean app)
if (window != NULL)
{
/* local restore event */
xf_rail_send_client_system_command(xfi, window->windowId, SC_RESTORE);
//This is now handled as part of the PropertyNotify
//Doing this here would inhibit the ability to restore a maximized window
//that is minimized back to the maximized state
//xf_rail_send_client_system_command(xfi, window->windowId, SC_RESTORE);
xfWindow *xfw = (xfWindow*) window->extra;
xfw->is_mapped = true;
}
@ -613,6 +630,92 @@ static boolean xf_event_SelectionClear(xfInfo* xfi, XEvent* event, boolean app)
static boolean xf_event_PropertyNotify(xfInfo* xfi, XEvent* event, boolean app)
{
//This section handles sending the appropriate commands to the rail server
//when the window has been minimized, maximized, restored locally
//ie. not using the buttons on the rail window itself
if (app == true)
{
rdpWindow* window;
rdpRail* rail = ((rdpContext*) xfi->context)->rail;
window = window_list_get_by_extra_id(rail->list, (void*) event->xany.window);
if ((((Atom)event->xproperty.atom == xfi->_NET_WM_STATE) && (event->xproperty.state != PropertyDelete)) ||
(((Atom)event->xproperty.atom == xfi->WM_STATE) && (event->xproperty.state != PropertyDelete)))
{
boolean status;
boolean maxVert = false;
boolean maxHorz = false;
boolean minimized = false;
unsigned long nitems;
unsigned long bytes;
unsigned char* prop;
int i;
status = xf_GetWindowProperty(xfi, event->xproperty.window,
xfi->_NET_WM_STATE, 12, &nitems, &bytes, &prop);
if (status != true) {
DEBUG_X11_LMS("No return _NET_WM_STATE, window is not maximized");
}
for (i=0;i<nitems;i++)
{
if ((Atom) ((uint16 **) prop)[i] == XInternAtom(xfi->display, "_NET_WM_STATE_MAXIMIZED_VERT", False))
{
maxVert = true;
}
if ((Atom) ((uint16 **)prop)[i] == XInternAtom(xfi->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False))
{
maxHorz = true;
}
}
XFree(prop);
status = xf_GetWindowProperty(xfi, event->xproperty.window,
xfi->WM_STATE, 1, &nitems, &bytes, &prop);
if (status != true) {
DEBUG_X11_LMS("No return WM_STATE, window is not minimized");
}
else
{
//If the window is in the iconic state
if (((uint32) *prop == 3))
{
minimized = true;
}
else
minimized = false;
XFree(prop);
}
if (maxVert && maxHorz && !minimized && (xfi->window->rail_state != WINDOW_SHOW_MAXIMIZED))
{
DEBUG_X11_LMS("Send SC_MAXIMIZE command to rail server.");
xfi->window->rail_state = WINDOW_SHOW_MAXIMIZED;
xf_rail_send_client_system_command(xfi, window->windowId, SC_MAXIMIZE);
}
else if (minimized && (xfi->window->rail_state != WINDOW_SHOW_MINIMIZED))
{
DEBUG_X11_LMS("Send SC_MINIMIZE command to rail server.");
xfi->window->rail_state = WINDOW_SHOW_MINIMIZED;
xf_rail_send_client_system_command(xfi, window->windowId, SC_MINIMIZE);
}
else if (!minimized && !maxVert && !maxHorz && (xfi->window->rail_state != WINDOW_SHOW))
{
DEBUG_X11_LMS("Send SC_RESTORE command to rail server");
xfi->window->rail_state = WINDOW_SHOW;
xf_rail_send_client_system_command(xfi, window->windowId, SC_RESTORE);
}
}
}
if (app != true)
{
if (xf_cliprdr_process_property_notify(xfi, event))
@ -631,6 +734,15 @@ static boolean xf_event_suppress_events(xfInfo *xfi, rdpWindow *window, XEvent*e
{
case LMS_NOT_ACTIVE:
// No local move in progress, nothing to do
//Prevent Configure from happening during indeterminant state of Horz or Vert Max only
if ( (event->type == ConfigureNotify) && xfi->window->rail_ignore_configure)
{
DEBUG_X11_LMS("ConfigureNotify Event Ignored");
xfi->window->rail_ignore_configure = false;
return true;
}
break;
case LMS_STARTING:
// Local move initiated by RDP server, but we
@ -677,9 +789,11 @@ static boolean xf_event_suppress_events(xfInfo *xfi, rdpWindow *window, XEvent*e
case VisibilityNotify:
case PropertyNotify:
case Expose:
case GravityNotify:
// Keep us up to date on position
break;
default:
DEBUG_X11_LMS("Event Type to break LMS: %s", X11_EVENT_STRINGS[event->type]);
// Any other event terminates move
xf_rail_end_local_move(xfi, window);
break;

View File

@ -117,6 +117,16 @@ boolean xf_detect_monitors(xfInfo* xfi, rdpSettings* settings)
vscreen->area.bottom = MAX(vscreen->monitors[i].area.bottom, vscreen->area.bottom);
}
//if no monitor information is present then make sure variables are set accordingly
if (settings->num_monitors == 0)
{
vscreen->area.left = 0;
vscreen->area.right = settings->width -1;
vscreen->area.top = 0;
vscreen->area.bottom = settings->height - 1;
}
if (settings->num_monitors)
{
settings->width = vscreen->area.right - vscreen->area.left + 1;

View File

@ -39,6 +39,16 @@ void xf_rail_enable_remoteapp_mode(xfInfo* xfi)
}
}
void xf_rail_disable_remoteapp_mode(xfInfo* xfi)
{
if (xfi->remote_app == true)
{
xfi->remote_app = false;
xf_create_window(xfi);
}
}
void xf_rail_paint(xfInfo* xfi, rdpRail* rail, sint32 uleft, sint32 utop, uint32 uright, uint32 ubottom)
{
xfWindow* xfw;
@ -64,10 +74,10 @@ void xf_rail_paint(xfInfo* xfi, rdpRail* rail, sint32 uleft, sint32 utop, uint32
continue;
}
wleft = window->windowOffsetX;
wtop = window->windowOffsetY;
wright = window->windowOffsetX + window->windowWidth - 1;
wbottom = window->windowOffsetY + window->windowHeight - 1;
wleft = window->visibleOffsetX;
wtop = window->visibleOffsetY;
wright = window->visibleOffsetX + window->windowWidth - 1;
wbottom = window->visibleOffsetY + window->windowHeight - 1;
ileft = MAX(uleft, wleft);
itop = MAX(utop, wtop);
@ -86,6 +96,14 @@ void xf_rail_paint(xfInfo* xfi, rdpRail* rail, sint32 uleft, sint32 utop, uint32
}
}
void xf_rail_DesktopNonMonitored(rdpRail *rail, rdpWindow* window)
{
xfInfo* xfi;
xfi = (xfInfo*) rail->extra;
xf_rail_disable_remoteapp_mode(xfi);
}
static void xf_rail_CreateWindow(rdpRail* rail, rdpWindow* window)
{
xfInfo* xfi;
@ -116,8 +134,28 @@ static void xf_rail_MoveWindow(rdpRail* rail, rdpWindow* window)
xfi = (xfInfo*) rail->extra;
xfw = (xfWindow*) window->extra;
//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 dont update
//our local window when that rail window state is minimized
if (xfw->rail_state == WINDOW_SHOW_MINIMIZED)
return;
// Do nothing if window is already in the correct position
if ( xfw->left == window->visibleOffsetX &&
xfw->top == window->visibleOffsetY &&
xfw->width == window->windowWidth &&
xfw->height == window->windowHeight)
{
//Just ensure entire window area is updated to
//handle cases where we have drawn locally before getting new bitmap
//from the server
xf_UpdateWindowArea(xfi, xfw, 0, 0, window->windowWidth, window->windowHeight);
return;
}
xf_MoveWindow(xfi, xfw,
window->windowOffsetX, window->windowOffsetY,
window->visibleOffsetX, window->visibleOffsetY,
window->windowWidth, window->windowHeight);
}
@ -197,6 +235,7 @@ void xf_rail_register_callbacks(xfInfo* xfi, rdpRail* rail)
rail->rail_SetWindowRects = xf_rail_SetWindowRects;
rail->rail_SetWindowVisibilityRects = xf_rail_SetWindowVisibilityRects;
rail->rail_DestroyWindow = xf_rail_DestroyWindow;
rail->rail_DesktopNonMonitored = xf_rail_DesktopNonMonitored;
}
static void xf_on_free_rail_client_event(RDP_EVENT* event)
@ -275,21 +314,39 @@ void xf_rail_adjust_position(xfInfo* xfi, rdpWindow *window)
// If current window position disagrees with RDP window position, send
// update to RDP server
if ( xfw->left != window->windowOffsetX ||
xfw->top != window->windowOffsetY ||
if ( xfw->left != window->visibleOffsetX ||
xfw->top != window->visibleOffsetY ||
xfw->width != window->windowWidth ||
xfw->height != window->windowHeight)
{
//Although the rail server can give negative window coordinates when updating windowOffsetX and windowOffsetY,
//we can only send unsigned integers to the rail server. Therefore, we always bring negative coordinates up to 0 when
//attempting to adjust the rail window.
uint32 offsetX = 0;
uint32 offsetY = 0;
if (window->windowOffsetX < 0)
offsetX = offsetX - window->windowOffsetX;
if (window->windowOffsetY < 0)
offsetY = offsetY - window->windowOffsetY;
//windowOffset corresponds to the window location on the rail server
//but our local window is based on the visibleOffset since using the windowOffset
//can result in blank areas for a maximized window
window_move.windowId = window->windowId;
window_move.left = xfw->left;
window_move.top = xfw->top;
window_move.right = xfw->right;
window_move.bottom = xfw->bottom;
//Calculate new offsets for the rail server window
//Negative offset correction + rail server window offset + (difference in visibleOffset and new window local offset)
window_move.left = offsetX + window->windowOffsetX + (xfw->left - window->visibleOffsetX);
window_move.top = offsetY + window->windowOffsetY + (xfw->top - window->visibleOffsetY);
window_move.right = window_move.left + xfw->width;
window_move.bottom = window_move.top + xfw->height;
DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%u h=%u"
" RDP=0x%X rc={l=%d t=%d} w=%d h=%d",
(uint32) xfw->handle, xfw->left, xfw->top,
xfw->right, xfw->bottom, xfw->width, xfw->height,
(uint32) xfw->handle, window_move.left, window_move.top,
window_move.right, window_move.bottom, xfw->width, xfw->height,
window->windowId,
window->windowOffsetX, window->windowOffsetY,
window->windowWidth, window->windowHeight);
@ -319,14 +376,31 @@ void xf_rail_end_local_move(xfInfo* xfi, rdpWindow *window)
xfw->left, xfw->top, xfw->right, xfw->bottom,
xfw->width, xfw->height);
//Although the rail server can give negative window coordinates when updating windowOffsetX and windowOffsetY,
//we can only send unsigned integers to the rail server. Therefore, we always bring negative coordinates up to 0 when
//attempting to adjust the rail window.
uint32 offsetX = 0;
uint32 offsetY = 0;
if (window->windowOffsetX < 0)
offsetX = offsetX - window->windowOffsetX;
if (window->windowOffsetY < 0)
offsetY = offsetY - window->windowOffsetY;
/*
* For keyboard moves send and explicit update to RDP server
*/
window_move.windowId = window->windowId;
window_move.left = xfw->left;
window_move.top = xfw->top;
window_move.right = xfw->right + 1; // The update to RDP the position is one past the window
window_move.bottom = xfw->bottom + 1;
//Calculate new offsets for the rail server window
//Negative offset correction + rail server window offset + (difference in visibleOffset and new window local offset)
window_move.left = offsetX + window->windowOffsetX + (xfw->left - window->visibleOffsetX);
window_move.top = offsetY + window->windowOffsetY + (xfw->top - window->visibleOffsetY);
window_move.right = window_move.left + xfw->width; // In the update to RDP the position is one past the window
window_move.bottom = window_move.top + xfw->height;
xf_send_rail_client_event(channels,
RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &window_move);
@ -340,12 +414,20 @@ void xf_rail_end_local_move(xfInfo* xfi, rdpWindow *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 ((xfw->local_move.direction != _NET_WM_MOVERESIZE_MOVE_KEYBOARD) &&
(xfw->local_move.direction != _NET_WM_MOVERESIZE_SIZE_KEYBOARD))
{
input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y);
DEBUG_X11_LMS("Mouse coordinates. x= %i, y= %i", x, y);
}
// Proactively update the RAIL window dimensions. There is a race condition where
// 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.
window->windowOffsetX = xfw->left;
window->windowOffsetY = xfw->top;
window->windowOffsetX = offsetX + window->windowOffsetX + (xfw->left - window->visibleOffsetX);
window->windowOffsetY = offsetY + window->windowOffsetY + (xfw->top - window->visibleOffsetY);
window->windowWidth = xfw->width;
window->windowHeight = xfw->height;

View File

@ -237,7 +237,7 @@ void xf_SetWindowStyle(xfInfo* xfi, xfWindow* window, uint32 style, uint32 ex_st
{
Atom window_type;
if ((ex_style & WS_EX_TOPMOST) || (ex_style & WS_EX_TOOLWINDOW))
if (/*(ex_style & WS_EX_TOPMOST) ||*/ (ex_style & WS_EX_TOOLWINDOW))
{
/*
* Tooltips and menu items should be unmanaged windows
@ -256,6 +256,12 @@ void xf_SetWindowStyle(xfInfo* xfi, xfWindow* window, uint32 style, uint32 ex_st
xf_SetWindowUnlisted(xfi, window);
window_type = xfi->_NET_WM_WINDOW_TYPE_POPUP;
}
//TOPMOST window that is not a toolwindow is treated like a regular window(ie. task manager).
//Want to do this here, since the window may have type WS_POPUP
else if (ex_style & WS_EX_TOPMOST)
{
window_type = xfi->_NET_WM_WINDOW_TYPE_NORMAL;
}
else if (style & WS_POPUP)
{
/* this includes dialogs, popups, etc, that need to be full-fledged windows */
@ -312,7 +318,7 @@ xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height,
window->is_transient = false;
window->handle = XCreateWindow(xfi->display, RootWindowOfScreen(xfi->screen),
xfi->workArea.x, xfi->workArea.y, xfi->width, xfi->height, 0, xfi->depth, InputOutput, xfi->visual,
xfi->workArea.x, xfi->workArea.y, xfi->workArea.width, xfi->workArea.height, 0, xfi->depth, InputOutput, xfi->visual,
CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
CWBorderPixel | CWWinGravity | CWBitGravity, &xfi->attribs);
@ -374,6 +380,13 @@ xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height,
XMaskEvent(xfi->display, VisibilityChangeMask, &xevent);
}
while (xevent.type != VisibilityNotify);
//The XCreateWindow call will start the window in the upper-left corner of our current
//monitor instead of the upper-left monitor for remote app mode(which uses all monitors).
//This extra call after the window is mapped will position the login window correctly
if (xfi->instance->settings->remote_app)
XMoveWindow(xfi->display, window->handle, 0, 0);
}
xf_SetWindowText(xfi, window, name);
@ -462,6 +475,8 @@ xfWindow* xf_CreateWindow(xfInfo* xfi, rdpWindow* wnd, int x, int y, int width,
window->local_move.state = LMS_NOT_ACTIVE;
window->is_mapped = false;
window->is_transient = false;
window->rail_state = 0;
window->rail_ignore_configure = false;
window->handle = XCreateWindow(xfi->display, RootWindowOfScreen(xfi->screen),
x, y, window->width, window->height, 0, xfi->depth, InputOutput, xfi->visual,
@ -489,6 +504,14 @@ xfWindow* xf_CreateWindow(xfInfo* xfi, rdpWindow* wnd, int x, int y, int width,
xfree(class);
}
//Set the input mode hint for the WM
XWMHints *InputModeHint = XAllocWMHints();
InputModeHint->flags = (1L << 0);
InputModeHint->input = True;
XSetWMHints(xfi->display, window->handle, InputModeHint);
XFree(InputModeHint);
XSetWMProtocols(xfi->display, window->handle, &(xfi->WM_DELETE_WINDOW), 1);
input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
@ -561,6 +584,7 @@ void xf_StartLocalMoveSize(xfInfo* xfi, xfWindow* window, int direction, int x,
window->local_move.root_x = x;
window->local_move.root_y = y;
window->local_move.state = LMS_STARTING;
window->local_move.direction = direction;
XUngrabPointer(xfi->display, CurrentTime);
@ -661,11 +685,37 @@ void xf_ShowWindow(xfInfo* xfi, xfWindow* window, uint8 state)
break;
case WINDOW_SHOW_MAXIMIZED:
XRaiseWindow(xfi->display, window->handle);
//Set the window as maximized
xf_SendClientEvent(xfi, window, xfi->_NET_WM_STATE, 4,
1,
XInternAtom(xfi->display, "_NET_WM_STATE_MAXIMIZED_VERT", False),
XInternAtom(xfi->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False),
0);
//This is a workaround for the case where the window is maximized locally before the rail server is told to maximize
//the window, this appears to be a race condition where the local window with incomplete data and once the window is
//actually maximized on the server - an update of the new areas may not happen. So, we simply to do a full update of
//the entire window once the rail server notifies us that the window is now maximized.
if (window->rail_state == WINDOW_SHOW_MAXIMIZED)
xf_UpdateWindowArea(xfi, window, 0, 0, window->window->windowWidth, window->window->windowHeight);
break;
case WINDOW_SHOW:
XMapWindow(xfi->display, window->handle);
//Ensure the window is not maximized
xf_SendClientEvent(xfi, window, xfi->_NET_WM_STATE, 4,
0,
XInternAtom(xfi->display, "_NET_WM_STATE_MAXIMIZED_VERT", False),
XInternAtom(xfi->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False),
0);
//Ignore configure requests until both the Maximized properties have been processed
//to prevent condition where WM overrides size of request due to one or both of these properties
//still being set - which causes a position adjustment to be sent back to the server
//thus causing the window to not return to its original size
if (window->rail_state == WINDOW_SHOW_MAXIMIZED)
window->rail_ignore_configure = true;
if (window->is_transient)
{
xf_SetWindowUnlisted(xfi, window);
@ -673,6 +723,9 @@ void xf_ShowWindow(xfInfo* xfi, xfWindow* window, uint8 state)
break;
}
//Save off the current rail state of this window
window->rail_state = state;
XFlush(xfi->display);
}
@ -730,7 +783,8 @@ void xf_SetWindowRects(xfInfo* xfi, xfWindow* window, RECTANGLE_16* rects, int n
}
#ifdef WITH_XEXT
XShapeCombineRectangles(xfi->display, window->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0);
//This is currently unsupported with the new logic to handle window placement with VisibleOffset variables
//XShapeCombineRectangles(xfi->display, window->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0);
#endif
xfree(xrects);
@ -755,7 +809,8 @@ void xf_SetWindowVisibilityRects(xfInfo* xfi, xfWindow* window, RECTANGLE_16* re
}
#ifdef WITH_XEXT
XShapeCombineRectangles(xfi->display, window->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0);
//This is currently unsupported with the new logic to handle window placement with VisibleOffset variables
//XShapeCombineRectangles(xfi->display, window->handle, ShapeBounding, 0, 0, xrects, nrects, ShapeSet, 0);
#endif
xfree(xrects);
@ -767,6 +822,9 @@ void xf_UpdateWindowArea(xfInfo* xfi, xfWindow* window, int x, int y, int width,
rdpWindow* wnd;
wnd = window->window;
//Remote app mode uses visibleOffset instead of windowOffset
if (!xfi->remote_app)
{
ax = x + wnd->windowOffsetX;
ay = y + wnd->windowOffsetY;
@ -775,6 +833,18 @@ void xf_UpdateWindowArea(xfInfo* xfi, xfWindow* window, int x, int y, int width,
if (ay + height > wnd->windowOffsetY + wnd->windowHeight)
height = (wnd->windowOffsetY + wnd->windowHeight - 1) - ay;
}
else
{
ax = x + wnd->visibleOffsetX;
ay = y + wnd->visibleOffsetY;
if (ax + width > wnd->visibleOffsetX + wnd->windowWidth)
width = (wnd->visibleOffsetX + wnd->windowWidth - 1) - ax;
if (ay + height > wnd->visibleOffsetY + wnd->windowHeight)
height = (wnd->visibleOffsetY + wnd->windowHeight - 1) - ay;
}
if (xfi->sw_gdi)
{

View File

@ -58,6 +58,7 @@ struct xf_localmove
int window_x; // relative to window
int window_y;
enum xf_localmove_state state;
int direction;
};
struct xf_window
@ -76,6 +77,8 @@ struct xf_window
boolean is_mapped;
boolean is_transient;
xfLocalMove local_move;
uint8 rail_state;
boolean rail_ignore_configure;
};
void xf_ewmhints_init(xfInfo* xfi);

View File

@ -299,8 +299,8 @@ void xf_create_window(xfInfo* xfi)
xfi->attribs.backing_store = xfi->primary ? NotUseful : Always;
xfi->attribs.override_redirect = xfi->fullscreen;
xfi->attribs.colormap = xfi->colormap;
xfi->attribs.bit_gravity = ForgetGravity;
xfi->attribs.win_gravity = StaticGravity;
xfi->attribs.bit_gravity = NorthWestGravity;
xfi->attribs.win_gravity = NorthWestGravity;
if (xfi->instance->settings->window_title != NULL)
{
@ -583,6 +583,7 @@ boolean xf_pre_connect(freerdp* instance)
xfi->WM_PROTOCOLS = XInternAtom(xfi->display, "WM_PROTOCOLS", False);
xfi->WM_DELETE_WINDOW = XInternAtom(xfi->display, "WM_DELETE_WINDOW", False);
xfi->WM_STATE = XInternAtom(xfi->display, "WM_STATE", False);
xf_kbd_init(xfi);

View File

@ -160,6 +160,7 @@ struct xf_info
Atom _NET_WM_MOVERESIZE;
Atom _NET_MOVERESIZE_WINDOW;
Atom WM_STATE;
Atom WM_PROTOCOLS;
Atom WM_DELETE_WINDOW;
};

View File

@ -40,6 +40,7 @@ typedef void (*railSetWindowText)(rdpRail* rail, rdpWindow* window);
typedef void (*railSetWindowIcon)(rdpRail* rail, rdpWindow* window, rdpIcon* icon);
typedef void (*railSetWindowRects)(rdpRail* rail, rdpWindow* window);
typedef void (*railSetWindowVisibilityRects)(rdpRail* rail, rdpWindow* window);
typedef void (*railDesktopNonMonitored) (rdpRail* rail, rdpWindow* window);
struct rdp_rail
{
@ -57,6 +58,7 @@ struct rdp_rail
railSetWindowIcon rail_SetWindowIcon;
railSetWindowRects rail_SetWindowRects;
railSetWindowVisibilityRects rail_SetWindowVisibilityRects;
railDesktopNonMonitored rail_DesktopNonMonitored;
};
FREERDP_API void rail_register_update_callbacks(rdpRail* rail, rdpUpdate* update);

View File

@ -48,6 +48,7 @@ FREERDP_API rdpWindow* window_list_get_by_extra_id(rdpWindowList* list, void* ex
FREERDP_API void window_list_create(rdpWindowList* list, WINDOW_ORDER_INFO* orderInfo, WINDOW_STATE_ORDER* window_state);
FREERDP_API void window_list_update(rdpWindowList* list, WINDOW_ORDER_INFO* orderInfo, WINDOW_STATE_ORDER* window_state);
FREERDP_API void window_list_delete(rdpWindowList* list, WINDOW_ORDER_INFO* orderInfo);
FREERDP_API void window_list_clear(rdpWindowList* list);
FREERDP_API rdpWindowList* window_list_new(rdpRail* rail);
FREERDP_API void window_list_free(rdpWindowList* list);

View File

@ -99,11 +99,24 @@ static void rail_MonitoredDesktop(rdpContext* context, WINDOW_ORDER_INFO* orderI
}
//This is used to switch FreeRDP back to showing the full desktop under remote app mode
//to handle cases where the screen is locked, etc. The rail server informs us that it is
//no longer monitoring the desktop. Once the desktop becomes monitored again. The full desktop
//window will be automatically destroyed and we will switch back into remote app mode.
static void rail_NonMonitoredDesktop(rdpContext* context, WINDOW_ORDER_INFO* orderInfo)
{
rdpWindow* window;
rdpRail* rail = context->rail;
window = window_list_get_by_id(rail->list, orderInfo->windowId);
IFCALL(rail->rail_DesktopNonMonitored, rail, window);
window_list_clear(rail->list);
}
void rail_register_update_callbacks(rdpRail* rail, rdpUpdate* update)
{
rdpWindowUpdate* window = update->window;

View File

@ -97,6 +97,16 @@ void window_list_create(rdpWindowList* list, WINDOW_ORDER_INFO* orderInfo, WINDO
{
rdpWindow* window;
//See if the window already exists
window = window_list_get_by_id(list, orderInfo->windowId);
//If the window already exists, just update the existing window
if (window != NULL)
{
window_list_update(list, orderInfo, window_state);
return;
}
window = (rdpWindow*) xzalloc(sizeof(rdpWindow));
if (window == NULL)
@ -175,6 +185,22 @@ void window_list_delete(rdpWindowList* list, WINDOW_ORDER_INFO* orderInfo)
rail_DestroyWindow(list->rail, window);
}
void window_list_clear(rdpWindowList* list)
{
rdpWindow* current = list->head;
rdpWindow* next;
while (current != NULL)
{
list->head = current->next;
rail_DestroyWindow(list->rail, current);
current = list->head;
}
list->tail = NULL;
}
rdpWindowList* window_list_new(rdpRail* rail)
{
rdpWindowList* list;