[gtk/wip/matthiasc/popup2: 86/126] Replace GtkPopover by GtkPopup



commit 84585940e8d0113cbd2bd4989d8d6ff77af9a360
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Mar 20 23:35:04 2019 -0400

    Replace GtkPopover by GtkPopup
    
    Rename GtkPopup to GtkPopover, and make things work.

 gtk/gtk.h                   |    1 -
 gtk/gtkmain.c               |    2 +-
 gtk/gtkpopover.c            | 2881 ++++++++++++++-----------------------------
 gtk/gtkpopover.h            |   98 +-
 gtk/gtkpopovermenu.c        |    2 +
 gtk/gtkpopoverprivate.h     |    2 -
 gtk/gtkpopup.c              | 1300 -------------------
 gtk/gtkpopup.h              |   97 --
 gtk/gtkwidget.c             |   10 +-
 gtk/gtkwindow.c             |    2 +
 gtk/inspector/object-tree.c |    4 +-
 gtk/meson.build             |    1 -
 tests/meson.build           |    1 -
 tests/testpopup.c           |   90 --
 14 files changed, 1000 insertions(+), 3491 deletions(-)
---
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 6cc64406bd..6d1ca27b5f 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -170,7 +170,6 @@
 #include <gtk/gtkpicture.h>
 #include <gtk/gtkpopover.h>
 #include <gtk/gtkpopovermenu.h>
-#include <gtk/gtkpopup.h>
 #include <gtk/gtkprintcontext.h>
 #include <gtk/gtkprintoperation.h>
 #include <gtk/gtkprintoperationpreview.h>
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 257de5c48b..c5bc0c4eae 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1341,7 +1341,7 @@ rewrite_event_for_grabs (GdkEvent *event)
     case GDK_TOUCHPAD_SWIPE:
     case GDK_TOUCHPAD_PINCH:
       if (grab_surface != event->any.surface &&
-          GTK_IS_POPUP (grab_widget))
+          GTK_IS_POPOVER (grab_widget))
         {
           gtk_widget_hide (grab_widget);
           return NULL;
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index a39270c5a7..f30a274cea 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -1,5 +1,8 @@
 /* GTK - The GIMP Toolkit
- * Copyright © 2013 Carlos Garnacho <carlosg gnome org>
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Authors:
+ * - Matthias Clasen <mclasen redhat com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -15,1514 +18,647 @@
  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
-/**
- * SECTION:gtkpopover
- * @Short_description: Context dependent bubbles
- * @Title: GtkPopover
- *
- * GtkPopover is a bubble-like context window, primarily meant to
- * provide context-dependent information or options. Popovers are
- * attached to a widget, passed at construction time on gtk_popover_new(),
- * or updated afterwards through gtk_popover_set_relative_to(), by
- * default they will point to the whole widget area, although this
- * behavior can be changed through gtk_popover_set_pointing_to().
- *
- * The position of a popover relative to the widget it is attached to
- * can also be changed through gtk_popover_set_position().
- *
- * By default, #GtkPopover performs a GTK+ grab, in order to ensure
- * input events get redirected to it while it is shown, and also so
- * the popover is dismissed in the expected situations (clicks outside
- * the popover, or the Esc key being pressed). If no such modal behavior
- * is desired on a popover, gtk_popover_set_modal() may be called on it
- * to tweak its behavior.
- *
- * ## GtkPopover as menu replacement
- *
- * GtkPopover is often used to replace menus. To facilitate this, it
- * supports being populated from a #GMenuModel, using
- * gtk_popover_new_from_model(). In addition to all the regular menu
- * model features, this function supports rendering sections in the
- * model in a more compact form, as a row of icon buttons instead of
- * menu items.
- *
- * To use this rendering, set the ”display-hint” attribute of the
- * section to ”horizontal-buttons” and set the icons of your items
- * with the ”verb-icon” attribute.
- *
- * |[
- * <section>
- *   <attribute name="display-hint">horizontal-buttons</attribute>
- *   <item>
- *     <attribute name="label">Cut</attribute>
- *     <attribute name="action">app.cut</attribute>
- *     <attribute name="verb-icon">edit-cut-symbolic</attribute>
- *   </item>
- *   <item>
- *     <attribute name="label">Copy</attribute>
- *     <attribute name="action">app.copy</attribute>
- *     <attribute name="verb-icon">edit-copy-symbolic</attribute>
- *   </item>
- *   <item>
- *     <attribute name="label">Paste</attribute>
- *     <attribute name="action">app.paste</attribute>
- *     <attribute name="verb-icon">edit-paste-symbolic</attribute>
- *   </item>
- * </section>
- * ]|
- *
- * # CSS nodes
- *
- * |[<!-- language="plain" -->
- * popover
- * ├── arrow
- * ╰── contents.background[.menu]
- *     ╰── <child>
- * ]|
- *
- * The contents child node always gets the .background style class and it
- * gets the .menu style class if the popover is menu-like (e.g. #GtkPopoverMenu
- * or created using gtk_popover_new_from_model()).
- *
- * Particular uses of GtkPopover, such as touch selection popups
- * or magnifiers in #GtkEntry or #GtkTextView get style classes
- * like .touch-selection or .magnifier to differentiate from
- * plain popovers.
- *
- * When styling a popover directly, the popover node should usually not have any
- * background.
- *
- * Note that, in order to accomplish appropriate arrow visuals, #GtkPopover uses
- * custom drawing for the arrow node. This makes it possible for the arrow to change
- * its shape dynamically, but it also limits the possibilities of styling it using CSS.
- * In particular, the arrow gets drawn over the content node's border so they look
- * like one shape, which means that the border-width of the content node and the arrow
- * node should be the same. The arrow also does not support any border shape other than
- * solid, no border-radius, only one border width (border-bottom-width is used) and no box-shadow.
- */
-
 #include "config.h"
 
 #include "gtkpopoverprivate.h"
-
-#include "gtkadjustment.h"
-#include "gtkbox.h"
-#include "gtkbutton.h"
-#include "gtkcontainerprivate.h"
+#include "gtkroot.h"
+#include "gtkwidgetprivate.h"
+#include "gtkeventcontrollerkey.h"
 #include "gtkcssnodeprivate.h"
-#include "gtkentry.h"
+#include "gtkbindings.h"
+#include "gtkenums.h"
+#include "gtktypebuiltins.h"
+#include "gtkmnemonichash.h"
 #include "gtkgizmoprivate.h"
 #include "gtkintl.h"
-#include "gtklabel.h"
-#include "gtkmain.h"
-#include "gtkmenusectionbox.h"
-#include "gtkmenutracker.h"
-#include "gtkmodelbutton.h"
 #include "gtkprivate.h"
-#include "gtkprogresstrackerprivate.h"
-#include "gtkrender.h"
-#include "gtkroundedboxprivate.h"
-#include "gtkscrollable.h"
-#include "gtksettingsprivate.h"
-#include "gtksizegroup.h"
-#include "gtksnapshot.h"
+#include "gtkmain.h"
 #include "gtkstack.h"
-#include "gtkstylecontextprivate.h"
-#include "gtktypebuiltins.h"
-#include "gtkwidgetprivate.h"
-#include "gtkwindowprivate.h"
-#include "gtkgesturemultipress.h"
-#include "gtkeventcontrollerkey.h"
+#include "gtkmenusectionbox.h"
+#include "gdk/gdkeventsprivate.h"
+#include "gtkpointerfocusprivate.h"
+
+static GListStore *popover_list = NULL;
 
-#include "a11y/gtkpopoveraccessible.h"
+typedef struct {
+  GdkDisplay *display;
+  GskRenderer *renderer;
+  GdkSurface *surface;
+  GtkWidget *focus_widget;
+  gboolean active;
+  GtkWidget *default_widget;
+  GtkMnemonicHash *mnemonic_hash;
+  GList *foci;
 
-#include "gsk/gskroundedrectprivate.h"
+  GdkSurfaceState state;
+  GtkWidget *relative_to;
+  GdkRectangle pointing_to;
+  gboolean has_pointing_to;
+  GtkPositionType position;
+  gboolean modal;
+  gboolean has_grab;
 
-#ifdef GDK_WINDOWING_WAYLAND
-#include "wayland/gdkwayland.h"
-#endif
+  GtkWidget *contents_widget;
+} GtkPopoverPrivate;
 
-#define TAIL_GAP_WIDTH  24
-#define TAIL_HEIGHT     12
-#define TRANSITION_DIFF 20
-#define TRANSITION_DURATION 150 * 1000
+enum {
+  ACTIVATE_FOCUS,
+  ACTIVATE_DEFAULT,
+  CLOSE,
+  CLOSED,
+  LAST_SIGNAL
+};
 
-#define POS_IS_VERTICAL(p) ((p) == GTK_POS_TOP || (p) == GTK_POS_BOTTOM)
+static guint signals[LAST_SIGNAL] = { 0 };
 
 enum {
   PROP_RELATIVE_TO = 1,
   PROP_POINTING_TO,
   PROP_POSITION,
   PROP_MODAL,
-  PROP_CONSTRAIN_TO,
   NUM_PROPERTIES
 };
 
-enum {
-  CLOSED,
-  N_SIGNALS
-};
-
-enum {
-  STATE_SHOWING,
-  STATE_SHOWN,
-  STATE_HIDING,
-  STATE_HIDDEN
-};
-
-typedef struct _GtkPopoverPrivate GtkPopoverPrivate;
-struct _GtkPopoverPrivate
-{
-  GtkWidget *widget;
-  GtkWidget *contents_widget;
-  GtkCssNode *arrow_node;
-  GtkWindow *window;
-  GtkWidget *prev_focus_widget;
-  GtkWidget *default_widget;
-  GtkWidget *prev_default;
-  GtkScrollable *parent_scrollable;
-  GtkAdjustment *vadj;
-  GtkAdjustment *hadj;
-  GdkRectangle pointing_to;
-  GtkPopoverConstraint constraint;
-  GtkProgressTracker tracker;
-  guint prev_focus_unmap_id;
-  guint hierarchy_changed_id;
-  guint size_allocate_id;
-  guint unmap_id;
-  guint scrollable_notify_id;
-  guint grab_notify_id;
-  guint state_changed_id;
-  guint has_pointing_to    : 1;
-  guint preferred_position : 2;
-  guint final_position     : 2;
-  guint current_position   : 2;
-  guint modal              : 1;
-  guint button_pressed     : 1;
-  guint grab_notify_blocked : 1;
-  guint state               : 2;
-  guint visible             : 1;
-  guint first_frame_skipped : 1;
-  gint transition_diff;
-  guint tick_id;
-
-  gint tip_x;
-  gint tip_y;
-};
-
-static GParamSpec *properties[NUM_PROPERTIES];
-static GQuark quark_widget_popovers = 0;
-static guint signals[N_SIGNALS] = { 0 };
-
-static void gtk_popover_update_relative_to (GtkPopover *popover,
-                                            GtkWidget  *relative_to);
-static void gtk_popover_set_state          (GtkPopover *popover,
-                                            guint       state);
-static void gtk_popover_apply_modality     (GtkPopover *popover,
-                                            gboolean    modal);
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL };
 
-static void gtk_popover_set_scrollable_full (GtkPopover    *popover,
-                                             GtkScrollable *scrollable);
+static void gtk_popover_root_interface_init (GtkRootInterface *iface);
 
-G_DEFINE_TYPE_WITH_PRIVATE (GtkPopover, gtk_popover, GTK_TYPE_BIN)
+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 void
-measure_contents (GtkGizmo       *gizmo,
-                  GtkOrientation  orientation,
-                  int             for_size,
-                  int            *minimum,
-                  int            *natural,
-                  int            *minimum_baseline,
-                  int            *natural_baseline)
-{
-  GtkPopover *popover = GTK_POPOVER (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
-  GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
-
-  if (child)
-    gtk_widget_measure (child, orientation, for_size,
-                        minimum, natural,
-                        minimum_baseline, natural_baseline);
-}
-
-static void
-allocate_contents (GtkGizmo *gizmo,
-                   int       width,
-                   int       height,
-                   int       baseline)
-{
-  GtkPopover *popover = GTK_POPOVER (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
-  GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
-
-  if (child)
-    gtk_widget_size_allocate (child,
-                              &(GtkAllocation) {
-                                0, 0,
-                                width, height
-                              }, -1);
-}
-
-static void
-node_style_changed_cb (GtkCssNode        *node,
-                       GtkCssStyleChange *change,
-                       GtkWidget         *widget)
-{
-  if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_SIZE))
-    gtk_widget_queue_resize (widget);
-  else
-    gtk_widget_queue_draw (widget);
-}
-
-static gboolean
-key_controller_key_pressed (GtkEventControllerKey *key,
-                            guint                  keyval,
-                            guint                  keycode,
-                            GdkModifierType        modifiers,
-                            GtkPopover            *popover)
+static GdkDisplay *
+gtk_popover_root_get_display (GtkRoot *root)
 {
+  GtkPopover *popover = GTK_POPOVER (root);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWidget *toplevel, *focus;
-
-  if (keyval == GDK_KEY_Escape)
-    {
-      gtk_popover_popdown (popover);
-      return TRUE;
-    }
-
-  if (priv->modal)
-    {
-      toplevel = gtk_widget_get_toplevel (GTK_WIDGET (popover));
-
-      if (GTK_IS_WINDOW (toplevel))
-        {
-          focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
 
-          if (focus && gtk_widget_is_ancestor (focus, GTK_WIDGET (popover)))
-            {
-              if (gtk_event_controller_key_forward (key, focus))
-                return TRUE;
-            }
-
-          /* Piggyback on the toplevel to have it handle key navigation */
-          return gtk_event_controller_key_forward (key, toplevel);
-        }
-    }
-
-  return FALSE;
+  return priv->display;
 }
 
-static void
-gesture_pressed (GtkGestureMultiPress *gesture,
-                 gint                  n_press,
-                 gdouble               x,
-                 gdouble               y,
-                 GtkPopover           *popover)
+static GskRenderer *
+gtk_popover_root_get_renderer (GtkRoot *root)
 {
+  GtkPopover *popover = GTK_POPOVER (root);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  priv->button_pressed = TRUE;
+  return priv->renderer;
 }
 
 static void
-gesture_released (GtkGestureMultiPress *gesture,
-                  gint                  n_press,
-                  gdouble               x,
-                  gdouble               y,
-                  GtkPopover           *popover)
+gtk_popover_root_get_surface_transform (GtkRoot *root,
+                                      int     *x,
+                                      int     *y)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  graphene_rect_t child_bounds;
-  GtkWidget *child;
+  GtkStyleContext *context;
+  GtkBorder margin, border, padding;
 
-  if (!priv->button_pressed)
-    return;
+  context = gtk_widget_get_style_context (GTK_WIDGET (root));
+  gtk_style_context_get_margin (context, &margin);
+  gtk_style_context_get_border (context, &border);
+  gtk_style_context_get_padding (context, &padding);
 
-  child = gtk_bin_get_child (GTK_BIN (popover));
-  if (!child ||
-      !gtk_widget_compute_bounds (child, GTK_WIDGET (popover), &child_bounds) ||
-      !graphene_rect_contains_point (&child_bounds,
-                                     &(graphene_point_t){x, y}))
-    gtk_popover_popdown (popover);
+  *x = margin.left + border.left + padding.left;
+  *y = margin.top + border.top + padding.top;
 }
 
 static void
-gtk_popover_init (GtkPopover *popover)
+move_to_rect (GtkPopover *popover)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWidget *widget;
-  GtkStyleContext *context;
-  GtkEventController *controller;
-
-  widget = GTK_WIDGET (popover);
-  gtk_widget_set_has_surface (widget, TRUE);
-  priv->modal = TRUE;
-  priv->tick_id = 0;
-  priv->state = STATE_HIDDEN;
-  priv->visible = FALSE;
-  priv->preferred_position = GTK_POS_TOP;
-  priv->constraint = GTK_POPOVER_CONSTRAINT_WINDOW;
-
-  priv->arrow_node = gtk_css_node_new ();
-  gtk_css_node_set_name (priv->arrow_node, I_("arrow"));
-  gtk_css_node_set_parent (priv->arrow_node, gtk_widget_get_css_node (widget));
-  gtk_css_node_set_state (priv->arrow_node,
-                          gtk_css_node_get_state (gtk_widget_get_css_node (widget)));
-  g_signal_connect_object (priv->arrow_node, "style-changed",
-                           G_CALLBACK (node_style_changed_cb), popover, 0);
-  g_object_unref (priv->arrow_node);
-
-  priv->contents_widget = gtk_gizmo_new ("contents",
-                                         measure_contents,
-                                         allocate_contents,
-                                         NULL);
-
-  gtk_widget_set_parent (priv->contents_widget, widget);
-
-  context = gtk_widget_get_style_context (priv->contents_widget);
-  gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
-
-  controller = gtk_event_controller_key_new ();
-  g_signal_connect (controller, "key-pressed",
-                    G_CALLBACK (key_controller_key_pressed), popover);
-  gtk_widget_add_controller (widget, controller);
-
-  controller = GTK_EVENT_CONTROLLER (gtk_gesture_multi_press_new ());
-  g_signal_connect (controller, "pressed",
-                    G_CALLBACK (gesture_pressed), popover);
-  g_signal_connect (controller, "released",
-                    G_CALLBACK (gesture_released), popover);
-  gtk_widget_add_controller (widget, controller);
-}
+  GdkRectangle rect;
+  GdkGravity parent_anchor;
+  GdkGravity surface_anchor;
+  GdkAnchorHints anchor_hints;
 
-static void
-gtk_popover_set_property (GObject      *object,
-                          guint         prop_id,
-                          const GValue *value,
-                          GParamSpec   *pspec)
-{
-  switch (prop_id)
+  gtk_widget_get_surface_allocation (priv->relative_to, &rect);
+  if (priv->has_pointing_to)
     {
-    case PROP_RELATIVE_TO:
-      gtk_popover_set_relative_to (GTK_POPOVER (object),
-                                   g_value_get_object (value));
-      break;
-    case PROP_POINTING_TO:
-      gtk_popover_set_pointing_to (GTK_POPOVER (object),
-                                   g_value_get_boxed (value));
-      break;
-    case PROP_POSITION:
-      gtk_popover_set_position (GTK_POPOVER (object),
-                                g_value_get_enum (value));
-      break;
-    case PROP_MODAL:
-      gtk_popover_set_modal (GTK_POPOVER (object),
-                             g_value_get_boolean (value));
-      break;
-    case PROP_CONSTRAIN_TO:
-      gtk_popover_set_constrain_to (GTK_POPOVER (object),
-                                    g_value_get_enum (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      rect.x += priv->pointing_to.x;
+      rect.y += priv->pointing_to.y;
+      rect.width = priv->pointing_to.width;
+      rect.height = priv->pointing_to.height;
     }
-}
-
-static void
-gtk_popover_get_property (GObject    *object,
-                          guint       prop_id,
-                          GValue     *value,
-                          GParamSpec *pspec)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (object));
 
-  switch (prop_id)
+  switch (priv->position)
     {
-    case PROP_RELATIVE_TO:
-      g_value_set_object (value, priv->widget);
-      break;
-    case PROP_POINTING_TO:
-      g_value_set_boxed (value, &priv->pointing_to);
-      break;
-    case PROP_POSITION:
-      g_value_set_enum (value, priv->preferred_position);
-      break;
-    case PROP_MODAL:
-      g_value_set_boolean (value, priv->modal);
-      break;
-    case PROP_CONSTRAIN_TO:
-      g_value_set_enum (value, priv->constraint);
+    case GTK_POS_LEFT:
+      parent_anchor = GDK_GRAVITY_WEST;
+      surface_anchor = GDK_GRAVITY_EAST;
+      anchor_hints = GDK_ANCHOR_FLIP_X;
       break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
-}
-
-static gboolean
-transitions_enabled (GtkPopover *popover)
-{
-  return gtk_settings_get_enable_animations (gtk_widget_get_settings (GTK_WIDGET (popover)));
-}
-
-static void
-gtk_popover_hide_internal (GtkPopover *popover)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWidget *widget = GTK_WIDGET (popover);
 
-  if (!priv->visible)
-    return;
+    case GTK_POS_RIGHT:
+      parent_anchor = GDK_GRAVITY_EAST;
+      surface_anchor = GDK_GRAVITY_WEST;
+      anchor_hints = GDK_ANCHOR_FLIP_X;
+      break;
 
-  priv->visible = FALSE;
-  g_signal_emit (widget, signals[CLOSED], 0);
+    case GTK_POS_TOP:
+      parent_anchor = GDK_GRAVITY_NORTH;
+      surface_anchor = GDK_GRAVITY_SOUTH;
+      anchor_hints = GDK_ANCHOR_FLIP_Y;
+      break;
 
-  if (priv->modal)
-    gtk_popover_apply_modality (popover, FALSE);
+    case GTK_POS_BOTTOM:
+      parent_anchor = GDK_GRAVITY_SOUTH;
+      surface_anchor = GDK_GRAVITY_NORTH;
+      anchor_hints = GDK_ANCHOR_FLIP_Y;
+      break;
 
-  if (gtk_widget_get_realized (widget))
-    {
-      cairo_region_t *region = cairo_region_create ();
-      gdk_surface_input_shape_combine_region (gtk_widget_get_surface (widget),
-                                             region, 0, 0);
-      cairo_region_destroy (region);
+    default:
+      g_assert_not_reached ();
     }
-}
 
-static void
-gtk_popover_finalize (GObject *object)
-{
-  GtkPopover *popover = GTK_POPOVER (object);
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (priv->widget)
-    gtk_popover_update_relative_to (popover, NULL);
-
-  G_OBJECT_CLASS (gtk_popover_parent_class)->finalize (object);
+  gdk_surface_move_to_rect (priv->surface,
+                            &rect,
+                            parent_anchor,
+                            surface_anchor,
+                            anchor_hints,
+                            0, 0);
 }
 
 static void
-popover_unset_prev_focus (GtkPopover *popover)
+gtk_popover_move_resize (GtkPopover *popover)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (!priv->prev_focus_widget)
-    return;
-
-  if (priv->prev_focus_unmap_id)
-    {
-      g_signal_handler_disconnect (priv->prev_focus_widget,
-                                   priv->prev_focus_unmap_id);
-      priv->prev_focus_unmap_id = 0;
-    }
-
-  g_clear_object (&priv->prev_focus_widget);
+  GtkRequisition req;
+ 
+  gtk_widget_get_preferred_size (GTK_WIDGET (popover), NULL, &req);
+  gdk_surface_resize (priv->surface, req.width, req.height);
+  move_to_rect (popover);
 }
 
 static void
-gtk_popover_dispose (GObject *object)
+gtk_popover_root_check_resize (GtkRoot *root)
 {
-  GtkPopover *popover = GTK_POPOVER (object);
+  GtkPopover *popover = GTK_POPOVER (root);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  GtkWidget *widget = GTK_WIDGET (popover);
 
-  if (priv->modal)
-    gtk_popover_apply_modality (popover, FALSE);
-
-  if (priv->window)
-    {
-      g_signal_handlers_disconnect_by_data (priv->window, popover);
-      _gtk_window_remove_popover (priv->window, GTK_WIDGET (object));
-    }
-
-  priv->window = NULL;
-
-  if (priv->widget)
-    gtk_popover_update_relative_to (popover, NULL);
-
-  popover_unset_prev_focus (popover);
-
-  g_clear_object (&priv->default_widget);
-
-  if (priv->contents_widget)
+  if (!_gtk_widget_get_alloc_needed (widget))
+    gtk_widget_ensure_allocate (widget);
+  else if (gtk_widget_get_visible (widget))
     {
-      GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
-
-      if (child)
-        {
-          /* Parent is content_widget! */
-          gtk_widget_unparent (child);
-          _gtk_bin_set_child (GTK_BIN (popover), NULL);
-        }
-
-      gtk_widget_unparent (priv->contents_widget);
-      priv->contents_widget = NULL;
+      gtk_popover_move_resize (popover);
+      gtk_widget_allocate (GTK_WIDGET (popover),
+                           gdk_surface_get_width (priv->surface),
+                           gdk_surface_get_height (priv->surface),
+                           -1, NULL);
     }
-
-  G_OBJECT_CLASS (gtk_popover_parent_class)->dispose (object);
 }
 
-static void
-gtk_popover_realize (GtkWidget *widget)
-{
-  GtkAllocation allocation;
-  GdkSurface *surface;
-
-  gtk_widget_get_surface_allocation (widget, &allocation);
-
-  surface = gdk_surface_new_child (gtk_widget_get_parent_surface (widget), &allocation);
-
-  gtk_widget_set_surface (widget, surface);
-  gtk_widget_register_surface (widget, surface);
-
-  GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget);
-}
+static void gtk_popover_set_is_active (GtkPopover *popover, gboolean active);
 
 static void
-window_active_changed (GtkWindow  *window,
-                       GParamSpec *pspec,
-                       GtkPopover *popover)
+gtk_popover_focus_in (GtkWidget *widget)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (!priv->modal ||
-      !gtk_widget_is_drawable (GTK_WIDGET (popover)))
-    return;
-
-  if (gtk_window_is_active (window))
-    {
-      /* Regain the grab when the window is focused */
-      GtkWidget *focus;
-
-      gtk_grab_add (GTK_WIDGET (popover));
-
-      focus = gtk_window_get_focus (window);
-
-      if (focus == NULL || !gtk_widget_is_ancestor (focus, GTK_WIDGET (popover)))
-        gtk_widget_grab_focus (GTK_WIDGET (popover));
-
-      if (priv->grab_notify_blocked)
-        g_signal_handler_unblock (priv->widget, priv->grab_notify_id);
-
-      priv->grab_notify_blocked = FALSE;
-    }
-  else
-    {
-      /* Temporarily remove the grab when unfocused */
-      g_signal_handler_block (priv->widget, priv->grab_notify_id);
-      gtk_grab_remove (GTK_WIDGET (popover));
-
-      priv->grab_notify_blocked = TRUE;
-    }
+  gtk_popover_set_is_active (GTK_POPOVER (widget), TRUE);
 }
 
 static void
-window_set_focus (GtkWindow  *window,
-                  GParamSpec *pspec,
-                  GtkPopover *popover)
+gtk_popover_focus_out (GtkWidget *widget)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWidget *widget = gtk_root_get_focus (GTK_ROOT (window));
-
-  if (!priv->modal || !widget || !gtk_widget_is_drawable (GTK_WIDGET (popover)))
-    return;
-
-  widget = gtk_widget_get_ancestor (widget, GTK_TYPE_POPOVER);
-  while (widget != NULL)
-    {
-      if (widget == GTK_WIDGET (popover))
-        return;
-
-      widget = gtk_popover_get_relative_to (GTK_POPOVER (widget));
-      if (widget == NULL)
-        break;
-      widget = gtk_widget_get_ancestor (widget, GTK_TYPE_POPOVER);
-    }
-
-  popover_unset_prev_focus (popover);
-  gtk_widget_hide (GTK_WIDGET (popover));
+  gtk_popover_set_is_active (GTK_POPOVER (widget), FALSE);
 }
 
 static void
-prev_focus_unmap_cb (GtkWidget  *widget,
-                     GtkPopover *popover)
-{
-  popover_unset_prev_focus (popover);
-}
-
-static void
-gtk_popover_apply_modality (GtkPopover *popover,
-                            gboolean    modal)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (!priv->window)
-    return;
-
-  if (modal)
-    {
-      GtkWidget *prev_focus;
-
-      prev_focus = gtk_window_get_focus (priv->window);
-      priv->prev_focus_widget = prev_focus;
-      if (priv->prev_focus_widget)
-        {
-          priv->prev_focus_unmap_id =
-            g_signal_connect (prev_focus, "unmap",
-                              G_CALLBACK (prev_focus_unmap_cb), popover);
-          g_object_ref (prev_focus);
-        }
-      gtk_grab_add (GTK_WIDGET (popover));
-      gtk_window_set_focus (priv->window, NULL);
-      gtk_widget_grab_focus (GTK_WIDGET (popover));
-
-      g_signal_connect (priv->window, "notify::is-active",
-                        G_CALLBACK (window_active_changed), popover);
-      g_signal_connect (priv->window, "notify::focus-widget",
-                        G_CALLBACK (window_set_focus), popover);
-    }
-  else
-    {
-      g_signal_handlers_disconnect_by_data (priv->window, popover);
-      if (priv->prev_focus_widget == GTK_WIDGET (priv->window))
-        priv->prev_focus_unmap_id = 0;
-      gtk_grab_remove (GTK_WIDGET (popover));
-
-      /* Let prev_focus_widget regain focus */
-      if (priv->prev_focus_widget &&
-          gtk_widget_is_drawable (priv->prev_focus_widget))
-        {
-           if (GTK_IS_ENTRY (priv->prev_focus_widget))
-             gtk_entry_grab_focus_without_selecting (GTK_ENTRY (priv->prev_focus_widget));
-           else
-             gtk_widget_grab_focus (priv->prev_focus_widget);
-        }
-      else if (priv->window)
-        gtk_widget_grab_focus (GTK_WIDGET (priv->window));
-
-      popover_unset_prev_focus (popover);
-    }
-}
-
-static gboolean
-show_animate_cb (GtkWidget     *widget,
-                 GdkFrameClock *frame_clock,
-                 gpointer       user_data)
+ensure_state_flag_backdrop (GtkWidget *widget)
 {
   GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  gdouble t;
-
-  if (priv->first_frame_skipped)
-    gtk_progress_tracker_advance_frame (&priv->tracker,
-                                        gdk_frame_clock_get_frame_time (frame_clock));
-  else
-    priv->first_frame_skipped = TRUE;
-
-  t = gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE);
-
-  if (priv->state == STATE_SHOWING)
-    {
-      priv->transition_diff = TRANSITION_DIFF - (TRANSITION_DIFF * t);
-      gtk_widget_set_opacity (widget, t);
-    }
-  else if (priv->state == STATE_HIDING)
-    {
-      priv->transition_diff = -TRANSITION_DIFF * t;
-      gtk_widget_set_opacity (widget, 1.0 - t);
-    }
-
-  gtk_popover_update_position (popover);
-  gtk_widget_queue_allocate (GTK_WIDGET (priv->window));
-
-  if (gtk_progress_tracker_get_state (&priv->tracker) == GTK_PROGRESS_STATE_AFTER)
-    {
-      if (priv->state == STATE_SHOWING)
-        {
-          gtk_popover_set_state (popover, STATE_SHOWN);
-
-          if (!priv->visible)
-            gtk_popover_set_state (popover, STATE_HIDING);
-        }
-      else
-        {
-          gtk_widget_hide (widget);
-        }
-
-      priv->tick_id = 0;
-      return G_SOURCE_REMOVE;
-    }
-  else
-    return G_SOURCE_CONTINUE;
-}
-
-static void
-gtk_popover_stop_transition (GtkPopover *popover)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (priv->tick_id != 0)
-    {
-      gtk_widget_remove_tick_callback (GTK_WIDGET (popover), priv->tick_id);
-      priv->tick_id = 0;
-    }
-}
-
-static void
-gtk_popover_start_transition (GtkPopover *popover)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (priv->tick_id != 0)
-    return;
-
-  priv->first_frame_skipped = FALSE;
-  gtk_progress_tracker_start (&priv->tracker, TRANSITION_DURATION, 0, 1.0);
-  priv->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (popover),
-                                                show_animate_cb,
-                                                popover, NULL);
-}
-
-static void
-gtk_popover_set_state (GtkPopover *popover,
-                       guint       state)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (!transitions_enabled (popover) ||
-      !gtk_widget_get_realized (GTK_WIDGET (popover)))
-    {
-      if (state == STATE_SHOWING)
-        state = STATE_SHOWN;
-      else if (state == STATE_HIDING)
-        state = STATE_HIDDEN;
-    }
-
-  priv->state = state;
 
-  if (state == STATE_SHOWING || state == STATE_HIDING)
-    gtk_popover_start_transition (popover);
+  if ((priv->state & GDK_SURFACE_STATE_FOCUSED) != 0)
+    gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_BACKDROP);
   else
-    {
-      gtk_popover_stop_transition (popover);
-
-      gtk_widget_set_visible (GTK_WIDGET (popover), state == STATE_SHOWN);
-    }
-}
-
-static void
-gtk_popover_map (GtkWidget *widget)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
-
-  priv->prev_default = gtk_window_get_default_widget (priv->window);
-  if (priv->prev_default)
-    g_object_ref (priv->prev_default);
-
-  GTK_WIDGET_CLASS (gtk_popover_parent_class)->map (widget);
-
-  gdk_surface_show (gtk_widget_get_surface (widget));
-  gtk_popover_update_position (GTK_POPOVER (widget));
-
-  gtk_window_set_default (priv->window, priv->default_widget);
-}
-
-static void
-gtk_popover_unmap (GtkWidget *widget)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
-
-  priv->button_pressed = FALSE;
-
-  gdk_surface_hide (gtk_widget_get_surface (widget));
-  GTK_WIDGET_CLASS (gtk_popover_parent_class)->unmap (widget);
-
-  if (gtk_window_get_default_widget (priv->window) == priv->default_widget)
-    gtk_window_set_default (priv->window, priv->prev_default);
-  g_clear_object (&priv->prev_default);
-}
-
-static GtkPositionType
-get_effective_position (GtkPopover      *popover,
-                        GtkPositionType  pos)
-{
-  if (_gtk_widget_get_direction (GTK_WIDGET (popover)) == GTK_TEXT_DIR_RTL)
-    {
-      if (pos == GTK_POS_LEFT)
-        pos = GTK_POS_RIGHT;
-      else if (pos == GTK_POS_RIGHT)
-        pos = GTK_POS_LEFT;
-    }
-
-  return pos;
+    gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_BACKDROP, FALSE);
 }
 
 static void
-get_margin (GtkWidget *widget,
-            GtkBorder *border)
+surface_state_changed (GtkWidget *widget)
 {
-  GtkStyleContext *context;
-
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_get_margin (context,
-                                border);
-}
-
-static void
-gtk_popover_get_gap_coords (GtkPopover      *popover,
-                            gint            *initial_x_out,
-                            gint            *initial_y_out,
-                            gint            *tip_x_out,
-                            gint            *tip_y_out,
-                            gint            *final_x_out,
-                            gint            *final_y_out)
-{
-  GtkWidget *widget = GTK_WIDGET (popover);
+  GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GdkRectangle rect = { 0 };
-  gint base, tip, tip_pos;
-  gint initial_x, initial_y;
-  gint tip_x, tip_y;
-  gint final_x, final_y;
-  GtkPositionType pos;
-  gint border_radius;
-  GtkStyleContext *context;
-  GtkBorder border;
-  int popover_width, popover_height;
-
-  gtk_popover_get_pointing_to (popover, &rect);
-  popover_width = gtk_widget_get_width (widget);
-  popover_height = gtk_widget_get_height (widget);
+  GdkSurfaceState new_surface_state;
+  GdkSurfaceState changed_mask;
 
-#ifdef GDK_WINDOWING_WAYLAND
-  if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
-    {
-      gint win_x, win_y;
-
-      gtk_widget_translate_coordinates (priv->widget, GTK_WIDGET (priv->window),
-                                        rect.x, rect.y, &rect.x, &rect.y);
-      gdk_surface_get_origin (gtk_widget_get_surface (GTK_WIDGET (popover)),
-                             &win_x, &win_y);
-      rect.x -= win_x;
-      rect.y -= win_y;
-    }
-  else
-#endif
-    gtk_widget_translate_coordinates (priv->widget, widget,
-                                      rect.x, rect.y, &rect.x, &rect.y);
+  new_surface_state = gdk_surface_get_state (_gtk_widget_get_surface (widget));
+  changed_mask = new_surface_state ^ priv->state;
+  priv->state = new_surface_state;
 
-  context = gtk_widget_get_style_context (priv->contents_widget);
-  gtk_style_context_get_border (context, &border);
-
-  pos = get_effective_position (popover, priv->final_position);
-
-  gtk_style_context_get_border (context, &border);
-  gtk_style_context_get (context,
-                         GTK_STYLE_PROPERTY_BORDER_RADIUS, &border_radius,
-                         NULL);
+  if (changed_mask & GDK_SURFACE_STATE_FOCUSED)
+    ensure_state_flag_backdrop (widget);
 
-  if (pos == GTK_POS_BOTTOM || pos == GTK_POS_RIGHT)
+  if (changed_mask & GDK_SURFACE_STATE_WITHDRAWN)
     {
-      tip = 0;
-      base = tip + TAIL_HEIGHT + border.top;
+      if (priv->state & GDK_SURFACE_STATE_WITHDRAWN)
+        gtk_widget_hide (widget);
     }
-  else if (pos == GTK_POS_TOP)
-    {
-      base = popover_height - border.bottom - TAIL_HEIGHT;
-      tip = base + TAIL_HEIGHT;
-    }
-  else if (pos == GTK_POS_LEFT)
-    {
-      base = popover_width - border.right - TAIL_HEIGHT;
-      tip = base + TAIL_HEIGHT;
-    }
-  else
-    g_assert_not_reached ();
-
-  if (POS_IS_VERTICAL (pos))
-    {
-      tip_pos = rect.x + (rect.width / 2);
-      initial_x = CLAMP (tip_pos - TAIL_GAP_WIDTH / 2,
-                         border_radius,
-                         popover_width - TAIL_GAP_WIDTH - border_radius);
-      initial_y = base;
-
-      tip_x = CLAMP (tip_pos, 0, popover_width);
-      tip_y = tip;
-
-      final_x = CLAMP (tip_pos + TAIL_GAP_WIDTH / 2,
-                       border_radius + TAIL_GAP_WIDTH,
-                       popover_width - border_radius);
-      final_y = base;
-    }
-  else
-    {
-      tip_pos = rect.y + (rect.height / 2);
-
-      initial_x = base;
-      initial_y = CLAMP (tip_pos - TAIL_GAP_WIDTH / 2,
-                         border_radius,
-                         popover_height - TAIL_GAP_WIDTH - border_radius);
-
-      tip_x = tip;
-      tip_y = CLAMP (tip_pos, 0, popover_height);
-
-      final_x = base;
-      final_y = CLAMP (tip_pos + TAIL_GAP_WIDTH / 2,
-                       border_radius + TAIL_GAP_WIDTH,
-                       popover_height - border_radius);
-    }
-
-  *initial_x_out = initial_x;
-  *initial_y_out = initial_y;
-
-  *tip_x_out = tip_x;
-  *tip_y_out = tip_y;
-
-  *final_x_out = final_x;
-  *final_y_out = final_y;
-}
-
-static void
-gtk_popover_get_rect_for_size (GtkPopover   *popover,
-                               int           popover_width,
-                               int           popover_height,
-                               GdkRectangle *rect)
-{
-  GtkWidget *widget = GTK_WIDGET (popover);
-  int x, y, w, h;
-  GtkBorder margin;
-
-  get_margin (widget, &margin);
-
-  x = 0;
-  y = 0;
-  w = popover_width;
-  h = popover_height;
-
-  x += MAX (TAIL_HEIGHT, margin.left);
-  y += MAX (TAIL_HEIGHT, margin.top);
-  w -= x + MAX (TAIL_HEIGHT, margin.right);
-  h -= y + MAX (TAIL_HEIGHT, margin.bottom);
-
-  rect->x = x;
-  rect->y = y;
-  rect->width = w;
-  rect->height = h;
-}
-
-static void
-gtk_popover_get_rect_coords (GtkPopover *popover,
-                             int        *x_out,
-                             int        *y_out,
-                             int        *w_out,
-                             int        *h_out)
-{
-  GtkWidget *widget = GTK_WIDGET (popover);
-  GdkRectangle rect;
-  GtkAllocation allocation;
-
-  gtk_widget_get_allocation (widget, &allocation);
-  gtk_popover_get_rect_for_size (popover, allocation.width, allocation.height, &rect);
-
-  *x_out = rect.x;
-  *y_out = rect.y;
-  *w_out = rect.width;
-  *h_out = rect.height;
 }
 
 static void
-gtk_popover_apply_tail_path (GtkPopover *popover,
-                             cairo_t    *cr)
+surface_size_changed (GtkWindow *window,
+                      guint      width,
+                      guint      height)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  gint initial_x, initial_y;
-  gint tip_x, tip_y;
-  gint final_x, final_y;
-  GtkStyleContext *context;
-  GtkBorder border;
-
-  if (!priv->widget)
-    return;
-
-  context = gtk_widget_get_style_context (priv->contents_widget);
-  gtk_style_context_get_border (context, &border);
-
-  cairo_set_line_width (cr, 1);
-  gtk_popover_get_gap_coords (popover,
-                              &initial_x, &initial_y,
-                              &tip_x, &tip_y,
-                              &final_x, &final_y);
-
-  cairo_move_to (cr, initial_x, initial_y);
-  cairo_line_to (cr, tip_x, tip_y);
-  cairo_line_to (cr, final_x, final_y);
 }
 
 static void
-gtk_popover_fill_border_path (GtkPopover *popover,
-                              cairo_t    *cr)
-{
-  GtkWidget *widget = GTK_WIDGET (popover);
-  GtkAllocation allocation;
-  GtkStyleContext *context;
-  int x, y, w, h;
-  GskRoundedRect box;
-
-  context = gtk_widget_get_style_context (widget);
-  gtk_widget_get_allocation (widget, &allocation);
-
-  cairo_set_source_rgba (cr, 0, 0, 0, 1);
-
-  gtk_popover_apply_tail_path (popover, cr);
-  cairo_close_path (cr);
-  cairo_fill (cr);
-
-  gtk_popover_get_rect_coords (popover, &x, &y, &w, &h);
-
-  gtk_rounded_boxes_init_for_style (&box,
-                                    NULL, NULL,
-                                    gtk_style_context_lookup_style (context),
-                                    x, y, w, h);
-  gsk_rounded_rect_path (&box, cr);
-  cairo_fill (cr);
-}
-
-static void
-gtk_popover_update_shape (GtkPopover *popover)
+measure_contents (GtkGizmo       *gizmo,
+                  GtkOrientation  orientation,
+                  int             for_size,
+                  int            *minimum,
+                  int            *natural,
+                  int            *minimum_baseline,
+                  int            *natural_baseline)
 {
-  GtkWidget *widget = GTK_WIDGET (popover);
-  cairo_surface_t *cairo_surface;
-  cairo_region_t *region;
-  GdkSurface *surface;
-  cairo_t *cr;
-
-#ifdef GDK_WINDOWING_WAYLAND
-  if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
-    return;
-#endif
-
-  surface = gtk_widget_get_surface (widget);
-  cairo_surface =
-    gdk_surface_create_similar_surface (surface,
-                                       CAIRO_CONTENT_COLOR_ALPHA,
-                                       gdk_surface_get_width (surface),
-                                       gdk_surface_get_height (surface));
-
-  cr = cairo_create (cairo_surface);
-  gtk_popover_fill_border_path (popover, cr);
-  cairo_destroy (cr);
-
-  region = gdk_cairo_region_create_from_surface (cairo_surface);
-  cairo_surface_destroy (cairo_surface);
-
-  gtk_widget_input_shape_combine_region (widget, region);
-  cairo_region_destroy (region);
+  GtkPopover *popover = GTK_POPOVER (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
+  GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
 
-  gdk_surface_set_child_input_shapes (gtk_widget_get_surface (widget));
+  if (child)
+    gtk_widget_measure (child, orientation, for_size,
+                        minimum, natural,
+                        minimum_baseline, natural_baseline);
 }
 
 static void
-_gtk_popover_update_child_visible (GtkPopover *popover)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWidget *widget = GTK_WIDGET (popover);
-  GdkRectangle rect;
-  GtkAllocation allocation;
-  GtkWidget *parent;
-
-  if (!priv->parent_scrollable)
-    {
-      gtk_widget_set_child_visible (widget, TRUE);
-      return;
-    }
-
-  parent = gtk_widget_get_parent (GTK_WIDGET (priv->parent_scrollable));
-  gtk_popover_get_pointing_to (popover, &rect);
-
-  gtk_widget_translate_coordinates (priv->widget, parent,
-                                    rect.x, rect.y, &rect.x, &rect.y);
-
-  gtk_widget_get_allocation (GTK_WIDGET (parent), &allocation);
-
-  if (rect.x + rect.width < 0 || rect.x > allocation.width ||
-      rect.y + rect.height < 0 || rect.y > allocation.height)
-    gtk_widget_set_child_visible (widget, FALSE);
-  else
-    gtk_widget_set_child_visible (widget, TRUE);
-}
-
-static GtkPositionType
-opposite_position (GtkPositionType pos)
-{
-  switch (pos)
-    {
-    default:
-    case GTK_POS_LEFT: return GTK_POS_RIGHT;
-    case GTK_POS_RIGHT: return GTK_POS_LEFT;
-    case GTK_POS_TOP: return GTK_POS_BOTTOM;
-    case GTK_POS_BOTTOM: return GTK_POS_TOP;
-    }
-}
-
-void
-gtk_popover_update_position (GtkPopover *popover)
+allocate_contents (GtkGizmo *gizmo,
+                   int       width,
+                   int       height,
+                   int       baseline)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWidget *widget = GTK_WIDGET (popover);
-  GtkAllocation window_alloc;
-  GtkBorder window_shadow;
-  GdkRectangle rect = { 0 };
-  GtkRequisition req;
-  GtkPositionType pos;
-  gint overshoot[4];
-  gint i, j;
-  gint best;
-
-  if (!priv->window || !gtk_widget_get_mapped (widget))
-    return;
-
-  gtk_widget_get_preferred_size (widget, NULL, &req);
-  gtk_widget_get_allocation (GTK_WIDGET (priv->window), &window_alloc);
-  _gtk_window_get_shadow_width (priv->window, &window_shadow);
-  priv->final_position = priv->preferred_position;
-
-  gtk_popover_get_pointing_to (popover, &rect);
-  gtk_widget_translate_coordinates (priv->widget, GTK_WIDGET (priv->window),
-                                    rect.x, rect.y, &rect.x, &rect.y);
-
-  pos = get_effective_position (popover, priv->preferred_position);
-
-  overshoot[GTK_POS_TOP] = req.height - rect.y + window_shadow.top;
-  overshoot[GTK_POS_BOTTOM] = rect.y + rect.height + req.height - window_alloc.height
-                              + window_shadow.bottom;
-  overshoot[GTK_POS_LEFT] = req.width - rect.x + window_shadow.left;
-  overshoot[GTK_POS_RIGHT] = rect.x + rect.width + req.width - window_alloc.width
-                             + window_shadow.right;
-
-#ifdef GDK_WINDOWING_WAYLAND
-  if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)) &&
-      priv->constraint == GTK_POPOVER_CONSTRAINT_NONE)
-    {
-      priv->final_position = priv->preferred_position;
-    }
-  else
-#endif
-  if (overshoot[pos] <= 0)
-    {
-      priv->final_position = priv->preferred_position;
-    }
-  else if (overshoot[opposite_position (pos)] <= 0)
-    {
-      priv->final_position = opposite_position (priv->preferred_position);
-    }
-  else
-    {
-      best = G_MAXINT;
-      pos = 0;
-      for (i = 0; i < 4; i++)
-        {
-          j = get_effective_position (popover, i);
-          if (overshoot[j] < best)
-            {
-              pos = i;
-              best = overshoot[j];
-            }
-        }
-      priv->final_position = pos;
-    }
-
-  switch (priv->final_position)
-    {
-    case GTK_POS_TOP:
-      rect.y += priv->transition_diff;
-      break;
-    case GTK_POS_BOTTOM:
-      rect.y -= priv->transition_diff;
-      break;
-    case GTK_POS_LEFT:
-      rect.x += priv->transition_diff;
-      break;
-    case GTK_POS_RIGHT:
-      rect.x -= priv->transition_diff;
-      break;
-    default:
-      break;
-    }
-
-  _gtk_window_set_popover_position (priv->window, widget,
-                                    priv->final_position, &rect);
-
-  if (priv->final_position != priv->current_position)
-    {
-      if (gtk_widget_is_drawable (widget))
-        gtk_popover_update_shape (popover);
-
-      priv->current_position = priv->final_position;
-    }
+  GtkPopover *popover = GTK_POPOVER (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
+  GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
 
-  _gtk_popover_update_child_visible (popover);
+  if (child)
+    gtk_widget_size_allocate (child,
+                              &(GtkAllocation) { 0, 0, width, height
+                              }, -1);
 }
 
-GtkWidget *
-gtk_popover_get_contents_widget (GtkPopover *popover)
+static void
+gtk_popover_init (GtkPopover *popover)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  GtkEventController *controller;
+  GtkStyleContext *context;
 
-  return priv->contents_widget;
+  gtk_widget_set_has_surface (GTK_WIDGET (popover), TRUE);
+
+  priv->position = GTK_POS_TOP;
+  priv->modal = TRUE;
+
+  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);
+
+  priv->contents_widget = gtk_gizmo_new ("contents",
+                                         measure_contents,
+                                         allocate_contents,
+                                         NULL);
+  gtk_widget_set_parent (priv->contents_widget, GTK_WIDGET (popover));
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (popover));
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
 }
 
 static void
-gtk_popover_snapshot (GtkWidget   *widget,
-                      GtkSnapshot *snapshot)
+gtk_popover_realize (GtkWidget *widget)
 {
   GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkStyleContext *context;
-  GtkBorder border;
-  cairo_t *cr;
-
-  /* Draw the child first so we can draw the arrow (partially) over it */
-  gtk_widget_snapshot_child (widget, priv->contents_widget, snapshot);
+  GdkRectangle parent_rect;
 
-  cr = gtk_snapshot_append_cairo (snapshot,
-                                  &GRAPHENE_RECT_INIT (
-                                    0, 0,
-                                    gtk_widget_get_width (widget),
-                                    gtk_widget_get_height (widget)
-                                  ));
+  gtk_widget_get_surface_allocation (priv->relative_to, &parent_rect);
 
-  /* Clip to the arrow shape */
-  cairo_save (cr);
+  priv->surface = gdk_surface_new_popup_full (priv->display, gtk_widget_get_surface (priv->relative_to));
 
-  gtk_popover_apply_tail_path (popover, cr);
+  gtk_widget_set_surface (widget, priv->surface);
+  g_signal_connect_swapped (priv->surface, "notify::state", G_CALLBACK (surface_state_changed), widget);
+  g_signal_connect_swapped (priv->surface, "size-changed", G_CALLBACK (surface_size_changed), widget);
 
-  cairo_clip (cr);
+  gtk_widget_register_surface (widget, priv->surface);
 
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_save_to_node (context, priv->arrow_node);
-  gtk_style_context_get_border (context, &border);
+  GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget);
 
-  /* Render the arrow background */
-  gtk_render_background (context, cr,
-                         0, 0,
-                         gtk_widget_get_width (widget),
-                         gtk_widget_get_height (widget));
+  priv->renderer = gsk_renderer_new_for_surface (priv->surface);
+}
 
-  /* Render the border of the arrow tip */
-  if (border.bottom > 0)
-    {
-      GdkRGBA border_color;
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-      gtk_style_context_get_border_color (context, &border_color);
-G_GNUC_END_IGNORE_DEPRECATIONS
+static void
+gtk_popover_unrealize (GtkWidget *widget)
+{
+  GtkPopover *popover = GTK_POPOVER (widget);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-      gtk_popover_apply_tail_path (popover, cr);
-      gdk_cairo_set_source_rgba (cr, &border_color);
+  GTK_WIDGET_CLASS (gtk_popover_parent_class)->unrealize (widget);
 
-      cairo_set_line_width (cr, border.bottom + 1);
-      cairo_stroke (cr);
-    }
+  gsk_renderer_unrealize (priv->renderer);
+  g_clear_object (&priv->renderer);
 
-  cairo_restore (cr);
-  /* We're done */
-  cairo_destroy (cr);
+  g_signal_handlers_disconnect_by_func (priv->surface, surface_state_changed, widget);
+  g_signal_handlers_disconnect_by_func (priv->surface, surface_size_changed, widget);
 
-  gtk_style_context_restore (context);
+  g_clear_object (&priv->surface);
 }
 
-static gint
-get_border_radius (GtkWidget *widget)
+static void
+gtk_popover_move_focus (GtkWidget         *widget,
+                      GtkDirectionType   dir)
 {
-  GtkStyleContext *context;
-  gint border_radius;
+  gtk_widget_child_focus (widget, dir);
 
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_get (context,
-                         GTK_STYLE_PROPERTY_BORDER_RADIUS, &border_radius,
-                         NULL);
-  return border_radius;
+  if (!gtk_widget_get_focus_child (widget))
+    gtk_root_set_focus (GTK_ROOT (widget), NULL);
 }
 
-static gint
-get_minimal_size (GtkPopover     *popover,
-                  GtkOrientation  orientation)
+static void
+gtk_popover_show (GtkWidget *widget)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkPositionType pos;
-  gint minimal_size;
+  _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_widget_map (widget);
 
-  minimal_size = 2 * get_border_radius (GTK_WIDGET (popover));
-  pos = get_effective_position (popover, priv->preferred_position);
+  if (!gtk_widget_get_focus_child (widget))
+    gtk_widget_child_focus (widget, GTK_DIR_TAB_FORWARD);
+}
 
-  if ((orientation == GTK_ORIENTATION_HORIZONTAL && POS_IS_VERTICAL (pos)) ||
-      (orientation == GTK_ORIENTATION_VERTICAL && !POS_IS_VERTICAL (pos)))
-    minimal_size += TAIL_GAP_WIDTH;
+static void
+gtk_popover_hide (GtkWidget *widget)
+{
+  _gtk_widget_set_visible_flag (widget, FALSE);
+  gtk_widget_unmap (widget);
+  g_signal_emit (widget, signals[CLOSED], 0);
+}
 
-  return minimal_size;
+static void
+grab_prepare_func (GdkSeat    *seat,
+                   GdkSurface *surface,
+                   gpointer    data)
+{
+  gdk_surface_show (surface);
 }
 
 static void
-gtk_popover_measure (GtkWidget      *widget,
-                     GtkOrientation  orientation,
-                     int             for_size,
-                     int            *minimum,
-                     int            *natural,
-                     int            *minimum_baseline,
-                     int            *natural_baseline)
+gtk_popover_map (GtkWidget *widget)
 {
   GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  int minimal_size;
-
-  *minimum = 0;
-  *natural = 0;
+  GtkWidget *child;
+  GdkRectangle parent_rect;
 
-  if (for_size >= 0)
-    for_size -= TAIL_HEIGHT;
+  if (priv->modal)
+    {
+      gdk_seat_grab (gdk_display_get_default_seat (priv->display),
+                     priv->surface,
+                     GDK_SEAT_CAPABILITY_ALL,
+                     TRUE,
+                     NULL, NULL, grab_prepare_func, NULL);
+      priv->has_grab = TRUE;
+    }
 
-  gtk_widget_measure (priv->contents_widget, orientation, for_size, minimum, natural, NULL, NULL);
+  gtk_widget_get_surface_allocation (priv->relative_to, &parent_rect);
+  move_to_rect (popover);
 
-  minimal_size = get_minimal_size (popover, orientation);
-  *minimum = MAX (*minimum, minimal_size);
-  *natural = MAX (*natural, minimal_size);
+  GTK_WIDGET_CLASS (gtk_popover_parent_class)->map (widget);
 
-  *minimum += TAIL_HEIGHT;
-  *natural += TAIL_HEIGHT;
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (child != NULL && gtk_widget_get_visible (child))
+    gtk_widget_map (child);
 }
 
 static void
-gtk_popover_size_allocate (GtkWidget *widget,
-                           int        width,
-                           int        height,
-                           int        baseline)
+gtk_popover_unmap (GtkWidget *widget)
 {
   GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkAllocation child_alloc = (GtkAllocation) {0, 0, width, height};
+  GtkWidget *child;
+
+  GTK_WIDGET_CLASS (gtk_popover_parent_class)->unmap (widget);
+
+  gdk_surface_hide (priv->surface);
+  if (priv->has_grab)
+    {
+      gdk_seat_ungrab (gdk_display_get_default_seat (priv->display));
+      priv->has_grab = FALSE;
+    }
 
-  /* Note that we in measure() we add TAIL_HEIGHT in both directions, regardless
-   * of the popovers position. This is to ensure that we get enough space
-   * even priv->current_position changes between measure and size-allocate.
-   */
-  child_alloc.height -= TAIL_HEIGHT;
-  child_alloc.width -= TAIL_HEIGHT;
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (child != NULL)
+    gtk_widget_unmap (child);
+}
+
+static void
+gtk_popover_dispose (GObject *object)
+{
+  GtkPopover *popover = GTK_POPOVER (object);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  guint i;
+  GtkWidget *child;
 
-  switch (priv->current_position)
+  for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (popover_list)); i++)
     {
-    case GTK_POS_TOP:
-      child_alloc.x += TAIL_HEIGHT / 2;
-      break;
-    case GTK_POS_BOTTOM:
-      child_alloc.x += TAIL_HEIGHT / 2;
-      child_alloc.y += TAIL_HEIGHT;
-      break;
-    case GTK_POS_LEFT:
-      child_alloc.y += TAIL_HEIGHT / 2;
-      break;
-    case GTK_POS_RIGHT:
-      child_alloc.x += TAIL_HEIGHT;
-      child_alloc.y += TAIL_HEIGHT / 2;
-      break;
-    default:
-      break;
+      gpointer item = g_list_model_get_item (G_LIST_MODEL (popover_list), i);
+      if (item == object)
+        {
+          g_list_store_remove (popover_list, i);
+          break;
+        }
+      else
+        g_object_unref (item);
     }
 
-  gtk_widget_size_allocate (priv->contents_widget, &child_alloc, -1);
+  child = gtk_bin_get_child (GTK_BIN (popover));
 
-  if (gtk_widget_get_realized (widget))
+  if (child)
     {
-      GtkAllocation a;
-      gtk_widget_get_surface_allocation (widget, &a);
-      gdk_surface_move_resize (gtk_widget_get_surface (widget),
-                              a.x, a.y, a.width, a.height);
-      gtk_popover_update_shape (popover);
+      gtk_widget_unparent (child);
+      _gtk_bin_set_child (GTK_BIN (popover), NULL);
     }
+
+  g_clear_pointer (&priv->contents_widget, gtk_widget_unparent);
+
+  G_OBJECT_CLASS (gtk_popover_parent_class)->dispose (object);
+}
+
+static void
+gtk_popover_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gtk_popover_parent_class)->finalize (object);
 }
 
 static void
-gtk_popover_grab_focus (GtkWidget *widget)
+gtk_popover_constructed (GObject *object)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
-  GtkWidget *child;
+  g_list_store_append (popover_list, object);
+  g_object_unref (object);
+}
 
-  if (!priv->visible)
-    return;
+static void
+gtk_popover_measure (GtkWidget      *widget,
+                   GtkOrientation  orientation,
+                   int             for_size,
+                   int            *minimum,
+                   int            *natural,
+                   int            *minimum_baseline,
+                   int            *natural_baseline)
+{
+  GtkPopover *popover = GTK_POPOVER (widget);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  /* Focus the first natural child */
-  child = gtk_bin_get_child (GTK_BIN (widget));
+  gtk_widget_measure (priv->contents_widget,
+                      orientation, for_size,
+                      minimum, natural,
+                      minimum_baseline, natural_baseline);
+}
 
-  if (child)
-    gtk_widget_child_focus (child, GTK_DIR_TAB_FORWARD);
+static void
+gtk_popover_size_allocate (GtkWidget *widget,
+                         int        width,
+                         int        height,
+                         int        baseline)
+{
+  GtkPopover *popover = GTK_POPOVER (widget);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
+  if (priv->surface)
+    gtk_popover_move_resize (popover);
+
+  gtk_widget_size_allocate (priv->contents_widget,
+                            &(GtkAllocation) { 0, 0, width, height },
+                            baseline);
 }
 
-static gboolean
-gtk_popover_focus (GtkWidget        *widget,
-                   GtkDirectionType  direction)
+static void
+gtk_popover_snapshot (GtkWidget   *widget,
+                      GtkSnapshot *snapshot)
 {
   GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  if (!priv->visible)
-    return FALSE;
+  gtk_widget_snapshot_child (widget, priv->contents_widget, snapshot);
+}
+
+static void gtk_popover_set_focus (GtkPopover  *popover,
+                                 GtkWidget *widget);
+
+static void gtk_popover_set_default (GtkPopover  *popover,
+                                   GtkWidget *widget);
 
-  if (!GTK_WIDGET_CLASS (gtk_popover_parent_class)->focus (widget, direction))
+static void
+gtk_popover_set_property (GObject       *object,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+  GtkPopover *popover = GTK_POPOVER (object);
+
+  switch (prop_id)
     {
-      GtkWidget *focus;
+    case PROP_RELATIVE_TO:
+      gtk_popover_set_relative_to (popover, g_value_get_object (value));
+      break;
 
-      focus = gtk_window_get_focus (priv->window);
-      focus = gtk_widget_get_parent (focus);
+    case PROP_POINTING_TO:
+      gtk_popover_set_pointing_to (popover, g_value_get_boxed (value));
+      break;
 
-      /* Unset focus child through children, so it is next stepped from
-       * scratch.
-       */
-      while (focus && focus != widget)
-        {
-          gtk_widget_set_focus_child (focus, NULL);
-          focus = gtk_widget_get_parent (focus);
-        }
+    case PROP_POSITION:
+      gtk_popover_set_position (popover, g_value_get_enum (value));
+      break;
 
-      return gtk_widget_child_focus (gtk_bin_get_child (GTK_BIN (widget)),
-                                     direction);
-    }
+    case PROP_MODAL:
+      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;
 
-  return TRUE;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
 }
 
 static void
-gtk_popover_show (GtkWidget *widget)
+gtk_popover_get_property (GObject      *object,
+                        guint         prop_id,
+                        GValue       *value,
+                        GParamSpec   *pspec)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
+  GtkPopover *popover = GTK_POPOVER (object);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
+  switch (prop_id)
+    {
+    case PROP_RELATIVE_TO:
+      g_value_set_object (value, priv->relative_to);
+      break;
 
-  if (priv->window)
-    _gtk_window_raise_popover (priv->window, widget);
+    case PROP_POINTING_TO:
+      g_value_set_boxed (value, &priv->pointing_to);
+      break;
 
-  priv->visible = TRUE;
+    case PROP_POSITION:
+      g_value_set_enum (value, priv->position);
+      break;
 
-  GTK_WIDGET_CLASS (gtk_popover_parent_class)->show (widget);
+    case PROP_MODAL:
+      g_value_set_boolean (value, priv->modal);
+      break;
 
-  if (priv->modal)
-    gtk_popover_apply_modality (GTK_POPOVER (widget), TRUE);
+    case NUM_PROPERTIES + GTK_ROOT_PROP_FOCUS_WIDGET:
+      g_value_set_object (value, priv->focus_widget);
+      break;
 
-  priv->state = STATE_SHOWN;
+    case NUM_PROPERTIES + GTK_ROOT_PROP_DEFAULT_WIDGET:
+      g_value_set_object (value, priv->default_widget);
+      break;
 
-  if (gtk_widget_get_realized (widget))
-    gdk_surface_input_shape_combine_region (gtk_widget_get_surface (widget),
-                                           NULL, 0, 0);
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
 }
 
 static void
-gtk_popover_hide (GtkWidget *widget)
+gtk_popover_activate_default (GtkPopover *popover)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
-
-  gtk_popover_hide_internal (GTK_POPOVER (widget));
+  gtk_root_activate_default (GTK_ROOT (popover));
+}
 
-  gtk_popover_stop_transition (GTK_POPOVER (widget));
-  priv->state = STATE_HIDDEN;
-  priv->transition_diff = 0;
-  gtk_progress_tracker_finish (&priv->tracker);
-  gtk_widget_set_opacity (widget, 1.0);
+static void
+gtk_popover_activate_focus (GtkPopover *popover)
+{
+  gtk_root_activate_focus (GTK_ROOT (popover));
+}
 
+static void
+gtk_popover_close (GtkPopover *popover)
+{
+  gtk_widget_hide (GTK_WIDGET (popover));
+}
 
-  GTK_WIDGET_CLASS (gtk_popover_parent_class)->hide (widget);
+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
@@ -1533,10 +669,9 @@ gtk_popover_add (GtkContainer *container,
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
   _gtk_bin_set_child (GTK_BIN (popover), child);
-
   gtk_widget_set_parent (child, priv->contents_widget);
 }
-
+ 
 static void
 gtk_popover_remove (GtkContainer *container,
                     GtkWidget    *child)
@@ -1547,52 +682,41 @@ gtk_popover_remove (GtkContainer *container,
   gtk_widget_unparent (child);
 }
 
-static void
-gtk_popover_state_flags_changed (GtkWidget     *widget,
-                                 GtkStateFlags  previous_state)
-{
-  GtkPopover *popover = GTK_POPOVER (widget);
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkStateFlags state;
-
-  state = gtk_widget_get_state_flags (widget);
-  gtk_css_node_set_state (priv->arrow_node, state);
-
-  GTK_WIDGET_CLASS (gtk_popover_parent_class)->state_flags_changed (widget, previous_state);
-}
-
 static void
 gtk_popover_class_init (GtkPopoverClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+  GtkBindingSet *binding_set;
 
+  if (popover_list == NULL)
+    popover_list = g_list_store_new (GTK_TYPE_WIDGET);
+
+  object_class->constructed = gtk_popover_constructed;
+  object_class->dispose = gtk_popover_dispose;
+  object_class->finalize = gtk_popover_finalize;
   object_class->set_property = gtk_popover_set_property;
   object_class->get_property = gtk_popover_get_property;
-  object_class->finalize = gtk_popover_finalize;
-  object_class->dispose = gtk_popover_dispose;
 
   widget_class->realize = gtk_popover_realize;
+  widget_class->unrealize = gtk_popover_unrealize;
   widget_class->map = gtk_popover_map;
   widget_class->unmap = gtk_popover_unmap;
+  widget_class->show = gtk_popover_show;
+  widget_class->hide = gtk_popover_hide;
   widget_class->measure = gtk_popover_measure;
   widget_class->size_allocate = gtk_popover_size_allocate;
   widget_class->snapshot = gtk_popover_snapshot;
-  widget_class->grab_focus = gtk_popover_grab_focus;
-  widget_class->focus = gtk_popover_focus;
-  widget_class->show = gtk_popover_show;
-  widget_class->hide = gtk_popover_hide;
-  widget_class->state_flags_changed = gtk_popover_state_flags_changed;
+  widget_class->move_focus = gtk_popover_move_focus;
 
   container_class->add = gtk_popover_add;
   container_class->remove = gtk_popover_remove;
 
-  /**
-   * GtkPopover:relative-to:
-   *
-   * Sets the attached widget.
-   */
+  klass->activate_default = gtk_popover_activate_default;
+  klass->activate_focus = gtk_popover_activate_focus;
+  klass->close = gtk_popover_close;
+
   properties[PROP_RELATIVE_TO] =
       g_param_spec_object ("relative-to",
                            P_("Relative to"),
@@ -1600,11 +724,6 @@ gtk_popover_class_init (GtkPopoverClass *klass)
                            GTK_TYPE_WIDGET,
                            GTK_PARAM_READWRITE);
 
-  /**
-   * GtkPopover:pointing-to:
-   *
-   * Marks a specific rectangle to be pointed.
-   */
   properties[PROP_POINTING_TO] =
       g_param_spec_boxed ("pointing-to",
                           P_("Pointing to"),
@@ -1612,11 +731,6 @@ gtk_popover_class_init (GtkPopoverClass *klass)
                           GDK_TYPE_RECTANGLE,
                           GTK_PARAM_READWRITE);
 
-  /**
-   * GtkPopover:position
-   *
-   * Sets the preferred position of the popover.
-   */
   properties[PROP_POSITION] =
       g_param_spec_enum ("position",
                          P_("Position"),
@@ -1624,12 +738,6 @@ gtk_popover_class_init (GtkPopoverClass *klass)
                          GTK_TYPE_POSITION_TYPE, GTK_POS_TOP,
                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
-  /**
-   * GtkPopover:modal
-   *
-   * Sets whether the popover is modal (so other elements in the window do not
-   * receive input while the popover is visible).
-   */
   properties[PROP_MODAL] =
       g_param_spec_boolean ("modal",
                             P_("Modal"),
@@ -1637,456 +745,575 @@ gtk_popover_class_init (GtkPopoverClass *klass)
                             TRUE,
                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
-  /**
-   * GtkPopover:constrain-to:
-   *
-   * Sets a constraint for the popover position.
-   */
-  properties[PROP_CONSTRAIN_TO] =
-      g_param_spec_enum ("constrain-to",
-                         P_("Constraint"),
-                         P_("Constraint for the popover position"),
-                         GTK_TYPE_POPOVER_CONSTRAINT, GTK_POPOVER_CONSTRAINT_WINDOW,
-                         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"),
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GtkPopoverClass, activate_focus),
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE,
+                  0);
+
+  signals[ACTIVATE_DEFAULT] =
+    g_signal_new (I_("activate-default"),
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GtkPopoverClass, activate_default),
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE,
+                  0);
+
+  signals[CLOSE] =
+    g_signal_new (I_("close"),
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GtkPopoverClass, close),
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE,
+                  0);
 
-  /**
-   * GtkPopover::closed:
-   *
-   * This signal is emitted when the popover is dismissed either through
-   * API or user interaction.
-   */
   signals[CLOSED] =
     g_signal_new (I_("closed"),
                   G_TYPE_FROM_CLASS (object_class),
                   G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (GtkPopoverClass, closed),
-                  NULL, NULL, NULL,
-                  G_TYPE_NONE, 0);
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE,
+                  0);
+
+  binding_set = gtk_binding_set_by_class (klass);
+
+  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);
 
-  quark_widget_popovers = g_quark_from_static_string ("gtk-quark-widget-popovers");
-  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_POPOVER_ACCESSIBLE);
-  gtk_widget_class_set_css_name (widget_class, I_("popover"));
+  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);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "activate-default", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "activate-default", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "activate-default", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "close", 0);
+
+  gtk_widget_class_set_css_name (widget_class, "popover");
+}
+
+GtkWidget *
+gtk_popover_new (GtkWidget *relative_to)
+{
+  return GTK_WIDGET (g_object_new (GTK_TYPE_POPOVER,
+                                   "relative-to", relative_to,
+                                   NULL));
 }
 
 static void
-gtk_popover_update_scrollable (GtkPopover *popover)
+size_changed (GtkWidget *widget,
+              int        width,
+              int        height,
+              int        baseline,
+              GtkPopover  *popover)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkScrollable *scrollable;
 
-  scrollable = GTK_SCROLLABLE (gtk_widget_get_ancestor (priv->widget,
-                                                        GTK_TYPE_SCROLLABLE));
-  gtk_popover_set_scrollable_full (popover, scrollable);
+  if (priv->surface)
+    gtk_popover_move_resize (popover);
 }
 
 static void
-_gtk_popover_parent_hierarchy_changed (GtkWidget  *widget,
-                                       GParamSpec *pspec,
-                                       GtkPopover *popover)
+gtk_popover_set_focus (GtkPopover  *popover,
+                     GtkWidget *focus)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWindow *new_window;
-
-  new_window = GTK_WINDOW (gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW));
+  GtkWidget *old_focus = NULL;
+  GdkSeat *seat;
+  GdkDevice *device;
+  GdkEvent *event;
 
-  if (priv->window == new_window)
+  if (focus && !gtk_widget_is_sensitive (focus))
     return;
 
-  g_object_ref (popover);
+  if (priv->focus_widget)
+    old_focus = g_object_ref (priv->focus_widget);
+  g_set_object (&priv->focus_widget, NULL);
 
-  if (gtk_widget_has_grab (GTK_WIDGET (popover)))
-    gtk_popover_apply_modality (popover, FALSE);
+  seat = gdk_display_get_default_seat (gtk_widget_get_display (GTK_WIDGET (popover)));
+  device = gdk_seat_get_keyboard (seat);
 
-  if (priv->window)
-    _gtk_window_remove_popover (priv->window, GTK_WIDGET (popover));
+  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);
 
-  if (priv->parent_scrollable)
-    gtk_popover_set_scrollable_full (popover, NULL);
+  gtk_synthesize_crossing_events (GTK_ROOT (popover), old_focus, focus, event, GDK_CROSSING_NORMAL);
 
-  priv->window = new_window;
+  g_object_unref (event);
 
-  if (new_window)
-    {
-      _gtk_window_add_popover (new_window, GTK_WIDGET (popover), priv->widget, TRUE);
-      gtk_popover_update_scrollable (popover);
-      gtk_popover_update_position (popover);
-    }
+  g_set_object (&priv->focus_widget, focus);
 
-  if (gtk_widget_is_visible (GTK_WIDGET (popover)))
-    gtk_widget_queue_resize (GTK_WIDGET (popover));
+  g_clear_object (&old_focus);
 
-  g_object_unref (popover);
+  g_object_notify (G_OBJECT (popover), "focus-widget");
 }
 
 static void
-_popover_propagate_state (GtkPopover    *popover,
-                          GtkStateFlags  state,
-                          GtkStateFlags  old_state,
-                          GtkStateFlags  flag)
+do_focus_change (GtkWidget *widget,
+                 gboolean   in)
 {
-  if ((state & flag) != (old_state & flag))
-    {
-      if ((state & flag) == flag)
-        gtk_widget_set_state_flags (GTK_WIDGET (popover), flag, FALSE);
-      else
-        gtk_widget_unset_state_flags (GTK_WIDGET (popover), flag);
-    }
+  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_parent_state_changed (GtkWidget     *widget,
-                                   GtkStateFlags  old_state,
-                                   GtkPopover    *popover)
+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)
 {
-  guint state;
+  if (popover_list == NULL)
+    popover_list = g_list_store_new (GTK_TYPE_WIDGET);
 
-  state = gtk_widget_get_state_flags (widget);
-  _popover_propagate_state (popover, state, old_state,
-                            GTK_STATE_FLAG_INSENSITIVE);
-  _popover_propagate_state (popover, state, old_state,
-                            GTK_STATE_FLAG_BACKDROP);
+  return G_LIST_MODEL (popover_list);
 }
 
 static void
-_gtk_popover_parent_grab_notify (GtkWidget  *widget,
-                                 gboolean    was_shadowed,
-                                 GtkPopover *popover)
+gtk_popover_set_default (GtkPopover  *popover,
+                       GtkWidget *widget)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  if (priv->modal &&
-      gtk_widget_is_visible (GTK_WIDGET (popover)) &&
-      !gtk_widget_has_grab (GTK_WIDGET (popover)))
-    {
-      GtkWidget *grab_widget;
+  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);
 
-      grab_widget = gtk_grab_get_current ();
+  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);
 
-      if (!grab_widget || !GTK_IS_POPOVER (grab_widget))
-        gtk_popover_popdown (popover);
+      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 void
-_gtk_popover_parent_unmap (GtkWidget *widget,
-                           GtkPopover *popover)
+static GtkMnemonicHash *
+gtk_popover_get_mnemonic_hash (GtkPopover *popover,
+                             gboolean  create)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  if (priv->state == STATE_SHOWING)
-    priv->visible = FALSE;
-  else if (priv->state == STATE_SHOWN)
-    gtk_popover_set_state (popover, STATE_HIDING);
+  if (!priv->mnemonic_hash && create)
+    priv->mnemonic_hash = _gtk_mnemonic_hash_new ();
+
+  return priv->mnemonic_hash;
 }
 
 static void
-gtk_popover_parent_size_allocate (GtkWidget  *widget,
-                                  int         width,
-                                  int         height,
-                                  int         baseline,
-                                  GtkPopover *popover)
+gtk_popover_root_add_mnemonic (GtkRoot   *root,
+                             guint      keyval,
+                             GtkWidget *target)
 {
-  gtk_popover_update_position (popover);
+  _gtk_mnemonic_hash_add (gtk_popover_get_mnemonic_hash (GTK_POPOVER (root), TRUE), keyval, target);
 }
 
 static void
-_unmanage_popover (GObject *object)
+gtk_popover_root_remove_mnemonic (GtkRoot   *root,
+                                guint      keyval,
+                                GtkWidget *target)
 {
-  gtk_popover_update_relative_to (GTK_POPOVER (object), NULL);
-  g_object_unref (object);
+  _gtk_mnemonic_hash_remove (gtk_popover_get_mnemonic_hash (GTK_POPOVER (root), TRUE), keyval, target);
 }
 
-static void
-widget_manage_popover (GtkWidget  *widget,
-                       GtkPopover *popover)
+static gboolean
+gtk_popover_root_activate_key (GtkRoot     *root,
+                             GdkEventKey *event)
 {
-  GHashTable *popovers;
-
-  popovers = g_object_get_qdata (G_OBJECT (widget), quark_widget_popovers);
+  GdkModifierType modifier = event->state;
+  guint keyval = event->keyval;
 
-  if (G_UNLIKELY (!popovers))
+  if ((modifier & gtk_accelerator_get_default_mod_mask ()) == GDK_MOD1_MASK)
     {
-      popovers = g_hash_table_new_full (NULL, NULL,
-                                        (GDestroyNotify) _unmanage_popover, NULL);
-      g_object_set_qdata_full (G_OBJECT (widget),
-                               quark_widget_popovers, popovers,
-                               (GDestroyNotify) g_hash_table_unref);
+      GtkMnemonicHash *hash = gtk_popover_get_mnemonic_hash (GTK_POPOVER (root), FALSE);
+      if (hash)
+        return _gtk_mnemonic_hash_activate (hash, keyval);      
     }
 
-  g_hash_table_add (popovers, g_object_ref_sink (popover));
+  return FALSE;
 }
 
-static void
-widget_unmanage_popover (GtkWidget  *widget,
-                         GtkPopover *popover)
+static GtkPointerFocus *
+gtk_popover_lookup_pointer_focus (GtkPopover         *popover,
+                                GdkDevice        *device,
+                                GdkEventSequence *sequence)
 {
-  GHashTable *popovers;
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  GList *l;
 
-  popovers = g_object_get_qdata (G_OBJECT (widget), quark_widget_popovers);
+  for (l = priv->foci; l; l = l->next)
+    {
+      GtkPointerFocus *focus = l->data;
 
-  if (G_UNLIKELY (!popovers))
-    return;
+      if (focus->device == device && focus->sequence == sequence)
+        return focus;
+    }
 
-  g_hash_table_remove (popovers, popover);
+  return NULL;
 }
 
 static void
-adjustment_changed_cb (GtkAdjustment *adjustment,
-                       GtkPopover    *popover)
+gtk_popover_add_pointer_focus (GtkPopover        *popover,
+                             GtkPointerFocus *focus)
 {
-  gtk_popover_update_position (popover);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
+  priv->foci = g_list_prepend (priv->foci, gtk_pointer_focus_ref (focus));
 }
 
 static void
-_gtk_popover_set_scrollable (GtkPopover    *popover,
-                             GtkScrollable *scrollable)
+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;
 
-  if (priv->parent_scrollable)
+  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)
     {
-      if (priv->vadj)
+      gtk_pointer_focus_ref (focus);
+
+      if (target)
         {
-          g_signal_handlers_disconnect_by_data (priv->vadj, popover);
-          g_object_unref (priv->vadj);
-          priv->vadj = NULL;
+          gtk_pointer_focus_set_target (focus, target);
+          gtk_pointer_focus_set_coordinates (focus, x, y);
         }
-
-      if (priv->hadj)
+      else
         {
-          g_signal_handlers_disconnect_by_data (priv->hadj, popover);
-          g_object_unref (priv->hadj);
-          priv->hadj = NULL;
+          gtk_popover_remove_pointer_focus (popover, focus);
         }
 
-      g_object_unref (priv->parent_scrollable);
+      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);
     }
+}
 
-  priv->parent_scrollable = scrollable;
+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;
 
-  if (scrollable)
+  while (l)
     {
-      g_object_ref (scrollable);
-      priv->vadj = gtk_scrollable_get_vadjustment (scrollable);
-      priv->hadj = gtk_scrollable_get_hadjustment (scrollable);
+      GtkPointerFocus *focus = l->data;
 
-      if (priv->vadj)
+      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)
         {
-          g_object_ref (priv->vadj);
-          g_signal_connect (priv->vadj, "changed",
-                            G_CALLBACK (adjustment_changed_cb), popover);
-          g_signal_connect (priv->vadj, "value-changed",
-                            G_CALLBACK (adjustment_changed_cb), popover);
+          /* Unmapping the toplevel, remove pointer focus */
+          priv->foci = g_list_remove_link (priv->foci, cur);
+          gtk_pointer_focus_unref (focus);
         }
-
-      if (priv->hadj)
+      else if (focus->target == widget ||
+               gtk_widget_is_ancestor (focus->target, widget))
         {
-          g_object_ref (priv->hadj);
-          g_signal_connect (priv->hadj, "changed",
-                            G_CALLBACK (adjustment_changed_cb), popover);
-          g_signal_connect (priv->hadj, "value-changed",
-                            G_CALLBACK (adjustment_changed_cb), popover);
+          gtk_pointer_focus_repick_target (focus);
         }
+
+      gtk_pointer_focus_unref (focus);
     }
 }
 
-static void
-scrollable_notify_cb (GObject    *object,
-                      GParamSpec *pspec,
-                      GtkPopover *popover)
+static GtkWidget *
+gtk_popover_root_lookup_pointer_focus (GtkRoot          *root,
+                                     GdkDevice        *device,
+                                     GdkEventSequence *sequence)
 {
-  if (pspec->value_type == GTK_TYPE_ADJUSTMENT)
-    _gtk_popover_set_scrollable (popover, GTK_SCROLLABLE (object));
+  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 void
-gtk_popover_set_scrollable_full (GtkPopover    *popover,
-                                 GtkScrollable *scrollable)
+static GtkWidget *
+gtk_popover_root_lookup_effective_pointer_focus (GtkRoot          *root,
+                                               GdkDevice        *device,
+                                               GdkEventSequence *sequence)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  GtkPopover *popover = GTK_POPOVER (root);
+  GtkPointerFocus *focus;
 
-  if (priv->scrollable_notify_id != 0 &&
-      g_signal_handler_is_connected (priv->parent_scrollable, priv->scrollable_notify_id))
-    {
-      g_signal_handler_disconnect (priv->parent_scrollable, priv->scrollable_notify_id);
-      priv->scrollable_notify_id = 0;
-    }
+  focus = gtk_popover_lookup_pointer_focus (popover, device, sequence);
+  return focus ? gtk_pointer_focus_get_effective_target (focus) : NULL;
+}
 
-  _gtk_popover_set_scrollable (popover, scrollable);
+static GtkWidget *
+gtk_popover_root_lookup_pointer_focus_implicit_grab (GtkRoot          *root,
+                                                   GdkDevice        *device,
+                                                    GdkEventSequence *sequence)
+{
+  GtkPopover *popover = GTK_POPOVER (root);
+  GtkPointerFocus *focus;
 
-  if (scrollable)
-    {
-      priv->scrollable_notify_id =
-        g_signal_connect (priv->parent_scrollable, "notify",
-                          G_CALLBACK (scrollable_notify_cb), popover);
-    }
+  focus = gtk_popover_lookup_pointer_focus (popover, device, sequence);
+  return focus ? gtk_pointer_focus_get_implicit_grab (focus) : NULL;
 }
 
 static void
-gtk_popover_update_relative_to (GtkPopover *popover,
-                                GtkWidget  *relative_to)
+gtk_popover_root_set_pointer_focus_grab (GtkRoot          *root,
+                                       GdkDevice        *device,
+                                       GdkEventSequence *sequence,
+                                       GtkWidget        *grab_widget)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  GtkPopover *popover = GTK_POPOVER (root);
+  GtkPointerFocus *focus;
 
-  if (priv->widget == relative_to)
+  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);
+}
 
-  g_object_ref (popover);
+static void
+update_cursor (GtkRoot   *root,
+               GdkDevice *device,
+               GtkWidget *grab_widget,
+               GtkWidget *target)
+{
+  GdkCursor *cursor = NULL;
 
-  if (priv->window)
+  if (grab_widget && !gtk_widget_is_ancestor (target, grab_widget))
     {
-      _gtk_window_remove_popover (priv->window, GTK_WIDGET (popover));
-      priv->window = NULL;
+      /* Outside the grab widget, cursor stays to whatever the grab
+       * widget says.
+       */
+      cursor = gtk_widget_get_cursor (grab_widget);
     }
-
-  popover_unset_prev_focus (popover);
-
-  if (priv->widget)
+  else
     {
-      if (g_signal_handler_is_connected (priv->widget, priv->hierarchy_changed_id))
-        g_signal_handler_disconnect (priv->widget, priv->hierarchy_changed_id);
-      if (g_signal_handler_is_connected (priv->widget, priv->size_allocate_id))
-        g_signal_handler_disconnect (priv->widget, priv->size_allocate_id);
-      if (g_signal_handler_is_connected (priv->widget, priv->unmap_id))
-        g_signal_handler_disconnect (priv->widget, priv->unmap_id);
-      if (g_signal_handler_is_connected (priv->widget, priv->state_changed_id))
-        g_signal_handler_disconnect (priv->widget, priv->state_changed_id);
-      if (g_signal_handler_is_connected (priv->widget, priv->grab_notify_id))
-        g_signal_handler_disconnect (priv->widget, priv->grab_notify_id);
-
-      widget_unmanage_popover (priv->widget, popover);
-    }
+      /* 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;
 
-  if (priv->parent_scrollable)
-    gtk_popover_set_scrollable_full (popover, NULL);
+          cursor = gtk_widget_get_cursor (target);
 
-  priv->widget = relative_to;
-  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_RELATIVE_TO]);
+          if (cursor)
+            break;
 
-  if (priv->widget)
-    {
-      priv->window =
-        GTK_WINDOW (gtk_widget_get_ancestor (priv->widget, GTK_TYPE_WINDOW));
-
-      priv->hierarchy_changed_id =
-        g_signal_connect (priv->widget, "notify::root",
-                          G_CALLBACK (_gtk_popover_parent_hierarchy_changed),
-                          popover);
-      priv->size_allocate_id =
-        g_signal_connect (priv->widget, "size-allocate",
-                          G_CALLBACK (gtk_popover_parent_size_allocate),
-                          popover);
-      priv->unmap_id =
-        g_signal_connect (priv->widget, "unmap",
-                          G_CALLBACK (_gtk_popover_parent_unmap),
-                          popover);
-      priv->state_changed_id =
-        g_signal_connect (priv->widget, "state-flags-changed",
-                          G_CALLBACK (_gtk_popover_parent_state_changed),
-                          popover);
-      priv->grab_notify_id =
-        g_signal_connect (priv->widget, "grab-notify",
-                          G_CALLBACK (_gtk_popover_parent_grab_notify),
-                          popover);
-
-      /* Give ownership of the popover to widget */
-      widget_manage_popover (priv->widget, popover);
+          target = _gtk_widget_get_parent (target);
+        }
     }
 
-  if (priv->window)
-    _gtk_window_add_popover (priv->window, GTK_WIDGET (popover), priv->widget, TRUE);
-
-  if (priv->widget)
-    gtk_popover_update_scrollable (popover);
-
-  _gtk_widget_update_parent_muxer (GTK_WIDGET (popover));
-  g_object_unref (popover);
+  gdk_surface_set_device_cursor (gtk_widget_get_surface (GTK_WIDGET (root)), device, cursor);
 }
 
 static void
-gtk_popover_update_pointing_to (GtkPopover         *popover,
-                                const GdkRectangle *pointing_to)
+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;
 
-  if (pointing_to)
+  for (l = priv->foci; l; l = l->next)
     {
-      priv->pointing_to = *pointing_to;
-      priv->has_pointing_to = TRUE;
-    }
-  else
-    priv->has_pointing_to = FALSE;
+      GtkPointerFocus *focus = l->data;
+      GtkWidget *grab_widget = NULL;
+      GtkWidget  *target;
 
-  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POINTING_TO]);
-}
+      if (focus->sequence)
+        continue;
+      if (device && device != focus->device)
+        continue;
 
-static void
-gtk_popover_update_preferred_position (GtkPopover      *popover,
-                                       GtkPositionType  position)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+#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 (priv->preferred_position == position)
-    return;
+      if (!grab_widget)
+        grab_widget = gtk_pointer_focus_get_implicit_grab (focus);
 
-  priv->preferred_position = position;
-  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POSITION]);
-}
+      target = gtk_pointer_focus_get_target (focus);
 
-/**
- * gtk_popover_new:
- * @relative_to: (allow-none): #GtkWidget the popover is related to
- *
- * Creates a new popover to point to @relative_to
- *
- * Returns: a new #GtkPopover
- **/
-GtkWidget *
-gtk_popover_new (GtkWidget *relative_to)
-{
-  g_return_val_if_fail (relative_to == NULL || GTK_IS_WIDGET (relative_to), NULL);
+      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;
+        }
 
-  return g_object_new (GTK_TYPE_POPOVER,
-                       "relative-to", relative_to,
-                       NULL);
+      update_cursor (focus->toplevel, focus->device, grab_widget, target);
+
+      if (device)
+        break;
+    }
+}
+
+static void
+gtk_popover_root_interface_init (GtkRootInterface *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;
 }
 
-/**
- * gtk_popover_set_relative_to:
- * @popover: a #GtkPopover
- * @relative_to: (allow-none): a #GtkWidget
- *
- * Sets a new widget to be attached to @popover. If @popover is
- * visible, the position will be updated.
- *
- * Note: the ownership of popovers is always given to their @relative_to
- * widget, so if @relative_to is set to %NULL on an attached @popover, it
- * will be detached from its previous widget, and consequently destroyed
- * unless extra references are kept.
- **/
 void
-gtk_popover_set_relative_to (GtkPopover *popover,
-                             GtkWidget  *relative_to)
+gtk_popover_set_relative_to (GtkPopover  *popover,
+                           GtkWidget *relative_to)
 {
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  
   g_return_if_fail (GTK_IS_POPOVER (popover));
-  g_return_if_fail (relative_to == NULL || GTK_IS_WIDGET (relative_to));
 
-  gtk_popover_update_relative_to (popover, relative_to);
+  g_object_ref (popover);
+
+  if (priv->relative_to)
+    {
+      g_signal_handlers_disconnect_by_func (priv->relative_to, size_changed, popover);
+      gtk_widget_unparent (GTK_WIDGET (popover));
+    }
+
+  priv->relative_to = relative_to;
+
+  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_widget_set_parent (GTK_WIDGET (popover), relative_to);
+    }
+
+  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_RELATIVE_TO]);
 
-  if (relative_to)
-    gtk_popover_update_position (popover);
+  g_object_unref (popover);
 }
 
-/**
- * gtk_popover_get_relative_to:
- * @popover: a #GtkPopover
- *
- * Returns the widget @popover is currently attached to
- *
- * Returns: (transfer none): a #GtkWidget
- **/
 GtkWidget *
 gtk_popover_get_relative_to (GtkPopover *popover)
 {
@@ -2094,44 +1321,31 @@ gtk_popover_get_relative_to (GtkPopover *popover)
 
   g_return_val_if_fail (GTK_IS_POPOVER (popover), NULL);
 
-  return priv->widget;
+  return priv->relative_to;
 }
 
-/**
- * gtk_popover_set_pointing_to:
- * @popover: a #GtkPopover
- * @rect: rectangle to point to
- *
- * Sets the rectangle that @popover will point to, in the
- * coordinate space of the widget @popover is attached to,
- * see gtk_popover_set_relative_to().
- **/
 void
-gtk_popover_set_pointing_to (GtkPopover         *popover,
-                             const GdkRectangle *rect)
+gtk_popover_set_pointing_to (GtkPopover           *popover,
+                           const GdkRectangle *rect)
 {
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
   g_return_if_fail (GTK_IS_POPOVER (popover));
-  g_return_if_fail (rect != NULL);
 
-  gtk_popover_update_pointing_to (popover, rect);
-  gtk_popover_update_position (popover);
+  if (rect)
+    {
+      priv->pointing_to = *rect;
+      priv->has_pointing_to = TRUE;
+    }
+  else
+    priv->has_pointing_to = FALSE;
+
+  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POINTING_TO]);
 }
 
-/**
- * gtk_popover_get_pointing_to:
- * @popover: a #GtkPopover
- * @rect: (out): location to store the rectangle
- *
- * If a rectangle to point to has been set, this function will
- * return %TRUE and fill in @rect with such rectangle, otherwise
- * it will return %FALSE and fill in @rect with the attached
- * widget coordinates.
- *
- * Returns: %TRUE if a rectangle to point to was set.
- **/
 gboolean
-gtk_popover_get_pointing_to (GtkPopover   *popover,
-                             GdkRectangle *rect)
+gtk_popover_get_pointing_to (GtkPopover     *popover,
+                           GdkRectangle *rect)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
@@ -2140,53 +1354,26 @@ gtk_popover_get_pointing_to (GtkPopover   *popover,
 
   if (priv->has_pointing_to)
     *rect = priv->pointing_to;
-  else if (priv->widget)
-    {
-      graphene_rect_t r;
-
-      if (!gtk_widget_compute_bounds (priv->widget, priv->widget, &r))
-        return FALSE;
-
-      rect->x = floorf (r.origin.x);
-      rect->y = floorf (r.origin.y);
-      rect->width = ceilf (r.size.width);
-      rect->height = ceilf (r.size.height);
-    }
 
   return priv->has_pointing_to;
 }
 
-/**
- * gtk_popover_set_position:
- * @popover: a #GtkPopover
- * @position: preferred popover position
- *
- * Sets the preferred position for @popover to appear. If the @popover
- * is currently visible, it will be immediately updated.
- *
- * This preference will be respected where possible, although
- * on lack of space (eg. if close to the window edges), the
- * #GtkPopover may choose to appear on the opposite side
- **/
 void
-gtk_popover_set_position (GtkPopover      *popover,
-                          GtkPositionType  position)
+gtk_popover_set_position (GtkPopover        *popover,
+                        GtkPositionType  position)
 {
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
   g_return_if_fail (GTK_IS_POPOVER (popover));
-  g_return_if_fail (position >= GTK_POS_LEFT && position <= GTK_POS_BOTTOM);
 
-  gtk_popover_update_preferred_position (popover, position);
-  gtk_popover_update_position (popover);
+  if (priv->position == position)
+    return;
+
+  priv->position = position;
+
+  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POSITION]);
 }
 
-/**
- * gtk_popover_get_position:
- * @popover: a #GtkPopover
- *
- * Returns the preferred position of @popover.
- *
- * Returns: The preferred position.
- **/
 GtkPositionType
 gtk_popover_get_position (GtkPopover *popover)
 {
@@ -2194,22 +1381,12 @@ gtk_popover_get_position (GtkPopover *popover)
 
   g_return_val_if_fail (GTK_IS_POPOVER (popover), GTK_POS_TOP);
 
-  return priv->preferred_position;
+  return priv->position;
 }
 
-/**
- * gtk_popover_set_modal:
- * @popover: a #GtkPopover
- * @modal: #TRUE to make popover claim all input within the toplevel
- *
- * Sets whether @popover is modal, a modal popover will grab all input
- * within the toplevel and grab the keyboard focus on it when being
- * displayed. Clicking outside the popover area or pressing Esc will
- * dismiss the popover and ungrab input.
- **/
 void
 gtk_popover_set_modal (GtkPopover *popover,
-                       gboolean    modal)
+                     gboolean  modal)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
@@ -2222,21 +1399,9 @@ gtk_popover_set_modal (GtkPopover *popover,
 
   priv->modal = modal;
 
-  if (gtk_widget_is_visible (GTK_WIDGET (popover)))
-    gtk_popover_apply_modality (popover, priv->modal);
-
   g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_MODAL]);
 }
 
-/**
- * gtk_popover_get_modal:
- * @popover: a #GtkPopover
- *
- * Returns whether the popover is modal, see gtk_popover_set_modal to
- * see the implications of this.
- *
- * Returns: #TRUE if @popover is modal
- **/
 gboolean
 gtk_popover_get_modal (GtkPopover *popover)
 {
@@ -2247,6 +1412,31 @@ gtk_popover_get_modal (GtkPopover *popover)
   return priv->modal;
 }
 
+void
+gtk_popover_popup (GtkPopover *popover)
+{
+  g_return_if_fail (GTK_IS_POPOVER (popover));
+
+  gtk_widget_show (GTK_WIDGET (popover));
+}
+
+void
+gtk_popover_popdown (GtkPopover *popover)
+{
+  g_return_if_fail (GTK_IS_POPOVER (popover));
+
+  gtk_widget_hide (GTK_WIDGET (popover));
+}
+
+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)
 {
@@ -2256,44 +1446,11 @@ back_to_main (GtkWidget *popover)
   gtk_stack_set_visible_child_name (GTK_STACK (stack), "main");
 }
 
-/**
- * gtk_popover_bind_model:
- * @popover: a #GtkPopover
- * @model: (allow-none): the #GMenuModel to bind to or %NULL to remove
- *   binding
- * @action_namespace: (allow-none): the namespace for actions in @model
- *
- * Establishes a binding between a #GtkPopover and a #GMenuModel.
- *
- * The contents of @popover are removed and then refilled with menu items
- * according to @model.  When @model changes, @popover is updated.
- * Calling this function twice on @popover with different @model will
- * cause the first binding to be replaced with a binding to the new
- * model. If @model is %NULL then any previous binding is undone and
- * all children are removed.
- *
- * If @action_namespace is non-%NULL then the effect is as if all
- * actions mentioned in the @model have their names prefixed with the
- * namespace, plus a dot.  For example, if the action “quit” is
- * mentioned and @action_namespace is “app” then the effective action
- * name is “app.quit”.
- *
- * This function uses #GtkActionable to define the action name and
- * target values on the created menu items.  If you want to use an
- * action group other than “app” and “win”, or if you want to use a
- * #GtkMenuShell outside of a #GtkApplicationWindow, then you will need
- * to attach your own action group to the widget hierarchy using
- * gtk_widget_insert_action_group().  As an example, if you created a
- * group with a “quit” action and inserted it with the name “mygroup”
- * then you would use the action name “mygroup.quit” in your
- * #GMenuModel.
- */
 void
 gtk_popover_bind_model (GtkPopover  *popover,
                         GMenuModel  *model,
                         const gchar *action_namespace)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
   GtkWidget *child;
   GtkWidget *stack;
   GtkStyleContext *style_context;
@@ -2305,7 +1462,7 @@ gtk_popover_bind_model (GtkPopover  *popover,
   if (child)
     gtk_widget_destroy (child);
 
-  style_context = gtk_widget_get_style_context (priv->contents_widget);
+  style_context = gtk_widget_get_style_context (GTK_WIDGET (popover));
 
   if (model)
     {
@@ -2313,6 +1470,7 @@ gtk_popover_bind_model (GtkPopover  *popover,
       gtk_stack_set_vhomogeneous (GTK_STACK (stack), FALSE);
       gtk_stack_set_transition_type (GTK_STACK (stack), GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT);
       gtk_stack_set_interpolate_size (GTK_STACK (stack), TRUE);
+      gtk_widget_show (stack);
       gtk_container_add (GTK_CONTAINER (popover), stack);
 
       gtk_menu_section_box_new_toplevel (GTK_STACK (stack),
@@ -2332,24 +1490,6 @@ gtk_popover_bind_model (GtkPopover  *popover,
     }
 }
 
-/**
- * gtk_popover_new_from_model:
- * @relative_to: (allow-none): #GtkWidget the popover is related to
- * @model: a #GMenuModel
- *
- * Creates a #GtkPopover and populates it according to
- * @model. The popover is pointed to the @relative_to widget.
- *
- * The created buttons are connected to actions found in the
- * #GtkApplicationWindow to which the popover belongs - typically
- * by means of being attached to a widget that is contained within
- * the #GtkApplicationWindows widget hierarchy.
- *
- * Actions can also be added using gtk_widget_insert_action_group()
- * on the menus attach widget or on any of its parent widgets.
- *
- * Returns: the new #GtkPopover
- */
 GtkWidget *
 gtk_popover_new_from_model (GtkWidget  *relative_to,
                             GMenuModel *model)
@@ -2365,155 +1505,10 @@ gtk_popover_new_from_model (GtkWidget  *relative_to,
   return 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)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  g_return_if_fail (GTK_IS_POPOVER (popover));
-  g_return_if_fail (widget == NULL || gtk_widget_get_can_default (widget));
-
-  if (priv->default_widget == widget)
-    return;
-
-  if (priv->default_widget)
-    g_object_unref (priv->default_widget);
-
-  priv->default_widget = widget;
-
-  if (priv->default_widget)
-    g_object_ref (priv->default_widget);
-
-  if (gtk_widget_get_mapped (GTK_WIDGET (popover)))
-    gtk_window_set_default (priv->window, priv->default_widget);
-}
-
-/**
- * gtk_popover_get_default_widget:
- * @popover: a #GtkPopover
- *
- * Gets the widget that should be set as the default while
- * the popover is shown.
- *
- * Returns: (nullable) (transfer none): the default widget,
- * or %NULL if there is none
- */
 GtkWidget *
-gtk_popover_get_default_widget (GtkPopover *popover)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  g_return_val_if_fail (GTK_IS_POPOVER (popover), NULL);
-
-  return priv->default_widget;
-}
-
-/**
- * gtk_popover_set_constrain_to:
- * @popover: a #GtkPopover
- * @constraint: the new constraint
- *
- * Sets a constraint for positioning this popover.
- *
- * Note that not all platforms support placing popovers freely,
- * and may already impose constraints.
- */
-void
-gtk_popover_set_constrain_to (GtkPopover           *popover,
-                              GtkPopoverConstraint  constraint)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  g_return_if_fail (GTK_IS_POPOVER (popover));
-
-  if (priv->constraint == constraint)
-    return;
-
-  priv->constraint = constraint;
-  gtk_popover_update_position (popover);
-
-  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_CONSTRAIN_TO]);
-}
-
-/**
- * gtk_popover_get_constrain_to:
- * @popover: a #GtkPopover
- *
- * Returns the constraint for placing this popover.
- * See gtk_popover_set_constrain_to().
- *
- * Returns: the constraint for placing this popover.
- */
-GtkPopoverConstraint
-gtk_popover_get_constrain_to (GtkPopover *popover)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  g_return_val_if_fail (GTK_IS_POPOVER (popover), GTK_POPOVER_CONSTRAINT_WINDOW);
-
-  return priv->constraint;
-}
-
-/**
- * gtk_popover_popup:
- * @popover: a #GtkPopover
- *
- * Pops @popover up. This is different than a gtk_widget_show() call
- * in that it shows the popover with a transition. If you want to show
- * the popover without a transition, use gtk_widget_show().
- */
-void
-gtk_popover_popup (GtkPopover *popover)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  g_return_if_fail (GTK_IS_POPOVER (popover));
-
-  if (priv->state == STATE_SHOWING ||
-      priv->state == STATE_SHOWN)
-    return;
-
-  gtk_widget_show (GTK_WIDGET (popover));
-
-  if (transitions_enabled (popover))
-    gtk_popover_set_state (popover, STATE_SHOWING);
-}
-
-/**
- * gtk_popover_popdown:
- * @popover: a #GtkPopover
- *
- * Pops @popover down.This is different than a gtk_widget_hide() call
- * in that it shows the popover with a transition. If you want to hide
- * the popover without a transition, use gtk_widget_hide().
- */
-void
-gtk_popover_popdown (GtkPopover *popover)
+gtk_popover_get_contents_widget (GtkPopover *popover)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  g_return_if_fail (GTK_IS_POPOVER (popover));
-
-  if (priv->state == STATE_HIDING ||
-      priv->state == STATE_HIDDEN)
-    return;
-
-
-  if (!transitions_enabled (popover))
-    gtk_widget_hide (GTK_WIDGET (popover));
-  else
-    gtk_popover_set_state (popover, STATE_HIDING);
-
-  gtk_popover_hide_internal (popover);
+  return priv->contents_widget;
 }
diff --git a/gtk/gtkpopover.h b/gtk/gtkpopover.h
index 11acc02645..d628bfdf1c 100644
--- a/gtk/gtkpopover.h
+++ b/gtk/gtkpopover.h
@@ -1,5 +1,8 @@
 /* GTK - The GIMP Toolkit
- * Copyright © 2013 Carlos Garnacho <carlosg gnome org>
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Authors:
+ * - Matthias Clasen <mclasen redhat com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,95 +25,92 @@
 #error "Only <gtk/gtk.h> can be included directly."
 #endif
 
-#include <gtk/gtkwindow.h>
+#include <gtk/gtkbin.h>
 
 G_BEGIN_DECLS
 
-#define GTK_TYPE_POPOVER           (gtk_popover_get_type ())
-#define GTK_POPOVER(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_POPOVER, GtkPopover))
-#define GTK_POPOVER_CLASS(c)       (G_TYPE_CHECK_CLASS_CAST ((c), GTK_TYPE_POPOVER, GtkPopoverClass))
-#define GTK_IS_POPOVER(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_POPOVER))
-#define GTK_IS_POPOVER_CLASS(o)    (G_TYPE_CHECK_CLASS_TYPE ((o), GTK_TYPE_POPOVER))
-#define GTK_POPOVER_GET_CLASS(o)   (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_POPOVER, GtkPopoverClass))
+#define GTK_TYPE_POPOVER                 (gtk_popover_get_type ())
+#define GTK_POPOVER(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_POPOVER, GtkPopover))
+#define GTK_POPOVER_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_POPOVER, 
GtkPopoverClass))
+#define GTK_IS_POPOVER(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_POPOVER))
+#define GTK_IS_POPOVER_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_POPOVER))
+#define GTK_POPOVER_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_POPOVER, 
GtkPopoverClass))
 
-typedef struct _GtkPopover GtkPopover;
-typedef struct _GtkPopoverClass GtkPopoverClass;
+typedef struct _GtkPopover       GtkPopover;
+typedef struct _GtkPopoverClass  GtkPopoverClass;
 
 struct _GtkPopover
 {
-  GtkBin parent_instance;
+  GtkBin parent;
 };
 
 struct _GtkPopoverClass
 {
   GtkBinClass parent_class;
 
-  void (* closed) (GtkPopover *popover);
+  /* keybinding signals */
+
+  void     (* activate_focus)   (GtkPopover *popover);
+  void     (* activate_default) (GtkPopover *popover);
+  void     (* close)            (GtkPopover *popover);
 
-  /*< private >*/
+  /* signals */
 
-  /* Padding for future expansion */
-  gpointer reserved[10];
+  void     (* closed)           (GtkPopover *popover);
 };
 
 GDK_AVAILABLE_IN_ALL
-GType           gtk_popover_get_type        (void) G_GNUC_CONST;
+GType           gtk_popover_get_type (void) G_GNUC_CONST;
 
 GDK_AVAILABLE_IN_ALL
-GtkWidget *     gtk_popover_new             (GtkWidget             *relative_to);
+GtkWidget *     gtk_popover_new      (GtkWidget *relative_to);
 
 GDK_AVAILABLE_IN_ALL
-GtkWidget *     gtk_popover_new_from_model  (GtkWidget             *relative_to,
-                                             GMenuModel            *model);
+GtkWidget *     gtk_popover_new_from_model  (GtkWidget  *relative_to,
+                                             GMenuModel *model);
 
 GDK_AVAILABLE_IN_ALL
-void            gtk_popover_set_relative_to (GtkPopover            *popover,
-                                             GtkWidget             *relative_to);
-GDK_AVAILABLE_IN_ALL
-GtkWidget *     gtk_popover_get_relative_to (GtkPopover            *popover);
+void            gtk_popover_bind_model      (GtkPopover  *popover,
+                                             GMenuModel  *model,
+                                             const gchar *action_namespace);
 
 GDK_AVAILABLE_IN_ALL
-void            gtk_popover_set_pointing_to (GtkPopover            *popover,
-                                             const GdkRectangle    *rect);
-GDK_AVAILABLE_IN_ALL
-gboolean        gtk_popover_get_pointing_to (GtkPopover            *popover,
-                                             GdkRectangle          *rect);
-GDK_AVAILABLE_IN_ALL
-void            gtk_popover_set_position    (GtkPopover            *popover,
-                                             GtkPositionType        position);
+void            gtk_popover_set_relative_to (GtkPopover   *popover,
+                                           GtkWidget  *relative_to);
 GDK_AVAILABLE_IN_ALL
-GtkPositionType gtk_popover_get_position    (GtkPopover            *popover);
+GtkWidget *     gtk_popover_get_relative_to (GtkPopover   *popover);
 
 GDK_AVAILABLE_IN_ALL
-void            gtk_popover_set_modal       (GtkPopover            *popover,
-                                             gboolean               modal);
+void            gtk_popover_set_pointing_to (GtkPopover           *popover,
+                                           const GdkRectangle *rect);
 GDK_AVAILABLE_IN_ALL
-gboolean        gtk_popover_get_modal       (GtkPopover            *popover);
-
+gboolean        gtk_popover_get_pointing_to (GtkPopover           *popover,
+                                           GdkRectangle       *rect);
+GDK_AVAILABLE_IN_ALL
+void            gtk_popover_set_position    (GtkPopover           *popover,
+                                           GtkPositionType     position);
 GDK_AVAILABLE_IN_ALL
-void            gtk_popover_bind_model      (GtkPopover            *popover,
-                                             GMenuModel            *model,
-                                             const gchar           *action_namespace);
+GtkPositionType gtk_popover_get_position    (GtkPopover           *popover);
 
 GDK_AVAILABLE_IN_ALL
-void            gtk_popover_set_default_widget (GtkPopover *popover,
-                                                GtkWidget  *widget);
+void            gtk_popover_set_modal       (GtkPopover           *popover,
+                                           gboolean            modal);
 GDK_AVAILABLE_IN_ALL
-GtkWidget *     gtk_popover_get_default_widget (GtkPopover *popover);
+gboolean        gtk_popover_get_modal       (GtkPopover           *popover);
 
 GDK_AVAILABLE_IN_ALL
-void                 gtk_popover_set_constrain_to (GtkPopover           *popover,
-                                                   GtkPopoverConstraint  constraint);
-
+void            gtk_popover_popup (GtkPopover *popover);
 GDK_AVAILABLE_IN_ALL
-GtkPopoverConstraint gtk_popover_get_constrain_to (GtkPopover           *popover);
+void            gtk_popover_popdown (GtkPopover *popover);
 
 GDK_AVAILABLE_IN_ALL
-void                 gtk_popover_popup            (GtkPopover *popover);
+void
+gtk_popover_set_default_widget (GtkPopover *popover,
+                                GtkWidget  *widget);
 
-GDK_AVAILABLE_IN_ALL
-void                 gtk_popover_popdown          (GtkPopover *popover);
 
+GDK_AVAILABLE_IN_ALL
+GListModel *    gtk_popover_get_popovers (void);
 
 G_END_DECLS
 
diff --git a/gtk/gtkpopovermenu.c b/gtk/gtkpopovermenu.c
index b5e0d47a2e..7de98bb33a 100644
--- a/gtk/gtkpopovermenu.c
+++ b/gtk/gtkpopovermenu.c
@@ -142,8 +142,10 @@ gtk_popover_menu_init (GtkPopoverMenu *popover)
   g_signal_connect (stack, "notify::visible-child-name",
                     G_CALLBACK (visible_submenu_changed), popover);
 
+#if 0
   style_context = gtk_widget_get_style_context (gtk_popover_get_contents_widget (GTK_POPOVER (popover)));
   gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_MENU);
+#endif
 }
 
 static void
diff --git a/gtk/gtkpopoverprivate.h b/gtk/gtkpopoverprivate.h
index fe24a5d775..db5fa6e57a 100644
--- a/gtk/gtkpopoverprivate.h
+++ b/gtk/gtkpopoverprivate.h
@@ -22,8 +22,6 @@
 
 G_BEGIN_DECLS
 
-void gtk_popover_update_position (GtkPopover *popover);
-
 GtkWidget *gtk_popover_get_contents_widget (GtkPopover *popover);
 
 G_END_DECLS
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 9f28e17081..54361d1e94 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -7465,10 +7465,12 @@ gtk_widget_get_scale_factor (GtkWidget *widget)
    * just returning 1:
    */
   display = _gtk_widget_get_display (widget);
-  monitor = gdk_display_get_monitor (display, 0);
-
-  if (monitor)
-    return gdk_monitor_get_scale_factor (monitor);
+  if (display)
+    {
+      monitor = gdk_display_get_monitor (display, 0);
+      if (monitor)
+        return gdk_monitor_get_scale_factor (monitor);
+    }
 
   return 1;
 }
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index ff5021b3ff..abc2e47c84 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -6631,8 +6631,10 @@ popover_size_allocate (GtkWindowPopover *popover,
   if (!gtk_widget_get_mapped (popover->widget))
     return;
 
+#if 0
   if (GTK_IS_POPOVER (popover->widget))
     gtk_popover_update_position (GTK_POPOVER (popover->widget));
+#endif
 
   popover_get_rect (popover, window, &rect);
   gtk_widget_size_allocate (popover->widget, &rect, -1);
diff --git a/gtk/inspector/object-tree.c b/gtk/inspector/object-tree.c
index 9a763e22a5..6f571e34d8 100644
--- a/gtk/inspector/object-tree.c
+++ b/gtk/inspector/object-tree.c
@@ -41,6 +41,7 @@
 #include "gtklabel.h"
 #include "gtklistbox.h"
 #include "gtkmenuitem.h"
+#include "gtkpopover.h"
 #include "gtksettings.h"
 #include "gtksizegroup.h"
 #include "gtktextview.h"
@@ -56,7 +57,6 @@
 #include "gtksearchbar.h"
 #include "gtksearchentry.h"
 #include "gtkeventcontrollerkey.h"
-#include "gtkpopup.h"
 
 enum
 {
@@ -1145,7 +1145,7 @@ create_root_model (void)
                                          g_object_unref);
   gtk_filter_list_model_set_model (filter, gtk_window_get_toplevels ());
   g_list_store_append (list, filter);
-  g_list_store_append (list, gtk_popup_get_popups ());
+  g_list_store_append (list, gtk_popover_get_popovers ());
   g_object_unref (filter);
 
   flatten = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list));
diff --git a/gtk/meson.build b/gtk/meson.build
index 14b4829f3f..fd955607b7 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -296,7 +296,6 @@ gtk_public_sources = files([
   'gtkpicture.c',
   'gtkpopover.c',
   'gtkpopovermenu.c',
-  'gtkpopup.c',
   'gtkprintcontext.c',
   'gtkprintoperation.c',
   'gtkprintoperationpreview.c',
diff --git a/tests/meson.build b/tests/meson.build
index fe9e09d86b..db90777a43 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -118,7 +118,6 @@ gtk_tests = [
   ['testpopover'],
   ['gdkgears', ['gtkgears.c']],
   ['listmodel'],
-  ['testpopup'],
   ['testpopupat'],
   ['testgaction'],
   ['testwidgetfocus'],


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