From 1ae257d00a2921f903048777664f1f171ff24c9b Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 7 Jun 2010 16:44:58 -0400 Subject: [PATCH] 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(-) create mode 100644 gtk/gtkapplication.c create mode 100644 gtk/gtkapplication.h create mode 100644 gtk/tests/gtk-example-application.c create mode 100644 tests/testapplication.c create mode 100644 tests/testapplication.desktop diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml index 7f5b99ceb0..3ffb6c25d7 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. + + + Application support + + @@ -414,8 +419,8 @@ that is, GUI components such as #GtkButton or #GtkTextView. - 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 5d12c3dd04..c7ef3c2f5a 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -6340,3 +6340,28 @@ GTK_TYPE_EXTENDED_LAYOUT gtk_extended_layout_get_type + +
+gtkapplication +GtkApplication +GtkApplication + +gtk_application_new +gtk_application_run +gtk_application_quit +gtk_application_set_action_group +gtk_application_get_window +gtk_application_add_window + + +GtkApplicationClass +GTK_TYPE_APPLICATION +GTK_APPLICATION +GTK_APPLICATION_CLASS +GTK_IS_APPLICATION +GTK_IS_APPLICATION_CLASS +GTK_APPLICATION_GET_CLASS + +gtk_application_get_type +GtkApplicationPrivate +
diff --git a/docs/reference/gtk/gtk3.types b/docs/reference/gtk/gtk3.types index 873c63ba32..b03bb0ca95 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 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 #include #include +#include #include #include #include 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 + */ + +/* + * 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 +#include + +#include "gtkapplication.h" +#include "gtkmain.h" +#include "gtkintl.h" +#include "gtkprivate.h" + +#include "gtkalias.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#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. + * + * A simple application + * + * + * FIXME: MISSING XINCLUDE CONTENT + * + * + * + */ +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: + * + * + * In GNOME 2 this exposes the actions for scripting. + * In GNOME 3, this function populates the application menu. + * In Windows prior to version 7, this function does nothing. + * In Windows 7, this function adds "Tasks" to the Jump List. + * In Mac OS X, this function extends the Dock menu. + * + * + * 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 + */ + +/* + * 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 can be included directly." +#endif + +#ifndef __GTK_APPLICATION_H__ +#define __GTK_APPLICATION_H__ + +#include +#include +#include +#include + +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 + +static const char *builder_data = +"" +"" +" Example Application" +" http://www.gtk.org" +"" +"" +" " +" " +" About" +" gtk-about" +" " +" " +"" +""; + +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 a4a9f5f345..a7c970518b 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 0000000000..a2883fa25f --- /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 +#include + +static const char *builder_data = +"" +"" +" Test Application" +" http://gtk.org" +"" +"" +" " +" " +" About" +" gtk-about" +" " +" " +"" +""; + +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 0000000000..430bb37f21 --- /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