From 91a55ae7411ddc666b3bd2cba123edacc8eb4c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 8 May 2013 21:51:16 -0400 Subject: [PATCH] xfreerdp: integrate corey's multitouch code --- client/X11/CMakeLists.txt | 13 ++ client/X11/xf_event.c | 43 +++++- client/X11/xf_input.c | 308 ++++++++++++++++++++++++++++++++++++++ client/X11/xf_input.h | 41 +++++ client/X11/xf_interface.c | 86 ++++++++++- client/X11/xf_interface.h | 1 + client/X11/xf_window.c | 68 +-------- client/X11/xfreerdp.h | 9 ++ 8 files changed, 497 insertions(+), 72 deletions(-) create mode 100644 client/X11/xf_input.c create mode 100644 client/X11/xf_input.h diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index 96f4ec419..7ccad8f37 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -30,6 +30,8 @@ set(${MODULE_PREFIX}_SRCS xf_tsmf.h xf_event.c xf_event.h + xf_input.c + xf_input.h xf_cliprdr.c xf_cliprdr.h xf_monitor.c @@ -99,12 +101,17 @@ set(XI_FEATURE_TYPE "RECOMMENDED") set(XI_FEATURE_PURPOSE "input") set(XI_FEATURE_DESCRIPTION "X11 input extension") +set(XRENDER_FEATURE_TYPE "RECOMMENDED") +set(XRENDER_FEATURE_PURPOSE "rendering") +set(XRENDER_FEATURE_DESCRIPTION "X11 render extension") + find_feature(XShm ${XSHM_FEATURE_TYPE} ${XSHM_FEATURE_PURPOSE} ${XSHM_FEATURE_DESCRIPTION}) find_feature(Xinerama ${XINERAMA_FEATURE_TYPE} ${XINERAMA_FEATURE_PURPOSE} ${XINERAMA_FEATURE_DESCRIPTION}) find_feature(Xext ${XEXT_FEATURE_TYPE} ${XEXT_FEATURE_PURPOSE} ${XEXT_FEATURE_DESCRIPTION}) find_feature(Xcursor ${XCURSOR_FEATURE_TYPE} ${XCURSOR_FEATURE_PURPOSE} ${XCURSOR_FEATURE_DESCRIPTION}) find_feature(Xv ${XV_FEATURE_TYPE} ${XV_FEATURE_PURPOSE} ${XV_FEATURE_DESCRIPTION}) find_feature(Xi ${XI_FEATURE_TYPE} ${XI_FEATURE_PURPOSE} ${XI_FEATURE_DESCRIPTION}) +find_feature(Xrender ${XRENDER_FEATURE_TYPE} ${XRENDER_FEATURE_PURPOSE} ${XRENDER_FEATURE_DESCRIPTION}) if(WITH_XINERAMA) add_definitions(-DWITH_XINERAMA) @@ -136,6 +143,12 @@ if(WITH_XI) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XI_LIBRARIES}) endif() +if(WITH_XRENDER) + add_definitions(-DWITH_XRENDER) + include_directories(${XRENDER_INCLUDE_DIRS}) + set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XRENDER_LIBRARIES}) +endif() + include_directories(${CMAKE_SOURCE_DIR}/resources) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index f8ebbf110..d6226ca67 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -29,6 +29,7 @@ #include "xf_rail.h" #include "xf_window.h" #include "xf_cliprdr.h" +#include "xf_input.h" #include "xf_event.h" @@ -95,7 +96,15 @@ static BOOL xf_event_Expose(xfInfo* xfi, XEvent* event, BOOL app) if (!app) { - XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y); + if (xfi->scale != 1.0) + { + xf_draw_screen_scaled(xfi); + } + else + { + XCopyArea(xfi->display, xfi->primary, + xfi->window->handle, xfi->gc, x, y, w, h, x, y); + } } else { @@ -151,6 +160,13 @@ static BOOL xf_event_MotionNotify(xfInfo* xfi, XEvent* event, BOOL app) x, y, &x, &y, &childWindow); } + if (xfi->scale != 1.0) + { + /* Take scaling in to consideration */ + x = (int) (x * (1.0 / xfi->scale)); + y = (int) (y * (1.0 / xfi->scale)); + } + input->MouseEvent(input, PTR_FLAGS_MOVE, x, y); if (xfi->fullscreen) @@ -254,6 +270,13 @@ static BOOL xf_event_ButtonPress(xfInfo* xfi, XEvent* event, BOOL app) x, y, &x, &y, &childWindow); } + if (xfi->scale != 1.0) + { + /* Take scaling in to consideration */ + x = (int) (x * (1.0 / xfi->scale)); + y = (int) (y * (1.0 / xfi->scale)); + } + if (extended) input->ExtendedMouseEvent(input, flags, x, y); else @@ -337,6 +360,13 @@ static BOOL xf_event_ButtonRelease(xfInfo* xfi, XEvent* event, BOOL app) x, y, &x, &y, &childWindow); } + if (xfi->scale != 1.0) + { + /* Take scaling in to consideration */ + x = (int) (x * (1.0 / xfi->scale)); + y = (int) (y * (1.0 / xfi->scale)); + } + if (extended) input->ExtendedMouseEvent(input, flags, x, y); else @@ -523,6 +553,15 @@ static BOOL xf_event_ConfigureNotify(xfInfo* xfi, XEvent* event, BOOL app) rdpWindow* window; rdpRail* rail = ((rdpContext*) xfi->context)->rail; + if (xfi->width != event->xconfigure.width) + { + xfi->scale = (double) event->xconfigure.width / (double) xfi->originalWidth; + xfi->currentWidth = event->xconfigure.width; + xfi->currentHeight = event->xconfigure.width; + + xf_draw_screen_scaled(xfi); + } + window = window_list_get_by_extra_id(rail->list, (void*) event->xconfigure.window); if (window != NULL) @@ -977,6 +1016,8 @@ BOOL xf_event_process(freerdp* instance, XEvent* event) break; } + xf_input_handle_event(xfi, event); + XSync(xfi->display, FALSE); return status; diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c new file mode 100644 index 000000000..c90cb38f4 --- /dev/null +++ b/client/X11/xf_input.c @@ -0,0 +1,308 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * X11 Input + * + * Copyright 2013 Corey Clayton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WITH_XI +#include +#endif + +#include + +#include "xf_input.h" + +#ifdef WITH_XI + +#define MAX_CONTACTS 2 + +typedef struct touch_contact +{ + int id; + int count; + double pos_x; + double pos_y; + double last_x; + double last_y; + +} touchContact; + +touchContact contacts[MAX_CONTACTS]; + +int active_contacts; +XIDeviceEvent lastEvent; +double firstDist = -1.0; +double lastDist; +double z_vector; +int xinput_opcode; +int scale_cnt; + +int xf_input_init(xfInfo* xfi, Window window) +{ + int i, j; + int ndevices; + int major = 2; + int minor = 2; + Status xstatus; + XIEventMask evmask; + XIDeviceInfo* info; + int opcode, event, error; + unsigned char mask[XIMaskLen(XI_LASTEVENT)]; + + active_contacts = 0; + ZeroMemory(contacts, sizeof(touchContact) * MAX_CONTACTS); + + if (!XQueryExtension(xfi->display, "XInputExtension", &opcode, &event, &error)) + { + printf("XInput extension not available.\n"); + return -1; + } + + xfi->XInputOpcode = opcode; + + XIQueryVersion(xfi->display, &major, &minor); + + if (major * 1000 + minor < 2002) + { + printf("Server does not support XI 2.2\n"); + return -1; + } + + info = XIQueryDevice(xfi->display, XIAllDevices, &ndevices); + + for (i = 0; i < ndevices; i++) + { + XIDeviceInfo* dev = &info[i]; + + for (j = 0; j < dev->num_classes; j++) + { + XIAnyClassInfo* class = dev->classes[j]; + //XITouchClassInfo* t = (XITouchClassInfo*) class; + + if (class->type != XITouchClass) + continue; + + //printf("%s %s touch device, supporting %d touches.\n", + // dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", t->num_touches); + } + } + + evmask.mask = mask; + evmask.mask_len = sizeof(mask); + ZeroMemory(mask, sizeof(mask)); + evmask.deviceid = XIAllDevices; + + XISetMask(mask, XI_TouchBegin); + XISetMask(mask, XI_TouchUpdate); + XISetMask(mask, XI_TouchEnd); + + xstatus = XISelectEvents(xfi->display, window, &evmask, 1); + + return -1; +} + +BOOL xf_input_is_duplicate(XIDeviceEvent* event) +{ + if ( (lastEvent.time == event->time) && + (lastEvent.detail == event->detail) && + (lastEvent.event_x == event->event_x) && + (lastEvent.event_y == event->event_y) ) + { + return TRUE; + } + + return FALSE; +} + +void xf_input_save_last_event(XIDeviceEvent* event) +{ + lastEvent.time = event->time; + lastEvent.detail = event->detail; + lastEvent.event_x = event->event_x; + lastEvent.event_y = event->event_y; +} + +void xf_input_detect_pinch(xfInfo* xfi) +{ + double dist; + double zoom; + double delta; + + if (active_contacts != 2) + { + firstDist = -1.0; + return; + } + + /* first calculate the distance */ + dist = sqrt(pow(contacts[1].pos_x - contacts[0].last_x, 2.0) + + pow(contacts[1].pos_y - contacts[0].last_y, 2.0)); + + /* if this is the first 2pt touch */ + if (firstDist <= 0) + { + firstDist = dist; + lastDist = firstDist; + scale_cnt = 0; + z_vector = 0; + } + else + { + delta = lastDist - dist; + + /* compare the current distance to the first one */ + zoom = (dist / firstDist); + + z_vector += delta; + //printf("d: %.2f\n", delta); + + lastDist = dist; + + if (z_vector > 10) + { + xfi->scale -= 0.05; + + if (xfi->scale < 0.5) + xfi->scale = 0.5; + + XResizeWindow(xfi->display, xfi->window->handle, xfi->originalWidth * xfi->scale, xfi->originalHeight * xfi->scale); + IFCALL(xfi->client->OnResizeWindow, xfi->instance, xfi->originalWidth * xfi->scale, xfi->originalHeight * xfi->scale); + + z_vector = 0; + } + + if (z_vector < -10) + { + xfi->scale += 0.05; + + if (xfi->scale > 1.5) + xfi->scale = 1.5; + + XResizeWindow(xfi->display, xfi->window->handle, xfi->originalWidth * xfi->scale, xfi->originalHeight * xfi->scale); + IFCALL(xfi->client->OnResizeWindow, xfi->instance, xfi->originalWidth * xfi->scale, xfi->originalHeight * xfi->scale); + + z_vector = 0; + } + } +} + +#endif + +int xf_input_handle_event(xfInfo* xfi, XEvent* event) +{ +#ifdef WITH_XI + XGenericEventCookie* cookie = &event->xcookie; + + XGetEventData(xfi->display, cookie); + + if ((cookie->type == GenericEvent) && (cookie->extension == xfi->XInputOpcode)) + { + switch(cookie->evtype) + { + case XI_TouchBegin: + if (xf_input_is_duplicate(cookie->data) == FALSE) + xf_input_touch_begin(xfi, cookie->data); + xf_input_save_last_event(cookie->data); + break; + + case XI_TouchUpdate: + if (xf_input_is_duplicate(cookie->data) == FALSE) + xf_input_touch_update(xfi, cookie->data); + xf_input_save_last_event(cookie->data); + break; + + case XI_TouchEnd: + if (xf_input_is_duplicate(cookie->data) == FALSE) + xf_input_touch_end(xfi, cookie->data); + xf_input_save_last_event(cookie->data); + break; + + default: + printf("unhandled xi type= %d\n", cookie->evtype); + break; + } + } + + XFreeEventData(xfi->display,cookie); +#endif + return 0; +} + +#ifdef WITH_XI +void xf_input_touch_begin(xfInfo* xfi, XIDeviceEvent* event) +{ + int i; + + for (i = 0; i < MAX_CONTACTS; i++) + { + if (contacts[i].id == 0) + { + contacts[i].id = event->detail; + contacts[i].count = 1; + contacts[i].pos_x = event->event_x; + contacts[i].pos_y = event->event_y; + + active_contacts++; + break; + } + } +} + +void xf_input_touch_update(xfInfo* xfi, XIDeviceEvent* event) +{ + int i; + + for (i = 0; i < MAX_CONTACTS; i++) + { + if (contacts[i].id == event->detail) + { + contacts[i].count++; + contacts[i].last_x = contacts[i].pos_x; + contacts[i].last_y = contacts[i].pos_y; + contacts[i].pos_x = event->event_x; + contacts[i].pos_y = event->event_y; + + xf_input_detect_pinch(xfi); + + break; + } + } +} + +void xf_input_touch_end(xfInfo* xfi, XIDeviceEvent* event) +{ + int i; + + for (i = 0; i < MAX_CONTACTS; i++) + { + if (contacts[i].id == event->detail) + { + contacts[i].id = 0; + contacts[i].count = 0; + //contacts[i].pos_x = (int)event->event_x; + //contacts[i].pos_y = (int)event->event_y; + + active_contacts--; + break; + } + } +} + +#endif diff --git a/client/X11/xf_input.h b/client/X11/xf_input.h new file mode 100644 index 000000000..6c540fef5 --- /dev/null +++ b/client/X11/xf_input.h @@ -0,0 +1,41 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * X11 Input + * + * Copyright 2013 Corey Clayton + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __XF_INPUT_H +#define __XF_INPUT_H + +#include "xf_interface.h" +#include "xfreerdp.h" + +#ifdef WITH_XI +#include +#endif + +int xf_input_init(xfInfo* xfi, Window win); +int xf_input_handle_event(xfInfo* xfi, XEvent* event); + +#ifdef WITH_XI + +void xf_input_touch_begin(xfInfo* xfi, XIDeviceEvent* event); +void xf_input_touch_update(xfInfo* xfi, XIDeviceEvent* event); +void xf_input_touch_end(xfInfo* xfi, XIDeviceEvent* event); + +#endif + +#endif diff --git a/client/X11/xf_interface.c b/client/X11/xf_interface.c index 1ffa502ba..c1d5f87e7 100644 --- a/client/X11/xf_interface.c +++ b/client/X11/xf_interface.c @@ -32,6 +32,14 @@ #include #endif +#ifdef WITH_XI +#include +#endif + +#ifdef WITH_XRENDER +#include +#endif + #include #include #include @@ -79,6 +87,35 @@ static long xv_port = 0; static const size_t password_size = 512; +void xf_draw_screen_scaled(xfInfo* xfi) +{ + XTransform transform; + Picture windowPicture; + Picture primaryPicture; + XRenderPictureAttributes pa; + XRenderPictFormat* picFormat; + + picFormat = XRenderFindStandardFormat(xfi->display, PictStandardRGB24); + pa.subwindow_mode = IncludeInferiors; + primaryPicture = XRenderCreatePicture(xfi->display, xfi->primary, picFormat, CPSubwindowMode, &pa); + windowPicture = XRenderCreatePicture(xfi->display, xfi->window->handle, picFormat, CPSubwindowMode, &pa); + + transform.matrix[0][0] = XDoubleToFixed(1); + 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(xfi->scale); + + XRenderSetPictureTransform(xfi->display, primaryPicture, &transform); + XRenderComposite(xfi->display, PictOpSrc, primaryPicture, 0, windowPicture, 0, 0, 0, 0, 0, 0, xfi->currentWidth, xfi->currentHeight); +} + void xf_context_new(freerdp* instance, rdpContext* context) { context->channels = freerdp_channels_new(); @@ -121,7 +158,15 @@ void xf_sw_end_paint(rdpContext* context) xf_lock_x11(xfi, FALSE); XPutImage(xfi->display, xfi->primary, xfi->gc, xfi->image, x, y, x, y, w, h); - XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y); + + if (xfi->scale != 1.0) + { + xf_draw_screen_scaled(xfi); + } + else + { + XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y); + } xf_unlock_x11(xfi, FALSE); } @@ -147,7 +192,15 @@ void xf_sw_end_paint(rdpContext* context) h = cinvalid[i].h; XPutImage(xfi->display, xfi->primary, xfi->gc, xfi->image, x, y, x, y, w, h); - XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y); + + if (xfi->scale != 1.0) + { + xf_draw_screen_scaled(xfi); + } + else + { + XCopyArea(xfi->display, xfi->primary, xfi->window->handle, xfi->gc, x, y, w, h, x, y); + } } XFlush(xfi->display); @@ -231,7 +284,14 @@ void xf_hw_end_paint(rdpContext* context) xf_lock_x11(xfi, FALSE); - XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, x, y, w, h, x, y); + if (xfi->scale != 1.0) + { + xf_draw_screen_scaled(xfi); + } + else + { + XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, x, y, w, h, x, y); + } xf_unlock_x11(xfi, FALSE); } @@ -256,7 +316,14 @@ void xf_hw_end_paint(rdpContext* context) w = cinvalid[i].w; h = cinvalid[i].h; - XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, x, y, w, h, x, y); + if (xfi->scale != 1.0) + { + xf_draw_screen_scaled(xfi); + } + else + { + XCopyArea(xfi->display, xfi->primary, xfi->drawable, xfi->gc, x, y, w, h, x, y); + } } XFlush(xfi->display); @@ -768,6 +835,12 @@ BOOL xf_post_connect(freerdp* instance) } } + xfi->originalWidth = settings->DesktopWidth; + xfi->originalHeight = settings->DesktopHeight; + xfi->currentWidth = xfi->originalWidth; + xfi->currentHeight = xfi->originalWidth; + xfi->scale = 1.0; + xfi->width = settings->DesktopWidth; xfi->height = settings->DesktopHeight; @@ -1481,6 +1554,11 @@ rdpClient* freerdp_client_get_interface(cfInfo* cfi) return cfi->client; } +double freerdp_client_get_scale(xfInfo* xfi) +{ + return xfi->scale; +} + xfInfo* freerdp_client_new(int argc, char** argv) { int index; diff --git a/client/X11/xf_interface.h b/client/X11/xf_interface.h index c27e7948f..6707f4be7 100644 --- a/client/X11/xf_interface.h +++ b/client/X11/xf_interface.h @@ -55,6 +55,7 @@ FREERDP_API int freerdp_client_stop(cfInfo* cfi); FREERDP_API freerdp* freerdp_client_get_instance(cfInfo* cfi); FREERDP_API HANDLE freerdp_client_get_thread(cfInfo* cfi); FREERDP_API rdpClient* freerdp_client_get_interface(cfInfo* cfi); +FREERDP_API double freerdp_client_get_scale(xfInfo* xfi); FREERDP_API cfInfo* freerdp_client_new(int argc, char** argv); FREERDP_API void freerdp_client_free(cfInfo* cfi); diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index bb9e1c95b..79427f5b0 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -44,6 +44,7 @@ #ifdef WITH_XI #include +#include "xf_input.h" #endif #ifdef WITH_DEBUG_X11 @@ -325,73 +326,6 @@ static void xf_SetWindowPID(xfInfo* xfi, xfWindow* window, pid_t pid) 32, PropModeReplace, (unsigned char *)&pid, 1); } -int xf_input_init(xfInfo* xfi, Window window) -{ - int i, j; - int ndevices; - int major = 2; - int minor = 2; - Status xstatus; - XIEventMask evmask; - XIDeviceInfo* info; - int opcode, event, error; - XIGrabModifiers mods = { 1 }; - unsigned char mask[XIMaskLen(XI_LASTEVENT)]; - - if (!XQueryExtension(xfi->display, "XInputExtension", &opcode, &event, &error)) - { - printf("XInput extension not available.\n"); - return -1; - } - - XIQueryVersion(xfi->display, &major, &minor); - - if (major * 1000 + minor < 2002) - { - printf("Server does not support XI 2.2\n"); - return -1; - } - - info = XIQueryDevice(xfi->display, XIAllDevices, &ndevices); - - for (i = 0; i < ndevices; i++) - { - XIDeviceInfo* dev = &info[i]; - - for (j = 0; j < dev->num_classes; j++) - { - XIAnyClassInfo* class = dev->classes[j]; - XITouchClassInfo* t = (XITouchClassInfo*) class; - - if (class->type != XITouchClass) - continue; - - printf("%s %s touch device, supporting %d touches.\n", - dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", t->num_touches); - } - } - - evmask.mask = mask; - evmask.mask_len = sizeof(mask); - ZeroMemory(mask, sizeof(mask)); - evmask.deviceid = XIAllDevices; - - XISetMask(mask, XI_TouchBegin); - XISetMask(mask, XI_TouchUpdate); - XISetMask(mask, XI_TouchEnd); - - xstatus = XISelectEvents(xfi->display, window, &evmask, 1); - //XIClearMask(mask, XI_TouchOwnership); - - mods.modifiers = XIAnyModifier; - - //XIGrabTouchBegin(xfi->display, XIAllMasterDevices, window, XINoOwnerEvents, &evmask, 1, &mods); - - XSync(xfi->display, False); - - return -1; -} - xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height, BOOL decorations) { xfWindow* window; diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 9f79c07d3..392436c7f 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -114,6 +114,13 @@ struct xf_info UINT16 frame_x2; UINT16 frame_y2; + double scale; + int originalWidth; + int originalHeight; + int currentWidth; + int currentHeight; + int XInputOpcode; + BOOL focused; BOOL mouse_active; BOOL suppress_output; @@ -204,6 +211,8 @@ enum XF_EXIT_CODE void xf_lock_x11(xfInfo* xfi, BOOL display); void xf_unlock_x11(xfInfo* xfi, BOOL display); +void xf_draw_screen_scaled(xfInfo* xfi); + DWORD xf_exit_code_from_disconnect_reason(DWORD reason); #endif /* __XFREERDP_H */