Merge pull request #2240 from nfedera/fix-2014-12-01-01

xfreerdp: pinch/pan fixes and smart-sizing
This commit is contained in:
Marc-André Moreau 2014-12-02 14:04:49 -05:00
commit c17a831367
14 changed files with 540 additions and 633 deletions

View File

@ -4,6 +4,8 @@
* *
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com> * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2013 Corey Clayton <can.of.tuna@gmail.com> * Copyright 2013 Corey Clayton <can.of.tuna@gmail.com>
* Copyright 2014 Thincast Technologies GmbH
* Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -29,6 +31,7 @@
#ifdef WITH_XRENDER #ifdef WITH_XRENDER
#include <X11/extensions/Xrender.h> #include <X11/extensions/Xrender.h>
#include <math.h>
#endif #endif
#ifdef WITH_XI #ifdef WITH_XI
@ -47,10 +50,6 @@
#include <X11/extensions/XInput2.h> #include <X11/extensions/XInput2.h>
#endif #endif
#ifdef WITH_XRENDER
#include <X11/extensions/Xrender.h>
#endif
#include <X11/XKBlib.h> #include <X11/XKBlib.h>
#include <errno.h> #include <errno.h>
@ -104,44 +103,63 @@
static const size_t password_size = 512; static const size_t password_size = 512;
void xf_transform_window(xfContext* xfc)
{
int ret;
int w;
int h;
long supplied;
Atom hints_atom;
XSizeHints *size_hints = NULL;
hints_atom = XInternAtom(xfc->display, "WM_SIZE_HINTS", 1);
ret = XGetWMSizeHints(xfc->display, xfc->window->handle, size_hints, &supplied, hints_atom);
if (ret == 0)
size_hints = XAllocSizeHints();
w = (xfc->originalWidth * xfc->settings->ScalingFactor) + xfc->offset_x;
h = (xfc->originalHeight * xfc->settings->ScalingFactor) + xfc->offset_y;
if (w < 1)
w = 1;
if (h < 1)
h = 1;
if (size_hints)
{
size_hints->flags |= PMinSize | PMaxSize;
size_hints->min_width = size_hints->max_width = w;
size_hints->min_height = size_hints->max_height = h;
XSetWMNormalHints(xfc->display, xfc->window->handle, size_hints);
XResizeWindow(xfc->display, xfc->window->handle, w, h);
XFree(size_hints);
}
}
void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h, BOOL scale)
{
#ifdef WITH_XRENDER #ifdef WITH_XRENDER
static void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h)
{
XTransform transform; XTransform transform;
Picture windowPicture; Picture windowPicture;
Picture primaryPicture; Picture primaryPicture;
XRenderPictureAttributes pa; XRenderPictureAttributes pa;
XRenderPictFormat *picFormat; XRenderPictFormat *picFormat;
XRectangle xr; double xScalingFactor;
double yScalingFactor;
int x2;
int y2;
if (xfc->scaledWidth <= 0 || xfc->scaledHeight <= 0)
{
WLog_ERR(TAG, "the current window dimensions are invalid");
return;
}
if (xfc->width <= 0 || xfc->height <= 0)
{
WLog_ERR(TAG, "the window dimensions are invalid");
return;
}
if (!w || !h)
{
WLog_ERR(TAG, "invalid width and/or height specified");
return;
}
xScalingFactor = xfc->width / (double)xfc->scaledWidth;
yScalingFactor = xfc->height / (double)xfc->scaledHeight;
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
XSetForeground(xfc->display, xfc->gc, 0);
/* Black out possible space between desktop and window borders */
{
XRectangle box1 = { 0, 0, xfc->window->width, xfc->window->height };
XRectangle box2 = { xfc->offset_x, xfc->offset_y, xfc->scaledWidth, xfc->scaledHeight };
Region reg1 = XCreateRegion();
Region reg2 = XCreateRegion();
XUnionRectWithRegion( &box1, reg1, reg1);
XUnionRectWithRegion( &box2, reg2, reg2);
if (XSubtractRegion(reg1, reg2, reg1) && !XEmptyRegion(reg1))
{
XSetRegion( xfc->display, xfc->gc, reg1);
XFillRectangle(xfc->display, xfc->window->handle, xfc->gc, 0, 0, xfc->window->width, xfc->window->height);
XSetClipMask(xfc->display, xfc->gc, None);
}
XDestroyRegion(reg1);
XDestroyRegion(reg2);
}
picFormat = XRenderFindStandardFormat(xfc->display, PictStandardRGB24); picFormat = XRenderFindStandardFormat(xfc->display, PictStandardRGB24);
@ -149,41 +167,55 @@ void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h, BOOL scal
primaryPicture = XRenderCreatePicture(xfc->display, xfc->primary, picFormat, CPSubwindowMode, &pa); primaryPicture = XRenderCreatePicture(xfc->display, xfc->primary, picFormat, CPSubwindowMode, &pa);
windowPicture = XRenderCreatePicture(xfc->display, xfc->window->handle, picFormat, CPSubwindowMode, &pa); windowPicture = XRenderCreatePicture(xfc->display, xfc->window->handle, picFormat, CPSubwindowMode, &pa);
transform.matrix[0][0] = XDoubleToFixed(1); XRenderSetPictureFilter(xfc->display, primaryPicture, FilterBilinear, 0, 0);
transform.matrix[0][1] = XDoubleToFixed(0);
transform.matrix[0][2] = XDoubleToFixed(0);
transform.matrix[1][0] = XDoubleToFixed(0);
transform.matrix[1][1] = XDoubleToFixed(1);
transform.matrix[1][2] = XDoubleToFixed(0);
transform.matrix[2][0] = XDoubleToFixed(0);
transform.matrix[2][1] = XDoubleToFixed(0);
transform.matrix[2][2] = XDoubleToFixed(xfc->settings->ScalingFactor);
if ((w != 0) && (h != 0)) transform.matrix[0][0] = XDoubleToFixed(xScalingFactor);
{ transform.matrix[0][1] = XDoubleToFixed(0.0);
if (scale) transform.matrix[0][2] = XDoubleToFixed(0.0);
{ transform.matrix[1][0] = XDoubleToFixed(0.0);
xr.x = x * xfc->settings->ScalingFactor; transform.matrix[1][1] = XDoubleToFixed(yScalingFactor);
xr.y = y * xfc->settings->ScalingFactor; transform.matrix[1][2] = XDoubleToFixed(0.0);
xr.width = (w+1) * xfc->settings->ScalingFactor; transform.matrix[2][0] = XDoubleToFixed(0.0);
xr.height = (h+1) * xfc->settings->ScalingFactor; transform.matrix[2][1] = XDoubleToFixed(0.0);
} transform.matrix[2][2] = XDoubleToFixed(1.0);
else
{
xr.x = x;
xr.y = y;
xr.width = w;
xr.height = h;
}
XRenderSetPictureClipRectangles(xfc->display, primaryPicture, 0, 0, &xr, 1); /* calculate and fix up scaled coordinates */
} x2 = x + w;
y2 = y + h;
x = floor(x / xScalingFactor) - 1;
y = floor(y / yScalingFactor) - 1;
w = ceil(x2 / xScalingFactor) + 1 - x;
h = ceil(y2 / yScalingFactor) + 1 - y;
XRenderSetPictureTransform(xfc->display, primaryPicture, &transform); XRenderSetPictureTransform(xfc->display, primaryPicture, &transform);
XRenderComposite(xfc->display, PictOpSrc, primaryPicture, 0, windowPicture, 0, 0, 0, 0, xfc->offset_x, xfc->offset_y, xfc->currentWidth, xfc->currentHeight); XRenderComposite(xfc->display, PictOpSrc, primaryPicture, 0, windowPicture, x, y, 0, 0, xfc->offset_x + x, xfc->offset_y + y, w, h);
XRenderFreePicture(xfc->display, primaryPicture); XRenderFreePicture(xfc->display, primaryPicture);
XRenderFreePicture(xfc->display, windowPicture); XRenderFreePicture(xfc->display, windowPicture);
}
BOOL xf_picture_transform_required(xfContext* xfc)
{
if (xfc->offset_x || xfc->offset_y ||
xfc->scaledWidth != xfc->width ||
xfc->scaledHeight != xfc->height)
{
return TRUE;
}
return FALSE;
}
#endif #endif
void xf_draw_screen(xfContext* xfc, int x, int y, int w, int h)
{
#ifdef WITH_XRENDER
if (xf_picture_transform_required(xfc)) {
xf_draw_screen_scaled(xfc, x, y, w, h);
return;
}
#endif
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y);
} }
void xf_sw_begin_paint(rdpContext* context) void xf_sw_begin_paint(rdpContext* context)
@ -222,14 +254,7 @@ void xf_sw_end_paint(rdpContext* context)
XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h); XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h);
if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) xf_draw_screen(xfc, x, y, w, h);
{
xf_draw_screen_scaled(xfc, x, y, w, h, TRUE);
}
else
{
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y);
}
xf_unlock_x11(xfc, FALSE); xf_unlock_x11(xfc, FALSE);
} }
@ -249,14 +274,7 @@ void xf_sw_end_paint(rdpContext* context)
XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h); XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h);
if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) xf_draw_screen(xfc, x, y, w, h);
{
xf_draw_screen_scaled(xfc, x, y, w, h, TRUE);
}
else
{
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y);
}
} }
XFlush(xfc->display); XFlush(xfc->display);
@ -328,14 +346,7 @@ void xf_hw_end_paint(rdpContext* context)
xf_lock_x11(xfc, FALSE); xf_lock_x11(xfc, FALSE);
if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) xf_draw_screen(xfc, x, y, w, h);
{
xf_draw_screen_scaled(xfc, x, y, w, h, TRUE);
}
else
{
XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, x, y, w, h, x, y);
}
xf_unlock_x11(xfc, FALSE); xf_unlock_x11(xfc, FALSE);
} }
@ -360,14 +371,7 @@ void xf_hw_end_paint(rdpContext* context)
w = cinvalid[i].w; w = cinvalid[i].w;
h = cinvalid[i].h; h = cinvalid[i].h;
if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) xf_draw_screen(xfc, x, y, w, h);
{
xf_draw_screen_scaled(xfc, x, y, w, h, TRUE);
}
else
{
XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, x, y, w, h, x, y);
}
} }
XFlush(xfc->display); XFlush(xfc->display);
@ -490,6 +494,10 @@ void xf_create_window(xfContext* xfc)
xfc->attribs.colormap = xfc->colormap; xfc->attribs.colormap = xfc->colormap;
xfc->attribs.bit_gravity = NorthWestGravity; xfc->attribs.bit_gravity = NorthWestGravity;
xfc->attribs.win_gravity = NorthWestGravity; xfc->attribs.win_gravity = NorthWestGravity;
#ifdef WITH_XRENDER
xfc->offset_x = 0;
xfc->offset_y = 0;
#endif
if (xfc->settings->WindowTitle) if (xfc->settings->WindowTitle)
{ {
@ -506,6 +514,30 @@ void xf_create_window(xfContext* xfc)
sprintf(windowTitle, "FreeRDP: %s:%i", xfc->settings->ServerHostname, xfc->settings->ServerPort); sprintf(windowTitle, "FreeRDP: %s:%i", xfc->settings->ServerHostname, xfc->settings->ServerPort);
} }
#ifdef WITH_XRENDER
if (xfc->settings->SmartSizing)
{
if(xfc->fullscreen)
{
if (xfc->window)
{
xfc->settings->SmartSizingWidth = xfc->window->width;
xfc->settings->SmartSizingHeight = xfc->window->height;
}
width = WidthOfScreen(xfc->screen);
height = HeightOfScreen(xfc->screen);
}
else
{
if (xfc->settings->SmartSizingWidth)
width = xfc->settings->SmartSizingWidth;
if (xfc->settings->SmartSizingHeight)
height = xfc->settings->SmartSizingHeight;
}
xfc->scaledWidth = width;
xfc->scaledHeight = height;
}
#endif
xfc->window = xf_CreateDesktopWindow(xfc, windowTitle, width, height, xfc->settings->Decorations); xfc->window = xf_CreateDesktopWindow(xfc, windowTitle, width, height, xfc->settings->Decorations);
free(windowTitle); free(windowTitle);
@ -525,23 +557,16 @@ void xf_create_window(xfContext* xfc)
void xf_toggle_fullscreen(xfContext* xfc) void xf_toggle_fullscreen(xfContext* xfc)
{ {
Pixmap contents = 0;
WindowStateChangeEventArgs e; WindowStateChangeEventArgs e;
xf_lock_x11(xfc, TRUE); xf_lock_x11(xfc, TRUE);
contents = XCreatePixmap(xfc->display, xfc->window->handle, xfc->width, xfc->height, xfc->depth);
XCopyArea(xfc->display, xfc->primary, contents, xfc->gc, 0, 0, xfc->width, xfc->height, 0, 0);
XDestroyWindow(xfc->display, xfc->window->handle); XDestroyWindow(xfc->display, xfc->window->handle);
xfc->fullscreen = (xfc->fullscreen) ? FALSE : TRUE; xfc->fullscreen = (xfc->fullscreen) ? FALSE : TRUE;
xf_create_window(xfc); xf_create_window(xfc);
XCopyArea(xfc->display, contents, xfc->primary, xfc->gc, 0, 0, xfc->width, xfc->height, 0, 0);
XFreePixmap(xfc->display, contents);
xf_unlock_x11(xfc, TRUE); xf_unlock_x11(xfc, TRUE);
EventArgsInit(&e, "xfreerdp"); EventArgsInit(&e, "xfreerdp");
@ -978,16 +1003,16 @@ BOOL xf_post_connect(freerdp *instance)
xfc->hdc = gdi_CreateDC(flags, xfc->bpp); xfc->hdc = gdi_CreateDC(flags, xfc->bpp);
} }
xfc->originalWidth = settings->DesktopWidth;
xfc->originalHeight = settings->DesktopHeight;
xfc->currentWidth = xfc->originalWidth;
xfc->currentHeight = xfc->originalWidth;
xfc->settings->ScalingFactor = 1.0;
xfc->offset_x = 0;
xfc->offset_y = 0;
xfc->width = settings->DesktopWidth; xfc->width = settings->DesktopWidth;
xfc->height = settings->DesktopHeight; xfc->height = settings->DesktopHeight;
#ifdef WITH_XRENDER
xfc->scaledWidth = xfc->width;
xfc->scaledHeight = xfc->height;
xfc->offset_x = 0;
xfc->offset_y = 0;
#endif
if (settings->RemoteApplicationMode) if (settings->RemoteApplicationMode)
xfc->remote_app = TRUE; xfc->remote_app = TRUE;
@ -1593,32 +1618,41 @@ void xf_TerminateEventHandler(rdpContext* context, TerminateEventArgs* e)
} }
} }
static void xf_ScalingFactorChangeEventHandler(rdpContext* context, ScalingFactorChangeEventArgs* e) static void xf_ZoomingChangeEventHandler(rdpContext* context, ZoomingChangeEventArgs* e)
{
xfContext* xfc = (xfContext*) context;
int w = xfc->scaledWidth + e->dx;
int h = xfc->scaledHeight + e->dy;
if (e->dx == 0 && e->dy == 0)
return;
if (w < 10)
w = 10;
if (h < 10)
h = 10;
if (w == xfc->scaledWidth && h == xfc->scaledHeight)
return;
xfc->scaledWidth = w;
xfc->scaledHeight = h;
xf_draw_screen(xfc, 0, 0, xfc->width, xfc->height);
}
static void xf_PanningChangeEventHandler(rdpContext* context, PanningChangeEventArgs* e)
{ {
xfContext* xfc = (xfContext*) context; xfContext* xfc = (xfContext*) context;
xfc->settings->ScalingFactor += e->ScalingFactor; if (e->dx == 0 && e->dy == 0)
return;
if (xfc->settings->ScalingFactor > 1.2) xfc->offset_x += e->dx;
xfc->settings->ScalingFactor = 1.2; xfc->offset_y += e->dy;
if (xfc->settings->ScalingFactor < 0.8) xf_draw_screen(xfc, 0, 0, xfc->width, xfc->height);
xfc->settings->ScalingFactor = 0.8;
xfc->currentWidth = xfc->originalWidth * xfc->settings->ScalingFactor;
xfc->currentHeight = xfc->originalHeight * xfc->settings->ScalingFactor;
xf_transform_window(xfc);
{
ResizeWindowEventArgs ev;
EventArgsInit(&ev, "xfreerdp");
ev.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor;
ev.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor;
PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &ev);
}
xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE);
} }
/** /**
@ -1695,7 +1729,8 @@ static int xfreerdp_client_new(freerdp* instance, rdpContext* context)
xfc->settings = instance->context->settings; xfc->settings = instance->context->settings;
PubSub_SubscribeTerminate(context->pubSub, (pTerminateEventHandler) xf_TerminateEventHandler); PubSub_SubscribeTerminate(context->pubSub, (pTerminateEventHandler) xf_TerminateEventHandler);
PubSub_SubscribeScalingFactorChange(context->pubSub, (pScalingFactorChangeEventHandler) xf_ScalingFactorChangeEventHandler); PubSub_SubscribeZoomingChange(context->pubSub, (pZoomingChangeEventHandler) xf_ZoomingChangeEventHandler);
PubSub_SubscribePanningChange(context->pubSub, (pPanningChangeEventHandler) xf_PanningChangeEventHandler);
return 0; return 0;
} }

View File

@ -178,15 +178,42 @@ int xf_event_execute_action_script(xfContext* xfc, XEvent* event)
return 1; return 1;
} }
void xf_event_adjust_coordinates(xfContext* xfc, int* x, int *y)
{
if (!xfc->remote_app)
{
#ifdef WITH_XRENDER
if (xf_picture_transform_required(xfc))
{
double xScalingFactor = xfc->width / (double)xfc->scaledWidth;
double yScalingFactor = xfc->height / (double)xfc->scaledHeight;
*x = (int)((*x - xfc->offset_x) * xScalingFactor);
*y = (int)((*y - xfc->offset_y) * yScalingFactor);
}
#endif
}
CLAMP_COORDINATES(*x, *y);
}
static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app) static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app)
{ {
int x, y; int x, y;
int w, h; int w, h;
if (!app && (xfc->settings->SmartSizing || xfc->settings->MultiTouchGestures))
{
x = 0;
y = 0;
w = xfc->width;
h = xfc->height;
}
else
{
x = event->xexpose.x; x = event->xexpose.x;
y = event->xexpose.y; y = event->xexpose.y;
w = event->xexpose.width; w = event->xexpose.width;
h = event->xexpose.height; h = event->xexpose.height;
}
if (xfc->gfx) if (xfc->gfx)
{ {
@ -196,15 +223,7 @@ static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app)
if (!app) if (!app)
{ {
if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) xf_draw_screen(xfc, x, y, w, h);
{
xf_draw_screen_scaled(xfc, x - xfc->offset_x,
y - xfc->offset_y, w, h, FALSE);
}
else
{
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y);
}
} }
else else
{ {
@ -252,13 +271,7 @@ BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window win
x, y, &x, &y, &childWindow); x, y, &x, &y, &childWindow);
} }
/* Take scaling in to consideration */ xf_event_adjust_coordinates(xfc, &x, &y);
if ( (xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y) )
{
x = (int)((x - xfc->offset_x) * (1.0 / xfc->settings->ScalingFactor) );
y = (int)((y - xfc->offset_y) * (1.0 / xfc->settings->ScalingFactor) );
}
CLAMP_COORDINATES(x,y);
input->MouseEvent(input, PTR_FLAGS_MOVE, x, y); input->MouseEvent(input, PTR_FLAGS_MOVE, x, y);
@ -358,16 +371,8 @@ BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, Window win
} }
if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) xf_event_adjust_coordinates(xfc, &x, &y);
|| (xfc->offset_y))
{
x = (int) ((x - xfc->offset_x)
* (1.0 / xfc->settings->ScalingFactor));
y = (int) ((y - xfc->offset_y)
* (1.0 / xfc->settings->ScalingFactor));
}
CLAMP_COORDINATES(x,y);
if (extended) if (extended)
input->ExtendedMouseEvent(input, flags, x, y); input->ExtendedMouseEvent(input, flags, x, y);
else else
@ -447,14 +452,7 @@ BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, Window w
x, y, &x, &y, &childWindow); x, y, &x, &y, &childWindow);
} }
xf_event_adjust_coordinates(xfc, &x, &y);
if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y))
{
x = (int) ((x - xfc->offset_x) * (1.0 / xfc->settings->ScalingFactor));
y = (int) ((y - xfc->offset_y) * (1.0 / xfc->settings->ScalingFactor));
}
CLAMP_COORDINATES(x,y);
if (extended) if (extended)
input->ExtendedMouseEvent(input, flags, x, y); input->ExtendedMouseEvent(input, flags, x, y);
@ -642,7 +640,28 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, XEvent* event, BOOL app)
xfAppWindow* appWindow; xfAppWindow* appWindow;
if (!app) if (!app)
{
#ifdef WITH_XRENDER
if (xfc->settings->SmartSizing && event->xconfigure.window == xfc->window->handle)
{
if (xfc->window->width != event->xconfigure.width ||
xfc->window->height != event->xconfigure.height)
{
xfc->window->width = event->xconfigure.width;
xfc->window->height = event->xconfigure.height;
if (!xfc->fullscreen)
{
xfc->scaledWidth = xfc->window->width;
xfc->scaledHeight = xfc->window->height;
}
xfc->offset_x = 0;
xfc->offset_y = 0;
xf_draw_screen(xfc, 0, 0, xfc->width, xfc->height);
}
}
#endif
return TRUE; return TRUE;
}
appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window);

View File

@ -31,6 +31,8 @@ void xf_event_action_script_free(xfContext* xfc);
BOOL xf_event_process(freerdp* instance, XEvent* event); BOOL xf_event_process(freerdp* instance, XEvent* event);
void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...); void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...);
void xf_event_adjust_coordinates(xfContext* xfc, int* x, int *y);
BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window window, BOOL app); BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window window, BOOL app);
BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, Window window, BOOL app); BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, Window window, BOOL app);
BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, Window window, BOOL app); BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, Window window, BOOL app);

View File

@ -3,6 +3,8 @@
* X11 GDI * X11 GDI
* *
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Thincast Technologies GmbH
* Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -440,10 +442,6 @@ void xf_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt)
if (xfc->drawing == xfc->primary) if (xfc->drawing == xfc->primary)
{ {
if (!xfc->remote_app)
{
XFillRectangle(xfc->display, xfc->drawable, xfc->gc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
}
gdi_InvalidateRegion(xfc->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight); gdi_InvalidateRegion(xfc->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight);
} }
@ -531,11 +529,6 @@ void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
if (xfc->drawing == xfc->primary) if (xfc->drawing == xfc->primary)
{ {
XSetFunction(xfc->display, xfc->gc, GXcopy);
if (!xfc->remote_app)
{
XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight, patblt->nLeftRect, patblt->nTopRect);
}
gdi_InvalidateRegion(xfc->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight); gdi_InvalidateRegion(xfc->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight);
} }
@ -557,19 +550,6 @@ void xf_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt)
if (xfc->drawing == xfc->primary) if (xfc->drawing == xfc->primary)
{ {
if (!xfc->remote_app)
{
if (xfc->unobscured)
{
XCopyArea(xfc->display, xfc->drawable, xfc->drawable, xfc->gc, scrblt->nXSrc, scrblt->nYSrc,
scrblt->nWidth, scrblt->nHeight, scrblt->nLeftRect, scrblt->nTopRect);
}
}
else
{
XSetFunction(xfc->display, xfc->gc, GXcopy);
XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight, scrblt->nLeftRect, scrblt->nTopRect);
}
gdi_InvalidateRegion(xfc->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight); gdi_InvalidateRegion(xfc->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight);
} }
@ -597,13 +577,6 @@ void xf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect)
if (xfc->drawing == xfc->primary) if (xfc->drawing == xfc->primary)
{ {
if (!xfc->remote_app)
{
XFillRectangle(xfc->display, xfc->drawable, xfc->gc,
opaque_rect->nLeftRect, opaque_rect->nTopRect,
opaque_rect->nWidth, opaque_rect->nHeight);
}
gdi_InvalidateRegion(xfc->hdc, opaque_rect->nLeftRect, opaque_rect->nTopRect, gdi_InvalidateRegion(xfc->hdc, opaque_rect->nLeftRect, opaque_rect->nTopRect,
opaque_rect->nWidth, opaque_rect->nHeight); opaque_rect->nWidth, opaque_rect->nHeight);
} }
@ -636,12 +609,6 @@ void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* mult
if (xfc->drawing == xfc->primary) if (xfc->drawing == xfc->primary)
{ {
if (!xfc->remote_app)
{
XFillRectangle(xfc->display, xfc->drawable, xfc->gc,
rectangle->left, rectangle->top,
rectangle->width, rectangle->height);
}
gdi_InvalidateRegion(xfc->hdc, rectangle->left, rectangle->top, rectangle->width, rectangle->height); gdi_InvalidateRegion(xfc->hdc, rectangle->left, rectangle->top, rectangle->width, rectangle->height);
} }
} }
@ -672,24 +639,15 @@ void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to)
if (xfc->drawing == xfc->primary) if (xfc->drawing == xfc->primary)
{ {
if (!xfc->remote_app) int x, y, w, h;
{
XDrawLine(xfc->display, xfc->drawable, xfc->gc,
line_to->nXStart, line_to->nYStart, line_to->nXEnd, line_to->nYEnd);
}
int width, height;
width = line_to->nXStart - line_to->nXEnd; x = MIN(line_to->nXStart, line_to->nXEnd);
height = line_to->nYStart - line_to->nYEnd; y = MIN(line_to->nYStart, line_to->nYEnd);
if (width < 0) w = abs(line_to->nXEnd - line_to->nXStart) + 1;
width *= (-1); h = abs(line_to->nYEnd - line_to->nYStart) + 1;
if (height < 0)
height *= (-1);
gdi_InvalidateRegion(xfc->hdc, line_to->nXStart, line_to->nYStart, width, height);
gdi_InvalidateRegion(xfc->hdc, x, y, w, h);
} }
XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFunction(xfc->display, xfc->gc, GXcopy);
@ -697,16 +655,51 @@ void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to)
xf_unlock_x11(xfc, FALSE); xf_unlock_x11(xfc, FALSE);
} }
static void xf_gdi_invalidate_poly_region(xfContext* xfc, XPoint* points, int npoints, BOOL autoclose)
{
int i, x, y, x1, y1, x2, y2, w, h;
x1 = points[0].x;
y1 = points[0].y;
for (i = 1; i <= npoints; i++)
{
if (i == npoints)
{
if (!autoclose)
break;
x2 = points[0].x;
y2 = points[0].y;
if (x2 == points[0].x && y2 == points[0].y)
break;
}
else
{
x2 = points[i].x + x1;
y2 = points[i].y + y1;
}
x = MIN(x1, x2);
y = MIN(y1, y2);
w = abs(x2 - x1) + 1;
h = abs(y2 - y1) + 1;
x1 = x2;
y1 = y2;
gdi_InvalidateRegion(xfc->hdc, x, y, w, h);
}
}
void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline) void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
{ {
int i; int i;
int x, y;
int x1, y1;
int x2, y2;
int npoints; int npoints;
UINT32 color; UINT32 color;
XPoint* points; XPoint* points;
int width, height;
xfContext* xfc = (xfContext*) context; xfContext* xfc = (xfContext*) context;
xf_lock_x11(xfc, FALSE); xf_lock_x11(xfc, FALSE);
@ -733,29 +726,7 @@ void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline)
if (xfc->drawing == xfc->primary) if (xfc->drawing == xfc->primary)
{ {
if (!xfc->remote_app) xf_gdi_invalidate_poly_region(xfc, points, npoints, FALSE);
{
XDrawLines(xfc->display, xfc->drawable, xfc->gc, points, npoints, CoordModePrevious);
}
x1 = points[0].x;
y1 = points[0].y;
for (i = 1; i < npoints; i++)
{
x2 = points[i].x + x1;
y2 = points[i].y + y1;
x = (x2 < x1) ? x2 : x1;
width = (x2 > x1) ? x2 - x1 : x1 - x2;
y = (y2 < y1) ? y2 : y1;
height = (y2 > y1) ? y2 - y1 : y1 - y2;
x1 = x2;
y1 = y2;
gdi_InvalidateRegion(xfc->hdc, x, y, width, height);
}
} }
XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFunction(xfc->display, xfc->gc, GXcopy);
@ -780,13 +751,6 @@ void xf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
if (xfc->drawing == xfc->primary) if (xfc->drawing == xfc->primary)
{ {
if (!xfc->remote_app)
{
XCopyArea(xfc->display, bitmap->pixmap, xfc->drawable, xfc->gc,
memblt->nXSrc, memblt->nYSrc, memblt->nWidth, memblt->nHeight,
memblt->nLeftRect, memblt->nTopRect);
}
gdi_InvalidateRegion(xfc->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth, memblt->nHeight); gdi_InvalidateRegion(xfc->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth, memblt->nHeight);
} }
@ -852,12 +816,6 @@ void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
if (xfc->drawing == xfc->primary) if (xfc->drawing == xfc->primary)
{ {
if (!xfc->remote_app)
{
XCopyArea(xfc->display, bitmap->pixmap, xfc->drawable, xfc->gc,
mem3blt->nXSrc, mem3blt->nYSrc, mem3blt->nWidth, mem3blt->nHeight,
mem3blt->nLeftRect, mem3blt->nTopRect);
}
gdi_InvalidateRegion(xfc->hdc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth, mem3blt->nHeight); gdi_InvalidateRegion(xfc->hdc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth, mem3blt->nHeight);
} }
@ -919,8 +877,7 @@ void xf_gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc)
if (xfc->drawing == xfc->primary) if (xfc->drawing == xfc->primary)
{ {
XFillPolygon(xfc->display, xfc->drawable, xfc->gc, xf_gdi_invalidate_poly_region(xfc, points, npoints, TRUE);
points, npoints, Complex, CoordModePrevious);
} }
XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFunction(xfc->display, xfc->gc, GXcopy);
@ -981,20 +938,6 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
XSetFillStyle(xfc->display, xfc->gc, FillTiled); XSetFillStyle(xfc->display, xfc->gc, FillTiled);
XSetTile(xfc->display, xfc->gc, pattern); XSetTile(xfc->display, xfc->gc, pattern);
XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y);
XFillPolygon(xfc->display, xfc->drawing, xfc->gc,
points, npoints, Complex, CoordModePrevious);
if (xfc->drawing == xfc->primary)
{
XFillPolygon(xfc->display, xfc->drawable, xfc->gc,
points, npoints, Complex, CoordModePrevious);
}
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
XSetTSOrigin(xfc->display, xfc->gc, 0, 0);
XFreePixmap(xfc->display, pattern);
} }
else else
{ {
@ -1009,20 +952,20 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled); XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled);
XSetStipple(xfc->display, xfc->gc, pattern); XSetStipple(xfc->display, xfc->gc, pattern);
}
XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y); XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y);
XFillPolygon(xfc->display, xfc->drawing, xfc->gc, XFillPolygon(xfc->display, xfc->drawing, xfc->gc,
points, npoints, Complex, CoordModePrevious); points, npoints, Complex, CoordModePrevious);
if (xfc->drawing == xfc->primary)
{
XFillPolygon(xfc->display, xfc->drawable, xfc->gc,
points, npoints, Complex, CoordModePrevious);
}
XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetFillStyle(xfc->display, xfc->gc, FillSolid);
XSetTSOrigin(xfc->display, xfc->gc, 0, 0); XSetTSOrigin(xfc->display, xfc->gc, 0, 0);
XFreePixmap(xfc->display, pattern); XFreePixmap(xfc->display, pattern);
if (xfc->drawing == xfc->primary)
{
xf_gdi_invalidate_poly_region(xfc, points, npoints, TRUE);
} }
} }
else else
@ -1174,18 +1117,12 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* cmd)
XFree(image); XFree(image);
} }
/* Copy the updated region from backstore to the window. */ /* Invalidate the updated region */
for (i = 0; i < message->numRects; i++) for (i = 0; i < message->numRects; i++)
{ {
tx = message->rects[i].x + cmd->destLeft; tx = message->rects[i].x + cmd->destLeft;
ty = message->rects[i].y + cmd->destTop; ty = message->rects[i].y + cmd->destTop;
if (!xfc->remote_app)
{
XCopyArea(xfc->display, xfc->primary, xfc->drawable, xfc->gc,
tx, ty, message->rects[i].width, message->rects[i].height, tx, ty);
}
xf_gdi_surface_update_frame(xfc, tx, ty, message->rects[i].width, message->rects[i].height); xf_gdi_surface_update_frame(xfc, tx, ty, message->rects[i].width, message->rects[i].height);
} }
@ -1224,13 +1161,6 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* cmd)
XFree(image); XFree(image);
if (!xfc->remote_app)
{
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc,
cmd->destLeft, cmd->destTop, cmd->width, cmd->height,
cmd->destLeft, cmd->destTop);
}
xf_gdi_surface_update_frame(xfc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height); xf_gdi_surface_update_frame(xfc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height);
XSetClipMask(xfc->display, xfc->gc, None); XSetClipMask(xfc->display, xfc->gc, None);
@ -1263,13 +1193,6 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* cmd)
cmd->width, cmd->height); cmd->width, cmd->height);
XFree(image); XFree(image);
if (!xfc->remote_app)
{
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc,
cmd->destLeft, cmd->destTop,
cmd->width, cmd->height, cmd->destLeft, cmd->destTop);
}
xf_gdi_surface_update_frame(xfc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height); xf_gdi_surface_update_frame(xfc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height);
XSetClipMask(xfc->display, xfc->gc, None); XSetClipMask(xfc->display, xfc->gc, None);

View File

@ -84,9 +84,21 @@ int xf_OutputUpdate(xfContext* xfc)
surface->width, surface->height, surface->data, surface->format, surface->scanline, 0, 0, NULL); surface->width, surface->height, surface->data, surface->format, surface->scanline, 0, 0, NULL);
} }
#ifdef WITH_XRENDER
if (xfc->settings->SmartSizing || xfc->settings->MultiTouchGestures)
{
XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image,
extents->left, extents->top, extents->left, extents->top, width, height);
xf_draw_screen(xfc, extents->left, extents->top, width, height);
}
else
#endif
{
XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image, XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image,
extents->left, extents->top, extents->left, extents->top, width, height); extents->left, extents->top, extents->left, extents->top, width, height);
} }
}
region16_clear(&(xfc->invalidRegion)); region16_clear(&(xfc->invalidRegion));

View File

@ -276,13 +276,12 @@ void xf_input_detect_pan(xfContext* xfc)
{ {
if (px_vector > PAN_THRESHOLD) if (px_vector > PAN_THRESHOLD)
{ {
{ {
PanningChangeEventArgs e; PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp"); EventArgsInit(&e, "xfreerdp");
e.XPan = 5; e.dx = 5;
e.YPan = 0; e.dy = 0;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
} }
@ -298,8 +297,8 @@ void xf_input_detect_pan(xfContext* xfc)
PanningChangeEventArgs e; PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp"); EventArgsInit(&e, "xfreerdp");
e.XPan = -5; e.dx = -5;
e.YPan = 0; e.dy = 0;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
} }
@ -321,8 +320,8 @@ void xf_input_detect_pan(xfContext* xfc)
PanningChangeEventArgs e; PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp"); EventArgsInit(&e, "xfreerdp");
e.XPan = 0; e.dx = 0;
e.YPan = 5; e.dy = 5;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
} }
@ -338,8 +337,8 @@ void xf_input_detect_pan(xfContext* xfc)
PanningChangeEventArgs e; PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp"); EventArgsInit(&e, "xfreerdp");
e.XPan = 0; e.dx = 0;
e.YPan = -5; e.dy = -5;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
} }
@ -358,7 +357,7 @@ void xf_input_detect_pinch(xfContext* xfc)
double zoom; double zoom;
double delta; double delta;
ResizeWindowEventArgs e; ZoomingChangeEventArgs e;
if (active_contacts != 2) if (active_contacts != 2)
{ {
@ -400,21 +399,11 @@ void xf_input_detect_pinch(xfContext* xfc)
if (z_vector > ZOOM_THRESHOLD) if (z_vector > ZOOM_THRESHOLD)
{ {
xfc->settings->ScalingFactor -= 0.05;
if (xfc->settings->ScalingFactor < 0.8)
xfc->settings->ScalingFactor = 0.8;
EventArgsInit(&e, "xfreerdp"); EventArgsInit(&e, "xfreerdp");
e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; e.dx = e.dy = -10;
e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; PubSub_OnZoomingChange(((rdpContext*) xfc)->pubSub, xfc, &e);
xf_transform_window(xfc);
PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e);
xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE);
z_vector = 0; z_vector = 0;
px_vector = 0; px_vector = 0;
py_vector = 0; py_vector = 0;
z_vector = 0; z_vector = 0;
@ -422,21 +411,11 @@ void xf_input_detect_pinch(xfContext* xfc)
if (z_vector < -ZOOM_THRESHOLD) if (z_vector < -ZOOM_THRESHOLD)
{ {
xfc->settings->ScalingFactor += 0.05;
if (xfc->settings->ScalingFactor > 1.2)
xfc->settings->ScalingFactor = 1.2;
EventArgsInit(&e, "xfreerdp"); EventArgsInit(&e, "xfreerdp");
e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; e.dx = e.dy = 10;
e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; PubSub_OnZoomingChange(((rdpContext*) xfc)->pubSub, xfc, &e);
xf_transform_window(xfc);
PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e);
xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE);
z_vector = 0; z_vector = 0;
px_vector = 0; px_vector = 0;
py_vector = 0; py_vector = 0;
z_vector = 0; z_vector = 0;
@ -620,6 +599,8 @@ int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype)
x = (int) event->event_x; x = (int) event->event_x;
y = (int) event->event_y; y = (int) event->event_y;
xf_event_adjust_coordinates(xfc, &x, &y);
if (evtype == XI_TouchBegin) if (evtype == XI_TouchBegin)
{ {
WLog_DBG(TAG, "TouchBegin: %d", touchId); WLog_DBG(TAG, "TouchBegin: %d", touchId);

View File

@ -468,139 +468,80 @@ BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym)
} }
} }
if (keysym == XK_period) #if 0 /* set to 1 to enable multi touch gesture simulation via keyboard */
#ifdef WITH_XRENDER
if (!xfc->remote_app && xfc->settings->MultiTouchGestures)
{ {
if (mod.Ctrl && mod.Alt) if (mod.Ctrl && mod.Alt)
{ {
/* Zoom In (scale larger) */ int pdx = 0;
int pdy = 0;
double s = xfc->settings->ScalingFactor; int zdx = 0;
int zdy = 0;
s += 0.1;
if (s > 2.0)
s = 2.0;
xfc->settings->ScalingFactor = s;
xfc->currentWidth = xfc->originalWidth * s;
xfc->currentHeight = xfc->originalHeight * s;
xf_transform_window(xfc);
switch(keysym)
{ {
ResizeWindowEventArgs e; case XK_0: /* Ctrl-Alt-0: Reset scaling and panning */
xfc->scaledWidth = xfc->width;
EventArgsInit(&e, "xfreerdp"); xfc->scaledHeight = xfc->height;
e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; xfc->offset_x = 0;
e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; xfc->offset_y = 0;
PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); if (!xfc->fullscreen && (xfc->width != xfc->window->width ||
xfc->height != xfc->window->height))
{
xf_ResizeDesktopWindow(xfc, xfc->window, xfc->width, xfc->height);
} }
xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE); xf_draw_screen(xfc, 0, 0, xfc->width, xfc->height);
return TRUE; return TRUE;
}
case XK_1: /* Ctrl-Alt-1: Zoom in */
zdx = zdy = 10;
break;
case XK_2: /* Ctrl-Alt-2: Zoom out */
zdx = zdy = -10;
break;
case XK_3: /* Ctrl-Alt-3: Pan left */
pdx = -10;
break;
case XK_4: /* Ctrl-Alt-4: Pan right */
pdx = 10;
break;
case XK_5: /* Ctrl-Alt-5: Pan up */
pdy = -10;
break;
case XK_6: /* Ctrl-Alt-6: Pan up */
pdy = 10;
break;
} }
if (keysym == XK_comma) if (pdx != 0 || pdy != 0)
{
if (mod.Ctrl && mod.Alt)
{
/* Zoom Out (scale smaller) */
double s = xfc->settings->ScalingFactor;
s -= 0.1;
if (s < 0.5)
s = 0.5;
xfc->settings->ScalingFactor = s;
xfc->currentWidth = xfc->originalWidth * s;
xfc->currentHeight = xfc->originalHeight * s;
xf_transform_window(xfc);
{
ResizeWindowEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor;
e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor;
PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e);
}
xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE);
return TRUE;
}
}
if (keysym == XK_KP_4)
{
if (mod.Ctrl && mod.Alt)
{
{ {
PanningChangeEventArgs e; PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp"); EventArgsInit(&e, "xfreerdp");
e.XPan = -5; e.dx = pdx;
e.YPan = 0; e.dy = pdy;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
return TRUE;
} }
if (zdx != 0 || zdy != 0)
{
ZoomingChangeEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.dx = zdx;
e.dy = zdy;
PubSub_OnZoomingChange(((rdpContext*) xfc)->pubSub, xfc, &e);
return TRUE; return TRUE;
} }
} }
if (keysym == XK_KP_6)
{
if (mod.Ctrl && mod.Alt)
{
{
PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.XPan = 5;
e.YPan = 0;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
}
return TRUE;
}
}
if (keysym == XK_KP_8)
{
if (mod.Ctrl && mod.Alt)
{
{
PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.XPan = 0;
e.YPan = -5;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
}
return TRUE;
}
}
if (keysym == XK_KP_2)
{
if (mod.Ctrl && mod.Alt)
{
{
PanningChangeEventArgs e;
EventArgsInit(&e, "xfreerdp");
e.XPan = 0;
e.YPan = 5;
PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e);
}
return TRUE;
}
} }
#endif /* WITH_XRENDER defined */
#endif /* pinch/zoom/pan simulation */
return FALSE; return FALSE;
} }

View File

@ -412,11 +412,20 @@ void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, int hei
if (size_hints) if (size_hints)
{ {
size_hints->flags = PMinSize | PMaxSize; size_hints->flags = PMinSize | PMaxSize;
size_hints->min_width = size_hints->max_width = xfc->width;
size_hints->min_height = size_hints->max_height = xfc->height; size_hints->min_width = size_hints->max_width = width;
size_hints->min_height = size_hints->max_height = height;
#ifdef WITH_XRENDER
if (xfc->settings->SmartSizing)
{
size_hints->min_width = size_hints->min_height = 1;
size_hints->max_width = size_hints->max_height = 16384;
}
#endif
XSetWMNormalHints(xfc->display, window->handle, size_hints); XSetWMNormalHints(xfc->display, window->handle, size_hints);
XResizeWindow(xfc->display, window->handle, xfc->width, xfc->height); XResizeWindow(xfc->display, window->handle, width, height);
XFree(size_hints); XFree(size_hints);
} }
} }

View File

@ -132,15 +132,14 @@ struct xf_context
UINT16 frame_x2; UINT16 frame_x2;
UINT16 frame_y2; UINT16 frame_y2;
int originalWidth;
int originalHeight;
int currentWidth;
int currentHeight;
int XInputOpcode; int XInputOpcode;
BOOL enableScaling;
#ifdef WITH_XRENDER
int scaledWidth;
int scaledHeight;
int offset_x; int offset_x;
int offset_y; int offset_y;
#endif
BOOL focused; BOOL focused;
BOOL use_xinput; BOOL use_xinput;
@ -250,8 +249,8 @@ enum XF_EXIT_CODE
void xf_lock_x11(xfContext* xfc, BOOL display); void xf_lock_x11(xfContext* xfc, BOOL display);
void xf_unlock_x11(xfContext* xfc, BOOL display); void xf_unlock_x11(xfContext* xfc, BOOL display);
void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h, BOOL scale); BOOL xf_picture_transform_required(xfContext* xfc);
void xf_transform_window(xfContext* xfc); void xf_draw_screen(xfContext* xfc, int x, int y, int w, int h);
FREERDP_API DWORD xf_exit_code_from_disconnect_reason(DWORD reason); FREERDP_API DWORD xf_exit_code_from_disconnect_reason(DWORD reason);

View File

@ -66,7 +66,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
{ "monitor-list", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT, NULL, NULL, NULL, -1, NULL, "List detected monitors" }, { "monitor-list", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT, NULL, NULL, NULL, -1, NULL, "List detected monitors" },
{ "t", COMMAND_LINE_VALUE_REQUIRED, "<title>", NULL, NULL, -1, "title", "Window title" }, { "t", COMMAND_LINE_VALUE_REQUIRED, "<title>", NULL, NULL, -1, "title", "Window title" },
{ "decorations", COMMAND_LINE_VALUE_BOOL, NULL, NULL, BoolValueTrue, -1, NULL, "Window decorations" }, { "decorations", COMMAND_LINE_VALUE_BOOL, NULL, NULL, BoolValueTrue, -1, NULL, "Window decorations" },
{ "smart-sizing", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Scale remote desktop to window size" }, { "smart-sizing", COMMAND_LINE_VALUE_OPTIONAL, "<width>x<height>", NULL, NULL, -1, NULL, "Scale remote desktop to window size" },
{ "a", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, "addin", "Addin" }, { "a", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, "addin", "Addin" },
{ "vc", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Static virtual channel" }, { "vc", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Static virtual channel" },
{ "dvc", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Dynamic virtual channel" }, { "dvc", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Dynamic virtual channel" },
@ -1344,7 +1344,19 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
} }
CommandLineSwitchCase(arg, "smart-sizing") CommandLineSwitchCase(arg, "smart-sizing")
{ {
settings->SmartSizing = arg->Value ? TRUE : FALSE; settings->SmartSizing = TRUE;
if (arg->Value)
{
str = _strdup(arg->Value);
if ((p = strchr(str, 'x')))
{
*p = '\0';
settings->SmartSizingWidth = atoi(str);
settings->SmartSizingHeight = atoi(&p[1]);
}
free(str);
}
} }
CommandLineSwitchCase(arg, "bpp") CommandLineSwitchCase(arg, "bpp")
{ {

View File

@ -43,13 +43,14 @@ DEFINE_EVENT_BEGIN(ResizeWindow)
DEFINE_EVENT_END(ResizeWindow) DEFINE_EVENT_END(ResizeWindow)
DEFINE_EVENT_BEGIN(PanningChange) DEFINE_EVENT_BEGIN(PanningChange)
int XPan; int dx;
int YPan; int dy;
DEFINE_EVENT_END(PanningChange) DEFINE_EVENT_END(PanningChange)
DEFINE_EVENT_BEGIN(ScalingFactorChange) DEFINE_EVENT_BEGIN(ZoomingChange)
double ScalingFactor; int dx;
DEFINE_EVENT_END(ScalingFactorChange) int dy;
DEFINE_EVENT_END(ZoomingChange)
DEFINE_EVENT_BEGIN(LocalResizeWindow) DEFINE_EVENT_BEGIN(LocalResizeWindow)
int width; int width;

View File

@ -661,7 +661,8 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_SmartSizing 1551 #define FreeRDP_SmartSizing 1551
#define FreeRDP_XPan 1552 #define FreeRDP_XPan 1552
#define FreeRDP_YPan 1553 #define FreeRDP_YPan 1553
#define FreeRDP_ScalingFactor 1554 #define FreeRDP_SmartSizingWidth 1554
#define FreeRDP_SmartSizingHeight 1555
#define FreeRDP_SoftwareGdi 1601 #define FreeRDP_SoftwareGdi 1601
#define FreeRDP_LocalConnection 1602 #define FreeRDP_LocalConnection 1602
#define FreeRDP_AuthenticationOnly 1603 #define FreeRDP_AuthenticationOnly 1603
@ -1068,8 +1069,9 @@ struct rdp_settings
ALIGN64 BOOL SmartSizing; /* 1551 */ ALIGN64 BOOL SmartSizing; /* 1551 */
ALIGN64 int XPan; /* 1552 */ ALIGN64 int XPan; /* 1552 */
ALIGN64 int YPan; /* 1553 */ ALIGN64 int YPan; /* 1553 */
ALIGN64 double ScalingFactor; /* 1554 */ ALIGN64 UINT32 SmartSizingWidth; /* 1554 */
UINT64 padding1601[1601 - 1555]; /* 1555 */ ALIGN64 UINT32 SmartSizingHeight; /* 1555 */
UINT64 padding1601[1601 - 1556]; /* 1556 */
/* Miscellaneous */ /* Miscellaneous */
ALIGN64 BOOL SoftwareGdi; /* 1601 */ ALIGN64 BOOL SoftwareGdi; /* 1601 */
@ -1453,9 +1455,6 @@ FREERDP_API int freerdp_set_param_uint64(rdpSettings* settings, int id, UINT64 p
FREERDP_API char* freerdp_get_param_string(rdpSettings* settings, int id); FREERDP_API char* freerdp_get_param_string(rdpSettings* settings, int id);
FREERDP_API int freerdp_set_param_string(rdpSettings* settings, int id, const char* param); FREERDP_API int freerdp_set_param_string(rdpSettings* settings, int id, const char* param);
FREERDP_API double freerdp_get_param_double(rdpSettings* settings, int id);
FREERDP_API int freerdp_set_param_double(rdpSettings* settings, int id, double param);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1834,6 +1834,12 @@ UINT32 freerdp_get_param_uint32(rdpSettings* settings, int id)
case FreeRDP_DynamicChannelArraySize: case FreeRDP_DynamicChannelArraySize:
return settings->DynamicChannelArraySize; return settings->DynamicChannelArraySize;
case FreeRDP_SmartSizingWidth:
return settings->SmartSizingWidth;
case FreeRDP_SmartSizingHeight:
return settings->SmartSizingHeight;
default: default:
WLog_ERR(TAG, "freerdp_get_param_uint32: unknown id: %d", id); WLog_ERR(TAG, "freerdp_get_param_uint32: unknown id: %d", id);
return 0; return 0;
@ -2587,35 +2593,3 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param)
return 0; return 0;
} }
double freerdp_get_param_double(rdpSettings* settings, int id)
{
switch (id)
{
case FreeRDP_ScalingFactor:
return settings->ScalingFactor;
default:
WLog_ERR(TAG, "unknown id: %d", id);
return 0;
}
}
int freerdp_set_param_double(rdpSettings* settings, int id, double param)
{
switch (id)
{
case FreeRDP_ScalingFactor:
settings->ScalingFactor = param;
break;
default:
return -1;
}
/* Mark field as modified */
settings->SettingsModified[id] = 1;
return 0;
}

View File

@ -385,7 +385,7 @@ static wEventType FreeRDP_Events[] =
DEFINE_EVENT_ENTRY(LocalResizeWindow) DEFINE_EVENT_ENTRY(LocalResizeWindow)
DEFINE_EVENT_ENTRY(EmbedWindow) DEFINE_EVENT_ENTRY(EmbedWindow)
DEFINE_EVENT_ENTRY(PanningChange) DEFINE_EVENT_ENTRY(PanningChange)
DEFINE_EVENT_ENTRY(ScalingFactorChange) DEFINE_EVENT_ENTRY(ZoomingChange)
DEFINE_EVENT_ENTRY(ErrorInfo) DEFINE_EVENT_ENTRY(ErrorInfo)
DEFINE_EVENT_ENTRY(Terminate) DEFINE_EVENT_ENTRY(Terminate)
DEFINE_EVENT_ENTRY(ConnectionResult) DEFINE_EVENT_ENTRY(ConnectionResult)