diff --git a/gdk/gdkmarshalers.list b/gdk/gdkmarshalers.list index adc37b985c..d70b190dcc 100644 --- a/gdk/gdkmarshalers.list +++ b/gdk/gdkmarshalers.list @@ -4,5 +4,6 @@ VOID:POINTER,POINTER,POINTER OBJECT:VOID OBJECT:DOUBLE,DOUBLE BOXED:INT,INT +BOXED:POINTER VOID:DOUBLE,DOUBLE,POINTER,POINTER VOID:POINTER,POINTER,BOOLEAN,BOOLEAN diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index a474443a49..b8eaff19d5 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -33,9 +33,9 @@ #include "gdkeventtranslator.h" #include "gdkframeclockprivate.h" #include "gdkinternals.h" -#include "gdkinternals.h" #include "gdkdeviceprivate.h" #include "gdkkeysprivate.h" +#include "gdkmarshalers.h" #include "xsettings-client.h" #include "gdkclipboard-x11.h" #include "gdkprivate-x11.h" @@ -76,6 +76,11 @@ #include #endif +enum { + TRANSLATE_EVENT, + LAST_SIGNAL +}; + typedef struct _GdkErrorTrap GdkErrorTrap; struct _GdkErrorTrap @@ -176,6 +181,8 @@ static const char *const precache_atoms[] = { static char *gdk_sm_client_id; +static guint signals[LAST_SIGNAL] = { 0 }; + G_DEFINE_TYPE_WITH_CODE (GdkX11Display, gdk_x11_display, GDK_TYPE_DISPLAY, G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR, gdk_x11_display_event_translator_init)) @@ -3156,6 +3163,24 @@ gdk_x11_display_get_last_seen_time (GdkDisplay *display) return gdk_x11_get_server_time (GDK_X11_DISPLAY (display)->leader_gdk_window); } +static gboolean +gdk_x11_display_translate_event_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy) +{ + GdkEvent *event; + + event = g_value_get_boxed (handler_return); + if (event == NULL) + return TRUE; + + if (event->type != GDK_NOTHING) + g_value_set_boxed (return_accu, event); + + return FALSE; +} + static void gdk_x11_display_class_init (GdkX11DisplayClass * class) { @@ -3216,5 +3241,53 @@ gdk_x11_display_class_init (GdkX11DisplayClass * class) display_class->get_last_seen_time = gdk_x11_display_get_last_seen_time; display_class->set_cursor_theme = gdk_x11_display_set_cursor_theme; + class->translate_event = gdk_event_source_translate_event; + + /** + * GdkX11Display::translate-event: + * @display: the object on which the signal is emitted + * @xevent: a pointer to the XEvent to process + * + * The ::translate-event signal is a low level signal that is emitted + * whenever an XEvent needs to be translated to a #GdkEvent. + * + * Handlers to this signal can return one of 3 possible values: + * + * 1. %NULL + * + * This will result in the next handler being invoked. + * + * 2. a #GdkEvent + * + * This will result in no further handlers being invoked and the returned + * event being enqueued for further processing by GDK. + * + * 3. gdk_event_new(GDK_NOTHING) + * + * If a handler returns an event of type GDK_NOTHING, the event will be + * discarded and no further handlers will be invoked. Use this if your + * function completely handled the @xevent. + * + * Note that the default handler for this function is GDK's own event + * translation mechanism, so by translating an event that GDK expects to + * translate, you may break GDK and/or GTK+ in interesting ways, so you + * have to know what you're doing. + * + * If you are interested in X GenericEvents, bear in mind that + * XGetEventData() has been already called on the event, and + * XFreeEventData() will be called afterwards. + * + * Returns: The translated #GdkEvent or %NULL to invoke further handlers to + * translate the event. + */ + signals[TRANSLATE_EVENT] = + g_signal_new (g_intern_static_string ("translate-event"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdkX11DisplayClass, translate_event), + gdk_x11_display_translate_event_accumulator, NULL, + _gdk_marshal_BOXED__POINTER, + GDK_TYPE_EVENT, 1, G_TYPE_POINTER); + _gdk_x11_windowing_init (); } diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h index 6da7cf634a..555b8551e7 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -26,8 +26,9 @@ #include "gdkkeys.h" #include "gdkwindow.h" #include "gdkinternals.h" -#include "gdkx11screen.h" #include "gdkx11devicemanager.h" +#include "gdkx11display.h" +#include "gdkx11screen.h" #include #include @@ -166,6 +167,9 @@ struct _GdkX11Display struct _GdkX11DisplayClass { GdkDisplayClass parent_class; + + GdkEvent * (* translate_event) (GdkX11Display *display, + const XEvent *event); }; GdkX11Screen *_gdk_x11_display_screen_for_xrootwin (GdkDisplay *display, diff --git a/gdk/x11/gdkeventsource.c b/gdk/x11/gdkeventsource.c index 5de5b7b7f1..ccf4c59a4c 100644 --- a/gdk/x11/gdkeventsource.c +++ b/gdk/x11/gdkeventsource.c @@ -263,29 +263,23 @@ handle_touch_synthetic_crossing (GdkEvent *event) } } -static GdkEvent * -gdk_event_source_translate_event (GdkEventSource *event_source, - XEvent *xevent) +GdkEvent * +gdk_event_source_translate_event (GdkX11Display *x11_display, + const XEvent *xevent) { + GdkEventSource *event_source = (GdkEventSource *) x11_display->event_source; GdkEvent *event = gdk_event_new (GDK_NOTHING); GdkFilterReturn result = GDK_FILTER_CONTINUE; + GdkDisplay *display = GDK_DISPLAY (x11_display); GdkEventTranslator *event_translator; GdkWindow *filter_window; Display *dpy; GdkX11Screen *x11_screen; gpointer cache; - x11_screen = GDK_X11_DISPLAY (event_source->display)->screen; + x11_screen = GDK_X11_DISPLAY (display)->screen; - dpy = GDK_DISPLAY_XDISPLAY (event_source->display); - -#ifdef HAVE_XGENERICEVENTS - /* Get cookie data here so it's available - * to every event translator and event filter. - */ - if (xevent->type == GenericEvent) - XGetEventData (dpy, &xevent->xcookie); -#endif + dpy = GDK_DISPLAY_XDISPLAY (display); filter_window = gdk_event_source_get_filter_window (event_source, xevent, &event_translator); @@ -300,7 +294,7 @@ gdk_event_source_translate_event (GdkEventSource *event_source, xevent->xany.window == x11_screen->xsettings_manager_window) result = gdk_xsettings_manager_window_filter (xevent, event, x11_screen); - cache = gdk_window_cache_get (event_source->display); + cache = gdk_window_cache_get (display); if (cache) { if (result == GDK_FILTER_CONTINUE) @@ -328,11 +322,6 @@ gdk_event_source_translate_event (GdkEventSource *event_source, if (result != GDK_FILTER_CONTINUE) { -#ifdef HAVE_XGENERICEVENTS - if (xevent->type == GenericEvent) - XFreeEventData (dpy, &xevent->xcookie); -#endif - if (result == GDK_FILTER_REMOVE) { gdk_event_free (event); @@ -349,7 +338,7 @@ gdk_event_source_translate_event (GdkEventSource *event_source, { /* Event translator was gotten before in get_filter_window() */ event = _gdk_x11_event_translator_translate (event_translator, - event_source->display, + display, xevent); } else @@ -362,7 +351,7 @@ gdk_event_source_translate_event (GdkEventSource *event_source, list = list->next; event = _gdk_x11_event_translator_translate (translator, - event_source->display, + display, xevent); } } @@ -386,11 +375,6 @@ gdk_event_source_translate_event (GdkEventSource *event_source, handle_touch_synthetic_crossing (event); } -#ifdef HAVE_XGENERICEVENTS - if (xevent->type == GenericEvent) - XFreeEventData (dpy, &xevent->xcookie); -#endif - return event; } @@ -449,11 +433,6 @@ _gdk_x11_display_queue_events (GdkDisplay *display) GdkEvent *event; XEvent xevent; Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); - GdkEventSource *event_source; - GdkX11Display *display_x11; - - display_x11 = GDK_X11_DISPLAY (display); - event_source = (GdkEventSource *) display_x11->event_source; while (!_gdk_event_queue_find_first (display) && XPending (xdisplay)) { @@ -469,9 +448,26 @@ _gdk_x11_display_queue_events (GdkDisplay *display) continue; } - event = gdk_event_source_translate_event (event_source, &xevent); +#ifdef HAVE_XGENERICEVENTS + /* Get cookie data here so it's available + * to every event translator and event filter. + */ + if (xevent.type == GenericEvent) + XGetEventData (xdisplay, &xevent.xcookie); +#endif - if (event) + g_signal_emit_by_name (display, "translate-event", &xevent, &event); + +#ifdef HAVE_XGENERICEVENTS + if (xevent.type == GenericEvent) + XFreeEventData (xdisplay, &xevent.xcookie); +#endif + + if (event && event->type == GDK_NOTHING) + { + gdk_event_free (event); + } + else if (event) { GList *node; diff --git a/gdk/x11/gdkeventsource.h b/gdk/x11/gdkeventsource.h index 8338fddfcb..5398f4f936 100644 --- a/gdk/x11/gdkeventsource.h +++ b/gdk/x11/gdkeventsource.h @@ -19,6 +19,7 @@ #define __GDK_X11_EVENT_SOURCE_H__ #include "gdkeventtranslator.h" +#include "gdkx11display.h" G_BEGIN_DECLS @@ -37,6 +38,9 @@ void gdk_x11_event_source_select_events (GdkEventSource *source, GdkEventMask event_mask, unsigned int extra_x_mask); +GdkEvent *gdk_event_source_translate_event (GdkX11Display *display, + const XEvent *xevent); + G_END_DECLS