[gtk+/wip/matthiasc/help-overlay] Add automatic help overlay support to GtkApplication



commit 2867a7dfa3900be9b63d8b58fffb51082b9861d4
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Oct 21 00:11:59 2015 -0400

    Add automatic help overlay support to GtkApplication
    
    When the $(resource_prefix)/gtk/help-overlay.ui resource exists,
    load a GtkShortcutsWindow from it for each GtkApplicationWindow,
    and set up a win.show-help-overlay action with accels <Primary>F1
    and <Primary>? to show it.

 gtk/gtkapplication.c       |   46 +++++++++++++++++++++++++++++----
 gtk/gtkapplicationwindow.c |   60 ++++++++++++++++++++++++++++++++++++++++++-
 gtk/gtkapplicationwindow.h |    8 ++++++
 3 files changed, 106 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c
index 0edfe92..d3b2559 100644
--- a/gtk/gtkapplication.c
+++ b/gtk/gtkapplication.c
@@ -38,6 +38,7 @@
 #include "gtkaccelmapprivate.h"
 #include "gtkicontheme.h"
 #include "gtkbuilder.h"
+#include "gtkshortcutswindow.h"
 #include "gtkintl.h"
 
 /* NB: please do not add backend-specific GDK headers here.  This should
@@ -485,9 +486,10 @@ struct _GtkApplicationPrivate
   Accels           accels;
   guint            last_window_id;
 
-  gboolean register_session;
+  gboolean         register_session;
   GtkActionMuxer  *muxer;
   GtkBuilder      *menus_builder;
+  gchar           *help_overlay_path;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
@@ -588,6 +590,22 @@ gtk_application_load_resources (GtkApplication *application)
           gtk_application_set_menubar (application, G_MENU_MODEL (menu));
       }
   }
+
+  /* Help overlay */
+  {
+    gchar *path;
+
+    path = g_strconcat (base_path, "/gtk/help-overlay.ui", NULL);
+    if (g_resources_get_info (path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL))
+    {
+      const gchar * const accels[] = { "<Primary>F1", "<Primary>question", NULL };
+
+      application->priv->help_overlay_path = path;
+      gtk_application_set_accels_for_action (application, "win.show-help-overlay", accels);
+    }
+  else
+    g_free (path);
+  }
 }
 
 
@@ -698,7 +716,21 @@ gtk_application_window_added (GtkApplication *application,
   GtkApplicationPrivate *priv = application->priv;
 
   if (GTK_IS_APPLICATION_WINDOW (window))
-    gtk_application_window_set_id (GTK_APPLICATION_WINDOW (window), ++application->priv->last_window_id);
+    {
+      gtk_application_window_set_id (GTK_APPLICATION_WINDOW (window), ++priv->last_window_id);
+      if (priv->help_overlay_path)
+        {
+          GtkBuilder *builder;
+          GtkWidget *help_overlay;
+
+          builder = gtk_builder_new_from_resource (priv->help_overlay_path);
+          help_overlay = GTK_WIDGET (gtk_builder_get_object (builder, "help_overlay"));
+          if (GTK_IS_SHORTCUTS_WINDOW (help_overlay))
+            gtk_application_window_set_help_overlay (GTK_APPLICATION_WINDOW (window),
+                                                     GTK_SHORTCUTS_WINDOW (help_overlay));
+          g_object_unref (builder);
+        }
+    }
 
   priv->windows = g_list_prepend (priv->windows, window);
   gtk_window_set_application (window, application);
@@ -708,9 +740,10 @@ gtk_application_window_added (GtkApplication *application,
                     G_CALLBACK (gtk_application_focus_in_event_cb),
                     application);
 
-  gtk_application_impl_window_added (application->priv->impl, window);
+  gtk_application_impl_window_added (priv->impl, window);
+
+  gtk_application_impl_active_window_changed (priv->impl, window);
 
-  gtk_application_impl_active_window_changed (application->priv->impl, window);
   g_object_notify_by_pspec (G_OBJECT (application), gtk_application_props[PROP_ACTIVE_WINDOW]);
 }
 
@@ -870,8 +903,9 @@ gtk_application_finalize (GObject *object)
 
   accels_finalize (&application->priv->accels);
 
-  G_OBJECT_CLASS (gtk_application_parent_class)
-    ->finalize (object);
+  g_free (application->priv->help_overlay_path);
+
+  G_OBJECT_CLASS (gtk_application_parent_class)->finalize (object);
 }
 
 static void
diff --git a/gtk/gtkapplicationwindow.c b/gtk/gtkapplicationwindow.c
index 8602a98..92c5798 100644
--- a/gtk/gtkapplicationwindow.c
+++ b/gtk/gtkapplicationwindow.c
@@ -228,6 +228,9 @@ struct _GtkApplicationWindowPrivate
   GMenu *menubar_section;
 
   guint            id;
+
+  GtkShortcutsWindow *help_overlay;
+  gboolean            has_help_overlay_action;
 };
 
 static void
@@ -788,9 +791,9 @@ gtk_application_window_dispose (GObject *object)
 
   g_clear_object (&window->priv->app_menu_section);
   g_clear_object (&window->priv->menubar_section);
+  g_clear_object (&window->priv->help_overlay);
 
-  G_OBJECT_CLASS (gtk_application_window_parent_class)
-    ->dispose (object);
+  G_OBJECT_CLASS (gtk_application_window_parent_class)->dispose (object);
 
   /* We do this below the chain-up above to give us a chance to be
    * removed from the GtkApplication (which is done in the dispose
@@ -959,3 +962,56 @@ gtk_application_window_set_id (GtkApplicationWindow *window,
   g_return_if_fail (GTK_IS_APPLICATION_WINDOW (window));
   window->priv->id = id;
 }
+
+static void
+show_help_overlay (GSimpleAction *action,
+                   GVariant      *parameter,
+                   gpointer       user_data)
+{
+  GtkApplicationWindow *window = user_data;
+
+  if (window->priv->help_overlay)
+    gtk_widget_show (GTK_WIDGET (window->priv->help_overlay));
+}
+
+void
+gtk_application_window_set_help_overlay (GtkApplicationWindow *window,
+                                         GtkShortcutsWindow   *help_overlay)
+{
+  g_return_if_fail (GTK_IS_APPLICATION_WINDOW (window));
+  g_return_if_fail (help_overlay == NULL || GTK_IS_SHORTCUTS_WINDOW (help_overlay));
+
+  if (window->priv->help_overlay)
+    g_signal_handlers_disconnect_by_func (window->priv->help_overlay,
+                                          G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+  g_set_object (&window->priv->help_overlay, help_overlay);
+
+  if (!window->priv->help_overlay)
+    return;
+
+  gtk_window_set_modal (GTK_WINDOW (help_overlay), TRUE);
+  gtk_window_set_transient_for (GTK_WINDOW (help_overlay), GTK_WINDOW (window));
+  g_signal_connect (help_overlay, "delete-event",
+                    G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+
+  if (!window->priv->has_help_overlay_action)
+    {
+      GActionEntry entries[1] = {
+        { "show-help-overlay", show_help_overlay, NULL, NULL, NULL },
+      };
+
+      g_action_map_add_action_entries (G_ACTION_MAP (window->priv->actions),
+                                       entries, 1,
+                                       window);
+
+      window->priv->has_help_overlay_action = TRUE;
+    }
+}
+
+GtkShortcutsWindow *
+gtk_application_window_get_help_overlay (GtkApplicationWindow *window)
+{
+  g_return_val_if_fail (GTK_IS_APPLICATION_WINDOW (window), NULL);
+
+  return window->priv->help_overlay;
+}
diff --git a/gtk/gtkapplicationwindow.h b/gtk/gtkapplicationwindow.h
index 234283c..abe41c9 100644
--- a/gtk/gtkapplicationwindow.h
+++ b/gtk/gtkapplicationwindow.h
@@ -25,6 +25,7 @@
 #endif
 
 #include <gtk/gtkwindow.h>
+#include <gtk/gtkshortcutswindow.h>
 
 G_BEGIN_DECLS
 
@@ -78,6 +79,13 @@ gboolean    gtk_application_window_get_show_menubar (GtkApplicationWindow *windo
 GDK_AVAILABLE_IN_3_6
 guint       gtk_application_window_get_id           (GtkApplicationWindow *window);
 
+GDK_AVAILABLE_IN_3_20
+void        gtk_application_window_set_help_overlay (GtkApplicationWindow *window,
+                                                     GtkShortcutsWindow   *help_overlay);
+GDK_AVAILABLE_IN_3_20
+GtkShortcutsWindow *
+            gtk_application_window_get_help_overlay (GtkApplicationWindow *window);
+
 G_END_DECLS
 
 #endif /* __GTK_APPLICATION_WINDOW_H__ */


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