[tepl] amtk: copy part of TeplApplicationWindow



commit 6c25823de703697ef73e0e6afbef6118ecf491c7
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Thu Jul 13 19:50:47 2017 +0200

    amtk: copy part of TeplApplicationWindow

 amtk/Makefile.am               |    2 +
 amtk/amtk-application-window.c |  605 ++++++++++++++++++++++++++++++++++++++++
 amtk/amtk-application-window.h |   80 ++++++
 amtk/amtk-types.h              |    1 +
 amtk/amtk-utils.c              |  129 +++++++++
 amtk/amtk-utils.h              |   12 +-
 amtk/amtk.h                    |    1 +
 7 files changed, 829 insertions(+), 1 deletions(-)
---
diff --git a/amtk/Makefile.am b/amtk/Makefile.am
index 3b3d7b4..2378db4 100644
--- a/amtk/Makefile.am
+++ b/amtk/Makefile.am
@@ -15,6 +15,7 @@ amtk_public_headers =                         \
        amtk-action-info-central-store.h        \
        amtk-action-info-store.h                \
        amtk-action-map.h                       \
+       amtk-application-window.h               \
        amtk-menu-item.h                        \
        amtk-menu-shell.h                       \
        amtk-types.h
@@ -24,6 +25,7 @@ amtk_public_c_files =                         \
        amtk-action-info-central-store.c        \
        amtk-action-info-store.c                \
        amtk-action-map.c                       \
+       amtk-application-window.c               \
        amtk-menu-item.c                        \
        amtk-menu-shell.c
 
diff --git a/amtk/amtk-application-window.c b/amtk/amtk-application-window.c
new file mode 100644
index 0000000..c826f58
--- /dev/null
+++ b/amtk/amtk-application-window.c
@@ -0,0 +1,605 @@
+/*
+ * This file is part of Amtk - Actions, Menus and Toolbars Kit
+ *
+ * Copyright 2017 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * Amtk 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.
+ *
+ * Amtk 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/>.
+ */
+
+#include "config.h"
+#include "amtk-application-window.h"
+#include <glib/gi18n-lib.h>
+#include "amtk-action-info.h"
+#include "amtk-action-info-central-store.h"
+#include "amtk-menu-item.h"
+#include "amtk-menu-shell.h"
+#include "amtk-utils.h"
+
+/**
+ * SECTION:amtk-application-window
+ * @Short_description: An extension of GtkApplicationWindow
+ * @Title: AmtkApplicationWindow
+ *
+ * #AmtkApplicationWindow extends the #GtkApplicationWindow class.
+ *
+ * Note that #AmtkApplicationWindow extends the #GtkApplicationWindow class but
+ * without subclassing it, because several libraries might want to extend
+ * #GtkApplicationWindow and an application needs to be able to use all those
+ * extensions at the same time.
+ */
+
+struct _AmtkApplicationWindowPrivate
+{
+       GtkApplicationWindow *gtk_window;
+       GtkStatusbar *statusbar;
+};
+
+enum
+{
+       PROP_0,
+       PROP_APPLICATION_WINDOW,
+       PROP_STATUSBAR,
+       N_PROPERTIES
+};
+
+#define AMTK_APPLICATION_WINDOW_KEY "amtk-application-window-key"
+#define MENU_SHELL_STATUSBAR_CONTEXT_ID_KEY "amtk-menu-shell-statusbar-context-id-key"
+#define MENU_SHELL_FOR_RECENT_CHOOSER_KEY "amtk-menu-shell-for-recent-chooser-key"
+
+static GParamSpec *properties[N_PROPERTIES];
+
+G_DEFINE_TYPE_WITH_PRIVATE (AmtkApplicationWindow, amtk_application_window, G_TYPE_OBJECT)
+
+static void
+amtk_application_window_get_property (GObject    *object,
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+       AmtkApplicationWindow *amtk_window = AMTK_APPLICATION_WINDOW (object);
+
+       switch (prop_id)
+       {
+               case PROP_APPLICATION_WINDOW:
+                       g_value_set_object (value, amtk_application_window_get_application_window 
(amtk_window));
+                       break;
+
+               case PROP_STATUSBAR:
+                       g_value_set_object (value, amtk_application_window_get_statusbar (amtk_window));
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+static void
+amtk_application_window_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+       AmtkApplicationWindow *amtk_window = AMTK_APPLICATION_WINDOW (object);
+
+       switch (prop_id)
+       {
+               case PROP_APPLICATION_WINDOW:
+                       g_assert (amtk_window->priv->gtk_window == NULL);
+                       amtk_window->priv->gtk_window = g_value_get_object (value);
+                       break;
+
+               case PROP_STATUSBAR:
+                       amtk_application_window_set_statusbar (amtk_window, g_value_get_object (value));
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+static void
+amtk_application_window_dispose (GObject *object)
+{
+       AmtkApplicationWindow *amtk_window = AMTK_APPLICATION_WINDOW (object);
+
+       amtk_window->priv->gtk_window = NULL;
+       g_clear_object (&amtk_window->priv->statusbar);
+
+       G_OBJECT_CLASS (amtk_application_window_parent_class)->dispose (object);
+}
+
+static void
+amtk_application_window_class_init (AmtkApplicationWindowClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->get_property = amtk_application_window_get_property;
+       object_class->set_property = amtk_application_window_set_property;
+       object_class->dispose = amtk_application_window_dispose;
+
+       /**
+        * AmtkApplicationWindow:application-window:
+        *
+        * The #GtkApplicationWindow.
+        *
+        * Since: 2.0
+        */
+       properties[PROP_APPLICATION_WINDOW] =
+               g_param_spec_object ("application-window",
+                                    "GtkApplicationWindow",
+                                    "",
+                                    GTK_TYPE_APPLICATION_WINDOW,
+                                    G_PARAM_READWRITE |
+                                    G_PARAM_CONSTRUCT_ONLY |
+                                    G_PARAM_STATIC_STRINGS);
+
+       /**
+        * AmtkApplicationWindow:statusbar:
+        *
+        * The #GtkStatusbar. %NULL by default.
+        *
+        * Since: 2.0
+        */
+       properties[PROP_STATUSBAR] =
+               g_param_spec_object ("statusbar",
+                                    "GtkStatusbar",
+                                    "",
+                                    GTK_TYPE_STATUSBAR,
+                                    G_PARAM_READWRITE |
+                                    G_PARAM_STATIC_STRINGS);
+
+       g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+}
+
+static void
+amtk_application_window_init (AmtkApplicationWindow *amtk_window)
+{
+       amtk_window->priv = amtk_application_window_get_instance_private (amtk_window);
+}
+
+/**
+ * amtk_application_window_get_from_gtk_application_window:
+ * @gtk_window: a #GtkApplicationWindow.
+ *
+ * Returns the #AmtkApplicationWindow of @gtk_window. The returned object is
+ * guaranteed to be the same for the lifetime of @gtk_window.
+ *
+ * Returns: (transfer none): the #AmtkApplicationWindow of @gtk_window.
+ * Since: 2.0
+ */
+AmtkApplicationWindow *
+amtk_application_window_get_from_gtk_application_window (GtkApplicationWindow *gtk_window)
+{
+       AmtkApplicationWindow *amtk_window;
+
+       g_return_val_if_fail (GTK_IS_APPLICATION_WINDOW (gtk_window), NULL);
+
+       amtk_window = g_object_get_data (G_OBJECT (gtk_window), AMTK_APPLICATION_WINDOW_KEY);
+
+       if (amtk_window == NULL)
+       {
+               amtk_window = g_object_new (AMTK_TYPE_APPLICATION_WINDOW,
+                                           "application-window", gtk_window,
+                                           NULL);
+
+               g_object_set_data_full (G_OBJECT (gtk_window),
+                                       AMTK_APPLICATION_WINDOW_KEY,
+                                       amtk_window,
+                                       g_object_unref);
+       }
+
+       g_return_val_if_fail (AMTK_IS_APPLICATION_WINDOW (amtk_window), NULL);
+       return amtk_window;
+}
+
+/**
+ * amtk_application_window_get_application_window:
+ * @amtk_window: a #AmtkApplicationWindow.
+ *
+ * Returns: (transfer none): the #GtkApplicationWindow of @amtk_window.
+ * Since: 2.0
+ */
+GtkApplicationWindow *
+amtk_application_window_get_application_window (AmtkApplicationWindow *amtk_window)
+{
+       g_return_val_if_fail (AMTK_IS_APPLICATION_WINDOW (amtk_window), NULL);
+
+       return amtk_window->priv->gtk_window;
+}
+
+/**
+ * amtk_application_window_get_statusbar:
+ * @amtk_window: a #AmtkApplicationWindow.
+ *
+ * Returns: (transfer none) (nullable): the #AmtkApplicationWindow:statusbar.
+ * Since: 2.0
+ */
+GtkStatusbar *
+amtk_application_window_get_statusbar (AmtkApplicationWindow *amtk_window)
+{
+       g_return_val_if_fail (AMTK_IS_APPLICATION_WINDOW (amtk_window), NULL);
+
+       return amtk_window->priv->statusbar;
+}
+
+/**
+ * amtk_application_window_set_statusbar:
+ * @amtk_window: a #AmtkApplicationWindow.
+ * @statusbar: (nullable): a #GtkStatusbar, or %NULL.
+ *
+ * Sets the #AmtkApplicationWindow:statusbar property.
+ *
+ * Since: 2.0
+ */
+void
+amtk_application_window_set_statusbar (AmtkApplicationWindow *amtk_window,
+                                      GtkStatusbar          *statusbar)
+{
+       g_return_if_fail (AMTK_IS_APPLICATION_WINDOW (amtk_window));
+       g_return_if_fail (statusbar == NULL || GTK_IS_STATUSBAR (statusbar));
+
+       if (amtk_window->priv->statusbar == statusbar)
+       {
+               return;
+       }
+
+       if (statusbar != NULL)
+       {
+               g_object_ref_sink (statusbar);
+       }
+
+       if (amtk_window->priv->statusbar != NULL)
+       {
+               g_object_unref (amtk_window->priv->statusbar);
+       }
+
+       amtk_window->priv->statusbar = statusbar;
+       g_object_notify_by_pspec (G_OBJECT (amtk_window), properties[PROP_STATUSBAR]);
+}
+
+/* Returns: %TRUE if a context ID exists and has been set to @context_id. */
+static gboolean
+get_statusbar_context_id_for_menu_shell (AmtkApplicationWindow *amtk_window,
+                                        AmtkMenuShell         *amtk_menu_shell,
+                                        gboolean               create,
+                                        guint                 *context_id)
+{
+       gpointer data;
+
+       g_assert (amtk_window->priv->statusbar != NULL);
+       g_assert (context_id != NULL);
+
+       data = g_object_get_data (G_OBJECT (amtk_menu_shell), MENU_SHELL_STATUSBAR_CONTEXT_ID_KEY);
+
+       if (data == NULL && !create)
+       {
+               return FALSE;
+       }
+
+       if (data == NULL)
+       {
+               *context_id = gtk_statusbar_get_context_id (amtk_window->priv->statusbar,
+                                                           "Show long description of menu items.");
+
+               g_object_set_data (G_OBJECT (amtk_menu_shell),
+                                  MENU_SHELL_STATUSBAR_CONTEXT_ID_KEY,
+                                  GUINT_TO_POINTER (*context_id));
+       }
+       else
+       {
+               *context_id = GPOINTER_TO_UINT (data);
+       }
+
+       return TRUE;
+}
+
+/* Free the return value with g_free(). */
+static gchar *
+get_menu_item_long_description (AmtkMenuShell *amtk_menu_shell,
+                               GtkMenuItem   *menu_item)
+{
+       const gchar *long_description;
+       gpointer data;
+       gboolean is_for_recent_chooser;
+
+       long_description = amtk_menu_item_get_long_description (menu_item);
+       if (long_description != NULL)
+       {
+               return g_strdup (long_description);
+       }
+
+       data = g_object_get_data (G_OBJECT (amtk_menu_shell), MENU_SHELL_FOR_RECENT_CHOOSER_KEY);
+       is_for_recent_chooser = data != NULL ? GPOINTER_TO_INT (data) : FALSE;
+
+       if (is_for_recent_chooser)
+       {
+               GtkMenuShell *gtk_menu_shell;
+               GtkRecentChooserMenu *recent_chooser_menu;
+               gchar *uri;
+               GFile *file;
+               gchar *parse_name;
+               gchar *nicer_filename;
+               gchar *ret;
+
+               gtk_menu_shell = amtk_menu_shell_get_menu_shell (amtk_menu_shell);
+               recent_chooser_menu = GTK_RECENT_CHOOSER_MENU (gtk_menu_shell);
+               uri = amtk_utils_recent_chooser_menu_get_item_uri (recent_chooser_menu, menu_item);
+
+               if (uri == NULL)
+               {
+                       return NULL;
+               }
+
+               file = g_file_new_for_uri (uri);
+               g_free (uri);
+
+               parse_name = g_file_get_parse_name (file);
+               g_object_unref (file);
+
+               nicer_filename = _amtk_utils_replace_home_dir_with_tilde (parse_name);
+               g_free (parse_name);
+
+               /* Translators: %s is a filename. */
+               ret = g_strdup_printf (_("Open “%s”"), nicer_filename);
+               g_free (nicer_filename);
+
+               return ret;
+       }
+
+       return NULL;
+}
+
+static void
+menu_item_selected_cb (AmtkMenuShell *amtk_menu_shell,
+                      GtkMenuItem   *menu_item,
+                      gpointer       user_data)
+{
+       AmtkApplicationWindow *amtk_window = AMTK_APPLICATION_WINDOW (user_data);
+       gchar *long_description;
+       guint context_id;
+
+       if (amtk_window->priv->statusbar == NULL)
+       {
+               return;
+       }
+
+       long_description = get_menu_item_long_description (amtk_menu_shell, menu_item);
+       if (long_description == NULL)
+       {
+               return;
+       }
+
+       get_statusbar_context_id_for_menu_shell (amtk_window,
+                                                amtk_menu_shell,
+                                                TRUE,
+                                                &context_id);
+
+       gtk_statusbar_push (amtk_window->priv->statusbar,
+                           context_id,
+                           long_description);
+
+       g_free (long_description);
+}
+
+static void
+menu_item_deselected_cb (AmtkMenuShell *amtk_menu_shell,
+                        GtkMenuItem   *menu_item,
+                        gpointer       user_data)
+{
+       AmtkApplicationWindow *amtk_window = AMTK_APPLICATION_WINDOW (user_data);
+       const gchar *long_description;
+       gpointer data;
+       gboolean is_for_recent_chooser;
+       guint context_id;
+
+       if (amtk_window->priv->statusbar == NULL)
+       {
+               return;
+       }
+
+       long_description = amtk_menu_item_get_long_description (menu_item);
+
+       data = g_object_get_data (G_OBJECT (amtk_menu_shell), MENU_SHELL_FOR_RECENT_CHOOSER_KEY);
+       is_for_recent_chooser = data != NULL ? GPOINTER_TO_INT (data) : FALSE;
+
+       if (long_description == NULL && !is_for_recent_chooser)
+       {
+               return;
+       }
+
+       if (get_statusbar_context_id_for_menu_shell (amtk_window,
+                                                    amtk_menu_shell,
+                                                    FALSE,
+                                                    &context_id))
+       {
+               gtk_statusbar_pop (amtk_window->priv->statusbar, context_id);
+       }
+}
+
+static void
+statusbar_notify_cb (AmtkApplicationWindow *amtk_window,
+                    GParamSpec            *pspec,
+                    gpointer               user_data)
+{
+       AmtkMenuShell *amtk_menu_shell = AMTK_MENU_SHELL (user_data);
+
+       g_object_set_data (G_OBJECT (amtk_menu_shell),
+                          MENU_SHELL_STATUSBAR_CONTEXT_ID_KEY,
+                          NULL);
+}
+
+/**
+ * amtk_application_window_connect_menu_to_statusbar:
+ * @amtk_window: a #AmtkApplicationWindow.
+ * @amtk_menu_shell: a #AmtkMenuShell.
+ *
+ * Connect to the #AmtkMenuShell::menu-item-selected and
+ * #AmtkMenuShell::menu-item-deselected signals of @amtk_menu_shell to push/pop
+ * the long description of #GtkMenuItem's to the
+ * #AmtkApplicationWindow:statusbar.
+ *
+ * The long description is retrieved with amtk_menu_item_get_long_description().
+ * So amtk_menu_item_set_long_description() must have been called, which is the
+ * case if the #GtkMenuItem has been created with the functions available in
+ * #AmtkActionInfoStore.
+ *
+ * Since: 2.0
+ */
+void
+amtk_application_window_connect_menu_to_statusbar (AmtkApplicationWindow *amtk_window,
+                                                  AmtkMenuShell         *amtk_menu_shell)
+{
+       g_return_if_fail (AMTK_IS_APPLICATION_WINDOW (amtk_window));
+       g_return_if_fail (AMTK_IS_MENU_SHELL (amtk_menu_shell));
+
+       g_signal_connect_object (amtk_menu_shell,
+                                "menu-item-selected",
+                                G_CALLBACK (menu_item_selected_cb),
+                                amtk_window,
+                                0);
+
+       g_signal_connect_object (amtk_menu_shell,
+                                "menu-item-deselected",
+                                G_CALLBACK (menu_item_deselected_cb),
+                                amtk_window,
+                                0);
+
+       g_signal_connect_object (amtk_window,
+                                "notify::statusbar",
+                                G_CALLBACK (statusbar_notify_cb),
+                                amtk_menu_shell,
+                                0);
+}
+
+/**
+ * amtk_application_window_connect_recent_chooser_menu_to_statusbar:
+ * @amtk_window: a #AmtkApplicationWindow.
+ * @menu: a #GtkRecentChooserMenu.
+ *
+ * An alternative to gtk_recent_chooser_set_show_tips(). Shows the full path in
+ * the #AmtkApplicationWindow:statusbar when a #GtkMenuItem of @menu is
+ * selected.
+ *
+ * The full path is retrieved with
+ * amtk_utils_recent_chooser_menu_get_item_uri().
+ *
+ * Since: 2.0
+ */
+void
+amtk_application_window_connect_recent_chooser_menu_to_statusbar (AmtkApplicationWindow *amtk_window,
+                                                                 GtkRecentChooserMenu  *menu)
+{
+       AmtkMenuShell *amtk_menu_shell;
+
+       g_return_if_fail (AMTK_IS_APPLICATION_WINDOW (amtk_window));
+       g_return_if_fail (GTK_IS_RECENT_CHOOSER_MENU (menu));
+
+       amtk_menu_shell = amtk_menu_shell_get_from_gtk_menu_shell (GTK_MENU_SHELL (menu));
+
+       g_object_set_data (G_OBJECT (amtk_menu_shell),
+                          MENU_SHELL_FOR_RECENT_CHOOSER_KEY,
+                          GINT_TO_POINTER (TRUE));
+
+       amtk_application_window_connect_menu_to_statusbar (amtk_window, amtk_menu_shell);
+}
+
+static void
+open_recent_file_cb (GtkRecentChooser *recent_chooser,
+                    gpointer          user_data)
+{
+       AmtkApplicationWindow *amtk_window = AMTK_APPLICATION_WINDOW (user_data);
+       GtkApplication *gtk_app;
+       AmtkApplication *amtk_app;
+       gchar *uri;
+       GFile *file;
+
+       gtk_app = gtk_window_get_application (GTK_WINDOW (amtk_window->priv->gtk_window));
+       amtk_app = amtk_application_get_from_gtk_application (gtk_app);
+
+       uri = gtk_recent_chooser_get_current_uri (recent_chooser);
+       file = g_file_new_for_uri (uri);
+
+       amtk_application_open_simple (amtk_app, file);
+
+       g_free (uri);
+       g_object_unref (file);
+}
+
+/**
+ * amtk_application_window_create_open_recent_menu_item:
+ * @amtk_window: a #AmtkApplicationWindow.
+ *
+ * Creates a #GtkMenuItem with a simple and generic #GtkRecentChooserMenu as
+ * submenu.
+ *
+ * The #GtkRecentChooser is configured to show files only recently used with the
+ * current application, as returned by g_get_application_name(). If recent files
+ * are added to the default #GtkRecentManager with
+ * gtk_recent_manager_add_item(), the files will normally show up in the
+ * #GtkRecentChooserMenu.
+ *
+ * The #GtkRecentChooserMenu is connected to the statusbar with
+ * amtk_application_window_connect_recent_chooser_menu_to_statusbar().
+ *
+ * When the #GtkRecentChooser::item-activated signal is emitted,
+ * amtk_application_open_simple() is called, so the #GApplication must have the
+ * %G_APPLICATION_HANDLES_OPEN flag set.
+ *
+ * Returns: (transfer floating): a new #GtkMenuItem.
+ * Since: 2.0
+ */
+GtkWidget *
+amtk_application_window_create_open_recent_menu_item (AmtkApplicationWindow *amtk_window)
+{
+       GtkMenuItem *menu_item;
+       gchar *long_description;
+       GtkRecentChooserMenu *recent_chooser_menu;
+       GtkRecentChooser *recent_chooser;
+       GtkRecentFilter *filter;
+
+       g_return_val_if_fail (AMTK_IS_APPLICATION_WINDOW (amtk_window), NULL);
+
+       menu_item = GTK_MENU_ITEM (gtk_menu_item_new_with_mnemonic (_("Open _Recent")));
+
+       /* Translators: %s is the application name. */
+       long_description = g_strdup_printf (_("Open a file recently used with %s"),
+                                           g_get_application_name ());
+       amtk_menu_item_set_long_description (menu_item, long_description);
+       g_free (long_description);
+
+       recent_chooser_menu = GTK_RECENT_CHOOSER_MENU (gtk_recent_chooser_menu_new ());
+       gtk_menu_item_set_submenu (menu_item, GTK_WIDGET (recent_chooser_menu));
+
+       recent_chooser = GTK_RECENT_CHOOSER (recent_chooser_menu);
+       gtk_recent_chooser_set_local_only (recent_chooser, FALSE);
+       gtk_recent_chooser_set_sort_type (recent_chooser, GTK_RECENT_SORT_MRU);
+
+       filter = gtk_recent_filter_new ();
+       gtk_recent_filter_add_application (filter, g_get_application_name ());
+       gtk_recent_chooser_set_filter (recent_chooser, filter);
+
+       amtk_application_window_connect_recent_chooser_menu_to_statusbar (amtk_window, recent_chooser_menu);
+
+       g_signal_connect_object (recent_chooser,
+                                "item-activated",
+                                G_CALLBACK (open_recent_file_cb),
+                                amtk_window,
+                                0);
+
+       return GTK_WIDGET (menu_item);
+}
+
+/* ex:set ts=8 noet: */
diff --git a/amtk/amtk-application-window.h b/amtk/amtk-application-window.h
new file mode 100644
index 0000000..918cac9
--- /dev/null
+++ b/amtk/amtk-application-window.h
@@ -0,0 +1,80 @@
+/*
+ * This file is part of Amtk - Actions, Menus and Toolbars Kit
+ *
+ * Copyright 2017 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * Amtk 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.
+ *
+ * Amtk 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/>.
+ */
+
+#ifndef AMTK_APPLICATION_WINDOW_H
+#define AMTK_APPLICATION_WINDOW_H
+
+#if !defined (AMTK_H_INSIDE) && !defined (AMTK_COMPILATION)
+#error "Only <amtk/amtk.h> can be included directly."
+#endif
+
+#include <gtk/gtk.h>
+#include <amtk/amtk-types.h>
+
+G_BEGIN_DECLS
+
+#define AMTK_TYPE_APPLICATION_WINDOW             (amtk_application_window_get_type ())
+#define AMTK_APPLICATION_WINDOW(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
AMTK_TYPE_APPLICATION_WINDOW, AmtkApplicationWindow))
+#define AMTK_APPLICATION_WINDOW_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), 
AMTK_TYPE_APPLICATION_WINDOW, AmtkApplicationWindowClass))
+#define AMTK_IS_APPLICATION_WINDOW(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
AMTK_TYPE_APPLICATION_WINDOW))
+#define AMTK_IS_APPLICATION_WINDOW_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), 
AMTK_TYPE_APPLICATION_WINDOW))
+#define AMTK_APPLICATION_WINDOW_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), 
AMTK_TYPE_APPLICATION_WINDOW, AmtkApplicationWindowClass))
+
+typedef struct _AmtkApplicationWindowClass    AmtkApplicationWindowClass;
+typedef struct _AmtkApplicationWindowPrivate  AmtkApplicationWindowPrivate;
+
+struct _AmtkApplicationWindow
+{
+       GObject parent;
+
+       AmtkApplicationWindowPrivate *priv;
+};
+
+struct _AmtkApplicationWindowClass
+{
+       GObjectClass parent_class;
+
+       gpointer padding[12];
+};
+
+GType                  amtk_application_window_get_type                        (void) G_GNUC_CONST;
+
+AmtkApplicationWindow *        amtk_application_window_get_from_gtk_application_window (GtkApplicationWindow 
*gtk_window);
+
+GtkApplicationWindow * amtk_application_window_get_application_window          (AmtkApplicationWindow 
*amtk_window);
+
+GtkStatusbar *         amtk_application_window_get_statusbar                   (AmtkApplicationWindow 
*amtk_window);
+
+void                   amtk_application_window_set_statusbar                   (AmtkApplicationWindow 
*amtk_window,
+                                                                                GtkStatusbar          
*statusbar);
+
+void                   amtk_application_window_connect_menu_to_statusbar       (AmtkApplicationWindow 
*amtk_window,
+                                                                                AmtkMenuShell         
*amtk_menu_shell);
+
+void                   amtk_application_window_connect_recent_chooser_menu_to_statusbar
+                                                                               (AmtkApplicationWindow 
*amtk_window,
+                                                                                GtkRecentChooserMenu  *menu);
+
+GtkWidget *            amtk_application_window_create_open_recent_menu_item    (AmtkApplicationWindow 
*amtk_window);
+
+G_END_DECLS
+
+#endif /* AMTK_APPLICATION_WINDOW_H */
+
+/* ex:set ts=8 noet: */
diff --git a/amtk/amtk-types.h b/amtk/amtk-types.h
index e3d359e..7575550 100644
--- a/amtk/amtk-types.h
+++ b/amtk/amtk-types.h
@@ -32,6 +32,7 @@ typedef struct _AmtkActionInfo                        AmtkActionInfo;
 typedef struct _AmtkActionInfoEntry            AmtkActionInfoEntry;
 typedef struct _AmtkActionInfoStore            AmtkActionInfoStore;
 typedef struct _AmtkActionInfoCentralStore     AmtkActionInfoCentralStore;
+typedef struct _AmtkApplicationWindow          AmtkApplicationWindow;
 typedef struct _AmtkMenuShell                  AmtkMenuShell;
 
 G_END_DECLS
diff --git a/amtk/amtk-utils.c b/amtk/amtk-utils.c
index 091f981..c0aa974 100644
--- a/amtk/amtk-utils.c
+++ b/amtk/amtk-utils.c
@@ -18,6 +18,60 @@
  */
 
 #include "amtk-utils.h"
+#include <string.h>
+
+/*
+ * _amtk_utils_replace_home_dir_with_tilde:
+ * @filename: the filename.
+ *
+ * Replaces the home directory with a tilde, if the home directory is present in
+ * the @filename.
+ *
+ * Returns: the new filename. Free with g_free().
+ */
+/* This function comes from gedit. */
+gchar *
+_amtk_utils_replace_home_dir_with_tilde (const gchar *filename)
+{
+       gchar *tmp;
+       gchar *home;
+
+       g_return_val_if_fail (filename != NULL, NULL);
+
+       /* Note that g_get_home_dir returns a const string */
+       tmp = (gchar *) g_get_home_dir ();
+
+       if (tmp == NULL)
+       {
+               return g_strdup (filename);
+       }
+
+       home = g_filename_to_utf8 (tmp, -1, NULL, NULL, NULL);
+       if (home == NULL)
+       {
+               return g_strdup (filename);
+       }
+
+       if (g_str_equal (filename, home))
+       {
+               g_free (home);
+               return g_strdup ("~");
+       }
+
+       tmp = home;
+       home = g_strdup_printf ("%s/", tmp);
+       g_free (tmp);
+
+       if (g_str_has_prefix (filename, home))
+       {
+               gchar *res = g_strdup_printf ("~/%s", filename + strlen (home));
+               g_free (home);
+               return res;
+       }
+
+       g_free (home);
+       return g_strdup (filename);
+}
 
 /* Deep copy of @strv. */
 gchar **
@@ -45,3 +99,78 @@ _amtk_utils_strv_copy (const gchar * const *strv)
 
        return new_strv;
 }
+
+static gint
+get_menu_item_position (GtkMenuShell *menu_shell,
+                       GtkMenuItem  *item)
+{
+       GList *children;
+       GList *l;
+       gint pos;
+       gboolean found = FALSE;
+
+       children = gtk_container_get_children (GTK_CONTAINER (menu_shell));
+
+       for (l = children, pos = 0; l != NULL; l = l->next, pos++)
+       {
+               GtkMenuItem *cur_item = l->data;
+
+               if (cur_item == item)
+               {
+                       found = TRUE;
+                       break;
+               }
+       }
+
+       g_list_free (children);
+
+       return found ? pos : -1;
+}
+
+/**
+ * amtk_utils_recent_chooser_menu_get_item_uri:
+ * @menu: a #GtkRecentChooserMenu.
+ * @item: a #GtkMenuItem.
+ *
+ * Gets the URI of @item. @item must be a child of @menu. @menu must be a
+ * #GtkRecentChooserMenu.
+ *
+ * This function has been written because the value returned by
+ * gtk_recent_chooser_get_current_uri() is not updated when #GtkMenuItem's of a
+ * #GtkRecentChooserMenu are selected/deselected.
+ *
+ * Returns: the URI of @item. Free with g_free() when no longer needed.
+ * Since: 2.0
+ */
+gchar *
+amtk_utils_recent_chooser_menu_get_item_uri (GtkRecentChooserMenu *menu,
+                                            GtkMenuItem          *item)
+{
+       gint pos;
+       gchar **all_uris;
+       gsize length;
+       gchar *item_uri = NULL;
+
+       g_return_val_if_fail (GTK_IS_RECENT_CHOOSER_MENU (menu), NULL);
+       g_return_val_if_fail (GTK_IS_MENU_ITEM (item), NULL);
+
+       {
+               GtkWidget *item_parent;
+
+               item_parent = gtk_widget_get_parent (GTK_WIDGET (item));
+               g_return_val_if_fail (item_parent == GTK_WIDGET (menu), NULL);
+       }
+
+       pos = get_menu_item_position (GTK_MENU_SHELL (menu), item);
+       g_return_val_if_fail (pos >= 0, NULL);
+
+       all_uris = gtk_recent_chooser_get_uris (GTK_RECENT_CHOOSER (menu), &length);
+
+       if ((gsize)pos < length)
+       {
+               item_uri = g_strdup (all_uris[pos]);
+       }
+
+       g_strfreev (all_uris);
+       return item_uri;
+}
diff --git a/amtk/amtk-utils.h b/amtk/amtk-utils.h
index 7ee743e..8929849 100644
--- a/amtk/amtk-utils.h
+++ b/amtk/amtk-utils.h
@@ -20,15 +20,25 @@
 #ifndef AMTK_UTILS_H
 #define AMTK_UTILS_H
 
-#include <glib.h>
+#include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
+/* File utilities */
+
+G_GNUC_INTERNAL
+gchar *                _amtk_utils_replace_home_dir_with_tilde         (const gchar *filename);
+
 /* String utilities */
 
 G_GNUC_INTERNAL
 gchar **       _amtk_utils_strv_copy                           (const gchar * const *strv);
 
+/* Widget utilities */
+
+gchar *                amtk_utils_recent_chooser_menu_get_item_uri     (GtkRecentChooserMenu *menu,
+                                                                GtkMenuItem          *item);
+
 G_END_DECLS
 
 #endif /* AMTK_UTILS_H */
diff --git a/amtk/amtk.h b/amtk/amtk.h
index 985e3ad..699fbeb 100644
--- a/amtk/amtk.h
+++ b/amtk/amtk.h
@@ -28,6 +28,7 @@
 #include <amtk/amtk-action-info-store.h>
 #include <amtk/amtk-action-info-central-store.h>
 #include <amtk/amtk-action-map.h>
+#include <amtk/amtk-application-window.h>
 #include <amtk/amtk-menu-item.h>
 #include <amtk/amtk-menu-shell.h>
 


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