[gtk+] wayland: Don't broadcast selection owner changes



commit d682aed55088a49e590b5e0e3fdb6ebb0d044d07
Author: Jonas Ådahl <jadahl gmail com>
Date:   Thu Aug 27 14:59:45 2015 +0800

    wayland: Don't broadcast selection owner changes
    
    When receiving a selection or when a drag icon enter a window, it was
    targeted at a specific window. Lets emit the GDK_OWNER_CHANGE event
    only for this window, instead of broadcasting.
    
    Broadcasting has some nasty side effects. For example, if there was n
    GdkWindows, and one would for every "owner-change" signal handler
    receive n signals about the owner being changed.
    
    An example of where this went a bit out of hand was gnome-terminal,
    which added one listener per terminal window. This meant that if
    one had m number of terminal windows, each time any one would loose or
    gain keyboard focus, O(m^2) owner-change events would be emitted.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=754158

 gdk/wayland/gdkdevice-wayland.c |   39 ++++++++++++++++++++++-----------------
 1 files changed, 22 insertions(+), 17 deletions(-)
---
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index 50b3ffc..792de22 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -75,6 +75,7 @@ struct _GdkWaylandDeviceData
   GdkModifierType button_modifiers;
   GdkWindow *pointer_focus;
   GdkWindow *keyboard_focus;
+  GdkAtom pending_selection;
   struct wl_data_device *data_device;
   double surface_x, surface_y;
   uint32_t time;
@@ -670,21 +671,6 @@ emit_selection_owner_change (GdkWindow *window,
 }
 
 static void
-emit_selection_owner_change_forall (GdkAtom atom)
-{
-  GdkDisplay *display = gdk_display_get_default ();
-  GdkScreen *screen = GDK_WAYLAND_DISPLAY (display)->screen;
-  GList *windows, *l;
-
-  windows = gdk_screen_get_toplevel_windows (screen);
-
-  for (l = windows; l; l = l->next)
-    emit_selection_owner_change (l->data, atom);
-
-  g_list_free (windows);
-}
-
-static void
 data_device_data_offer (void                  *data,
                         struct wl_data_device *data_device,
                         struct wl_data_offer  *offer)
@@ -744,7 +730,8 @@ data_device_enter (void                  *data,
                                         GDK_CURRENT_TIME);
 
   gdk_wayland_selection_set_offer (device->display, selection, offer);
-  emit_selection_owner_change_forall (selection);
+
+  emit_selection_owner_change (dest_window, selection);
 }
 
 static void
@@ -827,7 +814,16 @@ data_device_selection (void                  *data,
 
   selection = gdk_atom_intern_static_string ("CLIPBOARD");
   gdk_wayland_selection_set_offer (device->display, selection, offer);
-  emit_selection_owner_change_forall (selection);
+
+  /* If we already have keyboard focus, the selection was targeted at the
+   * focused surface. If we don't we will receive keyboard focus directly after
+   * this, so lets wait and find out what window will get the focus before
+   * emitting the owner-changed event.
+   */
+  if (device->keyboard_focus)
+    emit_selection_owner_change (device->keyboard_focus, selection);
+  else
+    device->pending_selection = selection;
 }
 
 static const struct wl_data_device_listener data_device_listener = {
@@ -1163,6 +1159,13 @@ keyboard_handle_enter (void               *data,
                        device, device->keyboard_focus));
 
   _gdk_wayland_display_deliver_event (device->display, event);
+
+  if (device->pending_selection != GDK_NONE)
+    {
+      emit_selection_owner_change (device->keyboard_focus,
+                                   device->pending_selection);
+      device->pending_selection = GDK_NONE;
+    }
 }
 
 static void stop_key_repeat (GdkWaylandDeviceData *device);
@@ -2231,6 +2234,8 @@ _gdk_wayland_device_manager_add_seat (GdkDeviceManager *device_manager,
   device->foreign_dnd_window = create_foreign_dnd_window (display);
   device->wl_seat = wl_seat;
 
+  device->pending_selection = GDK_NONE;
+
   wl_seat_add_listener (device->wl_seat, &seat_listener, device);
   wl_seat_set_user_data (device->wl_seat, device);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]