summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2010-06-07 16:44:58 -0400
committerMatthias Clasen <mclasen@redhat.com>2010-06-07 16:46:30 -0400
commit1ae257d00a2921f903048777664f1f171ff24c9b (patch)
treeb564b248f30571f29fa93873b4ba4e8ad8c9f737 /gtk
parent2c5871479e55a4a5d8e67aef5491c33e14a93f57 (diff)
downloadgtk+-1ae257d00a2921f903048777664f1f171ff24c9b.tar.gz
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
Diffstat (limited to 'gtk')
-rw-r--r--gtk/Makefile.am2
-rw-r--r--gtk/gtk.h1
-rw-r--r--gtk/gtk.symbols11
-rw-r--r--gtk/gtkapplication.c540
-rw-r--r--gtk/gtkapplication.h100
-rw-r--r--gtk/tests/Makefile.am6
-rw-r--r--gtk/tests/gtk-example-application.c60
7 files changed, 719 insertions, 1 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index ce1e2af8d8..e10be5f251 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 cbac47556d..120555b41a 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 03b815a83b..6439b90e34 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 0000000000..c8dbde904c
--- /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 0000000000..6581bcd923
--- /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 cf209a1c06..803314f026 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 0000000000..4248e0ef2b
--- /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;
+}