[gtk: 1/2] x11: emit ::enter/leave-monitor



commit 86f295f929f8ef05b135cfd56a72459808c65392
Author: Olivier Fourdan <ofourdan redhat com>
Date:   Thu Apr 16 12:58:39 2020 +0200

    x11: emit ::enter/leave-monitor
    
    For the X11 backend, keep a list of monitors for which the surface
    intersects the monitor area.
    
    Whenever the X11 surface is configured, check against the list of
    monitors to determine whether it enters a new monitor or if it left a
    monitor, to emit the corresponding ::enter/leave-monitor signals just
    like a Wayland compositor would.
    
    As monitors can be added, removed or reconfigured at any time, redo
    those checks whenever any of these events occur.

 gdk/x11/gdkdisplay-x11.c |   1 +
 gdk/x11/gdkprivate-x11.h |   2 +
 gdk/x11/gdksurface-x11.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++
 gdk/x11/gdksurface-x11.h |   2 +
 4 files changed, 106 insertions(+)
---
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 2857869343..7da3255687 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -990,6 +990,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
                }
 
               gdk_x11_surface_update_popups (surface);
+              gdk_x11_surface_enter_leave_monitors (surface);
            }
         }
       break;
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index 70c12159d5..667b14a142 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -217,6 +217,8 @@ void _gdk_x11_surface_register_dnd (GdkSurface *window);
 
 void gdk_x11_surface_update_popups (GdkSurface *surface);
 
+void gdk_x11_surface_enter_leave_monitors (GdkSurface *surface);
+
 GdkDrag        * _gdk_x11_surface_drag_begin (GdkSurface          *window,
                                               GdkDevice          *device,
                                               GdkContentProvider *content,
diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c
index 3607629819..01708cbc85 100644
--- a/gdk/x11/gdksurface-x11.c
+++ b/gdk/x11/gdksurface-x11.c
@@ -110,6 +110,10 @@ static void     set_wm_name                       (GdkDisplay  *display,
                                                   const gchar *name);
 static void     move_to_current_desktop           (GdkSurface *surface);
 static void     gdk_x11_toplevel_state_callback   (GdkSurface *surface);
+static void     gdk_x11_surface_on_monitor_added   (GdkSurface *surface,
+                                                    GdkMonitor *monitor);
+static void     gdk_x11_surface_on_monitor_removed (GdkSurface *surface,
+                                                    GdkMonitor *monitor);
 
 /* Return whether time1 is considered later than time2 as far as xserver
  * time is concerned.  Accounts for wraparound.
@@ -134,6 +138,7 @@ gdk_x11_surface_init (GdkX11Surface *impl)
 {  
   impl->surface_scale = 1;
   impl->frame_sync_enabled = TRUE;
+  impl->surface_is_on_monitor = NULL;
 }
 
 GdkToplevelX11 *
@@ -462,8 +467,17 @@ gdk_x11_surface_finalize (GObject *object)
       _gdk_x11_display_remove_window (display, impl->xid);
       if (impl->toplevel && impl->toplevel->focus_window)
         _gdk_x11_display_remove_window (display, impl->toplevel->focus_window);
+
+      g_signal_handlers_disconnect_by_func (display,
+                                            gdk_x11_surface_on_monitor_added,
+                                            GDK_SURFACE (object));
+      g_signal_handlers_disconnect_by_func (display,
+                                            gdk_x11_surface_on_monitor_removed,
+                                            GDK_SURFACE (object));
     }
 
+  g_clear_pointer (&impl->surface_is_on_monitor, g_list_free);
+
   g_free (impl->toplevel);
 
   if (impl->cursor)
@@ -974,6 +988,13 @@ _gdk_x11_display_create_surface (GdkDisplay     *display,
 
   gdk_surface_freeze_updates (surface);
 
+  g_signal_connect_swapped (surface->display, "monitor-added",
+                            G_CALLBACK (gdk_x11_surface_on_monitor_added),
+                            surface);
+  g_signal_connect_swapped (surface->display, "monitor-removed",
+                            G_CALLBACK (gdk_x11_surface_on_monitor_removed),
+                            surface);
+
   return surface;
 }
 
@@ -1557,6 +1578,86 @@ gdk_x11_surface_update_popups (GdkSurface *parent)
     }
 }
 
+static void
+gdk_x11_surface_set_is_on_monitor (GdkSurface *surface,
+                                   GdkMonitor *monitor,
+                                   gboolean    is_on_monitor)
+{
+  GdkX11Surface *impl = GDK_X11_SURFACE (surface);
+  GList *was_on_monitor;
+
+  was_on_monitor = g_list_find (impl->surface_is_on_monitor, monitor);
+
+  if (!was_on_monitor && is_on_monitor)
+    {
+      impl->surface_is_on_monitor = g_list_append (impl->surface_is_on_monitor,
+                                                   monitor);
+      gdk_surface_enter_monitor (surface, monitor);
+    }
+  else if (was_on_monitor && !is_on_monitor)
+    {
+      impl->surface_is_on_monitor = g_list_remove (impl->surface_is_on_monitor,
+                                                   monitor);
+      gdk_surface_leave_monitor (surface, monitor);
+    }
+}
+
+static void
+gdk_x11_surface_check_monitor (GdkSurface *surface,
+                               GdkMonitor *monitor)
+{
+  GdkRectangle monitor_geometry;
+  GdkRectangle surface_geometry;
+  gboolean is_on_monitor;
+
+  gdk_monitor_get_geometry (monitor, &monitor_geometry);
+  gdk_surface_get_geometry (surface,
+                            &surface_geometry.x,
+                            &surface_geometry.y,
+                            &surface_geometry.width,
+                            &surface_geometry.height);
+
+  is_on_monitor = gdk_rectangle_intersect (&surface_geometry,
+                                           &monitor_geometry,
+                                           NULL);
+
+  gdk_x11_surface_set_is_on_monitor (surface, monitor, is_on_monitor);
+}
+
+void
+gdk_x11_surface_enter_leave_monitors (GdkSurface *surface)
+{
+  GdkDisplay *display = gdk_surface_get_display (surface);
+  int n_monitors, i;
+
+  n_monitors = gdk_display_get_n_monitors (display);
+  for (i = 0; i < n_monitors; i++)
+    {
+      GdkMonitor *monitor = gdk_display_get_monitor (display, i);
+      gdk_x11_surface_check_monitor (surface, monitor);
+    }
+}
+
+static void
+gdk_x11_surface_on_monitor_added (GdkSurface *surface,
+                                  GdkMonitor *monitor)
+{
+  gdk_x11_surface_check_monitor (surface, monitor);
+  g_signal_connect_swapped (G_OBJECT (monitor), "notify::geometry",
+                            G_CALLBACK (gdk_x11_surface_check_monitor),
+                            surface);
+}
+
+static void
+gdk_x11_surface_on_monitor_removed (GdkSurface *surface,
+                                    GdkMonitor *monitor)
+{
+  gdk_x11_surface_check_monitor (surface, monitor);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (monitor),
+                                        gdk_x11_surface_check_monitor,
+                                        monitor);
+}
+
 static void gdk_x11_surface_set_geometry_hints (GdkSurface         *surface,
                                                 const GdkGeometry *geometry,
                                                 GdkSurfaceHints     geom_mask);
diff --git a/gdk/x11/gdksurface-x11.h b/gdk/x11/gdksurface-x11.h
index 609181f59a..53abd500e5 100644
--- a/gdk/x11/gdksurface-x11.h
+++ b/gdk/x11/gdksurface-x11.h
@@ -80,6 +80,8 @@ struct _GdkX11Surface
   int abs_y;
 
   guint64 map_time;
+
+  GList *surface_is_on_monitor;
 };
  
 struct _GdkX11SurfaceClass 


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