summaryrefslogtreecommitdiff
path: root/gdk
diff options
context:
space:
mode:
authorРуслан Ижбулатов <lrn1986@gmail.com>2018-03-24 16:39:13 +0000
committerРуслан Ижбулатов <lrn1986@gmail.com>2018-03-29 17:43:55 +0000
commitef01e6ee52aa3b0f4776bdeb524d0967a0f3dd0f (patch)
tree7e2c3eb562ec4517bd986bc943541765b5ff547b /gdk
parent38b4c8d1fa868441fc1ec83d9242b42c26c9ca19 (diff)
downloadgtk+-ef01e6ee52aa3b0f4776bdeb524d0967a0f3dd0f.tar.gz
GDK W32: Adapt to event filter removal
Add a new W32 backend-specific message filtering mechanism. Works roughly the same way old event filtering did, but without events (events are GDK/X11 concept that never really made sense on W32), so there's no functionality for 'altering' events being emitted. If an event needs to be emitted in response to a message do it yourself. Implemented like this, it should give better performance than if we were to use GLib signals for this, since W32 sends a LOT of messages (unlike X11, which doesn't send events as often) all the time, and invoking the signal machinery on *each* message would probably be bad. https://bugzilla.gnome.org/show_bug.cgi?id=773299
Diffstat (limited to 'gdk')
-rw-r--r--gdk/win32/gdkdisplay-win32.c124
-rw-r--r--gdk/win32/gdkdisplay-win32.h13
-rw-r--r--gdk/win32/gdkdrop-win32.c52
-rw-r--r--gdk/win32/gdkevents-win32.c76
-rw-r--r--gdk/win32/gdkwin32display.h44
5 files changed, 234 insertions, 75 deletions
diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c
index b8d3bff7e8..50d6fad098 100644
--- a/gdk/win32/gdkdisplay-win32.c
+++ b/gdk/win32/gdkdisplay-win32.c
@@ -39,6 +39,127 @@
static int debug_indent = 0;
+/**
+ * gdk_win32_display_add_filter:
+ * @display: a #GdkWin32Display
+ * @function: filter callback
+ * @data: data to pass to filter callback
+ *
+ * Adds an event filter to @window, allowing you to intercept messages
+ * before they reach GDK. This is a low-level operation and makes it
+ * easy to break GDK and/or GTK+, so you have to know what you're
+ * doing.
+ **/
+void
+gdk_win32_display_add_filter (GdkWin32Display *display,
+ GdkWin32MessageFilterFunc function,
+ gpointer data)
+{
+ GList *tmp_list;
+ GdkWin32MessageFilter *filter;
+
+ g_return_if_fail (GDK_IS_WIN32_DISPLAY (display));
+
+ tmp_list = display->filters;
+
+ for (tmp_list = display->filters; tmp_list; tmp_list = tmp_list->next)
+ {
+ filter = (GdkWin32MessageFilter *) tmp_list->data;
+
+ if ((filter->function == function) && (filter->data == data))
+ {
+ filter->ref_count++;
+ return;
+ }
+ }
+
+ filter = g_new (GdkWin32MessageFilter, 1);
+ filter->function = function;
+ filter->data = data;
+ filter->ref_count = 1;
+ filter->removed = FALSE;
+
+ display->filters = g_list_append (display->filters, filter);
+}
+
+/**
+ * _gdk_win32_message_filter_unref:
+ * @display: A #GdkWin32Display
+ * @filter: A message filter
+ *
+ * Release a reference to @filter. Note this function may
+ * mutate the list storage, so you need to handle this
+ * if iterating over a list of filters.
+ */
+void
+_gdk_win32_message_filter_unref (GdkWin32Display *display,
+ GdkWin32MessageFilter *filter)
+{
+ GList **filters;
+ GList *tmp_list;
+
+ filters = &display->filters;
+
+ tmp_list = *filters;
+ while (tmp_list)
+ {
+ GdkWin32MessageFilter *iter_filter = tmp_list->data;
+ GList *node;
+
+ node = tmp_list;
+ tmp_list = tmp_list->next;
+
+ if (iter_filter != filter)
+ continue;
+
+ g_assert (iter_filter->ref_count > 0);
+
+ filter->ref_count--;
+ if (filter->ref_count != 0)
+ continue;
+
+ *filters = g_list_remove_link (*filters, node);
+ g_free (filter);
+ g_list_free_1 (node);
+ }
+}
+
+/**
+ * gdk_win32_display_remove_filter:
+ * @display: A #GdkWin32Display
+ * @function: previously-added filter function
+ * @data: user data for previously-added filter function
+ *
+ * Remove a filter previously added with gdk_win32_display_add_filter().
+ */
+void
+gdk_win32_display_remove_filter (GdkWin32Display *display,
+ GdkWin32MessageFilterFunc function,
+ gpointer data)
+{
+ GList *tmp_list;
+ GdkWin32MessageFilter *filter;
+
+ g_return_if_fail (GDK_IS_WIN32_DISPLAY (display));
+
+ tmp_list = display->filters;
+
+ while (tmp_list)
+ {
+ filter = (GdkWin32MessageFilter *) tmp_list->data;
+ tmp_list = tmp_list->next;
+
+ if ((filter->function == function) && (filter->data == data))
+ {
+ filter->removed = TRUE;
+
+ _gdk_win32_message_filter_unref (display, filter);
+
+ return;
+ }
+ }
+}
+
static GdkMonitor *
_gdk_win32_display_find_matching_monitor (GdkWin32Display *win32_display,
GdkMonitor *needle)
@@ -582,6 +703,9 @@ gdk_win32_display_finalize (GObject *object)
g_ptr_array_free (display_win32->monitors, TRUE);
+ while (display_win32->filters)
+ _gdk_win32_message_filter_unref (display_win32, display_win32->filters->data);
+
G_OBJECT_CLASS (gdk_win32_display_parent_class)->finalize (object);
}
diff --git a/gdk/win32/gdkdisplay-win32.h b/gdk/win32/gdkdisplay-win32.h
index 3b73760036..76e4544981 100644
--- a/gdk/win32/gdkdisplay-win32.h
+++ b/gdk/win32/gdkdisplay-win32.h
@@ -101,6 +101,9 @@ struct _GdkWin32Display
/* Cursor Items (GdkCursor->HCURSOR) */
GHashTable *cursors;
GdkCursor *grab_cursor;
+
+ /* Message filters */
+ GList *filters;
};
struct _GdkWin32DisplayClass
@@ -119,4 +122,14 @@ guint _gdk_win32_display_get_monitor_scale_factor (GdkWin32Display *win32_d
HWND hwnd,
gint *dpi);
+typedef struct _GdkWin32MessageFilter GdkWin32MessageFilter;
+
+struct _GdkWin32MessageFilter
+{
+ GdkWin32MessageFilterFunc function;
+ gpointer data;
+ gboolean removed;
+ guint ref_count;
+};
+
#endif /* __GDK_DISPLAY__WIN32_H__ */
diff --git a/gdk/win32/gdkdrop-win32.c b/gdk/win32/gdkdrop-win32.c
index 4fd1f7896c..c88fdd4a39 100644
--- a/gdk/win32/gdkdrop-win32.c
+++ b/gdk/win32/gdkdrop-win32.c
@@ -697,27 +697,32 @@ close_it (gpointer data)
#endif
-static GdkFilterReturn
-gdk_dropfiles_filter (GdkXEvent *xev,
- GdkEvent *event,
- gpointer data)
+static GdkWin32MessageFilterReturn
+gdk_dropfiles_filter (GdkWin32Display *display,
+ MSG *msg,
+ gint *ret_valp,
+ gpointer data)
{
+ GdkSurface *window;
GdkDragContext *context;
GdkWin32DropContext *context_win32;
+ GdkEvent *event;
GString *result;
- MSG *msg = (MSG *) xev;
HANDLE hdrop;
POINT pt;
gint nfiles, i;
gchar *fileName, *linkedFile;
- if (msg->message == WM_DROPFILES)
- {
+ if (msg->message != WM_DROPFILES)
+ return GDK_WIN32_MESSAGE_FILTER_CONTINUE;
+
GDK_NOTE (DND, g_print ("WM_DROPFILES: %p\n", msg->hwnd));
- context = gdk_drop_context_new (gdk_surface_get_display (event->any.surface),
+ window = gdk_win32_handle_table_lookup (msg->hwnd);
+
+ context = gdk_drop_context_new (display,
NULL,
- event->any.surface,
+ window,
GDK_ACTION_COPY,
GDK_DRAG_PROTO_WIN32_DROPFILES);
context_win32 = GDK_WIN32_DROP_CONTEXT (context);
@@ -730,14 +735,18 @@ gdk_dropfiles_filter (GdkXEvent *xev,
context->suggested_action = GDK_ACTION_COPY;
current_dest_drag = context;
- event->any.type = GDK_DROP_START;
- event->dnd.context = current_dest_drag;
- gdk_event_set_device (event, gdk_drag_context_get_device (current_dest_drag));
hdrop = (HANDLE) msg->wParam;
DragQueryPoint (hdrop, &pt);
ClientToScreen (msg->hwnd, &pt);
+ event = gdk_event_new (GDK_DROP_START);
+
+ event->any.send_event = FALSE;
+ g_set_object (&event->dnd.context, context);
+ g_set_object (&event->any.surface, window);
+ gdk_event_set_display (event, display);
+ gdk_event_set_device (event, gdk_drag_context_get_device (context));
event->dnd.x_root = pt.x / context_win32->scale + _gdk_offset_x;
event->dnd.y_root = pt.y / context_win32->scale + _gdk_offset_y;
event->dnd.time = _gdk_win32_get_next_tick (msg->time);
@@ -813,14 +822,25 @@ gdk_dropfiles_filter (GdkXEvent *xev,
g_string_append (result, "\015\012");
}
+ /* FIXME: this call is currently a no-op, but it should
+ * stash the string somewhere, and later produce it,
+ * maybe in response to gdk_win32_drop_context_read_async()?
+ */
_gdk_dropfiles_store (result->str);
g_string_free (result, FALSE);
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
+ _gdk_event_emit (event);
+ gdk_event_free (event);
+
DragFinish (hdrop);
- return GDK_FILTER_TRANSLATE;
- }
- else
- return GDK_FILTER_CONTINUE;
+
+ gdk_display_put_event (display, event);
+ gdk_event_free (event);
+
+ *ret_valp = 0;
+
+ return GDK_WIN32_MESSAGE_FILTER_REMOVE;
}
/* Destination side */
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index dab4d7542f..bb422d91a4 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -1016,43 +1016,30 @@ fill_key_event_string (GdkEvent *event)
}
}
-static GdkFilterReturn
-apply_event_filters (GdkSurface *window,
- MSG *msg,
- GList **filters)
+static GdkWin32MessageFilterReturn
+apply_message_filters (GdkDisplay *display,
+ MSG *msg,
+ gint *ret_valp,
+ GList **filters)
{
- GdkFilterReturn result = GDK_FILTER_CONTINUE;
- GdkEvent *event;
- GdkDisplay *display;
+ GdkWin32MessageFilterReturn result = GDK_WIN32_MESSAGE_FILTER_CONTINUE;
GList *node;
GList *tmp_list;
- event = gdk_event_new (GDK_NOTHING);
- event->any.surface = g_object_ref (window);
- event->any.flags |= GDK_EVENT_PENDING;
-
- display = gdk_display_get_default ();
-
- /* I think GdkFilterFunc semantics require the passed-in event
- * to already be in the queue. The filter func can generate
- * more events and append them after it if it likes.
- */
- node = _gdk_event_queue_append (display, event);
-
tmp_list = *filters;
while (tmp_list)
{
- GdkEventFilter *filter = (GdkEventFilter *) tmp_list->data;
+ GdkWin32MessageFilter *filter = (GdkWin32MessageFilter *) tmp_list->data;
GList *node;
- if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0)
+ if (filter->removed)
{
tmp_list = tmp_list->next;
continue;
}
filter->ref_count++;
- result = filter->function (msg, event, filter->data);
+ result = filter->function (display, msg, ret_valp, filter->data);
/* get the next node after running the function since the
function may add or remove a next node */
@@ -1067,23 +1054,10 @@ apply_event_filters (GdkSurface *window,
g_free (filter);
}
- if (result != GDK_FILTER_CONTINUE)
+ if (result != GDK_WIN32_MESSAGE_FILTER_CONTINUE)
break;
}
- if (result == GDK_FILTER_CONTINUE || result == GDK_FILTER_REMOVE)
- {
- _gdk_event_queue_remove_link (display, node);
- g_list_free_1 (node);
- gdk_event_free (event);
- }
- else /* GDK_FILTER_TRANSLATE */
- {
- event->any.flags &= ~GDK_EVENT_PENDING;
- fixup_event (event);
- GDK_NOTE (EVENTS, _gdk_win32_print_event (event));
- }
-
return result;
}
@@ -2290,22 +2264,19 @@ gdk_event_translate (MSG *msg,
STGMEDIUM *property_change_data;
display = gdk_display_get_default ();
- window = gdk_win32_handle_table_lookup (msg->hwnd);
+ win32_display = GDK_WIN32_DISPLAY (display);
- if (_gdk_default_filters)
+ if (win32_display->filters)
{
- /* Apply global filters */
+ /* Apply display filters */
+ GdkWin32MessageFilterReturn result = apply_message_filters (win32_display, msg, ret_valp, &win32_display->filters);
- GdkFilterReturn result = apply_event_filters (window, msg, &_gdk_default_filters);
-
- /* If result is GDK_FILTER_CONTINUE, we continue as if nothing
- * happened. If it is GDK_FILTER_REMOVE or GDK_FILTER_TRANSLATE,
- * we return TRUE, and DefWindowProcW() will not be called.
- */
- if (result == GDK_FILTER_REMOVE || result == GDK_FILTER_TRANSLATE)
+ if (result == GDK_WIN32_MESSAGE_FILTER_REMOVE)
return TRUE;
}
+ window = gdk_win32_handle_table_lookup (msg->hwnd);
+
if (window == NULL)
{
/* XXX Handle WM_QUIT here ? */
@@ -2342,19 +2313,6 @@ gdk_event_translate (MSG *msg,
*/
#define return GOTO_DONE_INSTEAD
- if (!GDK_SURFACE_DESTROYED (window) && window->filters)
- {
- /* Apply per-window filters */
-
- GdkFilterReturn result = apply_event_filters (window, msg, &window->filters);
-
- if (result == GDK_FILTER_REMOVE || result == GDK_FILTER_TRANSLATE)
- {
- return_val = TRUE;
- goto done;
- }
- }
-
if (msg->message == aerosnap_message)
_gdk_win32_surface_handle_aerosnap (gdk_surface_get_toplevel (window),
(GdkWin32AeroSnapCombo) msg->wParam);
diff --git a/gdk/win32/gdkwin32display.h b/gdk/win32/gdkwin32display.h
index 7e0bf6d31e..fb1aecb6ef 100644
--- a/gdk/win32/gdkwin32display.h
+++ b/gdk/win32/gdkwin32display.h
@@ -61,6 +61,50 @@ GDK_AVAILABLE_IN_ALL
HCURSOR gdk_win32_display_get_hcursor (GdkDisplay *display,
GdkCursor *cursor);
+/**
+ * GdkWin32MessageFilterReturn:
+ * @GDK_WIN32_MESSAGE_FILTER_CONTINUE: event not handled, continue processing.
+ * @GDK_WIN32_MESSAGE_FILTER_REMOVE: event handled, terminate processing.
+ *
+ * Specifies the result of applying a #GdkWin32MessageFilterFunc to a Windows message.
+ */
+typedef enum {
+ GDK_WIN32_MESSAGE_FILTER_CONTINUE, /* Message not handled, continue processing */
+ GDK_WIN32_MESSAGE_FILTER_REMOVE /* Terminate processing, removing message */
+} GdkWin32MessageFilterReturn;
+
+/**
+ * GdkWin32MessageFilterFunc:
+ * @msg: the Windows message to filter.
+ * @return_value: a location to store the return value for the message
+ * @data: (closure): user data set when the filter was installed.
+ *
+ * Specifies the type of function used to filter Windows messages before they are
+ * processed by GDK Win32 backend.
+ *
+ * The @return_value must be set, if this function returns
+ * #GDK_WIN32_MESSAGE_FILTER_REMOVE, otherwise it is ignored.
+ *
+ * The event translation and message filtering are orthogonal -
+ * if a filter wants a GDK event queued, it should do that itself.
+ *
+ * Returns: a #GdkWin32MessageFilterReturn value.
+ */
+typedef GdkWin32MessageFilterReturn (*GdkWin32MessageFilterFunc) (GdkWin32Display *display,
+ MSG *message,
+ gint *return_value,
+ gpointer data);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_win32_display_add_filter (GdkWin32Display *display,
+ GdkWin32MessageFilterFunc function,
+ gpointer data);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_win32_display_remove_filter (GdkWin32Display *display,
+ GdkWin32MessageFilterFunc function,
+ gpointer data);
+
G_END_DECLS
#endif /* __GDK_WIN32_DISPLAY_H__ */