Add a function to synchronize the RDP server with the local window position and size when the window is moved locally.

Complete implementation for initiating RAIL local move support, however, this is still disabled until a method is found to tell when local moves complete on the X server.
This commit is contained in:
David Sundstrom 2011-11-28 15:50:08 -06:00 committed by Not Nyguen Doze
parent 354b00711b
commit 31cbac201d
6 changed files with 232 additions and 77 deletions

View File

@ -461,28 +461,9 @@ boolean xf_event_ConfigureNotify(xfInfo* xfi, XEvent* event, boolean app)
xfw->right = xfw->left + xfw->width - 1;
xfw->bottom = xfw->top + xfw->height - 1;
if (app)
{
// 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)
{
xf_rail_send_windowmove(xfi, window->windowId,
xfw->left, xfw->top, xfw->right, xfw->bottom);
}
}
if (app)
xf_rail_local_movesize(xfi, xfw);
DEBUG_X11_LMS("ConfigureNotify: send_event=%d eventWindow=0x%X window=0x%X above=0x%X rc={l=%d t=%d r=%d b=%d} "
"w=%d h=%d override_redirect=%d",
event->xconfigure.send_event,
(uint32) event->xconfigure.event,
(uint32) event->xconfigure.window,
(uint32) event->xconfigure.above,
xfw->left, xfw->top, xfw->right, xfw->bottom, xfw->width, xfw->height,
event->xconfigure.override_redirect);
}
return True;
@ -502,6 +483,27 @@ 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;
}
return true;
}
boolean xf_event_UnmapNotify(xfInfo* xfi, XEvent* event, boolean app)
{
rdpWindow* window;
rdpRail* rail = ((rdpContext*) xfi->context)->rail;
if (app != true)
return true;
window = window_list_get_by_extra_id(rail->list, (void*) event->xany.window);
if (window != NULL)
{
xfWindow *xfw = (xfWindow*) window->extra;
xfw->isMapped = false;
}
return true;
@ -631,6 +633,10 @@ boolean xf_event_process(freerdp* instance, XEvent* event)
status = xf_event_MapNotify(xfi, event, app);
break;
case UnmapNotify:
status = xf_event_UnmapNotify(xfi, event, app);
break;
case ReparentNotify:
break;

View File

@ -25,5 +25,6 @@
#include "xfreerdp.h"
boolean xf_event_process(freerdp* instance, XEvent* event);
void xf_event_SendClientEvent(xfInfo *xfi, xfWindow* window, Atom atom, unsigned int numArgs, ...);
#endif /* __XF_EVENT_H */

View File

@ -108,6 +108,39 @@ 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;
@ -364,6 +397,7 @@ void xf_process_rail_server_localmovesize_event(xfInfo* xfi, rdpChannels* channe
rdpRail* rail;
rdpWindow* rail_window = NULL;
RAIL_LOCALMOVESIZE_ORDER* movesize = (RAIL_LOCALMOVESIZE_ORDER*) event->user_data;
int direction = 0;
rail = ((rdpContext*) xfi->context)->rail;
rail_window = window_list_get_by_id(rail->list, movesize->windowId);
@ -377,12 +411,50 @@ void xf_process_rail_server_localmovesize_event(xfInfo* xfi, rdpChannels* channe
movesize->windowId, movesize->isMoveSizeStart,
movetype_names[movesize->moveSizeType], (sint16) movesize->posX, (sint16) movesize->posY);
if (movesize->isMoveSizeStart)
xf_StartLocalMoveSize(xfi, window, movesize->moveSizeType, (int) movesize->posX, (int) movesize->posY);
else
xf_StopLocalMoveSize(xfi, window, movesize->moveSizeType, (int) movesize->posX, (int) movesize->posY);
}
switch (movesize->moveSizeType)
{
case RAIL_WMSZ_LEFT: //0x1
direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
break;
case RAIL_WMSZ_RIGHT: //0x2
direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
break;
case RAIL_WMSZ_TOP: //0x3
direction = _NET_WM_MOVERESIZE_SIZE_TOP;
break;
case RAIL_WMSZ_TOPLEFT: //0x4
direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
break;
case RAIL_WMSZ_TOPRIGHT: //0x5
direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
break;
case RAIL_WMSZ_BOTTOM: //0x6
direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
break;
case RAIL_WMSZ_BOTTOMLEFT: //0x7
direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
break;
case RAIL_WMSZ_BOTTOMRIGHT: //0x8
direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
break;
case RAIL_WMSZ_MOVE: //0x9
direction = _NET_WM_MOVERESIZE_MOVE;
break;
case RAIL_WMSZ_KEYMOVE: //0xA
direction = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
break;
case RAIL_WMSZ_KEYSIZE: //0xB
direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
break;
}
if (movesize->isMoveSizeStart)
{
xf_StartLocalMoveSize(xfi, window, direction, movesize->posX, movesize->posY);
} else {
xf_EndLocalMoveSize(xfi, window, True);
}
}
}
void xf_process_rail_appid_resp_event(xfInfo* xfi, rdpChannels* channels, RDP_EVENT* event)

View File

@ -28,5 +28,6 @@ void xf_rail_send_client_system_command(xfInfo* xfi, uint32 windowId, uint16 com
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);
#endif /* __XF_RAIL_H */

View File

@ -17,6 +17,7 @@
* limitations under the License.
*/
#include <stdarg.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
@ -49,22 +50,35 @@ struct _PropMotifWmHints
};
typedef struct _PropMotifWmHints PropMotifWmHints;
void xf_SendClientMessage(xfInfo* xfi, xfWindow* window, Atom atom, long msg, long d1, long d2, long d3)
/**
* Post an event from the client to the X server
*/
void xf_SendClientEvent(xfInfo *xfi, xfWindow* window, Atom atom, unsigned int numArgs, ...)
{
XEvent xevent;
XEvent xevent;
unsigned int i;
va_list argp;
xevent.xclient.type = ClientMessage;
xevent.xclient.message_type = atom;
xevent.xclient.window = window->handle;
xevent.xclient.format = 32;
xevent.xclient.data.l[0] = CurrentTime;
xevent.xclient.data.l[1] = msg;
xevent.xclient.data.l[2] = d1;
xevent.xclient.data.l[3] = d2;
xevent.xclient.data.l[4] = d3;
va_start(argp, numArgs);
XSendEvent(xfi->display, window->handle, false, NoEventMask, &xevent);
XSync(xfi->display, false);
xevent.xclient.type = ClientMessage;
xevent.xclient.serial = 0;
xevent.xclient.send_event = True;
xevent.xclient.display = xfi->display;
xevent.xclient.window = window->handle;
xevent.xclient.message_type = atom;
xevent.xclient.format = 32;
for (i=0; i<numArgs; i++)
{
xevent.xclient.data.l[i] = va_arg(argp, int);
}
DEBUG_X11("Send ClientMessage Event: wnd=0x%04X", (unsigned int) xevent.xclient.window);
XSendEvent(xfi->display, window->handle, False, NoEventMask, &xevent);
XSync(xfi->display, False);
va_end(argp);
}
void xf_SetWindowFullscreen(xfInfo* xfi, xfWindow* window, boolean fullscreen)
@ -221,6 +235,7 @@ xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height,
window->height = height;
window->fullscreen = false;
window->decorations = decorations;
window->isMapped = 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,
@ -336,7 +351,8 @@ xfWindow* xf_CreateWindow(xfInfo* xfi, rdpWindow* wnd, int x, int y, int width,
window->decorations = false;
window->fullscreen = false;
window->window = wnd;
window->localMoveSize = false;
window->localMove.inProgress = false;
window->isMapped = false;
window->handle = XCreateWindow(xfi->display, RootWindowOfScreen(xfi->screen),
x, y, window->width, window->height, 0, xfi->depth, InputOutput, xfi->visual,
@ -403,41 +419,75 @@ void xf_SetWindowMinMaxInfo(xfInfo* xfi, xfWindow* window,
}
}
void xf_SendMoveResizeEvent(xfInfo* xfi, xfWindow* window, int direction, int x_root, int y_root)
void xf_StartLocalMoveSize(xfInfo* xfi, xfWindow* window, int direction, int windowRelativeX, int windowRelativeY)
{
// TODO:
// - how to receive movesize canceling event?
// - how to produce correct RAIL movesize finish?
// - how to receive move/size window coordinates in process of local move/size?
window->localMove.windowRelativeX = windowRelativeX;
window->localMove.windowRelativeY = windowRelativeY;
XEvent event;
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);
event.xclient.type = ClientMessage;
event.xclient.window = window->handle;
event.xclient.message_type = xfi->_NET_WM_MOVERESIZE;
event.xclient.serial = 0;
event.xclient.display = xfi->display;
event.xclient.send_event = true;
event.xclient.format = 32;
event.xclient.data.l[0] = x_root;
event.xclient.data.l[1] = y_root;
event.xclient.data.l[2] = direction;
event.xclient.data.l[3] = 1; /* button 1 */
event.xclient.data.l[4] = 0;
// 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);
XUngrabPointer(xfi->display, CurrentTime);
XSendEvent(xfi->display, RootWindowOfScreen(xfi->screen), false, SubstructureNotifyMask, &event);
xf_SendClientEvent(xfi, window,
xfi->_NET_WM_MOVERESIZE, // Request X window manager to initate a local move
5, // 5 arguments to follow
x, // x relative to root window
y, // y relative to root window
direction, // extended ICCM direction flag
1, // simulated mouse button 1
1);// 1 == application request per extended ICCM
}
void xf_StartLocalMoveSize(xfInfo* xfi, xfWindow* window, uint16 moveSizeType, int posX, int posY)
void xf_EndLocalMoveSize(xfInfo *xfi, xfWindow *window, boolean cancel)
{
window->localMoveSize = true;
}
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);
void xf_StopLocalMoveSize(xfInfo* xfi, xfWindow* window, uint16 moveSizeType, int posX, int posY)
{
window->localMoveSize = false;
if (!window->localMove.inProgress)
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
5, // 5 arguments to follow
x, // x relative to root window
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;
}
void xf_MoveWindow(xfInfo* xfi, xfWindow* window, int x, int y, int width, int height)
@ -450,11 +500,6 @@ void xf_MoveWindow(xfInfo* xfi, xfWindow* window, int x, int y, int width, int h
if ((window->width != width) || (window->height != height))
resize = true;
if (resize)
XMoveResizeWindow(xfi->display, window->handle, x, y, width, height);
else
XMoveWindow(xfi->display, window->handle, x, y);
window->left = x;
window->top = y;
window->right = x + width - 1;
@ -462,14 +507,20 @@ void xf_MoveWindow(xfInfo* xfi, xfWindow* window, int x, int y, int width, int h
window->width = width;
window->height = height;
DEBUG_X11_LMS("xf_MoveWindow: 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)
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);
}
}
void xf_ShowWindow(xfInfo* xfi, xfWindow* window, uint8 state)

View File

@ -24,10 +24,32 @@
#include <freerdp/freerdp.h>
#include <freerdp/utils/memory.h>
typedef struct xf_localmove xfLocalMove;
typedef struct xf_window xfWindow;
#include "xfreerdp.h"
// Extended ICCM flags http://standards.freedesktop.org/wm-spec/wm-spec-latest.html
#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
#define _NET_WM_MOVERESIZE_SIZE_TOP 1
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */
struct xf_localmove
{
int windowRelativeX;
int windowRelativeY;
boolean inProgress;
};
struct xf_window
{
GC gc;
@ -41,7 +63,8 @@ struct xf_window
boolean fullscreen;
boolean decorations;
rdpWindow* window;
boolean localMoveSize;
boolean isMapped;
xfLocalMove localMove;
};
void xf_ewmhints_init(xfInfo* xfi);
@ -71,7 +94,8 @@ 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, uint16 moveSizeType, int posX, int posY);
void xf_StopLocalMoveSize(xfInfo* xfi, xfWindow* window, uint16 moveSizeType, int topLeftX, int topLeftY);
void xf_StartLocalMoveSize(xfInfo* xfi, xfWindow* window, int direction, int windowRelativeX, int windowRelativeY);
void xf_EndLocalMoveSize(xfInfo *xfi, xfWindow *window, boolean cancel);
void xf_SendClientEvent(xfInfo *xfi, xfWindow* window, Atom atom, unsigned int numArgs, ...);
#endif /* __XF_WINDOW_H */