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.
This commit is contained in:
Matthias Clasen 2019-04-22 15:22:33 +00:00
parent 99783c7fb7
commit 6f1c32b3eb
4 changed files with 79 additions and 16 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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