Make popups transient, use local window manager for moves.
authorNot Nyguen Doze <sunds@ubuntu.(none)>
Fri, 2 Dec 2011 22:51:30 +0000 (14:51 -0800)
committerNot Nyguen Doze <sunds@ubuntu.(none)>
Tue, 6 Dec 2011 23:43:38 +0000 (15:43 -0800)
This fixes a number if issues on Ubuntu in particular.

client/X11/xf_event.c
client/X11/xf_rail.c
client/X11/xf_rail.h
client/X11/xf_window.c
client/X11/xf_window.h
client/X11/xfreerdp.c
client/X11/xfreerdp.h

index ddf11f3..73516d4 100644 (file)
@@ -24,6 +24,7 @@
 #include <freerdp/kbd/vkcodes.h>
 
 #include "xf_rail.h"
+#include "xf_window.h"
 #include "xf_cliprdr.h"
 
 #include "xf_event.h"
@@ -340,7 +341,7 @@ boolean xf_event_FocusIn(xfInfo* xfi, XEvent* event, boolean app)
        xf_rail_send_activate(xfi, event->xany.window, true);
        xf_kbd_focus_in(xfi);
 
-       if (xfi->remote_app != true)
+       if (app != true)
                xf_cliprdr_check_owner(xfi);
 
        return true;
@@ -462,7 +463,7 @@ boolean xf_event_ConfigureNotify(xfInfo* xfi, XEvent* event, boolean app)
                 xfw->bottom = xfw->top + xfw->height - 1;
 
                if (app)
-                       xf_rail_local_movesize(xfi, xfw);
+                       xf_rail_adjust_position(xfi, window);
 
         }
 
@@ -484,7 +485,7 @@ boolean xf_event_MapNotify(xfInfo* xfi, XEvent* event, boolean app)
                /* local restore event */
                xf_rail_send_client_system_command(xfi, window->windowId, SC_RESTORE);
                xfWindow *xfw = (xfWindow*) window->extra;
-               xfw->isMapped = true;
+               xfw->is_mapped = true;
        }
 
        return true;
@@ -503,7 +504,7 @@ boolean xf_event_UnmapNotify(xfInfo* xfi, XEvent* event, boolean app)
        if (window != NULL)
        {
                xfWindow *xfw = (xfWindow*) window->extra;
-               xfw->isMapped = false;
+               xfw->is_mapped = false;
        }
 
        return true;
@@ -511,7 +512,7 @@ boolean xf_event_UnmapNotify(xfInfo* xfi, XEvent* event, boolean app)
 
 boolean xf_event_SelectionNotify(xfInfo* xfi, XEvent* event, boolean app)
 {
-       if (xfi->remote_app != true)
+       if (app != true)
        {
                if (xf_cliprdr_process_selection_notify(xfi, event))
                        return true;
@@ -522,7 +523,7 @@ boolean xf_event_SelectionNotify(xfInfo* xfi, XEvent* event, boolean app)
 
 boolean xf_event_SelectionRequest(xfInfo* xfi, XEvent* event, boolean app)
 {
-       if (xfi->remote_app != true)
+       if (app != true)
        {
                if (xf_cliprdr_process_selection_request(xfi, event))
                        return true;
@@ -533,7 +534,7 @@ boolean xf_event_SelectionRequest(xfInfo* xfi, XEvent* event, boolean app)
 
 boolean xf_event_SelectionClear(xfInfo* xfi, XEvent* event, boolean app)
 {
-       if (xfi->remote_app != true)
+       if (app != true)
        {
                if (xf_cliprdr_process_selection_clear(xfi, event))
                        return true;
@@ -544,7 +545,7 @@ boolean xf_event_SelectionClear(xfInfo* xfi, XEvent* event, boolean app)
 
 boolean xf_event_PropertyNotify(xfInfo* xfi, XEvent* event, boolean app)
 {
-       if (xfi->remote_app != true)
+       if (app != true)
        {
                if (xf_cliprdr_process_property_notify(xfi, event))
                        return true;
@@ -555,20 +556,71 @@ boolean xf_event_PropertyNotify(xfInfo* xfi, XEvent* event, boolean app)
 
 boolean xf_event_process(freerdp* instance, XEvent* event)
 {
-       boolean app = false;
        boolean status = true;
        xfInfo* xfi = ((xfContext*) instance->context)->xfi;
 
-       if (xfi->remote_app == true)
-       {
-               app = true;
-       }
-       else
+       if (xfi->window && xfi->window->local_move.state == LMS_ACTIVE)
        {
-               if (event->xany.window != xfi->window->handle)
-                       app = true;
-       }
+               xfWindow* xfw;
+               rdpWindow* window;
+               rdpRail* rail = ((rdpContext*) xfi->context)->rail;
+               window = window_list_get_by_extra_id(rail->list, (void*) event->xexpose.window);
+               if (window != NULL)
+               {
+                       xfw = (xfWindow*) window->extra;
+                       xfi->window = xfw;
+                       switch (event->type)
+                       {
+                               case ButtonPress:
+                               case ButtonRelease:
+                               case KeyPress:
+                               case KeyRelease:
+                               case UnmapNotify:
+                               {
+                                       // A button release event means the X window server did not grab the
+                                       // mouse before the user released it.  In this case we must cancel
+                                       // the local move. The event will be processed below as normal, below.
+                                       xf_EndLocalMoveSize(xfi, xfw, true);
+                               }
+                                break;
+
+                               case FocusIn:
+                               case FocusOut:
+                               {
+                                       XFocusChangeEvent *focusEvent = (XFocusChangeEvent *)event;
+                                       if (focusEvent->mode == NotifyUngrab)
+                                               xf_rail_end_local_move(xfi, window);
+                                       else
+                                               return true;
+                               }
+                               break;
 
+                               case EnterNotify:
+                               case LeaveNotify:
+                               {
+                                       XCrossingEvent *crossingEvent = (XCrossingEvent *)event;
+                                       if(crossingEvent->mode == NotifyUngrab)
+                                               xf_rail_end_local_move(xfi, window);
+                                       else
+                                               return true;
+                               }
+                               break;
+
+                               case VisibilityNotify:
+                               case ConfigureNotify:
+                               case Expose:
+                               case PropertyNotify:
+                                       // Allow these events to be processed during move to keep
+                                       // our state up to date.
+                                       break;
+                               default:
+                                       // Any other event should signify the root no longer
+                                       // has the grap, so the move has finished.
+                                       xf_rail_end_local_move(xfi, window);
+                       }
+
+               }
+       }
 
        if (event->type != MotionNotify)
                DEBUG_X11("%s Event: wnd=0x%04X", X11_EVENT_STRINGS[event->type], (uint32) event->xany.window);
@@ -576,47 +628,47 @@ boolean xf_event_process(freerdp* instance, XEvent* event)
        switch (event->type)
        {
                case Expose:
-                       status = xf_event_Expose(xfi, event, app);
+                       status = xf_event_Expose(xfi, event, xfi->remote_app);
                        break;
 
                case VisibilityNotify:
-                       status = xf_event_VisibilityNotify(xfi, event, app);
+                       status = xf_event_VisibilityNotify(xfi, event, xfi->remote_app);
                        break;
 
                case MotionNotify:
-                       status = xf_event_MotionNotify(xfi, event, app);
+                       status = xf_event_MotionNotify(xfi, event, xfi->remote_app);
                        break;
 
                case ButtonPress:
-                       status = xf_event_ButtonPress(xfi, event, app);
+                       status = xf_event_ButtonPress(xfi, event, xfi->remote_app);
                        break;
 
                case ButtonRelease:
-                       status = xf_event_ButtonRelease(xfi, event, app);
+                       status = xf_event_ButtonRelease(xfi, event, xfi->remote_app);
                        break;
 
                case KeyPress:
-                       status = xf_event_KeyPress(xfi, event, app);
+                       status = xf_event_KeyPress(xfi, event, xfi->remote_app);
                        break;
 
                case KeyRelease:
-                       status = xf_event_KeyRelease(xfi, event, app);
+                       status = xf_event_KeyRelease(xfi, event, xfi->remote_app);
                        break;
 
                case FocusIn:
-                       status = xf_event_FocusIn(xfi, event, app);
+                       status = xf_event_FocusIn(xfi, event, xfi->remote_app);
                        break;
 
                case FocusOut:
-                       status = xf_event_FocusOut(xfi, event, app);
+                       status = xf_event_FocusOut(xfi, event, xfi->remote_app);
                        break;
 
                case EnterNotify:
-                       status = xf_event_EnterNotify(xfi, event, app);
+                       status = xf_event_EnterNotify(xfi, event, xfi->remote_app);
                        break;
 
                case LeaveNotify:
-                       status = xf_event_LeaveNotify(xfi, event, app);
+                       status = xf_event_LeaveNotify(xfi, event, xfi->remote_app);
                        break;
 
                case NoExpose:
@@ -626,42 +678,42 @@ boolean xf_event_process(freerdp* instance, XEvent* event)
                        break;
 
                case ConfigureNotify:
-                       status = xf_event_ConfigureNotify(xfi, event, app);
+                       status = xf_event_ConfigureNotify(xfi, event, xfi->remote_app);
                        break;
 
                case MapNotify:
-                       status = xf_event_MapNotify(xfi, event, app);
+                       status = xf_event_MapNotify(xfi, event, xfi->remote_app);
                        break;
 
                case UnmapNotify:
-                       status = xf_event_UnmapNotify(xfi, event, app);
+                       status = xf_event_UnmapNotify(xfi, event, xfi->remote_app);
                        break;
 
                case ReparentNotify:
                        break;
 
                case MappingNotify:
-                       status = xf_event_MappingNotify(xfi, event, app);
+                       status = xf_event_MappingNotify(xfi, event, xfi->remote_app);
                        break;
 
                case ClientMessage:
-                       status = xf_event_ClientMessage(xfi, event, app);
+                       status = xf_event_ClientMessage(xfi, event, xfi->remote_app);
                        break;
 
                case SelectionNotify:
-                       status = xf_event_SelectionNotify(xfi, event, app);
+                       status = xf_event_SelectionNotify(xfi, event, xfi->remote_app);
                        break;
 
                case SelectionRequest:
-                       status = xf_event_SelectionRequest(xfi, event, app);
+                       status = xf_event_SelectionRequest(xfi, event, xfi->remote_app);
                        break;
 
                case SelectionClear:
-                       status = xf_event_SelectionClear(xfi, event, app);
+                       status = xf_event_SelectionClear(xfi, event, xfi->remote_app);
                        break;
 
                case PropertyNotify:
-                       status = xf_event_PropertyNotify(xfi, event, app);
+                       status = xf_event_PropertyNotify(xfi, event, xfi->remote_app);
                        break;
 
                default:
index 7820b10..dc43229 100644 (file)
@@ -108,39 +108,6 @@ void xf_rail_MoveWindow(rdpRail* rail, rdpWindow* window)
                        window->windowWidth, window->windowHeight);
 }
 
-/**
- * The position of the X window can become out of sync with the RDP window
- * if the X window is moved locally by the window manager.  In this event
- * send an update to the RDP server informing it of the new window position
- * and size.
- */
-void xf_rail_local_movesize(xfInfo* xfi, xfWindow* window)
-{
-       rdpWindow* wnd = window->window;
-
-       if (window->isMapped)
-       {
-               // If current window position disagrees with RDP window position, send
-               // update to RDP server
-               if ( window->left != wnd->windowOffsetX ||
-                       window->top != wnd->windowOffsetY ||
-                        window->width != wnd->windowWidth ||
-                        window->height != wnd->windowHeight)
-                {
-                       xf_rail_send_windowmove(xfi, wnd->windowId,
-                               window->left, window->top, window->right+1, window->bottom+1);
-                }
-
-               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) window->handle, window->left, window->top, 
-                       window->right, window->bottom, window->width, window->height,
-                       wnd->windowId,
-                       wnd->windowOffsetX, wnd->windowOffsetY, 
-                       wnd->windowWidth, wnd->windowHeight);
-       }
-}
-
 void xf_rail_ShowWindow(rdpRail* rail, rdpWindow* window, uint8 state)
 {
        xfInfo* xfi;
@@ -241,22 +208,6 @@ static void xf_send_rail_client_event(rdpChannels* channels, uint16 event_type,
        }
 }
 
-void xf_rail_send_windowmove(xfInfo* xfi, uint32 windowId, uint32 left, uint32 top, uint32 right, uint32 bottom)
-{
-       rdpChannels* channels;
-       RAIL_WINDOW_MOVE_ORDER window_move;
-
-       channels = xfi->_context->channels;
-
-       window_move.windowId = windowId;
-       window_move.left = left;
-       window_move.top = top;
-       window_move.right = right;
-       window_move.bottom = bottom;
-
-       xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &window_move);
-}
-
 void xf_rail_send_activate(xfInfo* xfi, Window xwindow, boolean enabled)
 {
        rdpRail* rail;
@@ -291,6 +242,84 @@ void xf_rail_send_client_system_command(xfInfo* xfi, uint32 windowId, uint16 com
        xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_SYSCOMMAND, &syscommand);
 }
 
+/**
+ * The position of the X window can become out of sync with the RDP window
+ * if the X window is moved locally by the window manager.  In this event
+ * send an update to the RDP server informing it of the new window position
+ * and size.
+ */
+void xf_rail_adjust_position(xfInfo* xfi, rdpWindow *window)
+{
+       xfWindow* xfw;
+       rdpChannels* channels;
+       RAIL_WINDOW_MOVE_ORDER window_move;
+
+       xfw = (xfWindow*) window->extra;
+       channels = xfi->_context->channels;
+
+       if (! xfw->is_mapped || xfw->local_move.state != LMS_NOT_ACTIVE)
+               return;
+
+       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 lms_state=%d mapped=%d",
+               (uint32) xfw->handle, xfw->left, xfw->top, 
+               xfw->right, xfw->bottom, xfw->width, xfw->height,
+               window->windowId,
+               window->windowOffsetX, window->windowOffsetY, 
+               window->windowWidth, window->windowHeight,
+               xfw->local_move.state, xfw->is_mapped);
+
+       // If current window position disagrees with RDP window position, send
+       // update to RDP server
+       if ( xfw->left != window->windowOffsetX ||
+               xfw->top != window->windowOffsetY ||
+                xfw->width != window->windowWidth ||
+                xfw->height != window->windowHeight)
+        {
+               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;
+
+               xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &window_move);
+        }
+}
+
+void xf_rail_end_local_move(xfInfo* xfi, rdpWindow *window)
+{
+       xfWindow* xfw;
+       rdpChannels* channels;
+       RAIL_WINDOW_MOVE_ORDER window_move;
+       int x,y;
+       rdpInput* input = xfi->instance->input;
+
+       xfw = (xfWindow*) window->extra;
+       channels = xfi->_context->channels;
+
+       // Send RDP client event to inform RDP server
+
+       window_move.windowId = window->windowId;
+       window_move.left = xfw->left;
+       window_move.top = xfw->top;
+       window_move.right = xfw->right + 1;   // In the update to RDP the position is one past the window
+       window_move.bottom = xfw->bottom + 1;
+
+       DEBUG_X11_LMS("ClientWindowMove: window=0x%X rc={l=%d t=%d r=%d b=%d}",
+               (uint32) xfw->handle, xfw->left, xfw->top, xfw->right, xfw->bottom);
+
+       xf_send_rail_client_event(channels, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, &window_move);
+
+       // Send synthetic button up event to the RDP server.  This is per the RDP spec to
+       // indicate a local move has finished.
+
+       x = xfw->left + xfw->local_move.window_x;
+       y = xfw->top + xfw->local_move.window_y;
+        input->MouseEvent(input, PTR_FLAGS_BUTTON1, x, y);
+
+       xfw->local_move.state = LMS_TERMINATING;
+}
+
 void xf_process_rail_get_sysparams_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)
 {
        RAIL_SYSPARAM_ORDER* sysparam;
@@ -398,14 +427,16 @@ void xf_process_rail_server_localmovesize_event(xfInfo* xfi, rdpChannels* channe
        rdpWindow* rail_window = NULL;
        RAIL_LOCALMOVESIZE_ORDER* movesize = (RAIL_LOCALMOVESIZE_ORDER*) event->user_data;
        int direction = 0;
+       Window child_window;
+       int x,y;
 
        rail = ((rdpContext*) xfi->context)->rail;
        rail_window = window_list_get_by_id(rail->list, movesize->windowId);
 
        if (rail_window != NULL)
        {
-               xfWindow* window = NULL;
-               window = (xfWindow*) rail_window->extra;
+               xfWindow* xfw = NULL;
+               xfw = (xfWindow*) rail_window->extra;
 
                DEBUG_X11_LMS("windowId=0x%X isMoveSizeStart=%d moveSizeType=%s PosX=%d PosY=%d",
                        movesize->windowId, movesize->isMoveSizeStart,
@@ -415,44 +446,68 @@ void xf_process_rail_server_localmovesize_event(xfInfo* xfi, rdpChannels* channe
                {
                        case RAIL_WMSZ_LEFT: //0x1
                                direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
+                               x = movesize->posX;
+                               y = movesize->posY;
                                break;
                        case RAIL_WMSZ_RIGHT: //0x2
                                direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
+                               x = movesize->posX;
+                               y = movesize->posY;
                                break;
                        case RAIL_WMSZ_TOP: //0x3
                                direction = _NET_WM_MOVERESIZE_SIZE_TOP;
+                               x = movesize->posX;
+                               y = movesize->posY;
                                break;
                        case RAIL_WMSZ_TOPLEFT: //0x4
                                direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
+                               x = movesize->posX;
+                               y = movesize->posY;
                                break;
                        case RAIL_WMSZ_TOPRIGHT: //0x5
                                direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
+                               x = movesize->posX;
+                               y = movesize->posY;
                                break;
                        case RAIL_WMSZ_BOTTOM: //0x6
                                direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
+                               x = movesize->posX;
+                               y = movesize->posY;
                                break;
                        case RAIL_WMSZ_BOTTOMLEFT: //0x7
                                direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
+                               x = movesize->posX;
+                               y = movesize->posY;
                                break;
                        case RAIL_WMSZ_BOTTOMRIGHT: //0x8
                                direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
+                               x = movesize->posX;
+                               y = movesize->posY;
                                break;
                        case RAIL_WMSZ_MOVE: //0x9
                                direction = _NET_WM_MOVERESIZE_MOVE;
+                               XTranslateCoordinates(xfi->display, xfw->handle, DefaultRootWindow(xfi->display), 
+                                       movesize->posX, movesize->posY, &x, &y, &child_window);
                                break;
                        case RAIL_WMSZ_KEYMOVE: //0xA
                                direction = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
+                               x = movesize->posX;
+                               y = movesize->posY;
                                break;
                        case RAIL_WMSZ_KEYSIZE: //0xB
                                direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
+                               x = movesize->posX;
+                               y = movesize->posY;
                                break;
                }
 
                if (movesize->isMoveSizeStart)
                {
-                       xf_StartLocalMoveSize(xfi, window, direction, movesize->posX, movesize->posY);
+                       xf_StartLocalMoveSize(xfi, xfw, direction, x, y);
                } else {
-                       xf_EndLocalMoveSize(xfi, window, True);
+                       xf_MoveWindow(xfi, xfw, movesize->posX, movesize->posY, 
+                               xfw->width, xfw->height);
+                       xf_EndLocalMoveSize(xfi, xfw, false);
                }
        }
 }
index efae96a..3d768bb 100644 (file)
@@ -26,8 +26,8 @@ void xf_rail_paint(xfInfo* xfi, rdpRail* rail, uint32 uleft, uint32 utop, uint32
 void xf_rail_register_callbacks(xfInfo* xfi, rdpRail* rail);
 void xf_rail_send_client_system_command(xfInfo* xfi, uint32 windowId, uint16 command);
 void xf_rail_send_activate(xfInfo* xfi, Window xwindow, boolean enabled);
-void xf_rail_send_windowmove(xfInfo* xfi, uint32 windowId, uint32 left, uint32 top, uint32 right, uint32 bottom);
 void xf_process_rail_event(xfInfo* xfi, rdpChannels* chanman, RDP_EVENT* event);
-void xf_rail_local_movesize(xfInfo* xfi, xfWindow* window);
+void xf_rail_adjust_position(xfInfo* xfi, rdpWindow *window);
+void xf_rail_end_local_move(xfInfo* xfi, rdpWindow *window);
 
 #endif /* __XF_RAIL_H */
index b4be8a3..74e130a 100644 (file)
 
 /* Extended Window Manager Hints: http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html */
 
-#define MWM_HINTS_DECORATIONS          (1L << 1)
+/* bit definitions for MwmHints.flags */
+#define MWM_HINTS_FUNCTIONS     (1L << 0)
+#define MWM_HINTS_DECORATIONS   (1L << 1)
+#define MWM_HINTS_INPUT_MODE    (1L << 2)
+#define MWM_HINTS_STATUS        (1L << 3)
+
+/* bit definitions for MwmHints.functions */
+#define MWM_FUNC_ALL            (1L << 0)
+#define MWM_FUNC_RESIZE         (1L << 1)
+#define MWM_FUNC_MOVE           (1L << 2)
+#define MWM_FUNC_MINIMIZE       (1L << 3)
+#define MWM_FUNC_MAXIMIZE       (1L << 4)
+#define MWM_FUNC_CLOSE          (1L << 5)
+
+/* bit definitions for MwmHints.decorations */
+#define MWM_DECOR_ALL           (1L << 0)
+#define MWM_DECOR_BORDER        (1L << 1)
+#define MWM_DECOR_RESIZEH       (1L << 2)
+#define MWM_DECOR_TITLE         (1L << 3)
+#define MWM_DECOR_MENU          (1L << 4)
+#define MWM_DECOR_MINIMIZE      (1L << 5)
+#define MWM_DECOR_MAXIMIZE      (1L << 6)
+
 #define PROP_MOTIF_WM_HINTS_ELEMENTS   5
 
 struct _PropMotifWmHints
@@ -75,7 +97,8 @@ void xf_SendClientEvent(xfInfo *xfi, xfWindow* window, Atom atom, unsigned int n
        }
 
        DEBUG_X11("Send ClientMessage Event: wnd=0x%04X", (unsigned int) xevent.xclient.window);
-       XSendEvent(xfi->display, window->handle, False, NoEventMask, &xevent);
+       XSendEvent(xfi->display, DefaultRootWindow(xfi->display), False, 
+               SubstructureRedirectMask | SubstructureNotifyMask, &xevent);
        XSync(xfi->display, False);
 
        va_end(argp);
@@ -181,8 +204,9 @@ void xf_SetWindowDecorations(xfInfo* xfi, xfWindow* window, boolean show)
 {
        PropMotifWmHints hints;
 
-       hints.decorations = show;
-       hints.flags = MWM_HINTS_DECORATIONS;
+       hints.decorations = (show) ? MWM_DECOR_ALL : 0;
+       hints.functions = MWM_FUNC_ALL ; 
+       hints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS;
 
        XChangeProperty(xfi->display, window->handle, xfi->_MOTIF_WM_HINTS, xfi->_MOTIF_WM_HINTS, 32,
                PropModeReplace, (uint8*) &hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
@@ -203,21 +227,27 @@ void xf_SetWindowStyle(xfInfo* xfi, xfWindow* window, uint32 style, uint32 ex_st
 {
        Atom window_type;
 
-       window_type = xfi->_NET_WM_WINDOW_TYPE_NORMAL;
-
-       if ((style & WS_POPUP) || (style & WS_DLGFRAME) || (ex_style & WS_EX_DLGMODALFRAME))
+       if (style & WS_POPUP)
        {
-               window_type = xfi->_NET_WM_WINDOW_TYPE_DIALOG;
+               // WS_POPUP includes tool tips, dropdown menus, etc.  These won't work
+               // correctly if the local window manager resizes or moves them.  Set
+               // override redirect to prevent this from occurring.
+               XSetWindowAttributes attrs;
+               attrs.override_redirect = True;
+               XChangeWindowAttributes(xfi->display, window->handle, CWOverrideRedirect, &attrs);
+               window->is_transient = true;
+
+               window_type = xfi->_NET_WM_WINDOW_TYPE_POPUP;
        }
-
-       if (ex_style & WS_EX_TOOLWINDOW)
+       else
        {
-               xf_SetWindowUnlisted(xfi, window);
-               window_type = xfi->_NET_WM_WINDOW_TYPE_UTILITY;
+               window_type = xfi->_NET_WM_WINDOW_TYPE_NORMAL;
        }
 
        XChangeProperty(xfi->display, window->handle, xfi->_NET_WM_WINDOW_TYPE,
                XA_ATOM, 32, PropModeReplace, (uint8*) &window_type, 1);
+
 }
 
 xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height, boolean decorations)
@@ -235,12 +265,14 @@ xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height,
                window->height = height;
                window->fullscreen = false;
                window->decorations = decorations;
-               window->isMapped = false;
+               window->local_move.state = LMS_NOT_ACTIVE;
+               window->is_mapped = false;
+               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,
-                       CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
-                       CWBorderPixel, &xfi->attribs);
+                       CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | 
+                       CWBorderPixel | CWWinGravity | CWBitGravity, &xfi->attribs);
 
                class_hints = XAllocClassHint();
 
@@ -345,21 +377,32 @@ xfWindow* xf_CreateWindow(xfInfo* xfi, rdpWindow* wnd, int x, int y, int width,
        window->height = height;
 
        XGCValues gcv;
-       int input_mask;
        XClassHint* class_hints;
+       int input_mask;
 
        window->decorations = false;
        window->fullscreen = false;
        window->window = wnd;
-       window->localMove.inProgress = false;
-       window->isMapped = false;
+       window->local_move.state = LMS_NOT_ACTIVE;
+       window->is_mapped = false;
+       window->is_transient = false;
+
+       // Proper behavior of tooltips, dropdown menus, etc, depend on the local window
+       // manager not modify them.  Set override_redirect on these windows.  RDP window
+       // styles don't map 1 to 1 to X window styles, but the presence of WM_POPUP 
+       // appears to be sufficient for setting override_redirect.
 
        window->handle = XCreateWindow(xfi->display, RootWindowOfScreen(xfi->screen),
                x, y, window->width, window->height, 0, xfi->depth, InputOutput, xfi->visual,
-               CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
-               CWBorderPixel, &xfi->attribs);
+               CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | 
+               CWBorderPixel | CWWinGravity | CWBitGravity, &xfi->attribs);
+
+       DEBUG_X11_LMS("Create  window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d  rdp=0x%X",
+                       (uint32) window->handle, window->left, window->top, window->right, window->bottom,
+                       window->width, window->height, wnd->windowId);
 
        xf_SetWindowDecorations(xfi, window, window->decorations);
+       xf_SetWindowStyle(xfi, window, wnd->style, wnd->extendedStyle);
 
        class_hints = XAllocClassHint();
 
@@ -377,10 +420,14 @@ xfWindow* xf_CreateWindow(xfInfo* xfi, rdpWindow* wnd, int x, int y, int width,
 
        XSetWMProtocols(xfi->display, window->handle, &(xfi->WM_DELETE_WINDOW), 1);
 
-       input_mask =
-               KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
-               VisibilityChangeMask | FocusChangeMask | StructureNotifyMask |
-               PointerMotionMask | ExposureMask | EnterWindowMask;
+       input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
+               ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | 
+               PointerMotionMask | Button1MotionMask | Button2MotionMask | 
+               Button3MotionMask | Button4MotionMask | Button5MotionMask |
+                ButtonMotionMask | KeymapStateMask | ExposureMask | 
+               VisibilityChangeMask | StructureNotifyMask | SubstructureNotifyMask | 
+               SubstructureRedirectMask | FocusChangeMask | PropertyChangeMask |
+                ColormapChangeMask | OwnerGrabButtonMask;
 
        XSelectInput(xfi->display, window->handle, input_mask);
        XMapWindow(xfi->display, window->handle);
@@ -419,32 +466,31 @@ void xf_SetWindowMinMaxInfo(xfInfo* xfi, xfWindow* window,
        }
 }
 
-void xf_StartLocalMoveSize(xfInfo* xfi, xfWindow* window, int direction, int windowRelativeX, int windowRelativeY)
+void xf_StartLocalMoveSize(xfInfo* xfi, xfWindow* window, int direction, int x, int y)
 {
-       window->localMove.windowRelativeX = windowRelativeX;
-       window->localMove.windowRelativeY = windowRelativeY;
-
-       DEBUG_X11_LMS("direction=%d coords=%d,%d window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d",
-                       direction, windowRelativeX, windowRelativeY,
-                       (uint32) window->handle, window->left, window->top, window->right, window->bottom,
-                       window->width, window->height);
-
-       // FIXME: There does not appear a way to tell when the local window manager completes
-       // a window move or resize.  The client will receive a number of ConfigureNotify events
-       // but nothing indicates when the user has completed the move gesture (keyboard or mouse).
-       // 
-       return;
-
-       // X Server _WM_MOVERESIZE coordinates are expressed relative to the root window.
-       // RDP coordinates are expressed relative to the local window.
-       // Translate these to root window coordinates.
-
-       window->localMove.inProgress = True;
-       Window childWindow;
-       int x,y;
-
-       XTranslateCoordinates(xfi->display, window->handle, DefaultRootWindow(xfi->display), 
-               windowRelativeX, windowRelativeY, &x, &y, &childWindow);
+       rdpWindow* wnd = window->window;
+       Window child_window;
+
+       DEBUG_X11_LMS("direction=%d window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d   "
+               "RDP=0x%X rc={l=%d t=%d} w=%d h=%d  mouse_x=%d mouse_y=%d",
+               direction, (uint32) window->handle, 
+               window->left, window->top, window->right, window->bottom,
+               window->width, window->height,
+               wnd->windowId,
+               wnd->windowOffsetX, wnd->windowOffsetY, 
+               wnd->windowWidth, wnd->windowHeight,
+               x, y);
+
+       window->local_move.root_x = x; 
+       window->local_move.root_y = y;
+       window->local_move.state = LMS_ACTIVE;
+
+       XTranslateCoordinates(xfi->display, DefaultRootWindow(xfi->display), window->handle, 
+               window->local_move.root_x, 
+               window->local_move.root_y,
+               &window->local_move.window_x, 
+               &window->local_move.window_y, 
+               &child_window);
 
        XUngrabPointer(xfi->display, CurrentTime);
        xf_SendClientEvent(xfi, window, 
@@ -459,40 +505,42 @@ void xf_StartLocalMoveSize(xfInfo* xfi, xfWindow* window, int direction, int win
 
 void xf_EndLocalMoveSize(xfInfo *xfi, xfWindow *window, boolean cancel)
 {
-       DEBUG_X11_LMS("inProcess=%d cancel=%d window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d",
-                       window->localMove.inProgress, cancel, 
-                       (uint32) window->handle, window->left, window->top, window->right, window->bottom,
-                       window->width, window->height);
+       rdpWindow* wnd = window->window;
 
-       if (!window->localMove.inProgress)
+       DEBUG_X11_LMS("inProcess=%d cancel=%d window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d  "
+               "RDP=0x%X rc={l=%d t=%d} w=%d h=%d",
+               window->local_move.state, cancel, 
+               (uint32) window->handle, window->left, window->top, window->right, window->bottom,
+               window->width, window->height,
+               wnd->windowId,
+               wnd->windowOffsetX, wnd->windowOffsetY, 
+               wnd->windowWidth, wnd->windowHeight);
+
+       if (window->local_move.state == LMS_NOT_ACTIVE)
                return;
 
        if (cancel)
        {
                // Per ICCM, the X client can ask to cancel an active move.  Do this if we 
                // receive a local move stop from RDP while a local move is in progress
-               Window childWindow;
-               int x,y;
-
-               XTranslateCoordinates(xfi->display, window->handle, DefaultRootWindow(xfi->display), 
-                       window->localMove.windowRelativeX, window->localMove.windowRelativeY, &x, &y, &childWindow);
        
                xf_SendClientEvent(xfi, window, 
-                       xfi->_NET_WM_MOVERESIZE, // Request X window manager to initate a local move
+                       xfi->_NET_WM_MOVERESIZE, // Request X window manager to abort a local move
                        5, // 5 arguments to follow 
-                       x, // x relative to root window
-                       y, // y relative to root window
+                       window->local_move.root_x, // x relative to root window
+                       window->local_move.root_y, // y relative to root window
                        _NET_WM_MOVERESIZE_CANCEL, // extended ICCM direction flag
                        1, // simulated mouse button 1
                        1);// 1 == application request per extended ICCM
        }
 
-       window->localMove.inProgress = False;
+       window->local_move.state = LMS_NOT_ACTIVE;
 }
 
 void xf_MoveWindow(xfInfo* xfi, xfWindow* window, int x, int y, int width, int height)
 {
        boolean resize = false;
+       rdpWindow* wnd = window->window;
 
        if ((width * height) < 1)
                return;
@@ -500,6 +548,16 @@ void xf_MoveWindow(xfInfo* xfi, xfWindow* window, int x, int y, int width, int h
        if ((window->width != width) || (window->height != height))
                resize = true;
 
+       DEBUG_X11_LMS("window=0x%X current rc={l=%d t=%d r=%d b=%d} w=%u h=%u  "
+               "new 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) window->handle, window->left, window->top, 
+               window->right, window->bottom, window->width, window->height,
+               x, y, x + width -1, y + height -1, width, height,
+               wnd->windowId,
+               wnd->windowOffsetX, wnd->windowOffsetY, 
+               wnd->windowWidth, wnd->windowHeight);
+
        window->left = x;
        window->top = y;
        window->right = x + width - 1;
@@ -507,20 +565,24 @@ void xf_MoveWindow(xfInfo* xfi, xfWindow* window, int x, int y, int width, int h
        window->width = width;
        window->height = height;
 
-       if (resize)
-               XMoveResizeWindow(xfi->display, window->handle, x, y, width, height);
-       else
-               XMoveWindow(xfi->display, window->handle, x, y);
-
-       DEBUG_X11_LMS("window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d",
-               (uint32) window->handle, window->left, window->top, window->right, window->bottom,
-               window->width, window->height);
-
-       if (resize)
+       if (window->is_transient) 
        {
-               xf_UpdateWindowArea(xfi, window, 0, 0, width, height);
+               if (resize)
+                       XMoveResizeWindow(xfi->display, window->handle, x, y, width, height);
+               else
+                       XMoveWindow(xfi->display, window->handle, x, y);
+       } else {
+               // Sending a client event preserves
+               // window gravity
+               xf_SendClientEvent(xfi, window, 
+                       xfi->_NET_MOVERESIZE_WINDOW, // Request X window manager to move window
+                       5, // 5 arguments to follow 
+                       0x1F0A, // STATIC gravity
+                       x, // x relative to root window
+                       y, // y relative to root window
+                       width, 
+                       height);
        }
-
 }
 
 void xf_ShowWindow(xfInfo* xfi, xfWindow* window, uint8 state)
@@ -630,8 +692,8 @@ void xf_UpdateWindowArea(xfInfo* xfi, xfWindow* window, int x, int y, int width,
 {
        int ax, ay;
        rdpWindow* wnd;
-
        wnd = window->window;
+
        ax = x + wnd->windowOffsetX;
        ay = y + wnd->windowOffsetY;
 
index cc7d3ac..d9667b4 100644 (file)
@@ -43,11 +43,20 @@ typedef struct xf_window xfWindow;
 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD    10   /* move via keyboard */
 #define _NET_WM_MOVERESIZE_CANCEL           11   /* cancel operation */
 
+enum xf_localmove_state
+{
+       LMS_NOT_ACTIVE,
+       LMS_ACTIVE,
+       LMS_TERMINATING
+};
+
 struct xf_localmove
 {
-       int windowRelativeX;
-       int windowRelativeY;
-       boolean inProgress;
+       int root_x;  // relative to root
+       int root_y;
+       int window_x; // relative to window
+       int window_y;
+       enum xf_localmove_state state;
 };
 
 struct xf_window
@@ -63,8 +72,9 @@ struct xf_window
        boolean fullscreen;
        boolean decorations;
        rdpWindow* window;
-       boolean isMapped;
-       xfLocalMove localMove;
+       boolean is_mapped;
+       boolean is_transient;
+       xfLocalMove local_move;
 };
 
 void xf_ewmhints_init(xfInfo* xfi);
@@ -94,7 +104,7 @@ void xf_SetWindowMinMaxInfo(xfInfo* xfi, xfWindow* window, int maxWidth, int max
                int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight);
 
 
-void xf_StartLocalMoveSize(xfInfo* xfi, xfWindow* window, int direction, int windowRelativeX, int windowRelativeY);
+void xf_StartLocalMoveSize(xfInfo* xfi, xfWindow* window, int direction, int x, int y);
 void xf_EndLocalMoveSize(xfInfo *xfi, xfWindow *window, boolean cancel);
 void xf_SendClientEvent(xfInfo *xfi, xfWindow* window, Atom atom, unsigned int numArgs, ...);
 
index 1ef5e22..ee9c8ea 100644 (file)
@@ -288,6 +288,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;
 
        if (xfi->remote_app != true)
        {
@@ -470,24 +472,26 @@ boolean xf_pre_connect(freerdp* instance)
                return false;
        }
 
-       xfi->_NET_WM_ICON = XInternAtom(xfi->display, "_NET_WM_ICON", false);
-       xfi->_MOTIF_WM_HINTS = XInternAtom(xfi->display, "_MOTIF_WM_HINTS", false);
-       xfi->_NET_CURRENT_DESKTOP = XInternAtom(xfi->display, "_NET_CURRENT_DESKTOP", false);
-       xfi->_NET_WORKAREA = XInternAtom(xfi->display, "_NET_WORKAREA", false);
-       xfi->_NET_WM_STATE = XInternAtom(xfi->display, "_NET_WM_STATE", false);
-       xfi->_NET_WM_STATE_FULLSCREEN = XInternAtom(xfi->display, "_NET_WM_STATE_FULLSCREEN", false);
-       xfi->_NET_WM_WINDOW_TYPE = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE", false);
-
-       xfi->_NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_NORMAL", false);
-       xfi->_NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_DIALOG", false);
-       xfi->_NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_UTILITY", false);
-       xfi->_NET_WM_STATE_SKIP_TASKBAR = XInternAtom(xfi->display, "_NET_WM_STATE_SKIP_TASKBAR", false);
-       xfi->_NET_WM_STATE_SKIP_PAGER = XInternAtom(xfi->display, "_NET_WM_STATE_SKIP_PAGER", false);
-
-       xfi->_NET_WM_MOVERESIZE = XInternAtom(xfi->display, "_NET_WM_MOVERESIZE", false);
-
-       xfi->WM_PROTOCOLS = XInternAtom(xfi->display, "WM_PROTOCOLS", false);
-       xfi->WM_DELETE_WINDOW = XInternAtom(xfi->display, "WM_DELETE_WINDOW", false);
+       xfi->_NET_WM_ICON = XInternAtom(xfi->display, "_NET_WM_ICON", True);
+       xfi->_MOTIF_WM_HINTS = XInternAtom(xfi->display, "_MOTIF_WM_HINTS", True);
+       xfi->_NET_CURRENT_DESKTOP = XInternAtom(xfi->display, "_NET_CURRENT_DESKTOP", True);
+       xfi->_NET_WORKAREA = XInternAtom(xfi->display, "_NET_WORKAREA", True);
+       xfi->_NET_WM_STATE = XInternAtom(xfi->display, "_NET_WM_STATE", True);
+       xfi->_NET_WM_STATE_FULLSCREEN = XInternAtom(xfi->display, "_NET_WM_STATE_FULLSCREEN", True);
+       xfi->_NET_WM_WINDOW_TYPE = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE", True);
+
+       xfi->_NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_NORMAL", True);
+       xfi->_NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_DIALOG", True);
+       xfi->_NET_WM_WINDOW_TYPE_POPUP= XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_POPUP", True);
+       xfi->_NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_UTILITY", True);
+       xfi->_NET_WM_WINDOW_TYPE_DROPDOWN_MENU = XInternAtom(xfi->display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", True);
+       xfi->_NET_WM_STATE_SKIP_TASKBAR = XInternAtom(xfi->display, "_NET_WM_STATE_SKIP_TASKBAR", True);
+       xfi->_NET_WM_STATE_SKIP_PAGER = XInternAtom(xfi->display, "_NET_WM_STATE_SKIP_PAGER", True);
+       xfi->_NET_WM_MOVERESIZE = XInternAtom(xfi->display, "_NET_WM_MOVERESIZE", True);
+       xfi->_NET_MOVERESIZE_WINDOW = XInternAtom(xfi->display, "_NET_MOVERESIZE_WINDOW", True);
+
+       xfi->WM_PROTOCOLS = XInternAtom(xfi->display, "WM_PROTOCOLS", True);
+       xfi->WM_DELETE_WINDOW = XInternAtom(xfi->display, "WM_DELETE_WINDOW", True);
 
        xf_kbd_init(xfi);
 
index b3c2f04..08e0f91 100644 (file)
@@ -142,8 +142,11 @@ struct xf_info
        Atom _NET_WM_WINDOW_TYPE_NORMAL;
        Atom _NET_WM_WINDOW_TYPE_DIALOG;
        Atom _NET_WM_WINDOW_TYPE_UTILITY;
+       Atom _NET_WM_WINDOW_TYPE_POPUP;
+       Atom _NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
 
        Atom _NET_WM_MOVERESIZE;
+       Atom _NET_MOVERESIZE_WINDOW;
 
        Atom WM_PROTOCOLS;
        Atom WM_DELETE_WINDOW;