[gnome-builder] libide-gui: port global gui helpers to GTK 4
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] libide-gui: port global gui helpers to GTK 4
- Date: Tue, 12 Jul 2022 06:39:12 +0000 (UTC)
commit 4470f9720b42bb5b4ac9f2f192d036eb4f1508ee
Author: Christian Hergert <chergert redhat com>
Date: Mon Jul 11 21:51:08 2022 -0700
libide-gui: port global gui helpers to GTK 4
src/libide/gui/ide-gui-global.c | 327 ++++++++--------------------------------
src/libide/gui/ide-gui-global.h | 22 ++-
2 files changed, 69 insertions(+), 280 deletions(-)
---
diff --git a/src/libide/gui/ide-gui-global.c b/src/libide/gui/ide-gui-global.c
index 71fa59ca6..49c56ebc4 100644
--- a/src/libide/gui/ide-gui-global.c
+++ b/src/libide/gui/ide-gui-global.c
@@ -22,22 +22,20 @@
#include "config.h"
-#include <dazzle.h>
#include <libide-threading.h>
#include "ide-gui-global.h"
-#include "ide-gui-private.h"
#include "ide-workspace.h"
static GQuark quark_handler;
static GQuark quark_where_context_was;
-static void ide_widget_notify_context (GtkWidget *toplevel,
- GParamSpec *pspec,
- GtkWidget *widget);
-static void ide_widget_hierarchy_changed (GtkWidget *widget,
- GtkWidget *previous_toplevel,
- gpointer user_data);
+static void ide_widget_notify_context (GtkWidget *toplevel,
+ GParamSpec *pspec,
+ GtkWidget *widget);
+static void ide_widget_notify_root_cb (GtkWidget *widget,
+ GParamSpec *pspec,
+ gpointer user_data);
static void
ide_widget_notify_context (GtkWidget *toplevel,
@@ -68,7 +66,7 @@ ide_widget_notify_context (GtkWidget *toplevel,
G_CALLBACK (ide_widget_notify_context),
widget);
g_signal_handlers_disconnect_by_func (widget,
- G_CALLBACK (ide_widget_hierarchy_changed),
+ G_CALLBACK (ide_widget_notify_root_cb),
NULL);
handler (widget, context);
@@ -82,24 +80,23 @@ has_context_property (GtkWidget *widget)
g_assert (GTK_IS_WIDGET (widget));
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (widget), "context");
- return pspec != NULL && g_type_is_a (pspec->value_type, IDE_TYPE_CONTEXT);
+
+ return pspec != NULL &&
+ (pspec->flags & G_PARAM_READABLE) != 0 &&
+ g_type_is_a (pspec->value_type, IDE_TYPE_CONTEXT);
}
static void
-ide_widget_hierarchy_changed (GtkWidget *widget,
- GtkWidget *previous_toplevel,
- gpointer user_data)
+ide_widget_notify_root_cb (GtkWidget *widget,
+ GParamSpec *pspec,
+ gpointer user_data)
{
GtkWidget *toplevel;
g_assert (GTK_IS_WIDGET (widget));
+ g_assert (user_data == NULL);
- if (GTK_IS_WINDOW (previous_toplevel))
- g_signal_handlers_disconnect_by_func (previous_toplevel,
- G_CALLBACK (ide_widget_notify_context),
- widget);
-
- toplevel = gtk_widget_get_toplevel (widget);
+ toplevel = GTK_WIDGET (gtk_widget_get_native (widget));
if (GTK_IS_WINDOW (toplevel) && has_context_property (toplevel))
{
@@ -118,8 +115,6 @@ ide_widget_hierarchy_changed (GtkWidget *widget,
* @handler: (scope async): A callback to handle the context
*
* Calls @handler when the #IdeContext has been set for @widget.
- *
- * Since: 3.32
*/
void
ide_widget_set_context_handler (gpointer widget,
@@ -139,16 +134,18 @@ ide_widget_set_context_handler (gpointer widget,
g_object_set_qdata (G_OBJECT (widget), quark_handler, handler);
g_signal_connect (widget,
- "hierarchy-changed",
- G_CALLBACK (ide_widget_hierarchy_changed),
+ "notify::root",
+ G_CALLBACK (ide_widget_notify_root_cb),
NULL);
- toplevel = gtk_widget_get_toplevel (widget);
+ toplevel = GTK_WIDGET (gtk_widget_get_native (widget));
if (GTK_IS_WINDOW (toplevel))
- ide_widget_hierarchy_changed (widget, NULL, NULL);
+ ide_widget_notify_root_cb (widget, NULL, NULL);
}
+static gboolean dummy_cb (gpointer data) { return G_SOURCE_REMOVE; }
+
/**
* ide_widget_get_context:
* @widget: a #GtkWidget
@@ -156,20 +153,39 @@ ide_widget_set_context_handler (gpointer widget,
* Gets the context for the widget.
*
* Returns: (nullable) (transfer none): an #IdeContext, or %NULL
- *
- * Since: 3.32
*/
IdeContext *
ide_widget_get_context (GtkWidget *widget)
{
- GtkWidget *toplevel;
+ GtkRoot *root;
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
- toplevel = gtk_widget_get_toplevel (widget);
+ root = gtk_widget_get_root (widget);
+
+ if (IDE_IS_WORKSPACE (root))
+ return ide_workspace_get_context (IDE_WORKSPACE (root));
+
+ if (root != NULL)
+ {
+ GObjectClass *object_class = G_OBJECT_GET_CLASS (root);
+ GParamSpec *pspec = g_object_class_find_property (object_class, "context");
+
+ if (G_IS_PARAM_SPEC_OBJECT (pspec) &&
+ g_type_is_a (pspec->value_type, IDE_TYPE_CONTEXT))
+ {
+ g_auto(GValue) value = G_VALUE_INIT;
+ IdeContext *ret;
+
+ g_value_init (&value, IDE_TYPE_CONTEXT);
+ g_object_get_property (G_OBJECT (root), "context", &value);
+
+ ret = g_value_dup_object (&value);
+ g_idle_add_full (G_PRIORITY_LOW, dummy_cb, ret, g_object_unref);
- if (IDE_IS_WORKSPACE (toplevel))
- return ide_workspace_get_context (IDE_WORKSPACE (toplevel));
+ return ret;
+ }
+ }
return NULL;
}
@@ -181,8 +197,6 @@ ide_widget_get_context (GtkWidget *widget)
* Gets the #IdeWorkbench that contains @widget.
*
* Returns: (transfer none) (nullable): an #IdeWorkbench or %NULL
- *
- * Since: 3.32
*/
IdeWorkbench *
ide_widget_get_workbench (GtkWidget *widget)
@@ -191,7 +205,7 @@ ide_widget_get_workbench (GtkWidget *widget)
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
- toplevel = gtk_widget_get_toplevel (widget);
+ toplevel = GTK_WIDGET (gtk_widget_get_native (widget));
if (GTK_IS_WINDOW (toplevel))
{
@@ -211,246 +225,25 @@ ide_widget_get_workbench (GtkWidget *widget)
* Gets the #IdeWorkspace containing @widget.
*
* Returns: (transfer none) (nullable): an #IdeWorkspace or %NULL
- *
- * Since: 3.32
*/
IdeWorkspace *
ide_widget_get_workspace (GtkWidget *widget)
{
- g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
-
- return (IdeWorkspace *)dzl_gtk_widget_get_relative (widget, IDE_TYPE_WORKSPACE);
-}
-
-static gboolean
-ide_gtk_progress_bar_tick_cb (gpointer data)
-{
- GtkProgressBar *progress = data;
-
- g_assert (GTK_IS_PROGRESS_BAR (progress));
-
- gtk_progress_bar_pulse (progress);
- gtk_widget_queue_draw (GTK_WIDGET (progress));
-
- return G_SOURCE_CONTINUE;
-}
-
-void
-_ide_gtk_progress_bar_stop_pulsing (GtkProgressBar *progress)
-{
- guint tick_id;
-
- g_return_if_fail (GTK_IS_PROGRESS_BAR (progress));
-
- tick_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (progress), "PULSE_ID"));
-
- if (tick_id != 0)
- {
- g_source_remove (tick_id);
- g_object_set_data (G_OBJECT (progress), "PULSE_ID", NULL);
- }
-
- gtk_progress_bar_set_fraction (progress, 0.0);
-}
-
-void
-_ide_gtk_progress_bar_start_pulsing (GtkProgressBar *progress)
-{
- guint tick_id;
-
- g_return_if_fail (GTK_IS_PROGRESS_BAR (progress));
-
- if (g_object_get_data (G_OBJECT (progress), "PULSE_ID"))
- return;
-
- gtk_progress_bar_set_fraction (progress, 0.0);
- gtk_progress_bar_set_pulse_step (progress, .5);
-
- /* We want lower than the frame rate, because that is all that is needed */
- tick_id = dzl_frame_source_add_full (G_PRIORITY_DEFAULT,
- 2,
- ide_gtk_progress_bar_tick_cb,
- g_object_ref (progress),
- g_object_unref);
- g_object_set_data (G_OBJECT (progress), "PULSE_ID", GUINT_TO_POINTER (tick_id));
- ide_gtk_progress_bar_tick_cb (progress);
-}
-
-static void
-ide_gtk_show_uri_on_window_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- IdeSubprocess *subprocess = (IdeSubprocess *)object;
- g_autoptr(GError) error = NULL;
-
- g_assert (IDE_IS_SUBPROCESS (subprocess));
- g_assert (G_IS_ASYNC_RESULT (result));
-
- if (!ide_subprocess_wait_finish (subprocess, result, &error))
- g_warning ("Subprocess failed: %s", error->message);
-}
-
-gboolean
-ide_gtk_show_uri_on_window (GtkWindow *window,
- const gchar *uri,
- gint64 timestamp,
- GError **error)
-{
- g_return_val_if_fail (!window || GTK_IS_WINDOW (window), FALSE);
- g_return_val_if_fail (uri != NULL, FALSE);
-
- if (ide_is_flatpak ())
- {
- g_autoptr(IdeSubprocessLauncher) launcher = NULL;
- g_autoptr(IdeSubprocess) subprocess = NULL;
-
- /* We can't currently trust gtk_show_uri_on_window() because it tries
- * to open our HTML page with Builder inside our current flatpak
- * environment! We need to ensure this is fixed upstream, but it's
- * currently unclear how to do so since we register handles for html.
- */
-
- launcher = ide_subprocess_launcher_new (0);
- ide_subprocess_launcher_set_run_on_host (launcher, TRUE);
- ide_subprocess_launcher_set_clear_env (launcher, FALSE);
- ide_subprocess_launcher_push_argv (launcher, "xdg-open");
- ide_subprocess_launcher_push_argv (launcher, uri);
-
- if (!(subprocess = ide_subprocess_launcher_spawn (launcher, NULL, error)))
- return FALSE;
-
- ide_subprocess_wait_async (subprocess,
- NULL,
- ide_gtk_show_uri_on_window_cb,
- NULL);
- }
- else
- {
- /* XXX: Workaround for wayland timestamp issue */
- if (!gtk_show_uri_on_window (window, uri, timestamp / 1000L, error))
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-show_parents (GtkWidget *widget)
-{
- GtkWidget *workspace;
- GtkWidget *parent;
-
- g_assert (GTK_IS_WIDGET (widget));
-
- workspace = gtk_widget_get_ancestor (widget, IDE_TYPE_WORKSPACE);
- parent = gtk_widget_get_parent (widget);
-
- if (DZL_IS_DOCK_REVEALER (widget))
- dzl_dock_revealer_set_reveal_child (DZL_DOCK_REVEALER (widget), TRUE);
-
- if (IDE_IS_SURFACE (widget))
- ide_workspace_set_visible_surface (IDE_WORKSPACE (workspace), IDE_SURFACE (widget));
-
- if (GTK_IS_STACK (parent))
- gtk_stack_set_visible_child (GTK_STACK (parent), widget);
-
- if (parent != NULL)
- show_parents (parent);
-}
-
-void
-ide_widget_reveal_and_grab (GtkWidget *widget)
-{
- g_return_if_fail (GTK_IS_WIDGET (widget));
-
- show_parents (widget);
- gtk_widget_grab_focus (widget);
-}
-
-void
-ide_gtk_window_present (GtkWindow *window)
-{
- /* TODO: We need the last event time to do this properly. Until then,
- * we'll just fake some timing info to workaround wayland issues.
- */
- gtk_window_present_with_time (window, g_get_monotonic_time () / 1000L);
-}
-
-static void
-split_action_name (const gchar *action_name,
- gchar **prefix,
- gchar **name)
-{
- const gchar *dot;
-
- g_assert (prefix != NULL);
- g_assert (name != NULL);
-
- *prefix = NULL;
- *name = NULL;
+ GtkWindow *transient_for;
+ GtkRoot *root;
- if (action_name == NULL)
- return;
-
- dot = strchr (action_name, '.');
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
- if (dot == NULL)
- *name = g_strdup (action_name);
+ if (GTK_IS_ROOT (widget))
+ root = GTK_ROOT (widget);
else
- {
- *prefix = g_strndup (action_name, dot - action_name);
- *name = g_strdup (dot + 1);
- }
-}
-
-gboolean
-_ide_gtk_widget_action_is_stateful (GtkWidget *widget,
- const gchar *action_name)
-{
- g_autofree gchar *name = NULL;
- g_autofree gchar *prefix = NULL;
- GtkWidget *toplevel;
- GApplication *app;
- GActionGroup *group = NULL;
-
- g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
- g_return_val_if_fail (action_name, FALSE);
-
- split_action_name (action_name, &prefix, &name);
-
- app = g_application_get_default ();
- toplevel = gtk_widget_get_toplevel (widget);
-
- while ((group == NULL) && (widget != NULL))
- {
- group = gtk_widget_get_action_group (widget, prefix);
-
- if G_UNLIKELY (GTK_IS_POPOVER (widget))
- {
- GtkWidget *relative_to;
-
- relative_to = gtk_popover_get_relative_to (GTK_POPOVER (widget));
-
- if (relative_to != NULL)
- widget = relative_to;
- else
- widget = gtk_widget_get_parent (widget);
- }
- else
- {
- widget = gtk_widget_get_parent (widget);
- }
- }
-
- if (!group && g_str_equal (prefix, "win") && G_IS_ACTION_GROUP (toplevel))
- group = G_ACTION_GROUP (toplevel);
-
- if (!group && g_str_equal (prefix, "app") && G_IS_ACTION_GROUP (app))
- group = G_ACTION_GROUP (app);
+ root = gtk_widget_get_root (widget);
- if (group && g_action_group_has_action (group, name))
- return g_action_group_get_action_state_type (group, name) != NULL;
+ if (root != NULL &&
+ !IDE_IS_WORKSPACE (root) &&
+ GTK_IS_WINDOW (root) &&
+ (transient_for = gtk_window_get_transient_for (GTK_WINDOW (root))))
+ return ide_widget_get_workspace (GTK_WIDGET (transient_for));
- return FALSE;
+ return IDE_IS_WORKSPACE (root) ? IDE_WORKSPACE (root) : NULL;
}
diff --git a/src/libide/gui/ide-gui-global.h b/src/libide/gui/ide-gui-global.h
index 3dc2f0497..1fc5ee5ef 100644
--- a/src/libide/gui/ide-gui-global.h
+++ b/src/libide/gui/ide-gui-global.h
@@ -20,7 +20,12 @@
#pragma once
+#if !defined (IDE_GUI_INSIDE) && !defined (IDE_GUI_COMPILATION)
+# error "Only <libide-gui.h> can be included directly."
+#endif
+
#include <gtk/gtk.h>
+
#include <libide-core.h>
#include "ide-workbench.h"
@@ -44,23 +49,14 @@ G_BEGIN_DECLS
typedef void (*IdeWidgetContextHandler) (GtkWidget *widget,
IdeContext *context);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
void ide_widget_set_context_handler (gpointer widget,
IdeWidgetContextHandler handler);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
IdeContext *ide_widget_get_context (GtkWidget *widget);
-IDE_AVAILABLE_IN_3_32
-void ide_widget_reveal_and_grab (GtkWidget *widget);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
IdeWorkbench *ide_widget_get_workbench (GtkWidget *widget);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
IdeWorkspace *ide_widget_get_workspace (GtkWidget *widget);
-IDE_AVAILABLE_IN_3_32
-gboolean ide_gtk_show_uri_on_window (GtkWindow *window,
- const gchar *uri,
- gint64 timestamp,
- GError **error);
-IDE_AVAILABLE_IN_3_32
-void ide_gtk_window_present (GtkWindow *window);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]