From 6f1c32b3eb8d6beadab1df0aa923b8f8b78354c0 Mon Sep 17 00:00:00 2001 From: Matthias Clasen <mclasen@redhat.com> Date: Mon, 22 Apr 2019 15:22:33 +0000 Subject: [PATCH] x11: Implement popup surfaces Make them use o-r windows, and move with their parent. We do a sort-of ok job on stacking order here - whenever the parent window gets a ConfigureNotify, we just restack all popups directly on top of their parent. This is good enough to keep popups on top of their parent while we drag it around, and it gets the popup to disappear when raising another window on top of the parent. --- gdk/x11/gdkdisplay-x11.c | 10 ++++-- gdk/x11/gdkprivate-x11.h | 2 ++ gdk/x11/gdksurface-x11.c | 78 ++++++++++++++++++++++++++++++++-------- gdk/x11/gdksurface-x11.h | 5 +++ 4 files changed, 79 insertions(+), 16 deletions(-) diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index 95ca2211f3..62de7d39e9 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -985,8 +985,12 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, } if (!is_substructure) { - surface->x = event->configure.x; - surface->y = event->configure.y; + if (surface->x != event->configure.x || + surface->y != event->configure.y) + { + surface->x = event->configure.x; + surface->y = event->configure.y; + } if (surface_impl->unscaled_width != xevent->xconfigure.width || surface_impl->unscaled_height != xevent->xconfigure.height) @@ -1007,6 +1011,8 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator, if (surface->resize_count == 0) _gdk_x11_moveresize_configure_done (display, surface); } + + gdk_x11_surface_update_popups (surface); } } break; diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h index 05b8c1f7df..ff32ea7642 100644 --- a/gdk/x11/gdkprivate-x11.h +++ b/gdk/x11/gdkprivate-x11.h @@ -223,6 +223,8 @@ void _gdk_x11_cursor_display_finalize (GdkDisplay *display); void _gdk_x11_surface_register_dnd (GdkSurface *window); +void gdk_x11_surface_update_popups (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 0643948ec2..1d6dee093a 100644 --- a/gdk/x11/gdksurface-x11.c +++ b/gdk/x11/gdksurface-x11.c @@ -425,12 +425,20 @@ gdk_x11_surface_end_frame (GdkSurface *surface) static void gdk_x11_surface_finalize (GObject *object) { + GdkSurface *surface; GdkX11Surface *impl; g_return_if_fail (GDK_IS_X11_SURFACE (object)); + surface = GDK_SURFACE (object); impl = GDK_X11_SURFACE (object); + if (surface->parent) + { + GdkX11Surface *parent_impl = GDK_X11_SURFACE (surface->parent); + parent_impl->popups = g_list_remove (parent_impl->popups, surface); + } + if (impl->toplevel->in_frame) unhook_surface_changed (GDK_SURFACE (impl)); @@ -842,7 +850,8 @@ _gdk_x11_display_create_surface (GdkDisplay *display, xattributes.colormap = gdk_x11_display_get_window_colormap (display_x11); xattributes_mask |= CWColormap; - if (surface->surface_type == GDK_SURFACE_TEMP) + if (surface->surface_type == GDK_SURFACE_TEMP || + surface->surface_type == GDK_SURFACE_POPUP) { xattributes.save_under = True; xattributes.override_redirect = True; @@ -899,6 +908,12 @@ _gdk_x11_display_create_surface (GdkDisplay *display, gdk_surface_freeze_toplevel_updates (surface); + if (parent) + { + GdkX11Surface *parent_impl = GDK_X11_SURFACE (parent); + parent_impl->popups = g_list_prepend (parent_impl->popups, surface); + } + return surface; } @@ -1231,8 +1246,8 @@ gdk_x11_surface_hide (GdkSurface *surface) static inline void x11_surface_move (GdkSurface *surface, - gint x, - gint y) + gint x, + gint y) { GdkX11Surface *impl = GDK_X11_SURFACE (surface); @@ -1244,6 +1259,12 @@ x11_surface_move (GdkSurface *surface, { surface->x = x; surface->y = y; + + if (surface->parent) + { + impl->offset_x = surface->x - surface->parent->x; + impl->offset_y = surface->y - surface->parent->y; + } } } @@ -1283,10 +1304,10 @@ x11_surface_resize (GdkSurface *surface, static inline void x11_surface_move_resize (GdkSurface *surface, - gint x, - gint y, - gint width, - gint height) + gint x, + gint y, + gint width, + gint height) { GdkX11Surface *impl = GDK_X11_SURFACE (surface); @@ -1314,6 +1335,12 @@ x11_surface_move_resize (GdkSurface *surface, surface->height = height; _gdk_x11_surface_update_size (GDK_X11_SURFACE (surface)); + + if (surface->parent) + { + impl->offset_x = surface->x - surface->parent->x; + impl->offset_y = surface->y - surface->parent->y; + } } else { @@ -1324,11 +1351,11 @@ x11_surface_move_resize (GdkSurface *surface, static void gdk_x11_surface_move_resize (GdkSurface *surface, - gboolean with_move, - gint x, - gint y, - gint width, - gint height) + gboolean with_move, + gint x, + gint y, + gint width, + gint height) { if (with_move && (width < 0 && height < 0)) x11_surface_move (surface, x, y); @@ -1341,6 +1368,29 @@ gdk_x11_surface_move_resize (GdkSurface *surface, } } +static void gdk_x11_surface_restack_toplevel (GdkSurface *surface, + GdkSurface *sibling, + gboolean above); + +void +gdk_x11_surface_update_popups (GdkSurface *parent) +{ + GdkX11Surface *impl = GDK_X11_SURFACE (parent); + GList *l; + + for (l = impl->popups; l; l = l->next) + { + GdkX11Surface *popup_impl = l->data; + GdkSurface *popup = GDK_SURFACE (popup_impl); + int new_x = parent->x + popup_impl->offset_x; + int new_y = parent->y + popup_impl->offset_y; + + if (new_x != popup->x || new_y != popup->y) + x11_surface_move (popup, new_x, new_y); + gdk_x11_surface_restack_toplevel (popup, parent, TRUE); + } +} + void _gdk_x11_surface_set_surface_scale (GdkSurface *surface, int scale) @@ -1390,8 +1440,8 @@ gdk_x11_surface_raise (GdkSurface *surface) static void gdk_x11_surface_restack_toplevel (GdkSurface *surface, - GdkSurface *sibling, - gboolean above) + GdkSurface *sibling, + gboolean above) { XWindowChanges changes; diff --git a/gdk/x11/gdksurface-x11.h b/gdk/x11/gdksurface-x11.h index 6ffdbf24e6..c051d10d82 100644 --- a/gdk/x11/gdksurface-x11.h +++ b/gdk/x11/gdksurface-x11.h @@ -75,6 +75,11 @@ struct _GdkX11Surface #if defined (HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES) Damage damage; #endif + + int offset_x; + int offset_y; + + GList *popups; }; struct _GdkX11SurfaceClass