[gtk/wip/matthiasc/popup4: 119/121] Introduce GtkBug



commit 293ababe2c03fab6b8b0cf3e42914c3c58be9423
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Apr 25 00:44:55 2019 +0000

    Introduce GtkBug
    
    Split off the surface-handling bit from GtkRoot,
    and make GtkPopover only implement this interface.

 gtk/gtkbud.c        | 104 +++++++++
 gtk/gtkbud.h        |  60 +++++
 gtk/gtkbudprivate.h |  16 ++
 gtk/gtkmain.c       |  51 +++--
 gtk/gtkpopover.c    | 625 ++++------------------------------------------------
 gtk/gtkpopover.h    |   6 +-
 gtk/gtkroot.c       |   6 +-
 gtk/gtkwidget.c     |  34 +--
 gtk/gtkwindow.c     |  40 +++-
 gtk/meson.build     |   1 +
 10 files changed, 320 insertions(+), 623 deletions(-)
---
diff --git a/gtk/gtkbud.c b/gtk/gtkbud.c
new file mode 100644
index 0000000000..2757b183d6
--- /dev/null
+++ b/gtk/gtkbud.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "gtkbudprivate.h"
+#include "gtkcssnodeprivate.h"
+#include "gtkwidgetprivate.h"
+#include "gdk/gdk-private.h"
+#include "gtkprivate.h"
+#include "gtkintl.h"
+
+/**
+ * SECTION:gtkbud
+ * @Title: GtkBud
+ * @Short_description: Interface for widgets having surfaces
+ * @See_also: #GtkRoot
+ *
+ * #GtkBud is the interface implemented by all widgets that can provide
+ * a GdkSurface for widgets to render on.
+ *
+ * The obvious example of a #GtkBud is #GtkWindow.
+ */
+
+G_DEFINE_INTERFACE (GtkBud, gtk_bud, GTK_TYPE_WIDGET)
+
+static GskRenderer *
+gtk_bud_default_get_renderer (GtkBud *self)
+{
+  return NULL;
+}
+
+static void
+gtk_bud_default_get_surface_transform (GtkBud *self,
+                                       int    *x,
+                                       int    *y)
+{
+  *x = 0;
+  *y = 0;
+}
+
+static void
+gtk_bud_default_init (GtkBudInterface *iface)
+{
+  iface->get_renderer = gtk_bud_default_get_renderer;
+  iface->get_surface_transform = gtk_bud_default_get_surface_transform;
+}
+
+GskRenderer *
+gtk_bud_get_renderer (GtkBud *self)
+{
+  g_return_val_if_fail (GTK_IS_BUD (self), NULL);
+
+  return GTK_BUD_GET_IFACE (self)->get_renderer (self);
+}
+
+void
+gtk_bud_get_surface_transform (GtkBud *self,
+                               int    *x,
+                               int    *y)
+{
+  g_return_if_fail (GTK_IS_BUD (self));
+  g_return_if_fail (x != 0);
+  g_return_if_fail (y != 0);
+
+  return GTK_BUD_GET_IFACE (self)->get_surface_transform (self, x, y);
+}
+
+/**
+ * gtk_bud_get_for_surface:
+ * @surface: a #GdkSurface
+ *
+ * Finds the GtkBud associated with the surface.
+ * 
+ * Returns: (transfer none): the #GtkBud that is associated with @surface
+ */
+GtkWidget *
+gtk_bud_get_for_surface (GdkSurface *surface)
+{
+  GtkWidget *widget;
+
+  widget = (GtkWidget *)gdk_surface_get_widget (surface);
+
+  if (widget && GTK_IS_BUD (widget))
+    return widget;
+
+  return NULL;
+}
diff --git a/gtk/gtkbud.h b/gtk/gtkbud.h
new file mode 100644
index 0000000000..29acee0ce6
--- /dev/null
+++ b/gtk/gtkbud.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GTK_BUD_H__
+#define __GTK_BUD_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_BUD               (gtk_bud_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_INTERFACE (GtkBud, gtk_bud, GTK, BUD, GtkWidget)
+
+/**
+ * GtkBudIface:
+ *
+ * The list of functions that must be implemented for the #GtkBud interface.
+ */
+struct _GtkBudInterface
+{
+  /*< private >*/
+  GTypeInterface g_iface;
+
+  /*< public >*/
+  GskRenderer * (* get_renderer)          (GtkBud    *self);
+
+  void          (* get_surface_transform) (GtkBud    *self,
+                                           int       *x,
+                                           int       *y);
+};
+
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_bud_get_for_surface (GdkSurface *surface);
+
+G_END_DECLS
+
+#endif /* __GTK_BUD_H__ */
diff --git a/gtk/gtkbudprivate.h b/gtk/gtkbudprivate.h
new file mode 100644
index 0000000000..72f74e1140
--- /dev/null
+++ b/gtk/gtkbudprivate.h
@@ -0,0 +1,16 @@
+#ifndef __GTK_BUD_PRIVATE_H__
+#define __GTK_BUD_PRIVATE_H__
+
+#include "gtkbud.h"
+
+G_BEGIN_DECLS
+
+GskRenderer * gtk_bud_get_renderer          (GtkBud *self);
+
+void          gtk_bud_get_surface_transform (GtkBud *self,
+                                             int    *x,
+                                             int    *y);
+
+G_END_DECLS
+
+#endif /* __GTK_ROOT_PRIVATE_H__ */
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index e24c52f971..d748d7226a 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -132,6 +132,7 @@
 #include "gtkprintbackend.h"
 #include "gtkimmodule.h"
 #include "gtkroot.h"
+#include "gtkbud.h"
 
 #include "a11y/gtkaccessibility.h"
 #include "inspector/window.h"
@@ -1327,7 +1328,7 @@ rewrite_event_for_grabs (GdkEvent *event)
     }
 
   event_widget = gtk_get_event_widget (event);
-  grab_widget = gtk_root_get_for_surface (grab_surface);
+  grab_widget = gtk_bud_get_for_surface (grab_surface);
 
   if (grab_widget &&
       gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
@@ -1638,6 +1639,20 @@ is_pointing_event (GdkEvent *event)
     }
 }
 
+static gboolean
+is_key_event (GdkEvent *event)
+{
+  switch ((guint) event->any.type)
+    {
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+      return TRUE;
+      break;
+    default:
+      return FALSE;
+    }
+}
+
 static inline void
 set_widget_active_state (GtkWidget       *target,
                          const gboolean   release)
@@ -1664,6 +1679,7 @@ handle_pointing_event (GdkEvent *event)
   GdkEventSequence *sequence;
   GdkDevice *device;
   gdouble x, y;
+  GtkWidget *bud;
 
   event_widget = gtk_get_event_widget (event);
   device = gdk_event_get_device (event);
@@ -1671,6 +1687,7 @@ handle_pointing_event (GdkEvent *event)
     return event_widget;
 
   toplevel = gtk_widget_get_root (event_widget);
+  bud = gtk_widget_get_ancestor (event_widget, GTK_TYPE_BUD);
 
   sequence = gdk_event_get_event_sequence (event);
 
@@ -1700,10 +1717,10 @@ handle_pointing_event (GdkEvent *event)
       target = gtk_root_lookup_pointer_focus_implicit_grab (toplevel, device, sequence);
 
       if (!target)
-        target = gtk_widget_pick (GTK_WIDGET (toplevel), x, y, GTK_PICK_DEFAULT);
+       target = gtk_widget_pick (bud, x, y, GTK_PICK_DEFAULT);
 
       if (!target)
-        target = GTK_WIDGET (toplevel);
+        target = GTK_WIDGET (bud);
 
       old_target = update_pointer_focus_state (toplevel, event, target);
 
@@ -1735,7 +1752,7 @@ handle_pointing_event (GdkEvent *event)
       if (event->any.type == GDK_BUTTON_RELEASE)
         {
           GtkWidget *new_target;
-          new_target = gtk_widget_pick (GTK_WIDGET (toplevel), x, y, GTK_PICK_DEFAULT);
+          new_target = gtk_widget_pick (GTK_WIDGET (bud), x, y, GTK_PICK_DEFAULT);
           if (new_target == NULL)
             new_target = GTK_WIDGET (toplevel);
           gtk_synthesize_crossing_events (toplevel, target, new_target, event, GDK_CROSSING_UNGRAB);
@@ -1758,6 +1775,18 @@ handle_pointing_event (GdkEvent *event)
   return target ? target : old_target;
 }
 
+static GtkWidget *
+handle_key_event (GdkEvent *event)
+{
+  GtkWidget *event_widget;
+  GtkWidget *focus_widget;
+
+  event_widget = gtk_get_event_widget (event);
+
+  focus_widget = gtk_root_get_focus (gtk_widget_get_root (event_widget));
+  return focus_widget ? focus_widget : event_widget;
+}
+
 /**
  * gtk_main_do_event:
  * @event: An event to process (normally passed by GDK)
@@ -1837,19 +1866,13 @@ gtk_main_do_event (GdkEvent *event)
 
   if (is_pointing_event (event))
     target_widget = handle_pointing_event (event);
-  else if (GTK_IS_ROOT (target_widget) &&
-           (event->any.type == GDK_KEY_PRESS ||
-            event->any.type == GDK_KEY_RELEASE))
+  else if (is_key_event (event))
     {
-      GtkWidget *focus_widget;
-
       if (event->any.type == GDK_KEY_PRESS &&
-          gtk_root_activate_key (GTK_ROOT (target_widget), (GdkEventKey *) event))
+          gtk_root_activate_key (gtk_widget_get_root (target_widget), (GdkEventKey *) event))
         goto cleanup;
 
-      focus_widget = gtk_root_get_focus (GTK_ROOT (target_widget));
-      if (focus_widget)
-        target_widget = focus_widget;
+      target_widget = handle_key_event (event);
     }
 
   if (!target_widget)
@@ -2457,7 +2480,7 @@ gtk_get_event_widget (const GdkEvent *event)
   widget = NULL;
   if (event && event->any.surface &&
       (event->any.type == GDK_DESTROY || !gdk_surface_is_destroyed (event->any.surface)))
-    widget = gtk_root_get_for_surface (event->any.surface);
+    widget = gtk_bud_get_for_surface (event->any.surface);
 
   return widget;
 }
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 92d45c7fd3..539ba9b60b 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -108,7 +108,7 @@
 #include "config.h"
 
 #include "gtkpopoverprivate.h"
-#include "gtkroot.h"
+#include "gtkbud.h"
 #include "gtkwidgetprivate.h"
 #include "gtkeventcontrollerkey.h"
 #include "gtkcssnodeprivate.h"
@@ -129,7 +129,6 @@
 static GListStore *popover_list = NULL;
 
 typedef struct {
-  GdkDisplay *display;
   GskRenderer *renderer;
   GdkSurface *surface;
   GtkWidget *focus_widget;
@@ -167,50 +166,33 @@ enum {
   NUM_PROPERTIES
 };
 
-static void gtk_popover_set_is_active (GtkPopover *popover,
-                                       gboolean    active);
-static void gtk_popover_set_focus     (GtkPopover *popover,
-                                       GtkWidget  *widget);
-static void gtk_popover_set_default   (GtkPopover *popover,
-                                       GtkWidget  *widget);
-
 static GParamSpec *properties[NUM_PROPERTIES] = { NULL };
 
-static void gtk_popover_root_interface_init (GtkRootInterface *iface);
+static void gtk_popover_bud_interface_init (GtkBudInterface *iface);
 
 G_DEFINE_TYPE_WITH_CODE (GtkPopover, gtk_popover, GTK_TYPE_BIN,
                          G_ADD_PRIVATE (GtkPopover)
-                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ROOT,
-                                                gtk_popover_root_interface_init))
-
-
-static GdkDisplay *
-gtk_popover_root_get_display (GtkRoot *root)
-{
-  GtkPopover *popover = GTK_POPOVER (root);
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  return priv->display;
-}
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUD,
+                                                gtk_popover_bud_interface_init))
 
 static GskRenderer *
-gtk_popover_root_get_renderer (GtkRoot *root)
+gtk_popover_bud_get_renderer (GtkBud *bud)
 {
-  GtkPopover *popover = GTK_POPOVER (root);
+  GtkPopover *popover = GTK_POPOVER (bud);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
   return priv->renderer;
 }
 
 static void
-gtk_popover_root_get_surface_transform (GtkRoot *root,
-                                        int     *x,
-                                        int     *y)
+gtk_popover_bud_get_surface_transform (GtkBud *bud,
+                                       int    *x,
+                                       int    *y)
 {
   GtkStyleContext *context;
   GtkBorder margin, border, padding;
 
-  context = gtk_widget_get_style_context (GTK_WIDGET (root));
+  context = gtk_widget_get_style_context (GTK_WIDGET (bud));
   gtk_style_context_get_margin (context, &margin);
   gtk_style_context_get_border (context, &border);
   gtk_style_context_get_padding (context, &padding);
@@ -287,9 +269,8 @@ gtk_popover_move_resize (GtkPopover *popover)
 }
 
 static void
-gtk_popover_root_check_resize (GtkRoot *root)
+gtk_popover_check_resize (GtkPopover *popover)
 {
-  GtkPopover *popover = GTK_POPOVER (root);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
   GtkWidget *widget = GTK_WIDGET (popover);
 
@@ -305,19 +286,6 @@ gtk_popover_root_check_resize (GtkRoot *root)
     }
 }
 
-
-static void
-gtk_popover_focus_in (GtkWidget *widget)
-{
-  gtk_popover_set_is_active (GTK_POPOVER (widget), TRUE);
-}
-
-static void
-gtk_popover_focus_out (GtkWidget *widget)
-{
-  gtk_popover_set_is_active (GTK_POPOVER (widget), FALSE);
-}
-
 static void
 ensure_state_flag_backdrop (GtkWidget *widget)
 {
@@ -414,7 +382,6 @@ static void
 gtk_popover_init (GtkPopover *popover)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkEventController *controller;
   GtkStyleContext *context;
 
   gtk_widget_set_has_surface (GTK_WIDGET (popover), TRUE);
@@ -422,12 +389,13 @@ gtk_popover_init (GtkPopover *popover)
   priv->position = GTK_POS_TOP;
   priv->modal = TRUE;
 
-  priv->display = gdk_display_get_default ();
-
+#if 0
+  GtkEventController *controller;
   controller = gtk_event_controller_key_new ();
   g_signal_connect_swapped (controller, "focus-in", G_CALLBACK (gtk_popover_focus_in), popover);
   g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (gtk_popover_focus_out), popover);
   gtk_widget_add_controller (GTK_WIDGET (popover), controller);
+#endif
 
   priv->contents_widget = gtk_gizmo_new ("contents",
                                          measure_contents,
@@ -446,10 +414,12 @@ gtk_popover_realize (GtkWidget *widget)
   GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
   GdkRectangle parent_rect;
+  GdkDisplay *display;
 
   gtk_widget_get_surface_allocation (priv->relative_to, &parent_rect);
+  display = gtk_widget_get_display (priv->relative_to);
 
-  priv->surface = gdk_surface_new_popup (priv->display, gtk_widget_get_surface (priv->relative_to));
+  priv->surface = gdk_surface_new_popup (display, gtk_widget_get_surface (priv->relative_to));
 
   gtk_widget_set_surface (widget, priv->surface);
   gdk_surface_set_widget (priv->surface, widget);
@@ -484,23 +454,13 @@ gtk_popover_unrealize (GtkWidget *widget)
   g_clear_object (&priv->surface);
 }
 
-static void
-gtk_popover_move_focus (GtkWidget        *widget,
-                        GtkDirectionType  dir)
-{
-  gtk_widget_child_focus (widget, dir);
-
-  if (!gtk_widget_get_focus_child (widget))
-    gtk_root_set_focus (GTK_ROOT (widget), NULL);
-}
-
 static void
 gtk_popover_show (GtkWidget *widget)
 {
   _gtk_widget_set_visible_flag (widget, TRUE);
   gtk_css_node_validate (gtk_widget_get_css_node (widget));
   gtk_widget_realize (widget);
-  gtk_popover_root_check_resize (GTK_ROOT (widget));
+  gtk_popover_check_resize (GTK_POPOVER (widget));
   gtk_widget_map (widget);
 
   if (!gtk_widget_get_focus_child (widget))
@@ -544,9 +504,11 @@ gtk_popover_map (GtkWidget *widget)
 
   if (priv->modal)
     {
+      GdkDisplay *display;
       GdkSeat *seat;
 
-      seat = gdk_display_get_default_seat (priv->display),
+      display = gtk_widget_get_display (widget);
+      seat = gdk_display_get_default_seat (display);
       gdk_surface_show_with_auto_dismissal (priv->surface, seat);
     }
 
@@ -703,14 +665,6 @@ gtk_popover_set_property (GObject      *object,
       gtk_popover_set_modal (popover, g_value_get_boolean (value));
       break;
 
-    case NUM_PROPERTIES + GTK_ROOT_PROP_FOCUS_WIDGET:
-      gtk_popover_set_focus (popover, g_value_get_object (value));
-      break;
-
-    case NUM_PROPERTIES + GTK_ROOT_PROP_DEFAULT_WIDGET:
-      gtk_popover_set_default (popover, g_value_get_object (value));
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -744,14 +698,6 @@ gtk_popover_get_property (GObject      *object,
       g_value_set_boolean (value, priv->modal);
       break;
 
-    case NUM_PROPERTIES + GTK_ROOT_PROP_FOCUS_WIDGET:
-      g_value_set_object (value, priv->focus_widget);
-      break;
-
-    case NUM_PROPERTIES + GTK_ROOT_PROP_DEFAULT_WIDGET:
-      g_value_set_object (value, priv->default_widget);
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -761,13 +707,17 @@ gtk_popover_get_property (GObject      *object,
 static void
 gtk_popover_activate_default (GtkPopover *popover)
 {
-  gtk_root_activate_default (GTK_ROOT (popover));
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
+  gtk_root_activate_default (gtk_widget_get_root (priv->relative_to));
 }
 
 static void
 gtk_popover_activate_focus (GtkPopover *popover)
 {
-  gtk_root_activate_focus (GTK_ROOT (popover));
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
+  gtk_root_activate_focus (gtk_widget_get_root (priv->relative_to));
 }
 
 static void
@@ -776,40 +726,6 @@ gtk_popover_close (GtkPopover *popover)
   gtk_widget_hide (GTK_WIDGET (popover));
 }
 
-static void
-add_tab_bindings (GtkBindingSet    *binding_set,
-                  GdkModifierType   modifiers,
-                  GtkDirectionType  direction)
-{
-  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
-                                "move-focus", 1,
-                                GTK_TYPE_DIRECTION_TYPE, direction);
-  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
-                                "move-focus", 1,
-                                GTK_TYPE_DIRECTION_TYPE, direction);
-}
-
-static void
-add_arrow_bindings (GtkBindingSet    *binding_set,
-                    guint             keysym,
-                    GtkDirectionType  direction)
-{
-  guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
-
-  gtk_binding_entry_add_signal (binding_set, keysym, 0,
-                                "move-focus", 1,
-                                GTK_TYPE_DIRECTION_TYPE, direction);
-  gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
-                                "move-focus", 1,
-                                GTK_TYPE_DIRECTION_TYPE, direction);
-  gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
-                                "move-focus", 1,
-                                GTK_TYPE_DIRECTION_TYPE, direction);
-  gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
-                                "move-focus", 1,
-                                GTK_TYPE_DIRECTION_TYPE, direction);
-}
-
 static void
 gtk_popover_add (GtkContainer *container,
                  GtkWidget    *child)
@@ -857,7 +773,6 @@ gtk_popover_class_init (GtkPopoverClass *klass)
   widget_class->measure = gtk_popover_measure;
   widget_class->size_allocate = gtk_popover_size_allocate;
   widget_class->snapshot = gtk_popover_snapshot;
-  widget_class->move_focus = gtk_popover_move_focus;
 
   container_class->add = gtk_popover_add;
   container_class->remove = gtk_popover_remove;
@@ -895,7 +810,6 @@ gtk_popover_class_init (GtkPopoverClass *klass)
                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
   g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
-  gtk_root_install_properties (object_class, NUM_PROPERTIES);
 
   signals[ACTIVATE_FOCUS] =
     g_signal_new (I_("activate-focus"),
@@ -939,17 +853,6 @@ gtk_popover_class_init (GtkPopoverClass *klass)
 
   binding_set = gtk_binding_set_by_class (klass);
 
-  add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
-  add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
-  add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
-  add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
-
-  add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
-  add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
-  add_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
-  add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
-
-
   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "activate-focus", 0);
   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "activate-focus", 0);
 
@@ -982,90 +885,6 @@ size_changed (GtkWidget   *widget,
     gtk_popover_move_resize (popover);
 }
 
-static void
-gtk_popover_set_focus (GtkPopover *popover,
-                       GtkWidget  *focus)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWidget *old_focus = NULL;
-  GdkSeat *seat;
-  GdkDevice *device;
-  GdkEvent *event;
-
-  if (focus && !gtk_widget_is_sensitive (focus))
-    return;
-
-  if (priv->focus_widget)
-    old_focus = g_object_ref (priv->focus_widget);
-  g_set_object (&priv->focus_widget, NULL);
-
-  seat = gdk_display_get_default_seat (gtk_widget_get_display (GTK_WIDGET (popover)));
-  device = gdk_seat_get_keyboard (seat);
-
-  event = gdk_event_new (GDK_FOCUS_CHANGE);
-  gdk_event_set_display (event, gtk_widget_get_display (GTK_WIDGET (popover)));
-  gdk_event_set_device (event, device);
-  event->any.surface = _gtk_widget_get_surface (GTK_WIDGET (popover));
-  if (event->any.surface)
-    g_object_ref (event->any.surface);
-
-  gtk_synthesize_crossing_events (GTK_ROOT (popover), old_focus, focus, event, GDK_CROSSING_NORMAL);
-
-  g_object_unref (event);
-
-  g_set_object (&priv->focus_widget, focus);
-
-  g_clear_object (&old_focus);
-
-  g_object_notify (G_OBJECT (popover), "focus-widget");
-}
-
-static void
-do_focus_change (GtkWidget *widget,
-                 gboolean   in)
-{
-  GdkSeat *seat;
-  GdkDevice *device;
-  GdkEvent *event;
-
-  seat = gdk_display_get_default_seat (gtk_widget_get_display (widget));
-  device = gdk_seat_get_keyboard (seat);
-
-  event = gdk_event_new (GDK_FOCUS_CHANGE);
-  gdk_event_set_display (event, gtk_widget_get_display (widget));
-  gdk_event_set_device (event, device);
-
-  event->any.type = GDK_FOCUS_CHANGE;
-  event->any.surface = _gtk_widget_get_surface (widget);
-  if (event->any.surface)
-    g_object_ref (event->any.surface);
-  event->focus_change.in = in;
-  event->focus_change.mode = GDK_CROSSING_STATE_CHANGED;
-  event->focus_change.detail = GDK_NOTIFY_ANCESTOR;
-
-  gtk_widget_set_has_focus (widget, in);
-  gtk_widget_event (widget, event);
-
-  g_object_unref (event);
-}
-
-static void
-gtk_popover_set_is_active (GtkPopover *popover,
-                           gboolean    active)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (priv->active == active)
-    return;
-
-  priv->active = active;
-
-  if (priv->focus_widget &&
-      priv->focus_widget != GTK_WIDGET (popover) &&
-      gtk_widget_has_focus (priv->focus_widget) != active)
-    do_focus_change (priv->focus_widget, active);
-}
-
 GListModel *
 gtk_popover_get_popovers (void)
 {
@@ -1076,367 +895,10 @@ gtk_popover_get_popovers (void)
 }
 
 static void
-gtk_popover_set_default (GtkPopover *popover,
-                         GtkWidget  *widget)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  g_return_if_fail (GTK_IS_POPOVER (popover));
-
-  if (widget && !gtk_widget_get_can_default (widget))
-    return;
-
-  if (priv->default_widget == widget)
-    return;
-
-  if (priv->default_widget)
-    {
-      if (priv->focus_widget != priv->default_widget ||
-          !gtk_widget_get_receives_default (priv->default_widget))
-        _gtk_widget_set_has_default (priv->default_widget, FALSE);
-
-      gtk_widget_queue_draw (priv->default_widget);
-      g_object_notify (G_OBJECT (priv->default_widget), "has-default");
-    }
-
-  g_set_object (&priv->default_widget, widget);
-
-  if (priv->default_widget)
-    {
-      if (priv->focus_widget == NULL ||
-          !gtk_widget_get_receives_default (priv->focus_widget))
-        _gtk_widget_set_has_default (priv->default_widget, TRUE);
-
-      gtk_widget_queue_draw (priv->default_widget);
-      g_object_notify (G_OBJECT (priv->default_widget), "has-default");
-    }
-
-  g_object_notify (G_OBJECT (popover), "default-widget");
-}
-
-static GtkMnemonicHash *
-gtk_popover_get_mnemonic_hash (GtkPopover *popover,
-                               gboolean    create)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (!priv->mnemonic_hash && create)
-    priv->mnemonic_hash = _gtk_mnemonic_hash_new ();
-
-  return priv->mnemonic_hash;
-}
-
-static void
-gtk_popover_root_add_mnemonic (GtkRoot   *root,
-                               guint      keyval,
-                               GtkWidget *target)
-{
-  _gtk_mnemonic_hash_add (gtk_popover_get_mnemonic_hash (GTK_POPOVER (root), TRUE), keyval, target);
-}
-
-static void
-gtk_popover_root_remove_mnemonic (GtkRoot   *root,
-                                  guint      keyval,
-                                  GtkWidget *target)
-{
-  _gtk_mnemonic_hash_remove (gtk_popover_get_mnemonic_hash (GTK_POPOVER (root), TRUE), keyval, target);
-}
-
-static gboolean
-gtk_popover_root_activate_key (GtkRoot     *root,
-                               GdkEventKey *event)
-{
-  GdkModifierType modifier = event->state;
-  guint keyval = event->keyval;
-
-  if ((modifier & gtk_accelerator_get_default_mod_mask ()) == GDK_MOD1_MASK)
-    {
-      GtkMnemonicHash *hash = gtk_popover_get_mnemonic_hash (GTK_POPOVER (root), FALSE);
-      if (hash)
-        return _gtk_mnemonic_hash_activate (hash, keyval);      
-    }
-
-  return FALSE;
-}
-
-static GtkPointerFocus *
-gtk_popover_lookup_pointer_focus (GtkPopover       *popover,
-                                  GdkDevice        *device,
-                                  GdkEventSequence *sequence)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GList *l;
-
-  for (l = priv->foci; l; l = l->next)
-    {
-      GtkPointerFocus *focus = l->data;
-
-      if (focus->device == device && focus->sequence == sequence)
-        return focus;
-    }
-
-  return NULL;
-}
-
-static void
-gtk_popover_add_pointer_focus (GtkPopover      *popover,
-                               GtkPointerFocus *focus)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  priv->foci = g_list_prepend (priv->foci, gtk_pointer_focus_ref (focus));
-}
-
-static void
-gtk_popover_remove_pointer_focus (GtkPopover      *popover,
-                                  GtkPointerFocus *focus)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GList *pos;
-
-  pos = g_list_find (priv->foci, focus);
-  if (!pos)
-    return;
-
-  priv->foci = g_list_remove (priv->foci, focus);
-  gtk_pointer_focus_unref (focus);
-}
-
-static void
-gtk_popover_root_update_pointer_focus (GtkRoot          *root,
-                                       GdkDevice        *device,
-                                       GdkEventSequence *sequence,
-                                       GtkWidget        *target,
-                                       double            x,
-                                       double            y)
-{
-  GtkPopover *popover = GTK_POPOVER (root);
-  GtkPointerFocus *focus;
-
-  focus = gtk_popover_lookup_pointer_focus (popover, device, sequence);
-  if (focus)
-    {
-      gtk_pointer_focus_ref (focus);
-
-      if (target)
-        {
-          gtk_pointer_focus_set_target (focus, target);
-          gtk_pointer_focus_set_coordinates (focus, x, y);
-        }
-      else
-        {
-          gtk_popover_remove_pointer_focus (popover, focus);
-        }
-
-      gtk_pointer_focus_unref (focus);
-    }
-  else if (target)
-    {
-      focus = gtk_pointer_focus_new (root, target, device, sequence, x, y);
-      gtk_popover_add_pointer_focus (popover, focus);
-      gtk_pointer_focus_unref (focus);
-    }
-}
-
-static void
-gtk_popover_root_update_pointer_focus_on_state_change (GtkRoot   *root,
-                                                       GtkWidget *widget)
-{
-  GtkPopover *popover = GTK_POPOVER (root);
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GList *l = priv->foci, *cur;
-
-  while (l)
-    {
-      GtkPointerFocus *focus = l->data;
-
-      cur = l;
-      focus = cur->data;
-      l = cur->next;
-
-      gtk_pointer_focus_ref (focus);
-
-      if (focus->grab_widget &&
-          (focus->grab_widget == widget ||
-           gtk_widget_is_ancestor (focus->grab_widget, widget)))
-        gtk_pointer_focus_set_implicit_grab (focus, NULL);
-
-      if (GTK_WIDGET (focus->toplevel) == widget)
-        {
-          /* Unmapping the toplevel, remove pointer focus */
-          priv->foci = g_list_remove_link (priv->foci, cur);
-          gtk_pointer_focus_unref (focus);
-        }
-      else if (focus->target == widget ||
-               gtk_widget_is_ancestor (focus->target, widget))
-        {
-          gtk_pointer_focus_repick_target (focus);
-        }
-
-      gtk_pointer_focus_unref (focus);
-    }
-}
-
-static GtkWidget *
-gtk_popover_root_lookup_pointer_focus (GtkRoot          *root,
-                                       GdkDevice        *device,
-                                       GdkEventSequence *sequence)
-{
-  GtkPopover *popover = GTK_POPOVER (root);
-  GtkPointerFocus *focus;
-
-  focus = gtk_popover_lookup_pointer_focus (popover, device, sequence);
-  return focus ? gtk_pointer_focus_get_target (focus) : NULL;
-}
-
-static GtkWidget *
-gtk_popover_root_lookup_effective_pointer_focus (GtkRoot          *root,
-                                                 GdkDevice        *device,
-                                                 GdkEventSequence *sequence)
-{
-  GtkPopover *popover = GTK_POPOVER (root);
-  GtkPointerFocus *focus;
-
-  focus = gtk_popover_lookup_pointer_focus (popover, device, sequence);
-  return focus ? gtk_pointer_focus_get_effective_target (focus) : NULL;
-}
-
-static GtkWidget *
-gtk_popover_root_lookup_pointer_focus_implicit_grab (GtkRoot          *root,
-                                                     GdkDevice        *device,
-                                                     GdkEventSequence *sequence)
-{  
-  GtkPopover *popover = GTK_POPOVER (root);
-  GtkPointerFocus *focus;
-
-  focus = gtk_popover_lookup_pointer_focus (popover, device, sequence);
-  return focus ? gtk_pointer_focus_get_implicit_grab (focus) : NULL;
-}
-
-static void
-gtk_popover_root_set_pointer_focus_grab (GtkRoot          *root,
-                                         GdkDevice        *device,
-                                         GdkEventSequence *sequence,
-                                         GtkWidget        *grab_widget)
-{
-  GtkPopover *popover = GTK_POPOVER (root);
-  GtkPointerFocus *focus;
-
-  focus = gtk_popover_lookup_pointer_focus (popover, device, sequence);
-  if (!focus && !grab_widget)
-    return;
-  g_assert (focus != NULL);
-  gtk_pointer_focus_set_implicit_grab (focus, grab_widget);
-}
-
-static void
-update_cursor (GtkRoot   *root,
-               GdkDevice *device,
-               GtkWidget *grab_widget,
-               GtkWidget *target)
-{
-  GdkCursor *cursor = NULL;
-
-  if (grab_widget && !gtk_widget_is_ancestor (target, grab_widget))
-    {
-      /* Outside the grab widget, cursor stays to whatever the grab
-       * widget says.
-       */
-      cursor = gtk_widget_get_cursor (grab_widget);
-    }
-  else
-    {
-      /* Inside the grab widget or in absence of grabs, allow walking
-       * up the hierarchy to find out the cursor.
-       */
-      while (target)
-        {
-          if (grab_widget && target == grab_widget)
-            break;
-
-          cursor = gtk_widget_get_cursor (target);
-
-          if (cursor)
-            break;
-
-          target = _gtk_widget_get_parent (target);
-        }
-    }
-
-  gdk_surface_set_device_cursor (gtk_widget_get_surface (GTK_WIDGET (root)), device, cursor);
-}
-
-static void
-gtk_popover_root_maybe_update_cursor (GtkRoot   *root,
-                                      GtkWidget *widget,
-                                      GdkDevice *device)
-{
-  GtkPopover *popover = GTK_POPOVER (root);
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GList *l;
-
-  for (l = priv->foci; l; l = l->next)
-    {
-      GtkPointerFocus *focus = l->data;
-      GtkWidget *grab_widget = NULL;
-      GtkWidget  *target;
-
-      if (focus->sequence)
-        continue;
-      if (device && device != focus->device)
-        continue;
-
-#if 0
-        {
-          GtkWindowGroup *group = gtk_window_get_group (root);
-          grab_widget = gtk_window_group_get_current_device_grab (group, focus->device);
-          if (!grab_widget)
-            grab_widget = gtk_window_group_get_current_grab (group);
-        }
-#endif
-
-      if (!grab_widget)
-        grab_widget = gtk_pointer_focus_get_implicit_grab (focus);
-
-      target = gtk_pointer_focus_get_target (focus);
-
-      if (widget)
-        {
-          /* Check whether the changed widget affects the current cursor
-           * lookups.
-           */
-          if (grab_widget && grab_widget != widget &&
-              !gtk_widget_is_ancestor (widget, grab_widget))
-            continue;
-          if (target != widget &&
-              !gtk_widget_is_ancestor (target, widget))
-            continue;
-        }
-
-      update_cursor (focus->toplevel, focus->device, grab_widget, target);
-
-      if (device)
-        break;
-    }
-}
-
-static void
-gtk_popover_root_interface_init (GtkRootInterface *iface)
+gtk_popover_bud_interface_init (GtkBudInterface *iface)
 {
-  iface->get_display = gtk_popover_root_get_display;
-  iface->get_renderer = gtk_popover_root_get_renderer;
-  iface->get_surface_transform = gtk_popover_root_get_surface_transform;
-  iface->check_resize = gtk_popover_root_check_resize;
-  iface->add_mnemonic = gtk_popover_root_add_mnemonic;
-  iface->remove_mnemonic = gtk_popover_root_remove_mnemonic;
-  iface->activate_key = gtk_popover_root_activate_key;
-  iface->update_pointer_focus = gtk_popover_root_update_pointer_focus;
-  iface->update_pointer_focus_on_state_change = gtk_popover_root_update_pointer_focus_on_state_change;
-  iface->lookup_pointer_focus = gtk_popover_root_lookup_pointer_focus;
-  iface->lookup_pointer_focus_implicit_grab = gtk_popover_root_lookup_pointer_focus_implicit_grab;
-  iface->lookup_effective_pointer_focus = gtk_popover_root_lookup_effective_pointer_focus;
-  iface->set_pointer_focus_grab = gtk_popover_root_set_pointer_focus_grab;
-  iface->maybe_update_cursor = gtk_popover_root_maybe_update_cursor;
+  iface->get_renderer = gtk_popover_bud_get_renderer;
+  iface->get_surface_transform = gtk_popover_bud_get_surface_transform;
 }
 
 /**
@@ -1474,7 +936,6 @@ gtk_popover_set_relative_to (GtkPopover *popover,
   if (priv->relative_to)
     {
       g_signal_connect (priv->relative_to, "size-allocate", G_CALLBACK (size_changed), popover);
-      priv->display = gtk_widget_get_display (relative_to);
       gtk_css_node_set_parent (gtk_widget_get_css_node (GTK_WIDGET (popover)),
                                gtk_widget_get_css_node (relative_to));
       gtk_widget_set_parent (GTK_WIDGET (popover), relative_to);
@@ -1683,25 +1144,6 @@ gtk_popover_popdown (GtkPopover *popover)
   gtk_widget_hide (GTK_WIDGET (popover));
 }
 
-/**
- * gtk_popover_set_default_widget:
- * @popover: a #GtkPopover
- * @widget: (allow-none): the new default widget, or %NULL
- *
- * Sets the widget that should be set as default widget while
- * the popover is shown (see gtk_window_set_default()). #GtkPopover
- * remembers the previous default widget and reestablishes it
- * when the popover is dismissed.
- */
-void
-gtk_popover_set_default_widget (GtkPopover *popover,
-                                GtkWidget  *widget)
-{
-  g_return_if_fail (GTK_IS_POPOVER (popover));
-
-  gtk_root_set_default (GTK_ROOT (popover), widget);
-}
-
 static void
 back_to_main (GtkWidget *popover)
 {
@@ -1828,3 +1270,10 @@ gtk_popover_get_contents_widget (GtkPopover *popover)
 
   return priv->contents_widget;
 }
+
+void
+gtk_popover_set_default_widget (GtkPopover *popover,
+                                GtkWidget  *widget)
+{
+  // FIXME
+}
diff --git a/gtk/gtkpopover.h b/gtk/gtkpopover.h
index d628bfdf1c..bd8f8a123a 100644
--- a/gtk/gtkpopover.h
+++ b/gtk/gtkpopover.h
@@ -104,10 +104,8 @@ GDK_AVAILABLE_IN_ALL
 void            gtk_popover_popdown (GtkPopover *popover);
 
 GDK_AVAILABLE_IN_ALL
-void
-gtk_popover_set_default_widget (GtkPopover *popover,
-                                GtkWidget  *widget);
-
+void gtk_popover_set_default_widget (GtkPopover *popover,
+                                     GtkWidget  *widget);
 
 GDK_AVAILABLE_IN_ALL
 GListModel *    gtk_popover_get_popovers (void);
diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c
index bc5f12f076..b9f5858cef 100644
--- a/gtk/gtkroot.c
+++ b/gtk/gtkroot.c
@@ -20,6 +20,7 @@
 #include "config.h"
 
 #include "gtkrootprivate.h"
+#include "gtkbud.h"
 #include "gtkcssnodeprivate.h"
 #include "gtkwidgetprivate.h"
 #include "gdk/gdk-private.h"
@@ -40,7 +41,8 @@
  * The obvious example of a #GtkRoot is #GtkWindow.
  */
 
-G_DEFINE_INTERFACE (GtkRoot, gtk_root, GTK_TYPE_WIDGET)
+G_DEFINE_INTERFACE_WITH_CODE (GtkRoot, gtk_root, GTK_TYPE_WIDGET,
+                              g_type_interface_add_prerequisite (g_define_type_id, GTK_TYPE_BUD))
 
 static GdkDisplay *
 gtk_root_default_get_display (GtkRoot *self)
@@ -84,7 +86,7 @@ gtk_root_default_remove_mnemonic (GtkRoot   *self,
 
 static gboolean
 gtk_root_default_activate_key (GtkRoot     *self,
-                               GdkEventKey *event)
+                           GdkEventKey *event)
 {
   return FALSE;
 }
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 02d1a4b3ed..97bd438d30 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -57,6 +57,7 @@
 #include "gtkrenderbackgroundprivate.h"
 #include "gtkrenderborderprivate.h"
 #include "gtkrootprivate.h"
+#include "gtkbudprivate.h"
 #include "gtkscrollable.h"
 #include "gtkselection.h"
 #include "gtksettingsprivate.h"
@@ -3669,7 +3670,7 @@ sync_widget_surface_transform (GtkWidget *widget)
   was_valid = surface_transform_data->cached_surface_transform_valid;
   prev_transform = surface_transform_data->cached_surface_transform;
 
-  if (GTK_IS_ROOT (widget))
+  if (GTK_IS_BUD (widget))
     {
       gsk_transform_to_matrix (priv->transform,
                                &surface_transform_data->cached_surface_transform);
@@ -3679,15 +3680,20 @@ sync_widget_surface_transform (GtkWidget *widget)
     {
       surface_transform_data->cached_surface_transform_valid = FALSE;
     }
-  else if (gtk_widget_compute_transform (widget, GTK_WIDGET (priv->root),
-                                         &surface_transform_data->cached_surface_transform))
-    {
-      surface_transform_data->cached_surface_transform_valid = TRUE;
-    }
   else
     {
-      g_warning ("Could not compute surface transform");
-      surface_transform_data->cached_surface_transform_valid = FALSE;
+      GtkWidget *bud = gtk_widget_get_ancestor (widget, GTK_TYPE_BUD);
+
+      if (gtk_widget_compute_transform (widget, bud,
+                                        &surface_transform_data->cached_surface_transform))
+        {
+          surface_transform_data->cached_surface_transform_valid = TRUE;
+        }
+      else
+        {
+          g_warning ("Could not compute surface transform");
+          surface_transform_data->cached_surface_transform_valid = FALSE;
+        }
     }
 
   if (was_valid != surface_transform_data->cached_surface_transform_valid ||
@@ -11561,7 +11567,7 @@ gtk_widget_set_surface (GtkWidget *widget,
  *
  * Returns: (transfer none) (nullable): @widget’s surface.
  */
-GdkSurface*
+GdkSurface *
 gtk_widget_get_surface (GtkWidget *widget)
 {
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
@@ -13118,7 +13124,7 @@ gtk_widget_snapshot (GtkWidget   *widget,
 
 void
 gtk_widget_render (GtkWidget            *widget,
-                   GdkSurface            *surface,
+                   GdkSurface           *surface,
                    const cairo_region_t *region)
 {
   GtkSnapshot *snapshot;
@@ -13126,15 +13132,15 @@ gtk_widget_render (GtkWidget            *widget,
   GskRenderNode *root;
   int x, y;
 
-  if (!GTK_IS_ROOT (widget))
+  if (!GTK_IS_BUD (widget))
     return;
 
-  renderer = gtk_root_get_renderer (GTK_ROOT (widget));
+  renderer = gtk_bud_get_renderer (GTK_BUD (widget));
   if (renderer == NULL)
     return;
 
   snapshot = gtk_snapshot_new ();
-  gtk_root_get_surface_transform (GTK_ROOT (widget), &x, &y);
+  gtk_bud_get_surface_transform (GTK_BUD (widget), &x, &y);
   gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
   gtk_widget_snapshot (widget, snapshot);
   root = gtk_snapshot_free_to_node (snapshot);
@@ -13455,7 +13461,7 @@ gtk_widget_snapshot_child (GtkWidget   *widget,
   g_return_if_fail (_gtk_widget_get_parent (child) == widget);
   g_return_if_fail (snapshot != NULL);
 
-  if (GTK_IS_ROOT (child))
+  if (GTK_IS_BUD (child))
     return;
 
   gtk_snapshot_save (snapshot);
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 1dd1e367ec..03090e7beb 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -62,6 +62,7 @@
 #include "gtkpopoverprivate.h"
 #include "gtkprivate.h"
 #include "gtkroot.h"
+#include "gtkbud.h"
 #include "gtkseparatormenuitem.h"
 #include "gtksettings.h"
 #include "gtksnapshot.h"
@@ -559,7 +560,8 @@ static void gtk_window_buildable_custom_finished (GtkBuildable  *buildable,
                                                      gpointer       user_data);
 
 /* GtkRoot */
-static void             gtk_window_root_interface_init                  (GtkRootInterface       *iface);
+static void             gtk_window_root_interface_init (GtkRootInterface *iface);
+static void             gtk_window_bud_interface_init  (GtkBudInterface  *iface);
 
 static void ensure_state_flag_backdrop (GtkWidget *widget);
 static void unset_titlebar (GtkWindow *window);
@@ -576,6 +578,8 @@ G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN,
                          G_ADD_PRIVATE (GtkWindow)
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
                                                gtk_window_buildable_interface_init)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUD,
+                                               gtk_window_bud_interface_init)
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ROOT,
                                                gtk_window_root_interface_init))
 
@@ -2460,6 +2464,40 @@ gtk_window_root_interface_init (GtkRootInterface *iface)
   iface->maybe_update_cursor = gtk_window_root_maybe_update_cursor;
 }
 
+static GskRenderer *
+gtk_window_bud_get_renderer (GtkBud *bud)
+{
+  GtkWindow *self = GTK_WINDOW (bud);
+  GtkWindowPrivate *priv = gtk_window_get_instance_private (self);
+
+  return priv->renderer;
+}
+
+static void
+gtk_window_bud_get_surface_transform (GtkBud *bud,
+                                      int    *x,
+                                      int    *y)
+{
+  GtkWindow *self = GTK_WINDOW (bud);
+  GtkStyleContext *context;
+  GtkBorder margin, border, padding;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  gtk_style_context_get_margin (context, &margin);
+  gtk_style_context_get_border (context, &border);
+  gtk_style_context_get_padding (context, &padding);
+
+  *x = margin.left + border.left + padding.left;
+  *y = margin.top + border.top + padding.top;
+}
+
+static void
+gtk_window_bud_interface_init (GtkBudInterface *iface)
+{
+  iface->get_renderer = gtk_window_bud_get_renderer;
+  iface->get_surface_transform = gtk_window_bud_get_surface_transform;
+}
+
 /**
  * gtk_window_new:
  * @type: type of window
diff --git a/gtk/meson.build b/gtk/meson.build
index 76fef838f5..eebe23dd2a 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -316,6 +316,7 @@ gtk_public_sources = files([
   'gtkrendernodepaintable.c',
   'gtkrevealer.c',
   'gtkroot.c',
+  'gtkbud.c',
   'gtkroundedbox.c',
   'gtkscale.c',
   'gtkscalebutton.c',



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