Make popups transient, use local window manager for moves.

This fixes a number if issues on Ubuntu in particular.
This commit is contained in:
Not Nyguen Doze 2011-12-02 14:51:30 -08:00
parent 31cbac201d
commit 8f38bdb87a
7 changed files with 373 additions and 187 deletions

View 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)
if (xfi->window && xfi->window->local_move.state == LMS_ACTIVE)
{
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);
}
else
break;
case FocusIn:
case FocusOut:
{
if (event->xany.window != xfi->window->handle)
app = true;
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:

View 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);
}
}
}

View 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 */

View File

@ -37,7 +37,29 @@
/* Extended Window Manager Hints: http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html */
/* 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);
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);
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;
rdpWindow* wnd = window->window;
Window child_window;
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);
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);
// 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;
window->local_move.root_x = x;
window->local_move.root_y = y;
window->local_move.state = LMS_ACTIVE;
// 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);
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 (window->is_transient)
{
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)
{
xf_UpdateWindowArea(xfi, window, 0, 0, width, height);
} 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;

View 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, ...);

View 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_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", 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_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->_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->WM_PROTOCOLS = XInternAtom(xfi->display, "WM_PROTOCOLS", True);
xfi->WM_DELETE_WINDOW = XInternAtom(xfi->display, "WM_DELETE_WINDOW", True);
xf_kbd_init(xfi);

View 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;