[gtk/present-toplevel-2: 33/83] Introduce GdkToplevel



commit 85aebbffc281ca1cd43241e01e3cdf3f56710a45
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Feb 29 10:07:43 2020 -0500

    Introduce GdkToplevel
    
    This is a new interface for toplevel surfaces.

 gdk/gdk.h                |  12 +-
 gdk/gdksurface.c         | 262 ++++++++++++++++++++++--
 gdk/gdktoplevel.c        | 503 +++++++++++++++++++++++++++++++++++++++++++++++
 gdk/gdktoplevel.h        | 104 ++++++++++
 gdk/gdktoplevelprivate.h |  47 +++++
 gdk/meson.build          |   2 +
 6 files changed, 910 insertions(+), 20 deletions(-)
---
diff --git a/gdk/gdk.h b/gdk/gdk.h
index a4f434511e..30ab0d7590 100644
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -27,12 +27,11 @@
 
 #define __GDK_H_INSIDE__
 
-#include <gdk/gdkconfig.h>
-#include <gdk/gdkversionmacros.h>
 #include <gdk/gdkapplaunchcontext.h>
 #include <gdk/gdkcairo.h>
 #include <gdk/gdkcairocontext.h>
 #include <gdk/gdkclipboard.h>
+#include <gdk/gdkconfig.h>
 #include <gdk/gdkcontentdeserializer.h>
 #include <gdk/gdkcontentformats.h>
 #include <gdk/gdkcontentprovider.h>
@@ -60,16 +59,19 @@
 #include <gdk/gdkpaintable.h>
 #include <gdk/gdkpango.h>
 #include <gdk/gdkpixbuf.h>
+#include <gdk/gdkpopup.h>
+#include <gdk/gdkpopuplayout.h>
 #include <gdk/gdkrectangle.h>
 #include <gdk/gdkrgba.h>
 #include <gdk/gdkseat.h>
 #include <gdk/gdksnapshot.h>
+#include <gdk/gdksurface.h>
 #include <gdk/gdktexture.h>
+#include <gdk/gdktoplevel.h>
+#include <gdk/gdktoplevellayout.h>
 #include <gdk/gdktypes.h>
+#include <gdk/gdkversionmacros.h>
 #include <gdk/gdkvulkancontext.h>
-#include <gdk/gdksurface.h>
-#include <gdk/gdkpopup.h>
-#include <gdk/gdktoplevellayout.h>
 
 #include <gdk/gdk-autocleanup.h>
 
diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c
index 70a62487d2..5e30a06f10 100644
--- a/gdk/gdksurface.c
+++ b/gdk/gdksurface.c
@@ -40,6 +40,7 @@
 #include "gdkmarshalers.h"
 #include "gdkpopupprivate.h"
 #include "gdkrectangle.h"
+#include "gdktoplevelprivate.h"
 
 #include <math.h>
 
@@ -83,7 +84,6 @@ enum {
   PROP_CURSOR,
   PROP_DISPLAY,
   PROP_FRAME_CLOCK,
-  PROP_STATE,
   PROP_MAPPED,
   LAST_PROP
 };
@@ -112,10 +112,13 @@ static guint signals[LAST_SIGNAL] = { 0 };
 static GParamSpec *properties[LAST_PROP] = { NULL, };
 
 static void gdk_surface_popup_init (GdkPopupInterface *iface);
+static void gdk_surface_toplevel_init (GdkToplevelInterface *iface);
 
 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkSurface, gdk_surface, G_TYPE_OBJECT,
                                   G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP,
-                                                         gdk_surface_popup_init))
+                                                         gdk_surface_popup_init)
+                                  G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL,
+                                                         gdk_surface_toplevel_init))
 
 static gboolean
 gdk_surface_real_beep (GdkSurface *surface)
@@ -443,13 +446,6 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
                            GDK_TYPE_FRAME_CLOCK,
                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
-  properties[PROP_STATE] =
-      g_param_spec_flags ("state",
-                          P_("State"),
-                          P_("State"),
-                          GDK_TYPE_SURFACE_STATE, GDK_SURFACE_STATE_WITHDRAWN,
-                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
   properties[PROP_MAPPED] =
       g_param_spec_boolean ("mapped",
                             P_("Mapped"),
@@ -466,6 +462,7 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
 
   g_object_class_install_properties (object_class, LAST_PROP, properties);
   gdk_popup_install_properties (object_class, LAST_PROP);
+  gdk_toplevel_install_properties (object_class, LAST_PROP + GDK_POPUP_NUM_PROPERTIES);
 
   /**
    * GdkSurface::popup-layout-changed
@@ -644,12 +641,78 @@ gdk_surface_set_property (GObject      *object,
       surface->autohide = g_value_get_boolean (value);
       break;
 
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_TITLE:
+      gdk_surface_set_title (surface, g_value_get_string (value));
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_STARTUP_ID:
+      gdk_surface_set_startup_id (surface, g_value_get_string (value));
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
+      gdk_surface_set_transient_for (surface, g_value_get_object (value));
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_ICON_LIST:
+      gdk_surface_set_icon_list (surface, g_value_get_pointer (value));
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_STICKY:
+      if (g_value_get_boolean (value))
+        GDK_SURFACE_GET_CLASS (surface)->stick (surface);
+      else
+        GDK_SURFACE_GET_CLASS (surface)->unstick (surface);
+      g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_KEEP_ABOVE:
+      GDK_SURFACE_GET_CLASS (surface)->set_keep_above (surface, g_value_get_boolean (value));
+      g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_KEEP_BELOW:
+      GDK_SURFACE_GET_CLASS (surface)->set_keep_below (surface, g_value_get_boolean (value));
+      g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_ACCEPT_FOCUS:
+      if (surface->accept_focus != g_value_get_boolean (value))
+        {
+          surface->accept_focus = g_value_get_boolean (value);
+          GDK_SURFACE_GET_CLASS (surface)->set_accept_focus (surface, surface->accept_focus);
+          g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+        }
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_FOCUS_ON_MAP:
+      if (surface->focus_on_map != g_value_get_boolean (value))
+        {
+          surface->focus_on_map = g_value_get_boolean (value);
+          GDK_SURFACE_GET_CLASS (surface)->set_focus_on_map (surface, surface->focus_on_map);
+          g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+        }
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_DECORATED:
+      GDK_SURFACE_GET_CLASS (surface)->set_decorations (surface, g_value_get_boolean (value) ? GDK_DECOR_ALL 
: 0);
+      g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_DELETABLE:
+      GDK_SURFACE_GET_CLASS (surface)->set_functions (surface, g_value_get_boolean (value) ? GDK_FUNC_ALL : 
GDK_FUNC_ALL | GDK_FUNC_CLOSE);
+      g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
     }
 }
 
+#define GDK_SURFACE_IS_STICKY(surface) (((surface)->state & GDK_SURFACE_STATE_STICKY))
+#define GDK_SURFACE_IS_ABOVE(surface) (((surface)->state & GDK_SURFACE_STATE_ABOVE))
+#define GDK_SURFACE_IS_BELOW(surface) (((surface)->state & GDK_SURFACE_STATE_BELOW))
+
 static void
 gdk_surface_get_property (GObject    *object,
                           guint       prop_id,
@@ -672,10 +735,6 @@ gdk_surface_get_property (GObject    *object,
       g_value_set_object (value, surface->frame_clock);
       break;
 
-    case PROP_STATE:
-      g_value_set_flags (value, surface->state);
-      break;
-
     case PROP_MAPPED:
       g_value_set_boolean (value, GDK_SURFACE_IS_MAPPED (surface));
       break;
@@ -692,6 +751,54 @@ gdk_surface_get_property (GObject    *object,
       g_value_set_boolean (value, surface->autohide);
       break;
 
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_STATE:
+      g_value_set_flags (value, surface->state);
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_TITLE:
+      g_value_set_string (value, ""); // FIXME
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_STARTUP_ID:
+      g_value_set_string (value, ""); // FIXME
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
+      g_value_set_object (value, NULL); // FIXME
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_ICON_LIST:
+      g_value_set_pointer (value, NULL); // FIXME
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_STICKY:
+      g_value_set_boolean (value, GDK_SURFACE_IS_STICKY (surface));
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_KEEP_ABOVE:
+      g_value_set_boolean (value, GDK_SURFACE_IS_ABOVE (surface));
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_KEEP_BELOW:
+      g_value_set_boolean (value, GDK_SURFACE_IS_BELOW (surface));
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_ACCEPT_FOCUS:
+      g_value_set_boolean (value, surface->accept_focus);
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_FOCUS_ON_MAP:
+      g_value_set_boolean (value, surface->focus_on_map);
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_DECORATED:
+      g_value_set_boolean (value, FALSE); // FIXME
+      break;
+
+    case LAST_PROP + GDK_POPUP_NUM_PROPERTIES + GDK_TOPLEVEL_PROP_DELETABLE:
+      g_value_set_boolean (value, FALSE); // FIXME
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -867,7 +974,8 @@ _gdk_surface_destroy_hierarchy (GdkSurface *surface,
 
   surface_remove_from_pointer_info (surface, surface->display);
 
-  g_object_notify_by_pspec (G_OBJECT (surface), properties[PROP_STATE]);
+  if (GDK_IS_TOPLEVEL (surface))
+    g_object_notify (G_OBJECT (surface), "state");
   g_object_notify_by_pspec (G_OBJECT (surface), properties[PROP_MAPPED]);
 }
 
@@ -2078,6 +2186,117 @@ gdk_surface_popup_init (GdkPopupInterface *iface)
   iface->get_position_y = gdk_popup_surface_get_position_y;
 }
 
+static gboolean
+gdk_toplevel_surface_present (GdkToplevel       *toplevel,
+                              int                width,
+                              int                height,
+                              GdkToplevelLayout *layout)
+{
+  GdkSurface *surface = GDK_SURFACE (toplevel);
+  GdkGeometry geometry;
+  GdkSurfaceHints mask;
+
+  g_return_val_if_fail (surface->surface_type == GDK_SURFACE_TOPLEVEL, FALSE);
+  g_return_val_if_fail (!GDK_SURFACE_DESTROYED (surface), FALSE);
+
+  GDK_SURFACE_GET_CLASS (surface)->unminimize (surface);
+
+  if (gdk_toplevel_layout_get_resizable (layout))
+    {
+      geometry.min_width = gdk_toplevel_layout_get_min_width (layout);
+      geometry.min_height = gdk_toplevel_layout_get_min_height (layout);
+      mask = GDK_HINT_MIN_SIZE;
+    }
+  else
+    {
+      geometry.max_width = geometry.min_width = width;
+      geometry.max_height = geometry.min_height = height;
+      mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
+    }
+
+  GDK_SURFACE_GET_CLASS (surface)->set_geometry_hints (surface, &geometry, mask);
+  gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
+  GDK_SURFACE_GET_CLASS (surface)->toplevel_resize (surface, width, height);
+
+  if (gdk_toplevel_layout_get_maximized (layout))
+    gdk_surface_maximize (surface);
+  else
+    gdk_surface_unmaximize (surface);
+
+  if (gdk_toplevel_layout_get_fullscreen (layout))
+    {
+      GdkMonitor *monitor = gdk_toplevel_layout_get_fullscreen_monitor (layout);
+      if (monitor)
+        GDK_SURFACE_GET_CLASS (surface)->fullscreen_on_monitor (surface, monitor);
+      else
+        GDK_SURFACE_GET_CLASS (surface)->fullscreen (surface);
+    }
+  else
+    GDK_SURFACE_GET_CLASS (surface)->unfullscreen (surface);
+
+  GDK_SURFACE_GET_CLASS (surface)->set_modal_hint (surface, gdk_toplevel_layout_get_modal (layout));
+
+  gdk_surface_show_internal (surface, TRUE);
+
+  return TRUE;
+}
+
+static gboolean
+gdk_toplevel_surface_minimize (GdkToplevel *toplevel)
+{
+  GdkSurface *surface = GDK_SURFACE (toplevel);
+
+  g_return_val_if_fail (surface->surface_type == GDK_SURFACE_TOPLEVEL, FALSE);
+  
+  GDK_SURFACE_GET_CLASS (surface)->minimize (surface);
+
+  return TRUE;
+}
+
+static gboolean
+gdk_toplevel_surface_lower (GdkToplevel *toplevel)
+{
+  GdkSurface *surface = GDK_SURFACE (toplevel);
+
+  g_return_val_if_fail (surface->surface_type == GDK_SURFACE_TOPLEVEL, FALSE);
+
+  GDK_SURFACE_GET_CLASS (surface)->lower (surface);
+
+  return TRUE;
+}
+
+static void
+gdk_toplevel_surface_focus (GdkToplevel *toplevel,
+                            guint32      timestamp)
+{
+  GdkSurface *surface = GDK_SURFACE (toplevel);
+
+  g_return_if_fail (surface->surface_type == GDK_SURFACE_TOPLEVEL);
+  
+  GDK_SURFACE_GET_CLASS (surface)->focus (surface, timestamp);
+}
+
+static gboolean
+gdk_toplevel_surface_show_window_menu (GdkToplevel *toplevel,
+                                       GdkEvent    *event)
+{
+  GdkSurface *surface = GDK_SURFACE (toplevel);
+
+  g_return_val_if_fail (surface->surface_type == GDK_SURFACE_TOPLEVEL, FALSE);
+
+  return GDK_SURFACE_GET_CLASS (surface)->show_window_menu (surface, event);
+}
+
+static void
+gdk_surface_toplevel_init (GdkToplevelInterface *iface)
+{
+  iface->present = gdk_toplevel_surface_present;
+  iface->minimize = gdk_toplevel_surface_minimize;
+  iface->lower = gdk_toplevel_surface_lower;
+  iface->focus = gdk_toplevel_surface_focus;
+  iface->show_window_menu = gdk_toplevel_surface_show_window_menu;
+}
+
 static void
 gdk_surface_set_cursor_internal (GdkSurface *surface,
                                  GdkDevice *device,
@@ -2867,6 +3086,8 @@ gdk_surface_set_startup_id (GdkSurface   *surface,
                             const gchar *startup_id)
 {
   GDK_SURFACE_GET_CLASS (surface)->set_startup_id (surface, startup_id);
+
+  g_object_notify (G_OBJECT (surface), "startup-id");
 }
 
 /**
@@ -2889,6 +3110,8 @@ gdk_surface_set_transient_for (GdkSurface *surface,
   surface->transient_for = parent;
 
   GDK_SURFACE_GET_CLASS (surface)->set_transient_for (surface, parent);
+
+  g_object_notify (G_OBJECT (surface), "transient-for");
 }
 
 /**
@@ -2951,6 +3174,8 @@ gdk_surface_set_icon_list (GdkSurface *surface,
                            GList     *textures)
 {
   GDK_SURFACE_GET_CLASS (surface)->set_icon_list (surface, textures);
+
+  g_object_notify (G_OBJECT (surface), "icon-list");
 }
 
 /**
@@ -3790,6 +4015,7 @@ gdk_surface_set_state (GdkSurface      *surface,
                        GdkSurfaceState  new_state)
 {
   gboolean was_mapped, mapped;
+  gboolean was_sticky, sticky;
   g_return_if_fail (GDK_IS_SURFACE (surface));
 
   if (new_state == surface->state)
@@ -3801,17 +4027,23 @@ gdk_surface_set_state (GdkSurface      *surface,
    */
 
   was_mapped = GDK_SURFACE_IS_MAPPED (surface);
+  was_sticky = GDK_SURFACE_IS_STICKY (surface);
 
   surface->state = new_state;
 
   mapped = GDK_SURFACE_IS_MAPPED (surface);
+  sticky = GDK_SURFACE_IS_STICKY (surface);
 
   _gdk_surface_update_viewable (surface);
 
-  g_object_notify_by_pspec (G_OBJECT (surface), properties[PROP_STATE]);
+  if (GDK_IS_TOPLEVEL (surface))
+    g_object_notify (G_OBJECT (surface), "state");
 
   if (was_mapped != mapped)
     g_object_notify_by_pspec (G_OBJECT (surface), properties[PROP_MAPPED]);
+
+  if (was_sticky != sticky)
+    g_object_notify (G_OBJECT (surface), "sticky");
 }
 
 void
diff --git a/gdk/gdktoplevel.c b/gdk/gdktoplevel.c
new file mode 100644
index 0000000000..3571e466ca
--- /dev/null
+++ b/gdk/gdktoplevel.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "gdkintl.h"
+#include "gdk-private.h"
+#include "gdktoplevelprivate.h"
+
+/**
+ * SECTION:gdktoplevel
+ * @Short_description: Interface for toplevel surfaces
+ * @Title: Toplevels
+ *
+ * A #GdkToplevel is a freestanding toplevel surface.
+ */
+
+
+/* FIXME: this can't have GdkSurface as a prerequisite
+ * as long as GdkSurface implements this interface itself
+ */
+G_DEFINE_INTERFACE (GdkToplevel, gdk_toplevel, G_TYPE_OBJECT)
+
+static gboolean
+gdk_toplevel_default_present (GdkToplevel       *toplevel,
+                              int                width,
+                              int                height,
+                              GdkToplevelLayout *layout)
+{
+  return FALSE;
+}
+
+static gboolean
+gdk_toplevel_default_minimize (GdkToplevel *toplevel)
+{
+  return FALSE;
+}
+
+static gboolean
+gdk_toplevel_default_lower (GdkToplevel *toplevel)
+{
+  return FALSE;
+}
+
+static void
+gdk_toplevel_default_focus (GdkToplevel *toplevel,
+                            guint32      timestamp)
+{
+}
+
+static gboolean
+gdk_toplevel_default_show_window_menu (GdkToplevel *toplevel,
+                                       GdkEvent    *event)
+{
+  return FALSE;
+}
+
+static void
+gdk_toplevel_default_init (GdkToplevelInterface *iface)
+{
+  iface->present = gdk_toplevel_default_present;
+  iface->minimize = gdk_toplevel_default_minimize;
+  iface->lower = gdk_toplevel_default_lower;
+  iface->focus = gdk_toplevel_default_focus;
+  iface->show_window_menu = gdk_toplevel_default_show_window_menu;
+
+  g_object_interface_install_property (iface,
+      g_param_spec_flags ("state",
+                          P_("State"),
+                          P_("State"),
+                          GDK_TYPE_SURFACE_STATE, GDK_SURFACE_STATE_WITHDRAWN,
+                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_interface_install_property (iface,
+      g_param_spec_string ("title",
+                           "Title",
+                           "The title of the surface",
+                           NULL,
+                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+  g_object_interface_install_property (iface,
+      g_param_spec_string ("startup-id",
+                           "Startup ID",
+                           "The startup ID of the surface",
+                           NULL,
+                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+  g_object_interface_install_property (iface,
+      g_param_spec_object ("transient-for",
+                           "Transient For",
+                           "The transient parent of the surface",
+                           GDK_TYPE_SURFACE,
+                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+  g_object_interface_install_property (iface,
+      g_param_spec_pointer ("icon-list",
+                            "Icon List",
+                            "The list of icon textures",
+                            G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("sticky",
+                            "Sticky",
+                            "Whether the surface is on all workspaces",
+                            FALSE,
+                            G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("keep-above",
+                            "Keep above",
+                            "Whether the surface is on above all other surfaces",
+                            FALSE,
+                            G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("keep-below",
+                            "Keep below",
+                            "Whether the surface is below all other surfaces",
+                            FALSE,
+                            G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("accept-focus",
+                            "Accept focus",
+                            "Whether the surface should accept keyboard focus",
+                            TRUE,
+                            G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("focus-on-map",
+                            "Focus on map",
+                            "Whether the surface should receive keyboard focus on map",
+                            TRUE,
+                            G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("decorated",
+                            "Decorated",
+                            "Decorated",
+                            FALSE,
+                            G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+  g_object_interface_install_property (iface,
+      g_param_spec_boolean ("deletable",
+                            "Deletable",
+                            "Deletable",
+                            FALSE,
+                            G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
+}
+
+guint
+gdk_toplevel_install_properties (GObjectClass *object_class,
+                                 guint         first_prop)
+{
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_STATE, "state");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_TITLE, "title");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_STARTUP_ID, "startup-id");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_TRANSIENT_FOR, 
"transient-for");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_ICON_LIST, "icon-list");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_STICKY, "sticky");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_KEEP_ABOVE, "keep-above");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_KEEP_BELOW, "keep-below");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_ACCEPT_FOCUS, 
"accept-focus");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_FOCUS_ON_MAP, 
"focus-on-map");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_DECORATED, "decorated");
+  g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_DELETABLE, "deletable");
+
+  return GDK_TOPLEVEL_NUM_PROPERTIES;
+}
+
+/**
+ * gdk_toplevel_present:
+ * @toplevel: the #GdkToplevel to show
+ * @width: the unconstrained toplevel width to layout
+ * @height: the unconstrained toplevel height to layout
+ * @layout: the #GdkToplevelLayout object used to layout
+ *
+ * Present @toplevel after having processed the #GdkToplevelLayout rules.
+ * If the toplevel was previously now showing, it will be showed,
+ * otherwise it will change layout according to @layout.
+ *
+ * Presenting may fail.
+ *
+ * Returns: %FALSE if @toplevel failed to be presented, otherwise %TRUE.
+ */
+gboolean
+gdk_toplevel_present (GdkToplevel       *toplevel,
+                      int                width,
+                      int                height,
+                      GdkToplevelLayout *layout)
+{
+  g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE);
+  g_return_val_if_fail (width > 0, FALSE);
+  g_return_val_if_fail (height > 0, FALSE);
+  g_return_val_if_fail (layout != NULL, FALSE);
+
+  return GDK_TOPLEVEL_GET_IFACE (toplevel)->present (toplevel, width, height, layout);
+}
+
+/**
+ * gdk_toplevel_minimize:
+ * @toplevel: a #GdkToplevel
+ *
+ * Asks to minimize the @toplevel.
+ *
+ * The windowing system may choose to ignore the request.
+ *
+ * Returns: %TRUE if the surface was minimized
+ */
+gboolean
+gdk_toplevel_minimize (GdkToplevel *toplevel)
+{
+  g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE);
+
+  return GDK_TOPLEVEL_GET_IFACE (toplevel)->minimize (toplevel);
+}
+
+/**
+ * gdk_toplevel_lower:
+ * @toplevel: a #GdkToplevel
+ *
+ * Asks to lower the @toplevel below other windows.
+ *
+ * The windowing system may choose to ignore the request.
+ *
+ * Returns: %TRUE if the surface was lowered
+ */
+gboolean
+gdk_toplevel_lower (GdkToplevel *toplevel)
+{
+  g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE);
+
+  return GDK_TOPLEVEL_GET_IFACE (toplevel)->lower (toplevel);
+}
+
+/**
+ * gdk_toplevel_focus:
+ * @toplevel: a #GdkToplevel
+ * @timestamp: timestamp of the event triggering the surface focus
+ *
+ * Sets keyboard focus to @surface.
+ *
+ * In most cases, gtk_window_present_with_time() should be used
+ * on a #GtkWindow, rather than calling this function.
+ */
+void
+gdk_toplevel_focus (GdkToplevel *toplevel,
+                   guint32       timestamp)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  return GDK_TOPLEVEL_GET_IFACE (toplevel)->focus (toplevel, timestamp);
+}
+
+/**
+ * gdk_toplevel_get_state:
+ * @toplevel: a #GdkToplevel
+ *
+ * Gets the bitwise OR of the currently active surface state flags,
+ * from the #GdkSurfaceState enumeration.
+ *
+ * Returns: surface state bitfield
+ */
+GdkSurfaceState
+gdk_toplevel_get_state (GdkToplevel *toplevel)
+{
+  GdkSurfaceState state;
+
+  g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), 0);
+
+  g_object_get (toplevel, "state", &state, NULL);
+
+  return state;
+}
+
+/**
+ * gdk_toplevel_set_title:
+ * @toplevel: a #GdkToplevel
+ * @title: title of @surface
+ *
+ * Sets the title of a toplevel surface, to be displayed in the titlebar,
+ * in lists of windows, etc.
+ */
+void
+gdk_toplevel_set_title (GdkToplevel *toplevel,
+                        const char  *title)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "title", title, NULL);
+}
+
+/**
+ * gdk_toplevel_set_startup_id:
+ * @toplevel: a #GdkToplevel
+ * @startup_id: a string with startup-notification identifier
+ *
+ * When using GTK, typically you should use gtk_window_set_startup_id()
+ * instead of this low-level function.
+ */
+void
+gdk_toplevel_set_startup_id (GdkToplevel *toplevel,
+                             const char  *startup_id)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "startup-id", startup_id, NULL);
+}
+
+/**
+ * gdk_toplevel_set_transient_for:
+ * @toplevel: a #GdkToplevel
+ * @parent: another toplevel #GdkSurface
+ *
+ * Indicates to the window manager that @surface is a transient dialog
+ * associated with the application surface @parent. This allows the
+ * window manager to do things like center @surface on @parent and
+ * keep @surface above @parent.
+ *
+ * See gtk_window_set_transient_for() if you’re using #GtkWindow or
+ * #GtkDialog.
+ */
+void
+gdk_toplevel_set_transient_for (GdkToplevel *toplevel,
+                                GdkSurface  *parent)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "transient-for", parent, NULL);
+}
+
+
+/**
+ * gdk_toplevel_set_icon_list:
+ * @toplevel: a #GdkToplevel
+ * @surfaces: (transfer none) (element-type GdkTexture):
+ *     A list of textures to use as icon, of different sizes
+ *
+ * Sets a list of icons for the surface.
+ *
+ * One of these will be used to represent the surface in iconic form.
+ * The icon may be shown in window lists or task bars. Which icon
+ * size is shown depends on the window manager. The window manager
+ * can scale the icon but setting several size icons can give better
+ * image quality.
+ *
+ * Note that some platforms don't support surface icons.
+ */
+void
+gdk_toplevel_set_icon_list (GdkToplevel *toplevel,
+                            GList       *surfaces)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "icon-list", surfaces, NULL);
+}
+
+/**
+ * gdk_toplevel_show_window_menu:
+ * @toplevel: a #GdkToplevel
+ * @event: a #GdkEvent to show the menu for
+ *
+ * Asks the windowing system to show the window menu.
+ *
+ * The window menu is the menu shown when right-clicking the titlebar
+ * on traditional windows managed by the window manager. This is useful
+ * for windows using client-side decorations, activating it with a
+ * right-click on the window decorations.
+ *
+ * Returns: %TRUE if the window menu was shown and %FALSE otherwise.
+ */
+gboolean
+gdk_toplevel_show_window_menu (GdkToplevel *toplevel,
+                               GdkEvent    *event)
+{
+  g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE);
+
+  return GDK_TOPLEVEL_GET_IFACE (toplevel)->show_window_menu (toplevel, event);
+}
+
+/**
+ * gdk_toplevel_set_sticky:
+ * @toplevel: a #GdkToplevel
+ * @sticky: whether to make @toplevel show on all workspaces
+ *
+ * Set if @surface is sticky.
+ **/
+void
+gdk_toplevel_set_sticky (GdkToplevel *toplevel,
+                         gboolean     sticky)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "sticky", sticky, NULL);
+}
+
+/**
+ * gdk_toplevel_set_keep_above:
+ * @toplevel: a #GdkToplevel
+ * @above: whether to keep @toplevel above other surfaces
+ *
+ * Set if @surface must be kept above other surfaces.
+ **/
+void
+gdk_toplevel_set_keep_above (GdkToplevel *toplevel,
+                             gboolean     above)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "keep-above", above, NULL);
+}
+
+/**
+ * gdk_toplevel_set_keep_below:
+ * @toplevel: a #GdkToplevel
+ * @below: whether to keep @toplevel below other surfaces
+ *
+ * Set if @surface must be kept below other surfaces.
+ **/
+void
+gdk_toplevel_set_keep_below (GdkToplevel *toplevel,
+                             gboolean     below)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "keep-below", below, NULL);
+}
+
+/**
+ * gdk_toplevel_set_accept_focus:
+ * @toplevel: a #GdkToplevel
+ * @accept_focus: whether @toplevel should accept keyboard focus
+ *
+ * Setting @accept_focus to %FALSE hints the desktop environment
+ * that the surface doesn’t want to receive input focus.
+ */
+void
+gdk_toplevel_set_accept_focus (GdkToplevel *toplevel,
+                               gboolean     accept_focus)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "accept-focus", accept_focus, NULL);
+}
+
+/**
+ * gdk_toplevel_set_focus_on_map:
+ * @toplevel: a #GdkToplevel
+ * @focus_on_map: whether @toplevel should receive input focus when mapped
+ *
+ * Setting @focus_on_map to %FALSE hints the desktop environment that the
+ * surface doesn’t want to receive input focus when it is mapped.
+ * focus_on_map should be turned off for surfaces that aren’t triggered
+ * interactively (such as popups from network activity).
+ */
+void
+gdk_toplevel_set_focus_on_map (GdkToplevel *toplevel,
+                               gboolean     focus_on_map)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "focus-on-map", focus_on_map, NULL);
+}
+
+/**
+ * gdk_toplevel_set_decorated:
+ * @toplevel: a #GdkToplevel
+ * @decorated: %TRUE to request decorations
+ *
+ * Setting @decorated to %FALSE hints the desktop environment
+ * that the surface has its own, client-side decorations and
+ * does not need to have window decorations added.
+ */
+void
+gdk_toplevel_set_decorated (GdkToplevel *toplevel,
+                            gboolean     decorated)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "decorated", decorated, NULL);
+}
+
+/**
+ * gdk_toplevel_set_deletable:
+ * @toplevel: a #GdkToplevel
+ * @deletable: %TRUE to request a delete button
+ *
+ * Setting @deletable to %TRUE hints the desktop environment
+ * that it should offer the user a way to close the surface.
+ */
+void
+gdk_toplevel_set_deletable (GdkToplevel *toplevel,
+                            gboolean     deletable)
+{
+  g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
+
+  g_object_set (toplevel, "deletable", deletable, NULL);
+}
diff --git a/gdk/gdktoplevel.h b/gdk/gdktoplevel.h
new file mode 100644
index 0000000000..8037326b37
--- /dev/null
+++ b/gdk/gdktoplevel.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GDK_TOPLEVEL_H__
+#define __GDK_TOPLEVEL_H__
+
+#if !defined(__GDK_H_INSIDE__) && !defined(GTK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#include <gdk/gdksurface.h>
+#include <gdk/gdktoplevellayout.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_TOPLEVEL (gdk_toplevel_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_INTERFACE (GdkToplevel, gdk_toplevel, GDK, TOPLEVEL, GObject)
+
+GDK_AVAILABLE_IN_ALL
+gboolean        gdk_toplevel_present            (GdkToplevel       *toplevel,
+                                                 int                width,
+                                                 int                height,
+                                                 GdkToplevelLayout *layout);
+
+GDK_AVAILABLE_IN_ALL
+gboolean        gdk_toplevel_minimize           (GdkToplevel       *toplevel);
+
+GDK_AVAILABLE_IN_ALL
+gboolean        gdk_toplevel_lower              (GdkToplevel       *toplevel);
+
+GDK_AVAILABLE_IN_ALL
+void            gdk_toplevel_focus              (GdkToplevel       *toplevel,
+                                                 guint32            timestamp);
+
+GDK_AVAILABLE_IN_ALL
+GdkSurfaceState gdk_toplevel_get_state          (GdkToplevel       *toplevel);
+
+GDK_AVAILABLE_IN_ALL
+void            gdk_toplevel_set_title          (GdkToplevel       *toplevel,
+                                                 const char        *title);
+
+GDK_AVAILABLE_IN_ALL
+void            gdk_toplevel_set_startup_id     (GdkToplevel       *toplevel,
+                                                 const char        *startup_id);
+
+GDK_AVAILABLE_IN_ALL
+void            gdk_toplevel_set_transient_for  (GdkToplevel       *toplevel,
+                                                 GdkSurface        *parent);
+
+GDK_AVAILABLE_IN_ALL
+void            gdk_toplevel_set_icon_list      (GdkToplevel       *toplevel,
+                                                 GList             *surfaces);
+
+GDK_AVAILABLE_IN_ALL
+gboolean        gdk_toplevel_show_window_menu   (GdkToplevel       *toplevel,
+                                                 GdkEvent          *event);
+
+GDK_AVAILABLE_IN_ALL
+void            gdk_toplevel_set_sticky         (GdkToplevel       *toplevel,
+                                                 gboolean           sticky);
+
+GDK_AVAILABLE_IN_ALL
+void            gdk_toplevel_set_keep_above     (GdkToplevel       *toplevel,
+                                                 gboolean           above);
+GDK_AVAILABLE_IN_ALL
+void            gdk_toplevel_set_keep_below     (GdkToplevel       *toplevel,
+                                                 gboolean           below);
+
+GDK_AVAILABLE_IN_ALL
+void          gdk_toplevel_set_accept_focus      (GdkToplevel      *toplevel,
+                                                  gboolean          accept_focus);
+
+GDK_AVAILABLE_IN_ALL
+void          gdk_toplevel_set_focus_on_map      (GdkToplevel      *toplevel,
+                                                  gboolean          focus_on_map);
+
+GDK_AVAILABLE_IN_ALL
+void          gdk_toplevel_set_decorated         (GdkToplevel      *toplevel,
+                                                  gboolean          decorated);
+
+GDK_AVAILABLE_IN_ALL
+void          gdk_toplevel_set_deletable         (GdkToplevel      *toplevel,
+                                                  gboolean          deletable);
+G_END_DECLS
+
+#endif /* __GDK_TOPLEVEL_H__ */
diff --git a/gdk/gdktoplevelprivate.h b/gdk/gdktoplevelprivate.h
new file mode 100644
index 0000000000..4e1e489e15
--- /dev/null
+++ b/gdk/gdktoplevelprivate.h
@@ -0,0 +1,47 @@
+#ifndef __GDK_TOPLEVEL_PRIVATE_H__
+#define __GDK_TOPLEVEL_PRIVATE_H__
+
+#include "gdktoplevel.h"
+
+G_BEGIN_DECLS
+
+
+struct _GdkToplevelInterface
+{
+  GTypeInterface g_iface;
+
+  gboolean      (* present)             (GdkToplevel       *toplevel,
+                                         int                width,
+                                         int                height,
+                                         GdkToplevelLayout *layout);
+  gboolean      (* minimize)            (GdkToplevel       *toplevel);
+  gboolean      (* lower)               (GdkToplevel       *toplevel);
+  void          (* focus)               (GdkToplevel       *toplevel,
+                                         guint32            timestamp);
+  gboolean      (* show_window_menu)    (GdkToplevel       *toplevel,
+                                         GdkEvent          *event);
+};
+
+typedef enum
+{
+  GDK_TOPLEVEL_PROP_STATE,
+  GDK_TOPLEVEL_PROP_TITLE,
+  GDK_TOPLEVEL_PROP_STARTUP_ID,
+  GDK_TOPLEVEL_PROP_TRANSIENT_FOR,
+  GDK_TOPLEVEL_PROP_ICON_LIST,
+  GDK_TOPLEVEL_PROP_STICKY,
+  GDK_TOPLEVEL_PROP_KEEP_ABOVE,
+  GDK_TOPLEVEL_PROP_KEEP_BELOW,
+  GDK_TOPLEVEL_PROP_ACCEPT_FOCUS,
+  GDK_TOPLEVEL_PROP_FOCUS_ON_MAP,
+  GDK_TOPLEVEL_PROP_DECORATED,
+  GDK_TOPLEVEL_PROP_DELETABLE,
+  GDK_TOPLEVEL_NUM_PROPERTIES
+} GdkToplevelProperties;
+
+guint gdk_toplevel_install_properties (GObjectClass *object_class,
+                                       guint         first_prop);
+
+G_END_DECLS
+
+#endif /* __GDK_TOPLEVEL_PRIVATE_H__ */
diff --git a/gdk/meson.build b/gdk/meson.build
index 27d1bc3cda..0c1a277549 100644
--- a/gdk/meson.build
+++ b/gdk/meson.build
@@ -47,6 +47,7 @@ gdk_public_sources = files([
   'gdkprofiler.c',
   'gdkpopup.c',
   'gdktoplevellayout.c',
+  'gdktoplevel.c',
 ])
 
 gdk_public_headers = files([
@@ -93,6 +94,7 @@ gdk_public_headers = files([
   'gdkpopuplayout.h',
   'gdkpopup.h',
   'gdktoplevellayout.h',
+  'gdktoplevel.h',
 ])
 install_headers(gdk_public_headers, subdir: 'gtk-4.0/gdk/')
 



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