[gtk/wip/matthiasc/popup5: 11/75] Reimplement GtkPopover



commit 56baf05b7025e6020b5591e5c66dedd268f5d14a
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Apr 29 03:25:37 2019 +0000

    Reimplement GtkPopover

 gtk/gtkmain.c               |   21 +
 gtk/gtkpopover.c            | 2443 +++++++++++--------------------------------
 gtk/gtkpopover.h            |   94 +-
 gtk/gtkpopoverprivate.h     |    2 -
 gtk/gtkwidget.c             |   10 +-
 gtk/gtkwindow.c             |    2 +
 gtk/inspector/object-tree.c |    2 +
 tests/meson.build           |    1 -
 tests/testpopup.c           |   62 --
 9 files changed, 675 insertions(+), 1962 deletions(-)
---
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index da2aa2c85e..98adee3a3a 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1330,6 +1330,27 @@ rewrite_event_for_grabs (GdkEvent *event)
   event_widget = gtk_get_event_widget (event);
   grab_widget = gtk_native_get_for_surface (grab_surface);
 
+  switch ((guint) event->any.type)
+    {
+    case GDK_BUTTON_PRESS:
+    case GDK_BUTTON_RELEASE:
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+    case GDK_TOUCH_BEGIN:
+    case GDK_TOUCH_END:
+    case GDK_TOUCH_CANCEL:
+    case GDK_TOUCHPAD_SWIPE:
+    case GDK_TOUCHPAD_PINCH:
+      if (grab_surface != event->any.surface &&
+          GTK_IS_POPOVER (grab_widget))
+        {
+          gtk_widget_hide (grab_widget);
+          return NULL;
+        }
+      break;
+    default:;
+    }
+
   if (grab_widget &&
       gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
     return rewrite_event_for_surface (event, grab_surface);
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 70632e8eac..cccba821d4 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
@@ -22,7 +25,8 @@
  *
  * 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(),
+ * 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().
@@ -104,246 +108,265 @@
 #include "config.h"
 
 #include "gtkpopoverprivate.h"
-
-#include "gtkadjustment.h"
-#include "gtkbox.h"
-#include "gtkbutton.h"
-#include "gtkcontainerprivate.h"
+#include "gtknative.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"
+#include "gtkcssnodeprivate.h"
+
+static GListStore *popover_list = NULL;
 
-#include "a11y/gtkpopoveraccessible.h"
+typedef struct {
+  GskRenderer *renderer;
+  GdkSurface *surface;
+  GtkWidget *default_widget;
 
-#include "gsk/gskroundedrectprivate.h"
+  GdkSurfaceState state;
+  GtkWidget *relative_to;
+  GdkRectangle pointing_to;
+  gboolean has_pointing_to;
+  guint surface_transform_changed_cb;
+  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 {
+  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,
   PROP_DEFAULT_WIDGET,
   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] = { NULL };
 
-static GParamSpec *properties[NUM_PROPERTIES];
-static GQuark quark_widget_popovers = 0;
-static guint signals[N_SIGNALS] = { 0 };
+static void gtk_popover_native_interface_init (GtkNativeInterface *iface);
 
-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);
+G_DEFINE_TYPE_WITH_CODE (GtkPopover, gtk_popover, GTK_TYPE_BIN,
+                         G_ADD_PRIVATE (GtkPopover)
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_NATIVE,
+                                                gtk_popover_native_interface_init))
 
-static void gtk_popover_set_scrollable_full (GtkPopover    *popover,
-                                             GtkScrollable *scrollable);
 
-G_DEFINE_TYPE_WITH_PRIVATE (GtkPopover, gtk_popover, GTK_TYPE_BIN)
+static GskRenderer *
+gtk_popover_native_get_renderer (GtkNative *native)
+{
+  GtkPopover *popover = GTK_POPOVER (native);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
+  return priv->renderer;
+}
 
 static void
-measure_contents (GtkGizmo       *gizmo,
-                  GtkOrientation  orientation,
-                  int             for_size,
-                  int            *minimum,
-                  int            *natural,
-                  int            *minimum_baseline,
-                  int            *natural_baseline)
+gtk_popover_native_get_surface_transform (GtkNative *native,
+                                          int       *x,
+                                          int       *y)
 {
-  GtkPopover *popover = GTK_POPOVER (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
-  GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
+  GtkStyleContext *context;
+  GtkBorder margin, border, padding;
 
-  if (child)
-    gtk_widget_measure (child, orientation, for_size,
-                        minimum, natural,
-                        minimum_baseline, natural_baseline);
+  context = gtk_widget_get_style_context (GTK_WIDGET (native));
+  gtk_style_context_get_margin (context, &margin);
+  gtk_style_context_get_border (context, &border);
+  gtk_style_context_get_padding (context, &padding);
+
+  *x = margin.left + border.left + padding.left;
+  *y = margin.top + border.top + padding.top;
 }
 
 static void
-allocate_contents (GtkGizmo *gizmo,
-                   int       width,
-                   int       height,
-                   int       baseline)
+move_to_rect (GtkPopover *popover)
 {
-  GtkPopover *popover = GTK_POPOVER (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
-  GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  GdkRectangle rect;
+  GdkGravity parent_anchor;
+  GdkGravity surface_anchor;
+  GdkAnchorHints anchor_hints;
 
-  if (child)
-    gtk_widget_size_allocate (child,
-                              &(GtkAllocation) {
-                                0, 0,
-                                width, height
-                              }, -1);
+  gtk_widget_get_surface_allocation (priv->relative_to, &rect);
+  if (priv->has_pointing_to)
+    {
+      rect.x += priv->pointing_to.x;
+      rect.y += priv->pointing_to.y;
+      rect.width = priv->pointing_to.width;
+      rect.height = priv->pointing_to.height;
+    }
+
+  switch (priv->position)
+    {
+    case GTK_POS_LEFT:
+      parent_anchor = GDK_GRAVITY_WEST;
+      surface_anchor = GDK_GRAVITY_EAST;
+      anchor_hints = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_SLIDE_Y;
+      break;
+
+    case GTK_POS_RIGHT:
+      parent_anchor = GDK_GRAVITY_EAST;
+      surface_anchor = GDK_GRAVITY_WEST;
+      anchor_hints = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_SLIDE_Y;
+      break;
+
+    case GTK_POS_TOP:
+      parent_anchor = GDK_GRAVITY_NORTH;
+      surface_anchor = GDK_GRAVITY_SOUTH;
+      anchor_hints = GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE_X;
+      break;
+
+    case GTK_POS_BOTTOM:
+      parent_anchor = GDK_GRAVITY_SOUTH;
+      surface_anchor = GDK_GRAVITY_NORTH;
+      anchor_hints = GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE_X;
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+
+  gdk_surface_move_to_rect (priv->surface,
+                            &rect,
+                            parent_anchor,
+                            surface_anchor,
+                            anchor_hints,
+                            0, 0);
 }
 
 static void
-node_style_changed_cb (GtkCssNode        *node,
-                       GtkCssStyleChange *change,
-                       GtkWidget         *widget)
+gtk_popover_move_resize (GtkPopover *popover)
 {
-  if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_SIZE))
-    gtk_widget_queue_resize (widget);
-  else
-    gtk_widget_queue_draw (widget);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  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 gboolean
-key_controller_key_pressed (GtkEventControllerKey *key,
-                            guint                  keyval,
-                            guint                  keycode,
-                            GdkModifierType        modifiers,
-                            GtkPopover            *popover)
+static void
+gtk_popover_native_check_resize (GtkNative *native)
 {
+  GtkPopover *popover = GTK_POPOVER (native);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWidget *toplevel, *focus;
+  GtkWidget *widget = GTK_WIDGET (popover);
 
-  if (keyval == GDK_KEY_Escape)
+  if (!_gtk_widget_get_alloc_needed (widget))
+    gtk_widget_ensure_allocate (widget);
+  else if (gtk_widget_get_visible (widget))
     {
-      gtk_popover_popdown (popover);
-      return TRUE;
+      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);
     }
+}
 
-  if (priv->modal)
-    {
-      toplevel = gtk_widget_get_toplevel (GTK_WIDGET (popover));
 
-      if (GTK_IS_WINDOW (toplevel))
-        {
-          focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
+static void
+gtk_popover_focus_in (GtkWidget *widget)
+{
+}
 
-          if (focus && gtk_widget_is_ancestor (focus, GTK_WIDGET (popover)))
-            {
-              if (gtk_event_controller_key_forward (key, focus))
-                return TRUE;
-            }
+static void
+gtk_popover_focus_out (GtkWidget *widget)
+{
+}
 
-          /* Piggyback on the toplevel to have it handle key navigation */
-          return gtk_event_controller_key_forward (key, toplevel);
-        }
-    }
+static void
+ensure_state_flag_backdrop (GtkWidget *widget)
+{
+  GtkPopover *popover = GTK_POPOVER (widget);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  return FALSE;
+  if ((priv->state & GDK_SURFACE_STATE_FOCUSED) != 0)
+    gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_BACKDROP);
+  else
+    gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_BACKDROP, FALSE);
 }
 
 static void
-gesture_pressed (GtkGestureMultiPress *gesture,
-                 gint                  n_press,
-                 gdouble               x,
-                 gdouble               y,
-                 GtkPopover           *popover)
+surface_state_changed (GtkWidget *widget)
 {
+  GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  GdkSurfaceState new_surface_state;
+  GdkSurfaceState changed_mask;
+
+  new_surface_state = gdk_surface_get_state (_gtk_widget_get_surface (widget));
+  changed_mask = new_surface_state ^ priv->state;
+  priv->state = new_surface_state;
 
-  priv->button_pressed = TRUE;
+  if (changed_mask & GDK_SURFACE_STATE_FOCUSED)
+    ensure_state_flag_backdrop (widget);
+
+  if (changed_mask & GDK_SURFACE_STATE_WITHDRAWN)
+    {
+      if (priv->state & GDK_SURFACE_STATE_WITHDRAWN)
+        gtk_widget_hide (widget);
+    }
 }
 
 static void
-gesture_released (GtkGestureMultiPress *gesture,
-                  gint                  n_press,
-                  gdouble               x,
-                  gdouble               y,
-                  GtkPopover           *popover)
+surface_size_changed (GtkWindow *window,
+                      guint      width,
+                      guint      height)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  graphene_rect_t child_bounds;
-  GtkWidget *child;
+}
 
-  if (!priv->button_pressed)
-    return;
+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));
 
-  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);
+  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
@@ -355,9 +378,13 @@ activate_default_cb (GSimpleAction *action,
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
   GtkWidget *focus_widget;
 
-  focus_widget = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_root (priv->widget)));
+  focus_widget = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_root (priv->relative_to)));
+  if (!gtk_widget_is_ancestor (focus_widget, GTK_WIDGET (popover)))
+    focus_widget = NULL;
+
   if (priv->default_widget && gtk_widget_is_sensitive (priv->default_widget) &&
-      (!focus_widget || !gtk_widget_get_receives_default (focus_widget)))
+      (!focus_widget || !gtk_widget_get_receives_default (focus_widget)
+))
     gtk_widget_activate (priv->default_widget);
   else if (focus_widget && gtk_widget_is_sensitive (focus_widget))
     gtk_widget_activate (focus_widget);
@@ -384,1019 +411,240 @@ static void
 gtk_popover_init (GtkPopover *popover)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWidget *widget;
-  GtkStyleContext *context;
   GtkEventController *controller;
+  GtkStyleContext *context;
 
-  widget = GTK_WIDGET (popover);
-  gtk_widget_set_has_surface (widget, TRUE);
+  gtk_widget_set_has_surface (GTK_WIDGET (popover), TRUE);
+
+  priv->position = GTK_POS_TOP;
   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, 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);
+  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,
+                                         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);
 
   add_actions (popover);
 }
 
 static void
-gtk_popover_set_property (GObject      *object,
-                          guint         prop_id,
-                          const GValue *value,
-                          GParamSpec   *pspec)
+gtk_popover_realize (GtkWidget *widget)
 {
-  switch (prop_id)
-    {
-    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;
-    case PROP_DEFAULT_WIDGET:
-      gtk_popover_set_default_widget (GTK_POPOVER (object),
-                                      g_value_get_object (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
+  GtkPopover *popover = GTK_POPOVER (widget);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  GdkRectangle parent_rect;
+  GdkDisplay *display;
+
+  gtk_widget_get_surface_allocation (priv->relative_to, &parent_rect);
+
+  display = gtk_widget_get_display (priv->relative_to);
+
+  priv->surface = gdk_surface_new_popup_full (display, gtk_widget_get_surface (priv->relative_to));
+
+  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);
+
+  gtk_widget_register_surface (widget, priv->surface);
+
+  GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget);
+
+  priv->renderer = gsk_renderer_new_for_surface (priv->surface);
 }
 
 static void
-gtk_popover_get_property (GObject    *object,
-                          guint       prop_id,
-                          GValue     *value,
-                          GParamSpec *pspec)
+gtk_popover_unrealize (GtkWidget *widget)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (object));
+  GtkPopover *popover = GTK_POPOVER (widget);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  switch (prop_id)
-    {
-    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);
-      break;
-    case PROP_DEFAULT_WIDGET:
-      g_value_set_object (value, priv->default_widget);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-    }
+  GTK_WIDGET_CLASS (gtk_popover_parent_class)->unrealize (widget);
+
+  gsk_renderer_unrealize (priv->renderer);
+  g_clear_object (&priv->renderer);
+
+  g_signal_handlers_disconnect_by_func (priv->surface, surface_state_changed, widget);
+  g_signal_handlers_disconnect_by_func (priv->surface, surface_size_changed, widget);
+
+  g_clear_object (&priv->surface);
 }
 
-static gboolean
-transitions_enabled (GtkPopover *popover)
+static void
+gtk_popover_move_focus (GtkWidget        *widget,
+                        GtkDirectionType  dir)
 {
-  return gtk_settings_get_enable_animations (gtk_widget_get_settings (GTK_WIDGET (popover)));
+  gtk_widget_child_focus (widget, dir);
+
+  if (!gtk_widget_get_focus_child (widget))
+    gtk_root_set_focus (GTK_ROOT (widget), NULL);
 }
 
 static void
-gtk_popover_hide_internal (GtkPopover *popover)
+gtk_popover_show (GtkWidget *widget)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWidget *widget = GTK_WIDGET (popover);
+  _gtk_widget_set_visible_flag (widget, TRUE);
+  gtk_css_node_validate (gtk_widget_get_css_node (widget));
+  gtk_widget_realize (widget);
+  gtk_popover_native_check_resize (GTK_NATIVE (widget));
+  gtk_widget_map (widget);
 
-  if (!priv->visible)
-    return;
+  if (!gtk_widget_get_focus_child (widget))
+    gtk_widget_child_focus (widget, GTK_DIR_TAB_FORWARD);
+}
 
-  priv->visible = FALSE;
+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);
-
-  if (priv->modal)
-    gtk_popover_apply_modality (popover, FALSE);
-
-  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);
-    }
 }
 
 static void
-gtk_popover_finalize (GObject *object)
+grab_prepare_func (GdkSeat    *seat,
+                   GdkSurface *surface,
+                   gpointer    data)
 {
-  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_show (surface);
 }
 
 static void
-popover_unset_prev_focus (GtkPopover *popover)
+unset_surface_transform_changed_cb (gpointer data)
 {
+  GtkPopover *popover = data;
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  if (!priv->prev_focus_widget)
-    return;
+  priv->surface_transform_changed_cb = 0;
+}
 
-  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;
-    }
+static gboolean
+surface_transform_changed_cb (GtkWidget               *widget,
+                              const graphene_matrix_t *transform,
+                              gpointer                 user_data)
+{
+  move_to_rect (GTK_POPOVER (user_data));
 
-  g_clear_object (&priv->prev_focus_widget);
+  return G_SOURCE_CONTINUE;
 }
 
 static void
-gtk_popover_dispose (GObject *object)
+gtk_popover_map (GtkWidget *widget)
 {
-  GtkPopover *popover = GTK_POPOVER (object);
+  GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  GtkWidget *child;
+  GdkRectangle parent_rect;
+  GdkDisplay *display;
 
   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));
+      display = gtk_widget_get_display (priv->relative_to);
+      gdk_seat_grab (gdk_display_get_default_seat (display),
+                     priv->surface,
+                     GDK_SEAT_CAPABILITY_ALL,
+                     TRUE,
+                     NULL, NULL, grab_prepare_func, NULL);
+      priv->has_grab = TRUE;
     }
 
-  priv->window = NULL;
-
-  if (priv->widget)
-    gtk_popover_update_relative_to (popover, NULL);
-
-  popover_unset_prev_focus (popover);
+  gtk_widget_get_surface_allocation (priv->relative_to, &parent_rect);
+  move_to_rect (popover);
 
-  g_clear_object (&priv->default_widget);
-
-  if (priv->contents_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);
-        }
+  priv->surface_transform_changed_cb =
+    gtk_widget_add_surface_transform_changed_callback (priv->relative_to,
+                                                       surface_transform_changed_cb,
+                                                       popover,
+                                                       unset_surface_transform_changed_cb);
 
-      gtk_widget_unparent (priv->contents_widget);
-      priv->contents_widget = NULL;
-    }
+  GTK_WIDGET_CLASS (gtk_popover_parent_class)->map (widget);
 
-  G_OBJECT_CLASS (gtk_popover_parent_class)->dispose (object);
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (child != NULL && gtk_widget_get_visible (child))
+    gtk_widget_map (child);
 }
 
 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_surface (gtk_widget_get_parent (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
-window_active_changed (GtkWindow  *window,
-                       GParamSpec *pspec,
-                       GtkPopover *popover)
-{
-  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;
-    }
-}
-
-static void
-window_set_focus (GtkWindow  *window,
-                  GParamSpec *pspec,
-                  GtkPopover *popover)
-{
-  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));
-}
-
-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)
+gtk_popover_unmap (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);
-  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_widget (priv->window, priv->default_widget);
-}
-
-static void
-gtk_popover_unmap (GtkWidget *widget)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
+  GtkWidget *child;
 
-  priv->button_pressed = FALSE;
+  gtk_widget_remove_surface_transform_changed_callback (priv->relative_to,
+                                                        priv->surface_transform_changed_cb);
+  priv->surface_transform_changed_cb = 0;
 
-  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_widget (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;
-}
-
-static void
-get_margin (GtkWidget *widget,
-            GtkBorder *border)
-{
-  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);
-  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);
-
-#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);
-
-  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 (pos == GTK_POS_BOTTOM || pos == GTK_POS_RIGHT)
+  gdk_surface_hide (priv->surface);
+  if (priv->has_grab)
     {
-      tip = 0;
-      base = tip + TAIL_HEIGHT + border.top;
-    }
-  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)
-{
-  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)
-{
-  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);
-
-  gdk_surface_set_child_input_shapes (gtk_widget_get_surface (widget));
-}
-
-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)
-{
-  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);
+      GdkDisplay *display;
 
-  if (priv->final_position != priv->current_position)
-    {
-      if (gtk_widget_is_drawable (widget))
-        gtk_popover_update_shape (popover);
-
-      priv->current_position = priv->final_position;
+      display = gtk_widget_get_display (priv->relative_to);
+      gdk_seat_ungrab (gdk_display_get_default_seat (display));
+      priv->has_grab = FALSE;
     }
 
-  _gtk_popover_update_child_visible (popover);
-}
-
-GtkWidget *
-gtk_popover_get_contents_widget (GtkPopover *popover)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  return priv->contents_widget;
-}
-
-static void
-gtk_popover_snapshot (GtkWidget   *widget,
-                      GtkSnapshot *snapshot)
-{
-  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);
-
-  cr = gtk_snapshot_append_cairo (snapshot,
-                                  &GRAPHENE_RECT_INIT (
-                                    0, 0,
-                                    gtk_widget_get_width (widget),
-                                    gtk_widget_get_height (widget)
-                                  ));
-
-  /* Clip to the arrow shape */
-  cairo_save (cr);
-
-  gtk_popover_apply_tail_path (popover, cr);
-
-  cairo_clip (cr);
-
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_save_to_node (context, priv->arrow_node);
-  gtk_style_context_get_border (context, &border);
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (child != NULL)
+    gtk_widget_unmap (child);
+}
 
-  /* Render the arrow background */
-  gtk_render_background (context, cr,
-                         0, 0,
-                         gtk_widget_get_width (widget),
-                         gtk_widget_get_height (widget));
+static void
+gtk_popover_dispose (GObject *object)
+{
+  GtkPopover *popover = GTK_POPOVER (object);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  guint i;
+  GtkWidget *child;
 
-  /* Render the border of the arrow tip */
-  if (border.bottom > 0)
+  for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (popover_list)); i++)
     {
-      GdkRGBA *border_color;
+      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_style_context_get (context, "border-color", &border_color, NULL);
-      gtk_popover_apply_tail_path (popover, cr);
-      gdk_cairo_set_source_rgba (cr, border_color);
+  child = gtk_bin_get_child (GTK_BIN (popover));
 
-      cairo_set_line_width (cr, border.bottom + 1);
-      cairo_stroke (cr);
-      gdk_rgba_free (border_color);
+  if (child)
+    {
+      gtk_widget_unparent (child);
+      _gtk_bin_set_child (GTK_BIN (popover), NULL);
     }
 
-  cairo_restore (cr);
-  /* We're done */
-  cairo_destroy (cr);
+  g_clear_pointer (&priv->contents_widget, gtk_widget_unparent);
 
-  gtk_style_context_restore (context);
+  G_OBJECT_CLASS (gtk_popover_parent_class)->dispose (object);
 }
 
-static gint
-get_border_radius (GtkWidget *widget)
+static void
+gtk_popover_finalize (GObject *object)
 {
-  GtkStyleContext *context;
-  gint border_radius;
-
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_get (context,
-                         GTK_STYLE_PROPERTY_BORDER_RADIUS, &border_radius,
-                         NULL);
-  return border_radius;
+  G_OBJECT_CLASS (gtk_popover_parent_class)->finalize (object);
 }
 
-static gint
-get_minimal_size (GtkPopover     *popover,
-                  GtkOrientation  orientation)
+static void
+gtk_popover_constructed (GObject *object)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkPositionType pos;
-  gint minimal_size;
-
-  minimal_size = 2 * get_border_radius (GTK_WIDGET (popover));
-  pos = get_effective_position (popover, priv->preferred_position);
-
-  if ((orientation == GTK_ORIENTATION_HORIZONTAL && POS_IS_VERTICAL (pos)) ||
-      (orientation == GTK_ORIENTATION_VERTICAL && !POS_IS_VERTICAL (pos)))
-    minimal_size += TAIL_GAP_WIDTH;
-
-  return minimal_size;
+  g_list_store_append (popover_list, object);
+  g_object_unref (object);
 }
 
 static void
@@ -1410,22 +658,11 @@ gtk_popover_measure (GtkWidget      *widget,
 {
   GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  int minimal_size;
-
-  *minimum = 0;
-  *natural = 0;
-
-  if (for_size >= 0)
-    for_size -= TAIL_HEIGHT;
 
-  gtk_widget_measure (priv->contents_widget, orientation, for_size, minimum, natural, NULL, NULL);
-
-  minimal_size = get_minimal_size (popover, orientation);
-  *minimum = MAX (*minimum, minimal_size);
-  *natural = MAX (*natural, minimal_size);
-
-  *minimum += TAIL_HEIGHT;
-  *natural += TAIL_HEIGHT;
+  gtk_widget_measure (priv->contents_widget,
+                      orientation, for_size,
+                      minimum, natural,
+                      minimum_baseline, natural_baseline);
 }
 
 static void
@@ -1436,133 +673,102 @@ gtk_popover_size_allocate (GtkWidget *widget,
 {
   GtkPopover *popover = GTK_POPOVER (widget);
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkAllocation child_alloc = (GtkAllocation) {0, 0, width, height};
-
-  /* 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;
-
-  switch (priv->current_position)
-    {
-    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;
-    }
 
-  gtk_widget_size_allocate (priv->contents_widget, &child_alloc, -1);
+  if (priv->surface)
+    gtk_popover_move_resize (popover);
 
-  if (gtk_widget_get_realized (widget))
-    {
-      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_size_allocate (priv->contents_widget,
+                            &(GtkAllocation) { 0, 0, width, height },
+                            baseline);
 }
 
 static void
-gtk_popover_grab_focus (GtkWidget *widget)
+gtk_popover_snapshot (GtkWidget   *widget,
+                      GtkSnapshot *snapshot)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
-  GtkWidget *child;
-
-  if (!priv->visible)
-    return;
-
-  /* Focus the first natural child */
-  child = gtk_bin_get_child (GTK_BIN (widget));
+  GtkPopover *popover = GTK_POPOVER (widget);
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  if (child)
-    gtk_widget_child_focus (child, GTK_DIR_TAB_FORWARD);
+  gtk_widget_snapshot_child (widget, priv->contents_widget, snapshot);
 }
 
-static gboolean
-gtk_popover_focus (GtkWidget        *widget,
-                   GtkDirectionType  direction)
+static void
+gtk_popover_set_property (GObject      *object,
+                          guint         prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
 {
-  GtkPopover *popover = GTK_POPOVER (widget);
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (!priv->visible)
-    return FALSE;
+  GtkPopover *popover = GTK_POPOVER (object);
 
-  if (!GTK_WIDGET_CLASS (gtk_popover_parent_class)->focus (widget, direction))
+  switch (prop_id)
     {
-      GtkWidget *focus;
+    case PROP_RELATIVE_TO:
+      gtk_popover_set_relative_to (popover, g_value_get_object (value));
+      break;
+
+    case PROP_POINTING_TO:
+      gtk_popover_set_pointing_to (popover, g_value_get_boxed (value));
+      break;
 
-      focus = gtk_window_get_focus (priv->window);
-      focus = gtk_widget_get_parent (focus);
+    case PROP_POSITION:
+      gtk_popover_set_position (popover, g_value_get_enum (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_MODAL:
+      gtk_popover_set_modal (popover, g_value_get_boolean (value));
+      break;
 
-      return gtk_widget_child_focus (gtk_bin_get_child (GTK_BIN (widget)),
-                                     direction);
-    }
+    case PROP_DEFAULT_WIDGET:
+      gtk_popover_set_default_widget (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);
 
-  if (priv->window)
-    _gtk_window_raise_popover (priv->window, widget);
+  switch (prop_id)
+    {
+    case PROP_RELATIVE_TO:
+      g_value_set_object (value, priv->relative_to);
+      break;
 
-  priv->visible = TRUE;
+    case PROP_POINTING_TO:
+      g_value_set_boxed (value, &priv->pointing_to);
+      break;
 
-  GTK_WIDGET_CLASS (gtk_popover_parent_class)->show (widget);
+    case PROP_POSITION:
+      g_value_set_enum (value, priv->position);
+      break;
 
-  if (priv->modal)
-    gtk_popover_apply_modality (GTK_POPOVER (widget), TRUE);
+    case PROP_MODAL:
+      g_value_set_boolean (value, priv->modal);
+      break;
 
-  priv->state = STATE_SHOWN;
+    case 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_close (GtkPopover *popover)
 {
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
-
-  gtk_popover_hide_internal (GTK_POPOVER (widget));
-
-  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);
-
-
-  GTK_WIDGET_CLASS (gtk_popover_parent_class)->hide (widget);
+  gtk_widget_hide (GTK_WIDGET (popover));
 }
 
 static void
@@ -1573,10 +779,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)
@@ -1587,20 +792,6 @@ 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)
 {
@@ -1608,31 +799,31 @@ gtk_popover_class_init (GtkPopoverClass *klass)
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
 
+  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->close = gtk_popover_close;
+
   properties[PROP_RELATIVE_TO] =
       g_param_spec_object ("relative-to",
                            P_("Relative to"),
@@ -1640,11 +831,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"),
@@ -1652,452 +838,118 @@ 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"),
                          P_("Position to place the bubble window"),
                          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"),
-                            P_("Whether the popover is modal"),
-                            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);
-
-  properties[PROP_DEFAULT_WIDGET] =
-      g_param_spec_object ("default-widget",
-                           P_("Default widget"),
-                           P_("The default widget"),
-                           GTK_TYPE_WIDGET,
-                           GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
-
-  g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
-
-  /**
-   * 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);
-
-  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"));
-}
-
-static void
-gtk_popover_update_scrollable (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);
-}
-
-static void
-_gtk_popover_parent_hierarchy_changed (GtkWidget  *widget,
-                                       GParamSpec *pspec,
-                                       GtkPopover *popover)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-  GtkWindow *new_window;
-
-  new_window = GTK_WINDOW (gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW));
-
-  if (priv->window == new_window)
-    return;
-
-  g_object_ref (popover);
-
-  if (gtk_widget_has_grab (GTK_WIDGET (popover)))
-    gtk_popover_apply_modality (popover, FALSE);
-
-  if (priv->window)
-    _gtk_window_remove_popover (priv->window, GTK_WIDGET (popover));
-
-  if (priv->parent_scrollable)
-    gtk_popover_set_scrollable_full (popover, NULL);
-
-  priv->window = new_window;
-
-  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);
-    }
-
-  if (gtk_widget_is_visible (GTK_WIDGET (popover)))
-    gtk_widget_queue_resize (GTK_WIDGET (popover));
-
-  g_object_unref (popover);
-}
-
-static void
-_popover_propagate_state (GtkPopover    *popover,
-                          GtkStateFlags  state,
-                          GtkStateFlags  old_state,
-                          GtkStateFlags  flag)
-{
-  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);
-    }
-}
-
-static void
-_gtk_popover_parent_state_changed (GtkWidget     *widget,
-                                   GtkStateFlags  old_state,
-                                   GtkPopover    *popover)
-{
-  guint state;
-
-  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);
-}
-
-static void
-_gtk_popover_parent_grab_notify (GtkWidget  *widget,
-                                 gboolean    was_shadowed,
-                                 GtkPopover *popover)
-{
-  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;
-
-      grab_widget = gtk_grab_get_current ();
-
-      if (!grab_widget || !GTK_IS_POPOVER (grab_widget))
-        gtk_popover_popdown (popover);
-    }
-}
-
-static void
-_gtk_popover_parent_unmap (GtkWidget *widget,
-                           GtkPopover *popover)
-{
-  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);
-}
-
-static void
-gtk_popover_parent_size_allocate (GtkWidget  *widget,
-                                  int         width,
-                                  int         height,
-                                  int         baseline,
-                                  GtkPopover *popover)
-{
-  gtk_popover_update_position (popover);
-}
-
-static void
-_unmanage_popover (GObject *object)
-{
-  gtk_popover_update_relative_to (GTK_POPOVER (object), NULL);
-  g_object_unref (object);
-}
-
-static void
-widget_manage_popover (GtkWidget  *widget,
-                       GtkPopover *popover)
-{
-  GHashTable *popovers;
-
-  popovers = g_object_get_qdata (G_OBJECT (widget), quark_widget_popovers);
-
-  if (G_UNLIKELY (!popovers))
-    {
-      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);
-    }
-
-  g_hash_table_add (popovers, g_object_ref_sink (popover));
-}
-
-static void
-widget_unmanage_popover (GtkWidget  *widget,
-                         GtkPopover *popover)
-{
-  GHashTable *popovers;
-
-  popovers = g_object_get_qdata (G_OBJECT (widget), quark_widget_popovers);
-
-  if (G_UNLIKELY (!popovers))
-    return;
-
-  g_hash_table_remove (popovers, popover);
-}
-
-static void
-adjustment_changed_cb (GtkAdjustment *adjustment,
-                       GtkPopover    *popover)
-{
-  gtk_popover_update_position (popover);
-}
-
-static void
-_gtk_popover_set_scrollable (GtkPopover    *popover,
-                             GtkScrollable *scrollable)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (priv->parent_scrollable)
-    {
-      if (priv->vadj)
-        {
-          g_signal_handlers_disconnect_by_data (priv->vadj, popover);
-          g_object_unref (priv->vadj);
-          priv->vadj = NULL;
-        }
+                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
-      if (priv->hadj)
-        {
-          g_signal_handlers_disconnect_by_data (priv->hadj, popover);
-          g_object_unref (priv->hadj);
-          priv->hadj = NULL;
-        }
+  properties[PROP_MODAL] =
+      g_param_spec_boolean ("modal",
+                            P_("Modal"),
+                            P_("Whether the popover is modal"),
+                            TRUE,
+                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
-      g_object_unref (priv->parent_scrollable);
-    }
+  properties[PROP_DEFAULT_WIDGET] =
+      g_param_spec_object ("default-widget",
+                           P_("Default widget"),
+                           P_("The default widget"),
+                           GTK_TYPE_WIDGET,
+                           GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
 
-  priv->parent_scrollable = scrollable;
+  g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
 
-  if (scrollable)
-    {
-      g_object_ref (scrollable);
-      priv->vadj = gtk_scrollable_get_vadjustment (scrollable);
-      priv->hadj = gtk_scrollable_get_hadjustment (scrollable);
+  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);
 
-      if (priv->vadj)
-        {
-          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);
-        }
+  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);
 
-      if (priv->hadj)
-        {
-          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_widget_class_set_css_name (widget_class, "popover");
 }
 
-static void
-scrollable_notify_cb (GObject    *object,
-                      GParamSpec *pspec,
-                      GtkPopover *popover)
+GtkWidget *
+gtk_popover_new (GtkWidget *relative_to)
 {
-  if (pspec->value_type == GTK_TYPE_ADJUSTMENT)
-    _gtk_popover_set_scrollable (popover, GTK_SCROLLABLE (object));
+  return GTK_WIDGET (g_object_new (GTK_TYPE_POPOVER,
+                                   "relative-to", relative_to,
+                                   NULL));
 }
 
 static void
-gtk_popover_set_scrollable_full (GtkPopover    *popover,
-                                 GtkScrollable *scrollable)
+size_changed (GtkWidget   *widget,
+              int          width,
+              int          height,
+              int          baseline,
+              GtkPopover  *popover)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  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;
-    }
+  if (priv->surface)
+    gtk_popover_move_resize (popover);
+}
 
-  _gtk_popover_set_scrollable (popover, scrollable);
+GListModel *
+gtk_popover_get_popovers (void)
+{
+  if (popover_list == NULL)
+    popover_list = g_list_store_new (GTK_TYPE_WIDGET);
 
-  if (scrollable)
-    {
-      priv->scrollable_notify_id =
-        g_signal_connect (priv->parent_scrollable, "notify",
-                          G_CALLBACK (scrollable_notify_cb), popover);
-    }
+  return G_LIST_MODEL (popover_list);
 }
 
-static void
-gtk_popover_update_relative_to (GtkPopover *popover,
-                                GtkWidget  *relative_to)
+void
+gtk_popover_set_default_widget (GtkPopover *popover,
+                                GtkWidget  *widget)
 {
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
 
-  if (priv->widget == relative_to)
-    return;
-
-  g_object_ref (popover);
-
-  if (priv->window)
-    {
-      _gtk_window_remove_popover (priv->window, GTK_WIDGET (popover));
-      priv->window = NULL;
-    }
-
-  popover_unset_prev_focus (popover);
-
-  if (priv->widget)
-    {
-      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);
-    }
-
-  if (priv->parent_scrollable)
-    gtk_popover_set_scrollable_full (popover, NULL);
+  g_return_if_fail (GTK_IS_POPOVER (popover));
 
-  priv->widget = relative_to;
-  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_RELATIVE_TO]);
+  if (priv->default_widget == widget)
+    return;
 
-  if (priv->widget)
+  if (priv->default_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);
+      _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");
     }
 
-  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);
-}
-
-static void
-gtk_popover_update_pointing_to (GtkPopover         *popover,
-                                const GdkRectangle *pointing_to)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  g_set_object (&priv->default_widget, widget);
 
-  if (pointing_to)
+  if (priv->default_widget)
     {
-      priv->pointing_to = *pointing_to;
-      priv->has_pointing_to = TRUE;
+      _gtk_widget_set_has_default (priv->default_widget, TRUE);
+      gtk_widget_queue_draw (priv->default_widget);
+      g_object_notify (G_OBJECT (priv->default_widget), "has-default");
     }
-  else
-    priv->has_pointing_to = FALSE;
 
-  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POINTING_TO]);
+  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_DEFAULT_WIDGET]);
 }
 
 static void
-gtk_popover_update_preferred_position (GtkPopover      *popover,
-                                       GtkPositionType  position)
-{
-  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
-  if (priv->preferred_position == position)
-    return;
-
-  priv->preferred_position = position;
-  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POSITION]);
-}
-
-/**
- * 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)
+gtk_popover_native_interface_init (GtkNativeInterface *iface)
 {
-  g_return_val_if_fail (relative_to == NULL || GTK_IS_WIDGET (relative_to), NULL);
-
-  return g_object_new (GTK_TYPE_POPOVER,
-                       "relative-to", relative_to,
-                       NULL);
+  iface->get_renderer = gtk_popover_native_get_renderer;
+  iface->get_surface_transform = gtk_popover_native_get_surface_transform;
+  iface->check_resize = gtk_popover_native_check_resize;
 }
 
 /**
@@ -2108,7 +960,8 @@ gtk_popover_new (GtkWidget *relative_to)
  * 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
+ * Note: the ownership of popovers is always given to their @relative_t
+o
  * 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.
@@ -2117,13 +970,31 @@ void
 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);
+      gtk_css_node_set_parent (gtk_widget_get_css_node (GTK_WIDGET (popover)),
+                               gtk_widget_get_css_node (relative_to));
+      gtk_widget_set_parent (GTK_WIDGET (popover), relative_to);
+    }
+
+  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_RELATIVE_TO]);
 
-  if (relative_to)
-    gtk_popover_update_position (popover);
+  g_object_unref (popover);
 }
 
 /**
@@ -2141,7 +1012,7 @@ gtk_popover_get_relative_to (GtkPopover *popover)
 
   g_return_val_if_fail (GTK_IS_POPOVER (popover), NULL);
 
-  return priv->widget;
+  return priv->relative_to;
 }
 
 /**
@@ -2157,11 +1028,19 @@ void
 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]);
 }
 
 /**
@@ -2187,18 +1066,6 @@ 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;
 }
@@ -2219,11 +1086,16 @@ void
 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]);
 }
 
 /**
@@ -2241,7 +1113,7 @@ 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;
 }
 
 /**
@@ -2269,9 +1141,6 @@ 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]);
 }
 
@@ -2294,6 +1163,38 @@ gtk_popover_get_modal (GtkPopover *popover)
   return priv->modal;
 }
 
+/**
+ * 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)
+{
+  g_return_if_fail (GTK_IS_POPOVER (popover));
+
+  gtk_widget_show (GTK_WIDGET (popover));
+}
+
+/**
+ * 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)
+{
+  g_return_if_fail (GTK_IS_POPOVER (popover));
+
+  gtk_widget_hide (GTK_WIDGET (popover));
+}
+
 static void
 back_to_main (GtkWidget *popover)
 {
@@ -2340,7 +1241,6 @@ 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;
@@ -2352,7 +1252,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)
     {
@@ -2412,156 +1312,11 @@ 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));
-
-  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_widget (priv->window, priv->default_widget);
-
-  g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_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..e9456bd7cb 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,88 @@
 #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     (* 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);
-
+GListModel *    gtk_popover_get_popovers (void);
 
 G_END_DECLS
 
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 4a6796f9af..290e0d2a5f 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -7414,10 +7414,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 fa08ad83e4..902a8cc4f4 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -5878,8 +5878,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 f2caf34708..f977096d69 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"
@@ -1144,6 +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_popover_get_popovers ());
   g_object_unref (filter);
 
   flatten = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list));
diff --git a/tests/meson.build b/tests/meson.build
index f70401b2d4..677fbb74e6 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -114,7 +114,6 @@ gtk_tests = [
   ['testpopover'],
   ['gdkgears', ['gtkgears.c']],
   ['listmodel'],
-  ['testpopup'],
   ['testgaction'],
   ['testwidgetfocus'],
   ['testwidgettransforms'],


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