Compare commits

...

1 Commits

Author SHA1 Message Date
Matthias Clasen
b54e24ea29 wip: subsurface window type
Make subsurfaces for X11 as follows:
- toplevel
- override-redirect
- moves with the parent
Attempt to use subsurfaces for popovers again
This does not quite work yet
2018-01-28 23:30:29 +01:00
9 changed files with 151 additions and 64 deletions

View File

@@ -458,12 +458,6 @@ gdk_window_get_property (GObject *object,
}
}
static gboolean
gdk_window_is_subsurface (GdkWindow *window)
{
return window->window_type == GDK_WINDOW_SUBSURFACE;
}
static GdkWindow *
gdk_window_get_impl_window (GdkWindow *window)
{
@@ -700,10 +694,7 @@ recompute_visible_regions_internal (GdkWindow *private,
old_abs_y = private->abs_y;
/* Update absolute position */
if ((gdk_window_has_impl (private) &&
private->window_type != GDK_WINDOW_SUBSURFACE) ||
(gdk_window_is_toplevel (private) &&
private->window_type == GDK_WINDOW_SUBSURFACE))
if (gdk_window_has_impl (private))
{
/* Native windows and toplevel subsurfaces start here */
private->abs_x = 0;
@@ -745,7 +736,7 @@ recompute_visible_regions_internal (GdkWindow *private,
cairo_region_intersect (new_clip, private->shape);
}
else
new_clip = cairo_region_create ();
new_clip = cairo_region_create ();
if (private->clip_region == NULL ||
!cairo_region_equal (private->clip_region, new_clip))
@@ -855,7 +846,7 @@ get_native_device_event_mask (GdkWindow *private,
mask = private->event_mask;
/* We need thse for all native windows so we can
/* We need these for all native windows so we can
emulate events on children: */
mask |=
GDK_EXPOSURE_MASK |
@@ -929,13 +920,6 @@ gdk_window_new (GdkDisplay *display,
"a window of type GDK_WINDOW_ROOT");
break;
case GDK_WINDOW_SUBSURFACE:
#ifdef GDK_WINDOWING_WAYLAND
if (!GDK_IS_WAYLAND_DISPLAY (display))
{
g_warning (G_STRLOC "Subsurface windows can only be used on Wayland");
return NULL;
}
#endif
break;
case GDK_WINDOW_CHILD:
if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT ||
@@ -975,11 +959,6 @@ gdk_window_new (GdkDisplay *display,
native = TRUE; /* Always use native windows for toplevels */
}
#ifdef GDK_WINDOWING_WAYLAND
if (window->window_type == GDK_WINDOW_SUBSURFACE)
native = TRUE; /* Always use native windows for subsurfaces as well */
#endif
if (native)
{
event_mask = get_native_event_mask (window);
@@ -1064,6 +1043,41 @@ gdk_window_new_popup (GdkDisplay *display,
return gdk_window_new (display, NULL, &attr);
}
/**
* gdk_window_new_subsurface: (constructor)
* @parent: the parent window
* @position: placement of the window relative to @parent
*
* Creates a new toplevel window that is attached to @parent.
* The window will bypass window management and move together
* with its parent.
*
* Returns: (transfer full): the new #GdkWindow
*
* Since: 3.94
**/
GdkWindow *
gdk_window_new_subsurface (GdkWindow *parent,
const GdkRectangle *position)
{
GdkWindowAttr attr;
GdkWindow *window;
g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
attr.wclass = GDK_INPUT_OUTPUT;
attr.x = position->x;
attr.y = position->y;
attr.width = position->width;
attr.height = position->height;
attr.window_type = GDK_WINDOW_SUBSURFACE;
window = gdk_window_new (gdk_window_get_display (parent), NULL, &attr);
gdk_window_set_transient_for (window, parent);
return window;
}
/**
* gdk_window_new_temp: (constructor)
* @display: the display to create the window on
@@ -1547,9 +1561,6 @@ gdk_window_get_parent (GdkWindow *window)
{
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
if (gdk_window_is_subsurface (window))
return window->transient_for;
else
return window->parent;
}
@@ -1570,8 +1581,7 @@ gdk_window_get_toplevel (GdkWindow *window)
{
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
while (window->window_type == GDK_WINDOW_CHILD ||
window->window_type == GDK_WINDOW_SUBSURFACE)
while (window->window_type == GDK_WINDOW_CHILD)
{
if (gdk_window_is_toplevel (window))
break;

View File

@@ -452,6 +452,10 @@ GdkWindow * gdk_window_new_toplevel (GdkDisplay *display,
GDK_AVAILABLE_IN_3_90
GdkWindow * gdk_window_new_popup (GdkDisplay *display,
const GdkRectangle *position);
GDK_AVAILABLE_IN_3_94
GdkWindow * gdk_window_new_subsurface (GdkWindow *parent,
const GdkRectangle *position);
GDK_AVAILABLE_IN_3_90
GdkWindow * gdk_window_new_temp (GdkDisplay *display);
GDK_AVAILABLE_IN_3_90

View File

@@ -992,8 +992,14 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
}
if (!is_substructure)
{
window->x = event->configure.x;
window->y = event->configure.y;
if (window->x != event->configure.x ||
window->y != event->configure.y)
{
window->x = event->configure.x;
window->y = event->configure.y;
gdk_x11_window_update_position (window_impl);
}
if (window_impl->unscaled_width != xevent->xconfigure.width ||
window_impl->unscaled_height != xevent->xconfigure.height)

View File

@@ -113,10 +113,12 @@ static void gdk_window_impl_x11_finalize (GObject *object);
#define WINDOW_IS_TOPLEVEL_OR_FOREIGN(window) \
(GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL || \
GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP || \
GDK_WINDOW_TYPE (window) == GDK_WINDOW_SUBSURFACE || \
GDK_WINDOW_TYPE (window) == GDK_WINDOW_FOREIGN)
#define WINDOW_IS_TOPLEVEL(window) \
(GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL || \
GDK_WINDOW_TYPE (window) == GDK_WINDOW_SUBSURFACE || \
GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
/* Return whether time1 is considered later than time2 as far as xserver
@@ -510,9 +512,16 @@ gdk_window_impl_x11_finalize (GObject *object)
g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (object));
impl = GDK_WINDOW_IMPL_X11 (object);
wrapper = impl->wrapper;
if (wrapper->transient_for)
{
GdkWindowImplX11 *x11_parent;
x11_parent = GDK_WINDOW_IMPL_X11 (wrapper->transient_for->impl);
x11_parent->transients = g_list_remove (x11_parent->transients, wrapper);
}
if (WINDOW_IS_TOPLEVEL (wrapper) && impl->toplevel->in_frame)
unhook_surface_changed (wrapper);
@@ -900,6 +909,7 @@ _gdk_x11_display_create_window_impl (GdkDisplay *display,
{
case GDK_WINDOW_TOPLEVEL:
case GDK_WINDOW_TEMP:
case GDK_WINDOW_SUBSURFACE:
if (window->parent)
{
/* The common code warns for this case */
@@ -928,7 +938,8 @@ _gdk_x11_display_create_window_impl (GdkDisplay *display,
xattributes.colormap = gdk_x11_display_get_window_colormap (display_x11);
xattributes_mask |= CWColormap;
if (window->window_type == GDK_WINDOW_TEMP)
if (window->window_type == GDK_WINDOW_TEMP ||
window->window_type == GDK_WINDOW_SUBSURFACE)
{
xattributes.save_under = True;
xattributes.override_redirect = True;
@@ -944,7 +955,8 @@ _gdk_x11_display_create_window_impl (GdkDisplay *display,
{
class = InputOnly;
if (window->window_type == GDK_WINDOW_TEMP)
if (window->window_type == GDK_WINDOW_TEMP ||
window->window_type == GDK_WINDOW_SUBSURFACE)
{
xattributes.override_redirect = True;
xattributes_mask |= CWOverrideRedirect;
@@ -992,6 +1004,7 @@ _gdk_x11_display_create_window_impl (GdkDisplay *display,
switch (GDK_WINDOW_TYPE (window))
{
case GDK_WINDOW_SUBSURFACE:
case GDK_WINDOW_TOPLEVEL:
case GDK_WINDOW_TEMP:
gdk_window_set_title (window, get_default_title ());
@@ -1450,6 +1463,7 @@ gdk_window_x11_hide (GdkWindow *window)
{
case GDK_WINDOW_TOPLEVEL:
case GDK_WINDOW_TEMP: /* ? */
case GDK_WINDOW_SUBSURFACE:
gdk_window_withdraw (window);
return;
@@ -1583,6 +1597,17 @@ gdk_window_x11_move_resize (GdkWindow *window,
gint width,
gint height)
{
if (gdk_window_get_window_type (window) == GDK_WINDOW_SUBSURFACE)
{
GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
impl->offset_x = x;
impl->offset_y = y;
x = window->transient_for->x + impl->offset_x;
y = window->transient_for->y + impl->offset_y;
}
if (with_move && (width < 0 && height < 0))
window_x11_move (window, x, y);
else
@@ -1594,6 +1619,23 @@ gdk_window_x11_move_resize (GdkWindow *window,
}
}
void
gdk_x11_window_update_position (GdkWindowImplX11 *impl)
{
GList *l;
for (l = impl->transients; l; l = l->next)
{
GdkWindow *window = l->data;
if (gdk_window_get_window_type (window) == GDK_WINDOW_SUBSURFACE)
{
GdkWindowImplX11 *win_impl = GDK_WINDOW_IMPL_X11 (window->impl);
gdk_window_x11_move_resize (window, TRUE, win_impl->offset_x, win_impl->offset_y, window->width, window->height);
}
}
}
void
_gdk_x11_window_set_window_scale (GdkWindow *window,
int scale)
@@ -2446,19 +2488,34 @@ static void
gdk_x11_window_set_transient_for (GdkWindow *window,
GdkWindow *parent)
{
GdkWindowImplX11 *x11_parent;
if (GDK_WINDOW_DESTROYED (window) ||
!WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
return;
/* XSetTransientForHint() doesn't allow unsetting, so do it manually */
if (parent && !GDK_WINDOW_DESTROYED (parent))
XSetTransientForHint (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
GDK_WINDOW_XID (parent));
{
XSetTransientForHint (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
GDK_WINDOW_XID (parent));
x11_parent = GDK_WINDOW_IMPL_X11 (parent->impl);
x11_parent->transients = g_list_prepend (x11_parent->transients, window);
}
else
XDeleteProperty (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), "WM_TRANSIENT_FOR"));
{
if (window->transient_for)
{
x11_parent = GDK_WINDOW_IMPL_X11 (window->transient_for->impl);
x11_parent->transients = g_list_remove (x11_parent->transients, window);
}
XDeleteProperty (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), "WM_TRANSIENT_FOR"));
}
}
GdkCursor *

View File

@@ -89,6 +89,14 @@ struct _GdkWindowImplX11
#if defined (HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
Damage damage;
#endif
/* Subsurfaces are positioned relative to their transient parent.
* We keep the offset here.
*/
int offset_x;
int offset_y;
GList *transients;
};
struct _GdkWindowImplX11Class
@@ -191,9 +199,11 @@ GdkToplevelX11 *_gdk_x11_window_get_toplevel (GdkWindow *window);
GdkCursor *_gdk_x11_window_get_cursor (GdkWindow *window);
void _gdk_x11_window_update_size (GdkWindowImplX11 *impl);
void gdk_x11_window_update_position (GdkWindowImplX11 *impl);
void _gdk_x11_window_set_window_scale (GdkWindow *window,
int scale);
G_END_DECLS
#endif /* __GDK_WINDOW_X11_H__ */

View File

@@ -1546,6 +1546,7 @@ handle_pointing_event (GdkEvent *event)
return widget;
toplevel_widget = gtk_widget_get_toplevel (widget);
g_print ("pointing event on %s\n", G_OBJECT_TYPE_NAME (toplevel_widget));
if (!GTK_IS_WINDOW (toplevel_widget))
return widget;

View File

@@ -472,36 +472,21 @@ gtk_popover_realize (GtkWidget *widget)
{
GtkAllocation allocation;
GdkWindow *window;
GtkWidget *toplevel;
GskRenderer *renderer;
toplevel = gtk_widget_get_toplevel (widget);
gtk_widget_get_window_allocation (widget, &allocation);
/* We want to use subsurfaces for popovers, so they can extend outside
* the main window, but for that, we first need to have clean subsurface
* support that works with GSK.
*/
#if 0
if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
{
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
g_assert (GTK_IS_WINDOW (toplevel));
window = gdk_wayland_window_new_subsurface (gtk_widget_get_display (toplevel),
&allocation);
gdk_window_set_transient_for (window,
gtk_widget_get_window (toplevel));
}
else
#endif
{
window = gdk_window_new_child (gtk_widget_get_parent_window (widget),
&allocation);
}
window = gdk_window_new_subsurface (gtk_widget_get_window (toplevel),
&allocation);
gtk_widget_set_window (widget, window);
gtk_widget_register_window (widget, window);
gtk_widget_set_realized (widget, TRUE);
renderer = gsk_renderer_new_for_window (window);
g_object_set_data_full (G_OBJECT (window), "renderer", renderer, g_object_unref);
}
static void
@@ -1021,6 +1006,7 @@ gtk_popover_update_shape (GtkPopover *popover)
GdkWindow *win;
cairo_t *cr;
return;
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
return;

View File

@@ -5446,6 +5446,13 @@ static GskRenderer *
gtk_widget_get_renderer (GtkWidget *widget)
{
GtkWidget *toplevel;
GdkWindow *window;
GskRenderer *renderer;
window = gtk_widget_get_window (widget);
renderer = g_object_get_data (G_OBJECT (window), "renderer");
if (renderer)
return renderer;
toplevel = _gtk_widget_get_toplevel (widget);
if (_gtk_widget_is_toplevel (toplevel))

View File

@@ -6953,7 +6953,11 @@ gtk_window_realize (GtkWidget *widget)
gtk_widget_set_realized (widget, TRUE);
if (priv->renderer == NULL)
priv->renderer = gsk_renderer_new_for_window (gdk_window);
{
priv->renderer = gsk_renderer_new_for_window (gdk_window);
g_object_set_data_full (G_OBJECT (gdk_window), "renderer",
g_object_ref (priv->renderer), g_object_unref);
}
if (priv->transient_parent &&
_gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)))
@@ -9385,11 +9389,13 @@ gtk_window_snapshot (GtkWidget *widget,
gtk_widget_snapshot_child (widget, child, snapshot);
}
#if 0
for (l = priv->popovers.head; l; l = l->next)
{
GtkWindowPopover *data = l->data;
gtk_widget_snapshot_child (widget, data->widget, snapshot);
}
#endif
gtk_debug_updates_snapshot (widget, snapshot);
}