diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index bb57fc056..c89ac4bfa 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -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); - + { + 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;idisplay, "_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; diff --git a/client/X11/xf_monitor.c b/client/X11/xf_monitor.c index eedf715a3..8fdfcf3cb 100644 --- a/client/X11/xf_monitor.c +++ b/client/X11/xf_monitor.c @@ -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; diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index d4408a5f9..9546803ff 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -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); @@ -339,13 +413,21 @@ void xf_rail_end_local_move(xfInfo* xfi, rdpWindow *window) &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 ((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; diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index 1e055280b..9b05ee315 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -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,15 +822,30 @@ void xf_UpdateWindowArea(xfInfo* xfi, xfWindow* window, int x, int y, int width, rdpWindow* wnd; wnd = window->window; - ax = x + wnd->windowOffsetX; - ay = y + wnd->windowOffsetY; + //Remote app mode uses visibleOffset instead of windowOffset + if (!xfi->remote_app) + { + ax = x + wnd->windowOffsetX; + ay = y + wnd->windowOffsetY; - if (ax + width > wnd->windowOffsetX + wnd->windowWidth) - width = (wnd->windowOffsetX + wnd->windowWidth - 1) - ax; + if (ax + width > wnd->windowOffsetX + wnd->windowWidth) + width = (wnd->windowOffsetX + wnd->windowWidth - 1) - ax; - if (ay + height > wnd->windowOffsetY + wnd->windowHeight) - height = (wnd->windowOffsetY + wnd->windowHeight - 1) - ay; + 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) { XPutImage(xfi->display, xfi->primary, window->gc, xfi->image, diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h index 760838c7a..82b8ddb1c 100644 --- a/client/X11/xf_window.h +++ b/client/X11/xf_window.h @@ -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); diff --git a/client/X11/xfreerdp.c b/client/X11/xfreerdp.c index a0e69eb84..8ea76c3e3 100644 --- a/client/X11/xfreerdp.c +++ b/client/X11/xfreerdp.c @@ -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); diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 82fcec3dc..46fb1c8fb 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -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; }; diff --git a/include/freerdp/rail/rail.h b/include/freerdp/rail/rail.h index a5b4f5412..ce0686ffb 100644 --- a/include/freerdp/rail/rail.h +++ b/include/freerdp/rail/rail.h @@ -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); diff --git a/include/freerdp/rail/window_list.h b/include/freerdp/rail/window_list.h index 82914a497..57da47c11 100644 --- a/include/freerdp/rail/window_list.h +++ b/include/freerdp/rail/window_list.h @@ -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); diff --git a/libfreerdp-rail/rail.c b/libfreerdp-rail/rail.c index 89decc0c8..0423b9087 100644 --- a/libfreerdp-rail/rail.c +++ b/libfreerdp-rail/rail.c @@ -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; diff --git a/libfreerdp-rail/window_list.c b/libfreerdp-rail/window_list.c index 340801170..e8bc190a9 100644 --- a/libfreerdp-rail/window_list.c +++ b/libfreerdp-rail/window_list.c @@ -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;