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