[gtk+] Add GtkApplication



commit 1ae257d00a2921f903048777664f1f171ff24c9b
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Jun 7 16:44:58 2010 -0400

    Add GtkApplication
    
    This is a work in progress to stub out an application class. The
    primary goal is to provide a mechanism for applications to export
    GtkActions, and there is a standard "Quit" action.
    
    This is based on GApplication.
    
    Future work:
     * Add a way to say "This is my application menubar", which gets
       put into all toplevel windows on non-OS-X, and into the top
       on OS X.
     * Support session management.
     * Support application settings.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=127958

 docs/reference/gtk/gtk-docs.sgml     |    9 +-
 docs/reference/gtk/gtk3-sections.txt |   25 ++
 docs/reference/gtk/gtk3.types        |    1 +
 gtk/Makefile.am                      |    2 +
 gtk/gtk.h                            |    1 +
 gtk/gtk.symbols                      |   11 +
 gtk/gtkapplication.c                 |  540 ++++++++++++++++++++++++++++++++++
 gtk/gtkapplication.h                 |  100 +++++++
 gtk/tests/Makefile.am                |    6 +-
 gtk/tests/gtk-example-application.c  |   60 ++++
 tests/Makefile.am                    |    7 +-
 tests/testapplication.c              |  105 +++++++
 tests/testapplication.desktop        |    6 +
 13 files changed, 868 insertions(+), 5 deletions(-)
---
diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml
index 7f5b99c..3ffb6c2 100644
--- a/docs/reference/gtk/gtk-docs.sgml
+++ b/docs/reference/gtk/gtk-docs.sgml
@@ -407,6 +407,11 @@ that is, GUI components such as #GtkButton or #GtkTextView.
       <xi:include href="xml/gtkbuildable.xml" />
       <xi:include href="xml/gtkbuilder.xml" />
     </chapter>
+
+    <chapter id="Application">
+      <title>Application support</title>
+      <xi:include href="xml/gtkapplication.xml" />
+    </chapter>
   </part>
 
   <part id="migrating">
@@ -414,8 +419,8 @@ that is, GUI components such as #GtkButton or #GtkTextView.
 
     <partintro>
       <para>
-	This part describes what you need to change in programs use
-	older versions of GTK+ so that they can use the new features.
+        This part describes what you need to change in programs use
+        older versions of GTK+ so that they can use the new features.
         It also mentions how to convert applications using widgets
         found in the libgnomeui library to use their counterparts
         in GTK+.
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index 5d12c3d..c7ef3c2 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -6340,3 +6340,28 @@ GTK_TYPE_EXTENDED_LAYOUT
 <SUBSECTION Private>
 gtk_extended_layout_get_type
 </SECTION>
+
+<SECTION>
+<FILE>gtkapplication</FILE>
+<TITLE>GtkApplication</TITLE>
+GtkApplication
+
+gtk_application_new
+gtk_application_run
+gtk_application_quit
+gtk_application_set_action_group
+gtk_application_get_window
+gtk_application_add_window
+
+<SUBSECTION Standard>
+GtkApplicationClass
+GTK_TYPE_APPLICATION
+GTK_APPLICATION
+GTK_APPLICATION_CLASS
+GTK_IS_APPLICATION
+GTK_IS_APPLICATION_CLASS
+GTK_APPLICATION_GET_CLASS
+<SUBSECTION Private>
+gtk_application_get_type
+GtkApplicationPrivate
+</SECTION>
diff --git a/docs/reference/gtk/gtk3.types b/docs/reference/gtk/gtk3.types
index 873c63b..b03bb0c 100644
--- a/docs/reference/gtk/gtk3.types
+++ b/docs/reference/gtk/gtk3.types
@@ -11,6 +11,7 @@ gtk_action_group_get_type
 gtk_activatable_get_type
 gtk_adjustment_get_type
 gtk_alignment_get_type
+gtk_application_get_type
 gtk_arrow_get_type
 gtk_aspect_frame_get_type
 gtk_assistant_get_type
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index ce1e2af..e10be5f 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -170,6 +170,7 @@ gtk_public_h_sources =          \
 	gtkactivatable.h	\
 	gtkadjustment.h		\
 	gtkalignment.h		\
+	gtkapplication.h    \
 	gtkarrow.h		\
 	gtkaspectframe.h	\
 	gtkassistant.h		\
@@ -428,6 +429,7 @@ gtk_base_c_sources =            \
 	gtkactivatable.c	\
 	gtkadjustment.c		\
 	gtkalignment.c		\
+	gtkapplication.c \
 	gtkarrow.c		\
 	gtkaspectframe.c	\
 	gtkassistant.c		\
diff --git a/gtk/gtk.h b/gtk/gtk.h
index cbac475..120555b 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -40,6 +40,7 @@
 #include <gtk/gtkactivatable.h>
 #include <gtk/gtkadjustment.h>
 #include <gtk/gtkalignment.h>
+#include <gtk/gtkapplication.h>
 #include <gtk/gtkarrow.h>
 #include <gtk/gtkaspectframe.h>
 #include <gtk/gtkassistant.h>
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 03b815a..6439b90 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -257,6 +257,17 @@ gtk_alignment_set_padding
 #endif
 #endif
 
+#if IN_HEADER(__GTK_APPLICATION_H__)
+#if IN_FILE(__GTK_APPLICATION_C__)
+gtk_application_get_type G_GNUC_CONST
+gtk_application_new
+gtk_application_set_action_group
+gtk_application_get_window
+gtk_application_add_window
+gtk_application_run
+gtk_application_quit
+#endif
+#endif
 
 #if IN_HEADER(__GTK_ASSISTANT_H__)
 #if IN_FILE(__GTK_ASSISTANT_C__)
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c
new file mode 100644
index 0000000..c8dbde9
--- /dev/null
+++ b/gtk/gtkapplication.c
@@ -0,0 +1,540 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "gtkapplication.h"
+#include "gtkmain.h"
+#include "gtkintl.h"
+#include "gtkprivate.h"
+
+#include "gtkalias.h"
+
+#include <gdk/gdk.h>
+#ifdef GDK_WINDOWING_X11
+#include <gdk/x11/gdkx.h>
+#endif
+
+/**
+ * SECTION:gtkapplication
+ * @title: GtkApplication
+ * @short_description: Application class
+ *
+ * #GtkApplication is a class that handles many important aspects
+ * of a GTK+ application in a convenient fashion, without enforcing
+ * a one-size-fits-all application model.
+ *
+ * Currently, GtkApplication handles application uniqueness, provides
+ * some basic scriptability by exporting 'actions', implements some
+ * standard actions itself (such as 'Quit') and provides a main window
+ * whose life-cycle is automatically tied to the life-cycle of your
+ * application.
+ *
+ * <example id="gtkapplication"><title>A simple application</title>
+ * <programlisting>
+ * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; parse="text" href="../../../../gtk/tests/gtk-example-application.c">
+ *  <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
+ * </xi:include>
+ * </programlisting>
+ * </example>
+ */
+enum
+{
+  PROP_0,
+  PROP_WINDOW
+};
+
+enum
+{
+  ACTIVATED,
+
+  LAST_SIGNAL
+};
+
+static guint gtk_application_signals[LAST_SIGNAL] = { 0 };
+
+struct _GtkApplicationPrivate
+{
+  char *appid;
+  GtkActionGroup *main_actions;
+
+  GtkWindow *default_window;
+  GSList *windows;
+};
+
+G_DEFINE_TYPE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
+
+static gboolean
+gtk_application_default_quit (GApplication *application,
+                              guint         timestamp)
+{
+  gtk_main_quit ();
+  return TRUE;
+}
+
+static void
+gtk_application_default_run (GApplication *application)
+{
+  gtk_main ();
+}
+
+static void
+gtk_application_default_prepare_activation (GApplication *application,
+					    GVariant     *arguments,
+					    GVariant     *platform_data)
+{
+  GVariantIter iter;
+  gchar *key;
+  GVariant *value;
+
+  g_variant_iter_init (&iter, platform_data);
+  while (g_variant_iter_next (&iter, "{sv}", &key, &value))
+    {
+      if (strcmp (key, "startup-notification-id") == 0 &&
+          strcmp (g_variant_get_type_string (value), "s") == 0)
+        gdk_notify_startup_complete_with_id (g_variant_get_string (value, NULL));
+      g_free (key);
+      g_variant_unref (value);
+    }
+  
+  g_signal_emit (G_OBJECT (application), gtk_application_signals[ACTIVATED], 0, arguments);
+}
+
+static void
+gtk_application_default_activated (GApplication *application,
+                                   GVariant     *arguments)
+{
+  GtkApplication *app = GTK_APPLICATION (application);
+
+  /* TODO: should we raise the last focused window instead ? */
+  if (app->priv->default_window != NULL)
+    gtk_window_present (app->priv->default_window);
+}
+
+static void
+gtk_application_default_action (GApplication *application,
+                                const gchar  *action,
+                                guint         timestamp)
+{
+  GtkApplication *app = GTK_APPLICATION (application);
+  GList *actions, *iter;
+
+  actions = gtk_action_group_list_actions (app->priv->main_actions);
+  for (iter = actions; iter; iter = iter->next)
+    {
+      GtkAction *gtkaction = iter->data;
+      if (strcmp (action, gtk_action_get_name (gtkaction)) == 0)
+        {
+          /* TODO set timestamp */
+          gtk_action_activate (gtkaction);
+          break;
+        }
+    }
+  g_list_free (actions);
+}
+
+static GVariant *
+gtk_application_format_activation_data (void)
+{
+  const gchar *startup_id = NULL;
+  GdkDisplay *display = gdk_display_get_default ();
+  GVariantBuilder builder;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+  /* try and get the startup notification id from GDK, the environment
+   * or, if everything else failed, fake one.
+   */
+#ifdef GDK_WINDOWING_X11
+  startup_id = gdk_x11_display_get_startup_notification_id (display);
+#endif /* GDK_WINDOWING_X11 */
+
+  if (startup_id)
+    g_variant_builder_add (&builder, "{sv}", "startup-notification-id",
+                           g_variant_new ("s", startup_id));
+  return g_variant_builder_end (&builder);
+}
+
+/**
+ * gtk_application_new:
+ * @argc: (allow-none) (inout): System argument count
+ * @argv: (allow-none) (inout): System argument vector
+ * @appid: System-dependent application identifier
+ *
+ * Create a new #GtkApplication, or if one has already been initialized
+ * in this process, return the existing instance. This function will as
+ * a side effect initialize the display system; see gtk_init().
+ *
+ * For the behavior if this application is running in another process,
+ * see g_application_new().
+ *
+ * Returns: (transfer full): A newly-referenced #GtkApplication
+ *
+ * Since: 3.0
+ */
+GtkApplication*
+gtk_application_new (gint          *argc,
+                     gchar       ***argv,
+                     const gchar   *appid)
+{
+  GtkApplication *app;
+  gint argc_for_app;
+  gchar **argv_for_app;
+  GVariant *platform_data;
+
+  gtk_init (argc, argv);
+
+  if (argc)
+    argc_for_app = *argc;
+  else
+    argc_for_app = 0;
+  if (argv)
+    argv_for_app = *argv;
+  else
+    argv_for_app = NULL;
+
+  app = g_object_new (GTK_TYPE_APPLICATION, "appid", appid, NULL);
+
+  platform_data = gtk_application_format_activation_data ();
+  g_application_register_with_data (G_APPLICATION (app), argc_for_app, argv_for_app,
+				    platform_data);
+  g_variant_unref (platform_data);
+
+  return app;
+}
+
+static void
+on_action_sensitive (GtkAction      *action,
+                     GParamSpec     *pspec,
+                     GtkApplication *app)
+{
+  g_application_set_action_enabled (G_APPLICATION (app),
+                                    gtk_action_get_name (action),
+                                    gtk_action_get_sensitive (action));
+}
+
+/**
+ * gtk_application_set_action_group:
+ * @app: A #GtkApplication
+ * @group: A #GtkActionGroup
+ *
+ * Set @group as this application's global action group.
+ * This will ensure the operating system interface uses
+ * these actions as follows:
+ *
+ * <itemizedlist>
+ *   <listitem>In GNOME 2 this exposes the actions for scripting.</listitem>
+ *   <listitem>In GNOME 3, this function populates the application menu.</listitem>
+ *   <listitem>In Windows prior to version 7, this function does nothing.</listitem>
+ *   <listitem>In Windows 7, this function adds "Tasks" to the Jump List.</listitem>
+ *   <listitem>In Mac OS X, this function extends the Dock menu.</listitem>
+ * </itemizedlist>
+ *
+ * It is an error to call this function more than once.
+ *
+ * Since: 3.0
+ */
+void
+gtk_application_set_action_group (GtkApplication *app,
+                                  GtkActionGroup *group)
+{
+  GList *actions, *iter;
+
+  g_return_if_fail (GTK_IS_APPLICATION (app));
+  g_return_if_fail (app->priv->main_actions == NULL);
+
+  app->priv->main_actions = g_object_ref (group);
+  actions = gtk_action_group_list_actions (group);
+  for (iter = actions; iter; iter = iter->next)
+    {
+      GtkAction *action = iter->data;
+      g_application_add_action (G_APPLICATION (app),
+                                gtk_action_get_name (action),
+                                gtk_action_get_tooltip (action));
+      g_signal_connect (action, "notify::sensitive",
+                        G_CALLBACK (on_action_sensitive), app);
+    }
+  g_list_free (actions);
+}
+
+static gboolean
+gtk_application_on_window_destroy (GtkWidget *window,
+                                   gpointer   user_data)
+{
+  GtkApplication *app = GTK_APPLICATION (user_data);
+
+  app->priv->windows = g_slist_remove (app->priv->windows, window);
+
+  if (app->priv->windows == NULL)
+    gtk_application_quit (app);
+
+  return FALSE;
+}
+
+static gchar *default_title;
+
+/**
+ * gtk_application_add_window:
+ * @app: a #GtkApplication
+ * @window: a toplevel window to add to @app
+ *
+ * Adds a window to the #GtkApplication.
+ *
+ * If the user closes all of the windows added to @app, the default
+ * behaviour is to call gtk_application_quit().
+ *
+ * If your application uses only a single toplevel window, you can
+ * use gtk_application_get_window().
+ *
+ * Since: 3.0
+ */
+void
+gtk_application_add_window (GtkApplication *app,
+                            GtkWindow      *window)
+{
+  app->priv->windows = g_slist_prepend (app->priv->windows, window);
+
+  if (gtk_window_get_title (window) == NULL && default_title != NULL)
+    gtk_window_set_title (window, default_title);
+
+  g_signal_connect (window, "destroy",
+                    G_CALLBACK (gtk_application_on_window_destroy), app);
+}
+
+/**
+ * gtk_application_get_window:
+ * @app: a #GtkApplication
+ *
+ * A simple #GtkApplication has a "default window". This window should
+ * act as the primary user interaction point with your application.
+ * The window returned by this function is of type #GTK_WINDOW_TYPE_TOPLEVEL
+ * and its properties such as "title" and "icon-name" will be initialized
+ * as appropriate for the platform.
+ *
+ * If the user closes this window, and your application hasn't created
+ * any other windows, the default action will be to call gtk_application_quit().
+ *
+ * If your application has more than one toplevel window (e.g. an
+ * single-document-interface application with multiple open documents),
+ * or if you are constructing your toplevel windows yourself (e.g. using
+ * #GtkBuilder), use gtk_application_add_window() instead.
+ *
+ * Returns: (transfer none): The default #GtkWindow for this application
+ *
+ * Since: 3.0
+ */
+GtkWindow *
+gtk_application_get_window (GtkApplication *app)
+{
+  if (app->priv->default_window != NULL)
+    return app->priv->default_window;
+
+  app->priv->default_window = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
+  g_object_ref_sink (app->priv->default_window);
+
+  gtk_application_add_window (app, app->priv->default_window);
+
+  return app->priv->default_window;
+}
+
+/**
+ * gtk_application_run:
+ * @app: a #GtkApplication
+ *
+ * Runs the main loop; see g_application_run().
+ * The default implementation for #GtkApplication uses gtk_main().
+ *
+ * Since: 3.0
+ */
+void
+gtk_application_run (GtkApplication *app)
+{
+  g_application_run (G_APPLICATION (app));
+}
+
+/**
+ * gtk_application_quit:
+ * @app: a #GtkApplication
+ *
+ * Request the application exit.
+ * By default, this method will exit the main loop; see gtk_main_quit().
+ *
+ * Since: 3.0
+ */
+void
+gtk_application_quit (GtkApplication *app)
+{
+  g_application_quit (G_APPLICATION (app), gtk_get_current_event_time ());
+}
+
+static void
+gtk_application_get_property (GObject    *object,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  GtkApplication *app = GTK_APPLICATION (object);
+
+  switch (prop_id)
+    {
+      case PROP_WINDOW:
+        g_value_set_object (value, gtk_application_get_window (app));
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtk_application_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  GtkApplication *app = GTK_APPLICATION (object);
+
+  g_assert (app != NULL);
+
+  switch (prop_id)
+    {
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+setup_default_window_decorations (void)
+{
+  const gchar *pid;
+  const gchar *filename;
+  GKeyFile *keyfile;
+  gchar *title;
+  gchar *icon_name;
+
+  pid = g_getenv ("GIO_LAUNCHED_DESKTOP_FILE_PID");
+  filename = g_getenv ("GIO_LAUNCHED_DESKTOP_FILE");
+
+  keyfile = g_key_file_new ();
+
+  if (pid != NULL && filename != NULL && atoi (pid) == getpid () &&
+      g_key_file_load_from_file (keyfile, filename, 0, NULL))
+    {
+      title = g_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
+      icon_name = g_key_file_get_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL);
+
+      g_print ("default title: %s\n", title);
+      g_print ("default icon: %s\n", icon_name);
+
+      if (default_title == NULL)
+        default_title = title;
+
+      if (gtk_window_get_default_icon_name () == NULL)
+        gtk_window_set_default_icon_name (icon_name);
+
+      g_free (icon_name);
+    }
+
+  g_key_file_free (keyfile);
+}
+
+static void
+gtk_application_init (GtkApplication *application)
+{
+  application->priv = G_TYPE_INSTANCE_GET_PRIVATE (application, GTK_TYPE_APPLICATION, GtkApplicationPrivate);
+
+  setup_default_window_decorations ();
+}
+
+
+static GObject*
+gtk_application_constructor (GType                  type,
+                             guint                  n_construct_properties,
+                             GObjectConstructParam *construct_params)
+{
+  GObject *object;
+
+  /* Last ditch effort here */
+  gtk_init (0, NULL);
+
+  object = (* G_OBJECT_CLASS (gtk_application_parent_class)->constructor) (type,
+                                                                           n_construct_properties,
+                                                                           construct_params);
+
+  return object;
+}
+
+static void
+gtk_application_class_init (GtkApplicationClass *klass)
+{
+  GObjectClass *gobject_class;
+  GApplicationClass *application_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  application_class = G_APPLICATION_CLASS (klass);
+
+  gobject_class->constructor = gtk_application_constructor;
+  gobject_class->get_property = gtk_application_get_property;
+  gobject_class->set_property = gtk_application_set_property;
+
+  application_class->run = gtk_application_default_run;
+  application_class->quit = gtk_application_default_quit;
+  application_class->action = gtk_application_default_action;
+  application_class->prepare_activation = gtk_application_default_prepare_activation;
+
+  klass->activated = gtk_application_default_activated;
+
+  /**
+   * GtkApplication::activated:
+   * @arguments: A #GVariant with the signature "aay"
+   *
+   * This signal is emitted when a non-primary process for a given
+   * application is invoked while your application is running; for
+   * example, when a file browser launches your program to open a
+   * file.  The raw operating system arguments are passed in the
+   * variant @arguments.
+   */
+
+  gtk_application_signals[ACTIVATED] =
+    g_signal_new (g_intern_static_string ("activated"),
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkApplicationClass, activated),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__BOXED,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_VARIANT);
+
+  g_type_class_add_private (gobject_class, sizeof (GtkApplicationPrivate));
+}
+
+#define __GTK_APPLICATION_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkapplication.h b/gtk/gtkapplication.h
new file mode 100644
index 0000000..6581bcd
--- /dev/null
+++ b/gtk/gtkapplication.h
@@ -0,0 +1,100 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2010 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_APPLICATION_H__
+#define __GTK_APPLICATION_H__
+
+#include <gio/gio.h>
+#include <gtk/gtkaction.h>
+#include <gtk/gtkactiongroup.h>
+#include <gtk/gtkwindow.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_APPLICATION            (gtk_application_get_type ())
+#define GTK_APPLICATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APPLICATION, GtkApplication))
+#define GTK_APPLICATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_APPLICATION, GtkApplicationClass))
+#define GTK_IS_APPLICATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APPLICATION))
+#define GTK_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_APPLICATION))
+#define GTK_APPLICATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_APPLICATION, GtkApplicationClass))
+
+typedef struct _GtkApplication        GtkApplication;
+typedef struct _GtkApplicationClass   GtkApplicationClass;
+typedef struct _GtkApplicationPrivate GtkApplicationPrivate;
+
+struct _GtkApplication
+{
+  GApplication parent;
+
+  /*< private >*/
+
+  GtkApplicationPrivate *priv;
+};
+
+struct _GtkApplicationClass
+{
+  GApplicationClass parent_class;
+
+  /*< vfuncs >*/
+  void        (* activated)   (GApplication  *application,
+			       GVariant      *args);
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+  void (*_gtk_reserved5) (void);
+  void (*_gtk_reserved6) (void);
+  void (*_gtk_reserved7) (void);
+  void (*_gtk_reserved8) (void);
+  void (*_gtk_reserved9) (void);
+  void (*_gtk_reserved10) (void);
+};
+
+GType           gtk_application_get_type         (void) G_GNUC_CONST;
+GtkApplication* gtk_application_new              (gint             *argc,
+                                                  gchar          ***argv,
+                                                  const gchar      *appid);
+void            gtk_application_set_action_group (GtkApplication   *app,
+                                                  GtkActionGroup   *group);
+GtkWindow *     gtk_application_get_window       (GtkApplication   *app);
+void            gtk_application_add_window       (GtkApplication   *app,
+                                                  GtkWindow        *window);
+void            gtk_application_run              (GtkApplication   *app);
+void            gtk_application_quit             (GtkApplication   *app);
+
+G_END_DECLS
+
+#endif /* __GTK_APPLICATION_H__ */
+
diff --git a/gtk/tests/Makefile.am b/gtk/tests/Makefile.am
index cf209a1..803314f 100644
--- a/gtk/tests/Makefile.am
+++ b/gtk/tests/Makefile.am
@@ -20,7 +20,7 @@ progs_ldadd = \
 	$(top_builddir)/gtk/$(gtktargetlib)				\
 	$(GTK_DEP_LIBS)
 
-noinst_PROGRAMS = $(TEST_PROGS)
+noinst_PROGRAMS = $(TEST_PROGS) $(SAMPLE_PROGS)
 
 
 TEST_PROGS			+= testing
@@ -94,6 +94,10 @@ TEST_PROGS			+= action
 action_SOURCES			 = action.c
 action_LDADD			 = $(progs_ldadd)
 
+SAMPLE_PROGS = gtk-example-application
+gtk_example_application_SOURCES	= gtk-example-application.c
+gtk_example_application_LDADD	= $(progs_ldadd)
+
 
 EXTRA_DIST +=				\
 	file-chooser-test-dir/empty     \
diff --git a/gtk/tests/gtk-example-application.c b/gtk/tests/gtk-example-application.c
new file mode 100644
index 0000000..4248e0e
--- /dev/null
+++ b/gtk/tests/gtk-example-application.c
@@ -0,0 +1,60 @@
+#include <gtk/gtk.h>
+
+static const char *builder_data =
+"<interface>"
+"<object class=\"GtkAboutDialog\" id=\"about_dialog\">"
+"  <property name=\"program-name\">Example Application</property>"
+"  <property name=\"website\">http://www.gtk.org</property>"
+"</object>"
+"<object class=\"GtkActionGroup\" id=\"actions\">"
+"  <child>"
+"      <object class=\"GtkAction\" id=\"About\">"
+"          <property name=\"name\">About</property>"
+"          <property name=\"stock_id\">gtk-about</property>"
+"      </object>"
+"  </child>"
+"</object>"
+"</interface>";
+
+static GtkWidget *about_dialog;
+
+static void
+about_activate (GtkAction *action,
+                gpointer   user_data)
+{
+  gtk_dialog_run (GTK_DIALOG (about_dialog));
+  gtk_widget_hide (GTK_WIDGET (about_dialog));
+}
+
+int
+main (int argc, char **argv)
+{
+  GtkApplication *app;
+  GtkWindow *window;
+  GtkBuilder *builder;
+  GtkAction *action;
+  GtkActionGroup *actions;
+
+  app = gtk_application_new (&argc, &argv, "org.gtk.Example");
+  builder = gtk_builder_new ();
+  if (!gtk_builder_add_from_string (builder, builder_data, -1, NULL))
+    g_error ("failed to parse UI");
+  actions = GTK_ACTION_GROUP (gtk_builder_get_object (builder, "actions"));
+  gtk_application_set_action_group (app, actions);
+
+  action = gtk_action_group_get_action (actions, "About");
+  g_signal_connect (action, "activate", G_CALLBACK (about_activate), app);
+
+  about_dialog = GTK_WIDGET (gtk_builder_get_object (builder, "about_dialog"));
+
+  gtk_builder_connect_signals (builder, app);
+  g_object_unref (builder);
+
+  window = gtk_application_get_window (app);
+  gtk_container_add (GTK_CONTAINER (window), gtk_label_new ("Hello world"));
+  gtk_widget_show_all (GTK_WIDGET (window));
+
+  gtk_application_run (app);
+
+  return 0;
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a4a9f5f..a7c9705 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -8,7 +8,8 @@ INCLUDES =				\
 	-DGDK_DISABLE_DEPRECATED	\
 	-DGTK_DISABLE_DEPRECATED	\
 	$(GTK_DEBUG_FLAGS)		\
-	$(GTK_DEP_CFLAGS)
+	$(GTK_DEP_CFLAGS)		\
+	$(GDK_DEP_CFLAGS)
 
 DEPS =									\
 	$(top_builddir)/gdk-pixbuf/libgdk_pixbuf-$(GTK_API_VERSION).la	\
@@ -31,6 +32,7 @@ noinst_PROGRAMS =  $(TEST_PROGS)	\
 	print-editor			\
 	extendedlayoutexample		\
 	testaccel			\
+	testapplication			\
 	testassistant			\
 	testbbox			\
 	testbuttons			\
@@ -116,6 +118,7 @@ extendedlayoutexample_DEPENDENCIES = $(TEST_DEPS)
 testicontheme_DEPENDENCIES = $(TEST_DEPS)
 testiconview_DEPENDENCIES = $(TEST_DEPS)
 testaccel_DEPENDENCIES = $(TEST_DEPS)
+testapplication_DEPENDENCIES = $(TEST_DEPS)
 testassistant_DEPENDENCIES = $(TEST_DEPS)
 testbbox_DEPENDENCIES = $(TEST_DEPS)
 testbuttons_DEPENDENCIES = $(TEST_DEPS)
@@ -178,6 +181,7 @@ simple_LDADD = $(LDADDS)
 print_editor_LDADD = $(LDADDS)
 extendedlayoutexample_LDADD = $(LDADDS)
 testaccel_LDADD = $(LDADDS)
+testapplication_LDADD = $(LDADDS)
 testassistant_LDADD = $(LDADDS)
 testbbox_LDADD = $(LDADDS)
 testbuttons_LDADD = $(LDADDS)
@@ -245,7 +249,6 @@ testtooltips_LDADD = $(LDADDS)
 testvolumebutton_LDADD = $(LDADDS)
 testwindows_LDADD = $(LDADDS)
 
-
 testentrycompletion_SOURCES = 	\
 	prop-editor.c		\
 	testentrycompletion.c
diff --git a/tests/testapplication.c b/tests/testapplication.c
new file mode 100644
index 0000000..a2883fa
--- /dev/null
+++ b/tests/testapplication.c
@@ -0,0 +1,105 @@
+/* GTK - The GIMP Toolkit
+ * testapplication.c: Using GtkApplication
+ * Copyright (C) 2010, 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <gtk/gtk.h>
+#include <gio/gdesktopappinfo.h>
+
+static const char *builder_data =
+"<interface>"
+"<object class=\"GtkAboutDialog\" id=\"about_dialog\">"
+"  <property name=\"program-name\">Test Application</property>"
+"  <property name=\"website\">http://gtk.org</property>"
+"</object>"
+"<object class=\"GtkActionGroup\" id=\"actions\">"
+"  <child>"
+"      <object class=\"GtkAction\" id=\"About\">"
+"          <property name=\"name\">About</property>"
+"          <property name=\"stock_id\">gtk-about</property>"
+"      </object>"
+"  </child>"
+"</object>"
+"</interface>";
+
+static GtkWidget *about_dialog;
+
+static void
+about_activate (GtkAction *action,
+                gpointer   user_data)
+{
+  gtk_dialog_run (GTK_DIALOG (about_dialog));
+  gtk_widget_hide (GTK_WIDGET (about_dialog));
+}
+
+static void
+launch_myself (void)
+{
+  GAppInfo *ai;
+
+  g_type_init ();
+
+  ai = (GAppInfo*)g_desktop_app_info_new_from_filename ("./testapplication.desktop");
+  g_app_info_launch (ai, NULL, NULL, NULL);
+}
+
+int
+main (int argc, char **argv)
+{
+  GtkApplication *app;
+  GtkWindow *window;
+  GtkWindow *window2;
+  GtkBuilder *builder;
+  GtkAction *action;
+  GtkActionGroup *actions;
+
+  if (argc > 1 && strcmp (argv[1], "--launch-yourself") == 0)
+    {
+      launch_myself ();
+      exit (0);
+    }
+
+  app = gtk_application_new (&argc, &argv, "org.gtk.TestApp");
+  builder = gtk_builder_new ();
+  if (!gtk_builder_add_from_string (builder, builder_data, -1, NULL))
+    g_error ("failed to parse UI");
+  actions = GTK_ACTION_GROUP (gtk_builder_get_object (builder, "actions"));
+  gtk_application_set_action_group (app, actions);
+
+  action = gtk_action_group_get_action (actions, "About");
+  g_signal_connect (action, "activate", G_CALLBACK (about_activate), app);
+
+  about_dialog = GTK_WIDGET (gtk_builder_get_object (builder, "about_dialog"));
+
+  gtk_builder_connect_signals (builder, app);
+  g_object_unref (builder);
+
+  window = gtk_application_get_window (app);
+  gtk_container_add (GTK_CONTAINER (window), gtk_label_new ("Hello world"));
+  gtk_widget_show_all (GTK_WIDGET (window));
+
+  window2 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_container_add (GTK_CONTAINER (window2), gtk_label_new ("Hello again"));
+  gtk_widget_show_all (GTK_WIDGET (window2));
+  gtk_application_add_window (app, window2);
+
+  gtk_application_run (app);
+
+  return 0;
+}
diff --git a/tests/testapplication.desktop b/tests/testapplication.desktop
new file mode 100644
index 0000000..430bb37
--- /dev/null
+++ b/tests/testapplication.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Type=Application
+Name=testapplication
+Name[de]=Test-Applikation
+Exec=./testapplication
+Icon=accessories-calculator



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