diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index d63771c02..d674ce0ef 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -496,9 +496,9 @@ void xf_toggle_fullscreen(xfContext* xfc) xf_unlock_x11(xfc, TRUE); + EventArgsInit(&e, "xfreerdp"); e.state = xfc->fullscreen ? FREERDP_WINDOW_STATE_FULLSCREEN : 0; - - PubSub_OnEvent(((rdpContext*) xfc)->pubSub, "WindowStateChange", xfc, (wEventArgs*) &e); + PubSub_OnWindowStateChange(((rdpContext*) xfc)->pubSub, xfc, &e); } void xf_lock_x11(xfContext* xfc, BOOL display) @@ -894,10 +894,10 @@ BOOL xf_post_connect(freerdp* instance) xf_cliprdr_init(xfc, channels); + EventArgsInit(&e, "xfreerdp"); e.width = settings->DesktopWidth; e.height = settings->DesktopHeight; - - PubSub_OnEvent(((rdpContext*) xfc)->pubSub, "ResizeWindow", xfc, (wEventArgs*) &e); + PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); return TRUE; } @@ -1567,9 +1567,10 @@ void freerdp_client_reset_scale(rdpContext* context) xfc->scale = 1.0; XResizeWindow(xfc->display, xfc->window->handle, xfc->originalWidth * xfc->scale, xfc->originalHeight * xfc->scale); + EventArgsInit(&e, "xfreerdp"); e.width = (int) xfc->originalWidth * xfc->scale; e.height = (int) xfc->originalHeight * xfc->scale; - PubSub_OnEvent(((rdpContext*) xfc)->pubSub, "ResizeWindow", xfc, (wEventArgs*) &e); + PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); xf_draw_screen_scaled(xfc); } diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index 77a24bd68..8c3f29fc9 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -130,32 +130,29 @@ static BOOL xf_event_VisibilityNotify(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_MotionNotify(xfContext* xfc, XEvent* event, BOOL app) +BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window window, BOOL app) { - int x, y; rdpInput* input; Window childWindow; input = xfc->instance->input; - x = event->xmotion.x; - y = event->xmotion.y; if (!xfc->settings->MouseMotion) { - if ((event->xmotion.state & (Button1Mask | Button2Mask | Button3Mask)) == 0) + if ((state & (Button1Mask | Button2Mask | Button3Mask)) == 0) return TRUE; - } + } if (app) { /* make sure window exists */ - if (xf_rdpWindowFromWindow(xfc, event->xmotion.window) == 0) + if (xf_rdpWindowFromWindow(xfc, window) == 0) { return TRUE; } /* Translate to desktop coordinates */ - XTranslateCoordinates(xfc->display, event->xmotion.window, + XTranslateCoordinates(xfc->display, window, RootWindowOfScreen(xfc->screen), x, y, &x, &y, &childWindow); } @@ -177,40 +174,38 @@ static BOOL xf_event_MotionNotify(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app) +static BOOL xf_event_MotionNotify(xfContext* xfc, XEvent* event, BOOL app) +{ + return xf_generic_MotionNotify(xfc, event->xmotion.x, event->xmotion.y, + event->xmotion.state, event->xmotion.window, app); +} + +BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, Window window, BOOL app) { - int x, y; int flags; BOOL wheel; BOOL extended; rdpInput* input; Window childWindow; - input = xfc->instance->input; - - x = 0; - y = 0; flags = 0; wheel = FALSE; extended = FALSE; + input = xfc->instance->input; - switch (event->xbutton.button) + printf("ButtonPress: x: %d y: %d button: %d\n", x, y, button); + + switch (button) { case 1: - x = event->xbutton.x; - y = event->xbutton.y; flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1; break; case 2: - x = event->xbutton.x; - y = event->xbutton.y; flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3; break; case 3: - x = event->xbutton.x; - y = event->xbutton.y; flags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2; break; @@ -228,8 +223,6 @@ static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app) case 8: /* back */ case 97: /* Xming */ extended = TRUE; - x = event->xbutton.x; - y = event->xbutton.y; flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON1; break; @@ -237,8 +230,6 @@ static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app) case 9: /* forward */ case 112: /* Xming */ extended = TRUE; - x = event->xbutton.x; - y = event->xbutton.y; flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON2; break; @@ -260,12 +251,12 @@ static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app) if (app) { /* make sure window exists */ - if (xf_rdpWindowFromWindow(xfc, event->xbutton.window) == 0) + if (xf_rdpWindowFromWindow(xfc, window) == 0) { return TRUE; } /* Translate to desktop coordinates */ - XTranslateCoordinates(xfc->display, event->xbutton.window, + XTranslateCoordinates(xfc->display, window, RootWindowOfScreen(xfc->screen), x, y, &x, &y, &childWindow); } @@ -287,38 +278,36 @@ static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_ButtonRelease(xfContext* xfc, XEvent* event, BOOL app) +static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app) +{ + return xf_generic_ButtonPress(xfc, event->xbutton.x, event->xbutton.y, + event->xbutton.button, event->xbutton.window, app); +} + +BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, Window window, BOOL app) { - int x, y; int flags; + BOOL wheel; BOOL extended; rdpInput* input; Window childWindow; + flags = 0; + wheel = FALSE; + extended = FALSE; input = xfc->instance->input; - x = 0; - y = 0; - flags = 0; - extended = FALSE; - - switch (event->xbutton.button) + switch (button) { case 1: - x = event->xbutton.x; - y = event->xbutton.y; flags = PTR_FLAGS_BUTTON1; break; case 2: - x = event->xbutton.x; - y = event->xbutton.y; flags = PTR_FLAGS_BUTTON3; break; case 3: - x = event->xbutton.x; - y = event->xbutton.y; flags = PTR_FLAGS_BUTTON2; break; @@ -326,8 +315,6 @@ static BOOL xf_event_ButtonRelease(xfContext* xfc, XEvent* event, BOOL app) case 8: case 97: extended = TRUE; - x = event->xbutton.x; - y = event->xbutton.y; flags = PTR_XFLAGS_BUTTON1; break; @@ -335,8 +322,6 @@ static BOOL xf_event_ButtonRelease(xfContext* xfc, XEvent* event, BOOL app) case 9: case 112: extended = TRUE; - x = event->xbutton.x; - y = event->xbutton.y; flags = PTR_XFLAGS_BUTTON2; break; @@ -350,12 +335,12 @@ static BOOL xf_event_ButtonRelease(xfContext* xfc, XEvent* event, BOOL app) if (app) { /* make sure window exists */ - if (xf_rdpWindowFromWindow(xfc, event->xbutton.window) == NULL) + if (xf_rdpWindowFromWindow(xfc, window) == NULL) { return TRUE; } /* Translate to desktop coordinates */ - XTranslateCoordinates(xfc->display, event->xbutton.window, + XTranslateCoordinates(xfc->display, window, RootWindowOfScreen(xfc->screen), x, y, &x, &y, &childWindow); } @@ -376,6 +361,12 @@ static BOOL xf_event_ButtonRelease(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } +static BOOL xf_event_ButtonRelease(xfContext* xfc, XEvent* event, BOOL app) +{ + return xf_generic_ButtonRelease(xfc, event->xbutton.x, event->xbutton.y, + event->xbutton.button, event->xbutton.window, app); +} + static BOOL xf_event_KeyPress(xfContext* xfc, XEvent* event, BOOL app) { KeySym keysym; diff --git a/client/X11/xf_event.h b/client/X11/xf_event.h index 4a6492f37..05d4e3e04 100644 --- a/client/X11/xf_event.h +++ b/client/X11/xf_event.h @@ -28,4 +28,8 @@ BOOL xf_event_process(freerdp* instance, XEvent* event); void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...); +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_ButtonRelease(xfContext* xfc, int x, int y, int button, Window window, BOOL app); + #endif /* __XF_EVENT_H */ diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c index 2cfffd922..4b7309821 100644 --- a/client/X11/xf_input.c +++ b/client/X11/xf_input.c @@ -27,6 +27,8 @@ #include +#include "xf_event.h" + #include "xf_input.h" #ifdef WITH_XI @@ -54,6 +56,22 @@ double z_vector; int xinput_opcode; int scale_cnt; +const char* xf_input_get_class_string(int class) +{ + if (class == XIKeyClass) + return "XIKeyClass"; + else if (class == XIButtonClass) + return "XIButtonClass"; + else if (class == XIValuatorClass) + return "XIValuatorClass"; + else if (class == XIScrollClass) + return "XIScrollClass"; + else if (class == XITouchClass) + return "XITouchClass"; + + return "XIUnknownClass"; +} + int xf_input_init(xfContext* xfc, Window window) { int i, j; @@ -63,7 +81,7 @@ int xf_input_init(xfContext* xfc, Window window) int minor = 2; Status xstatus; XIDeviceInfo* info; - XIEventMask evmasks[8]; + XIEventMask evmasks[64]; int opcode, event, error; BYTE masks[8][XIMaskLen(XI_LASTEVENT)]; @@ -88,10 +106,14 @@ int xf_input_init(xfContext* xfc, Window window) return -1; } + if (xfc->settings->MultiTouchInput) + xfc->use_xinput = TRUE; + info = XIQueryDevice(xfc->display, XIAllDevices, &ndevices); for (i = 0; i < ndevices; i++) { + BOOL touch = FALSE; XIDeviceInfo* dev = &info[i]; for (j = 0; j < dev->num_classes; j++) @@ -99,28 +121,56 @@ int xf_input_init(xfContext* xfc, Window window) XIAnyClassInfo* class = dev->classes[j]; XITouchClassInfo* t = (XITouchClassInfo*) class; - if (class->type != XITouchClass) - continue; + if ((class->type == XITouchClass) && (t->mode == XIDirectTouch) && + (strcmp(dev->name, "Virtual core pointer") != 0)) + { + touch = TRUE; + } + } - if (t->mode != XIDirectTouch) - continue; + for (j = 0; j < dev->num_classes; j++) + { + XIAnyClassInfo* class = dev->classes[j]; + XITouchClassInfo* t = (XITouchClassInfo*) class; - if (strcmp(dev->name, "Virtual core pointer") == 0) - continue; - - printf("%s %s touch device (id: %d, mode: %d), supporting %d touches.\n", - dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", - dev->deviceid, t->mode, t->num_touches); + if (xfc->settings->MultiTouchInput) + { + printf("%s (%d) \"%s\" id: %d\n", + xf_input_get_class_string(class->type), + class->type, dev->name, dev->deviceid); + } evmasks[nmasks].mask = masks[nmasks]; evmasks[nmasks].mask_len = sizeof(masks[0]); ZeroMemory(masks[nmasks], sizeof(masks[0])); evmasks[nmasks].deviceid = dev->deviceid; - XISetMask(masks[nmasks], XI_TouchBegin); - XISetMask(masks[nmasks], XI_TouchUpdate); - XISetMask(masks[nmasks], XI_TouchEnd); - nmasks++; + if ((class->type == XITouchClass) && (t->mode == XIDirectTouch) && + (strcmp(dev->name, "Virtual core pointer") != 0)) + { + if (xfc->settings->MultiTouchInput) + { + printf("%s %s touch device (id: %d, mode: %d), supporting %d touches.\n", + dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", + dev->deviceid, t->mode, t->num_touches); + } + + XISetMask(masks[nmasks], XI_TouchBegin); + XISetMask(masks[nmasks], XI_TouchUpdate); + XISetMask(masks[nmasks], XI_TouchEnd); + nmasks++; + } + + if (xfc->use_xinput) + { + if (!touch && (class->type == XIButtonClass)) + { + XISetMask(masks[nmasks], XI_ButtonPress); + XISetMask(masks[nmasks], XI_ButtonRelease); + XISetMask(masks[nmasks], XI_Motion); + nmasks++; + } + } } } @@ -197,9 +247,10 @@ void xf_input_detect_pinch(xfContext* xfc) XResizeWindow(xfc->display, xfc->window->handle, xfc->originalWidth * xfc->scale, xfc->originalHeight * xfc->scale); + EventArgsInit(&e, "xfreerdp"); e.width = (int) xfc->originalWidth * xfc->scale; e.height = (int) xfc->originalHeight * xfc->scale; - PubSub_OnEvent(((rdpContext*) xfc)->pubSub, "ResizeWindow", xfc, (wEventArgs*) &e); + PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); z_vector = 0; } @@ -213,9 +264,10 @@ void xf_input_detect_pinch(xfContext* xfc) XResizeWindow(xfc->display, xfc->window->handle, xfc->originalWidth * xfc->scale, xfc->originalHeight * xfc->scale); + EventArgsInit(&e, "xfreerdp"); e.width = (int) xfc->originalWidth * xfc->scale; e.height = (int) xfc->originalHeight * xfc->scale; - PubSub_OnEvent(((rdpContext*) xfc)->pubSub, "ResizeWindow", xfc, (wEventArgs*) &e); + PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); z_vector = 0; } @@ -365,6 +417,34 @@ int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype) return 0; } +int xf_input_event(xfContext* xfc, XIDeviceEvent* event, int evtype) +{ + return TRUE; + + switch (evtype) + { + case XI_ButtonPress: + printf("ButtonPress\n"); + xf_generic_ButtonPress(xfc, (int) event->event_x, (int) event->event_y, + event->detail, event->event, xfc->remote_app); + break; + + case XI_ButtonRelease: + printf("ButtonRelease\n"); + xf_generic_ButtonRelease(xfc, (int) event->event_x, (int) event->event_y, + event->detail, event->event, xfc->remote_app); + break; + + case XI_Motion: + printf("Motion\n"); + xf_generic_MotionNotify(xfc, (int) event->event_x, (int) event->event_y, + event->detail, event->event, xfc->remote_app); + break; + } + + return 0; +} + int xf_input_handle_event_remote(xfContext* xfc, XEvent* event) { XGenericEventCookie* cookie = &event->xcookie; @@ -388,6 +468,7 @@ int xf_input_handle_event_remote(xfContext* xfc, XEvent* event) break; default: + xf_input_event(xfc, cookie->data, cookie->evtype); break; } } diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 802c9732f..37f187487 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -115,6 +115,7 @@ struct xf_context BOOL enableScaling; BOOL focused; + BOOL use_xinput; BOOL mouse_active; BOOL suppress_output; BOOL fullscreen_toggle; diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index 70ab66706..640e25e4f 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -1189,8 +1189,9 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) // Mark field as modified settings->settings_modified[id] = 1; + EventArgsInit(&e, "freerdp"); e.id = id; - PubSub_OnEvent(context->pubSub, "ParamChange", context->instance, (wEventArgs*) &e); + PubSub_OnParamChange(context->pubSub, context->instance, &e); return -1; } @@ -1830,8 +1831,9 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param) // Mark field as modified settings->settings_modified[id] = 1; + EventArgsInit(&e, "freerdp"); e.id = id; - PubSub_OnEvent(context->pubSub, "ParamChange", context->instance, (wEventArgs*) &e); + PubSub_OnParamChange(context->pubSub, context->instance, &e); return 0; } @@ -1871,8 +1873,9 @@ int freerdp_set_param_uint64(rdpSettings* settings, int id, UINT64 param) // Mark field as modified settings->settings_modified[id] = 1; + EventArgsInit(&e, "freerdp"); e.id = id; - PubSub_OnEvent(context->pubSub, "ParamChange", context->instance, (wEventArgs*) &e); + PubSub_OnParamChange(context->pubSub, context->instance, &e); return 0; } @@ -2208,8 +2211,9 @@ int freerdp_set_param_string(rdpSettings* settings, int id, char* param) // Mark field as modified settings->settings_modified[id] = 1; + EventArgsInit(&e, "freerdp"); e.id = id; - PubSub_OnEvent(context->pubSub, "ParamChange", context->instance, (wEventArgs*) &e); + PubSub_OnParamChange(context->pubSub, context->instance, &e); return 0; } diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 3d82652ea..a10b921b2 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -507,8 +507,9 @@ BOOL rdp_recv_set_error_info_data_pdu(rdpRdp* rdp, wStream* s) rdp_print_errinfo(rdp->errorInfo); + EventArgsInit(&e, "freerdp"); e.code = rdp->errorInfo; - PubSub_OnEvent(context->pubSub, "ErrorInfo", context, (wEventArgs*) &e); + PubSub_OnErrorInfo(context->pubSub, context, &e); } return TRUE; diff --git a/winpr/include/winpr/collections.h b/winpr/include/winpr/collections.h index 9a028fd87..a54e2cc87 100644 --- a/winpr/include/winpr/collections.h +++ b/winpr/include/winpr/collections.h @@ -343,7 +343,8 @@ WINPR_API void MessagePipe_Free(wMessagePipe* pipe); struct _wEventArgs { - DWORD size; + DWORD Size; + const char* Sender; }; typedef struct _wEventArgs wEventArgs; @@ -360,16 +361,36 @@ struct _wEvent }; typedef struct _wEvent wEvent; +#define EventArgsInit(_event_args, _sender) \ + memset(_event_args, 0, sizeof(*_event_args)); \ + ((wEventArgs*) _event_args)->Size = sizeof(*_event_args); \ + ((wEventArgs*) _event_args)->Sender = _sender + #define DEFINE_EVENT_HANDLER(_name) \ typedef void (*p ## _name ## EventHandler)(void* context, _name ## EventArgs* e) +#define DEFINE_EVENT_RAISE(_name) \ + static INLINE int PubSub_On ## _name (wPubSub* pubSub, void* context, _name ## EventArgs* e) { \ + return PubSub_OnEvent(pubSub, #_name, context, (wEventArgs*) e); } + +#define DEFINE_EVENT_SUBSCRIBE(_name) \ + static INLINE int PubSub_Subscribe ## _name (wPubSub* pubSub, p ## _name ## EventHandler EventHandler) { \ + return PubSub_Subscribe(pubSub, #_name, (pEventHandler) EventHandler); } + +#define DEFINE_EVENT_UNSUBSCRIBE(_name) \ + static INLINE int PubSub_Unsubscribe ## _name (wPubSub* pubSub, p ## _name ## EventHandler EventHandler) { \ + return PubSub_Unsubscribe(pubSub, #_name, (pEventHandler) EventHandler); } + #define DEFINE_EVENT_BEGIN(_name) \ typedef struct _ ## _name ## EventArgs { \ wEventArgs e; #define DEFINE_EVENT_END(_name) \ } _name ## EventArgs; \ - DEFINE_EVENT_HANDLER(_name); + DEFINE_EVENT_HANDLER(_name); \ + DEFINE_EVENT_RAISE(_name); \ + DEFINE_EVENT_SUBSCRIBE(_name); \ + DEFINE_EVENT_UNSUBSCRIBE(_name); #define DEFINE_EVENT_ENTRY(_name) \ { #_name, { sizeof( _name ## EventArgs) }, 0, { \ diff --git a/winpr/libwinpr/utils/collections/PubSub.c b/winpr/libwinpr/utils/collections/PubSub.c index 9c4358263..59b0e7af3 100644 --- a/winpr/libwinpr/utils/collections/PubSub.c +++ b/winpr/libwinpr/utils/collections/PubSub.c @@ -25,6 +25,11 @@ #include +/** + * Events (C# Programming Guide) + * http://msdn.microsoft.com/en-us/library/awbftdfh.aspx + */ + /** * Properties */ @@ -171,7 +176,7 @@ int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, wEvent if (event->EventHandlers[index]) { event->EventHandlers[index](context, e); - status = 1; + status++; } } }