]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/application.c
6889e6128010b78200c038a6138f4a0cd98bbfb8
[~andy/gtk] / demos / gtk-demo / application.c
1 /* Application class :: menus.ui application.ui
2  *
3  * Demonstrates a simple application.
4  *
5  * This examples uses GtkApplication, GtkApplicationWindow, GtkBuilder
6  * as well as GMenu and GResource. Due to the way GtkApplication is structured,
7  * it is run as a separate process.
8  */
9
10 #include "config.h"
11
12 #include <gtk/gtk.h>
13
14 #ifdef STANDALONE
15
16 static void
17 show_action_dialog (GSimpleAction *action)
18 {
19   const gchar *name;
20   GtkWidget *dialog;
21
22   name = g_action_get_name (G_ACTION (action));
23
24   dialog = gtk_message_dialog_new (NULL,
25                                    GTK_DIALOG_DESTROY_WITH_PARENT,
26                                    GTK_MESSAGE_INFO,
27                                    GTK_BUTTONS_CLOSE,
28                                    "You activated action: \"%s\"",
29                                     name);
30
31   g_signal_connect (dialog, "response",
32                     G_CALLBACK (gtk_widget_destroy), NULL);
33
34   gtk_widget_show (dialog);
35 }
36
37 static void
38 show_action_infobar (GSimpleAction *action,
39                      GVariant      *parameter,
40                      gpointer       window)
41 {
42   GtkWidget *infobar;
43   GtkWidget *message;
44   gchar *text;
45   const gchar *name;
46   const gchar *value;
47
48   name = g_action_get_name (G_ACTION (action));
49   value = g_variant_get_string (parameter, NULL);
50
51   message = g_object_get_data (G_OBJECT (window), "message");
52   infobar = g_object_get_data (G_OBJECT (window), "infobar");
53   text = g_strdup_printf ("You activated radio action: \"%s\".\n"
54                           "Current value: %s", name, value);
55   gtk_label_set_text (GTK_LABEL (message), text);
56   gtk_widget_show (infobar);
57   g_free (text);
58 }
59
60 static void
61 activate_action (GSimpleAction  *action,
62                  GVariant       *parameter,
63                  gpointer        user_data)
64 {
65   show_action_dialog (action);
66 }
67
68 static void
69 activate_toggle (GSimpleAction *action,
70                  GVariant      *parameter,
71                  gpointer       user_data)
72 {
73   GVariant *state;
74
75   show_action_dialog (action);
76
77   state = g_action_get_state (G_ACTION (action));
78   g_action_change_state (G_ACTION (action), g_variant_new_boolean (!g_variant_get_boolean (state)));
79   g_variant_unref (state);
80 }
81
82 static void
83 activate_radio (GSimpleAction *action,
84                 GVariant      *parameter,
85                 gpointer       user_data)
86 {
87   show_action_infobar (action, parameter, user_data);
88
89   g_action_change_state (G_ACTION (action), parameter);
90 }
91
92 static void
93 activate_about (GSimpleAction *action,
94                 GVariant      *parameter,
95                 gpointer       user_data)
96 {
97   GtkWidget *window = user_data;
98   GdkPixbuf *pixbuf;
99
100   const gchar *authors[] = {
101     "Peter Mattis",
102     "Spencer Kimball",
103     "Josh MacDonald",
104     "and many more...",
105     NULL
106   };
107
108   const gchar *documentors[] = {
109     "Owen Taylor",
110     "Tony Gale",
111     "Matthias Clasen <mclasen@redhat.com>",
112     "and many more...",
113     NULL
114   };
115
116   pixbuf = gdk_pixbuf_new_from_resource ("/application/logos/gtk-logo-48.png", NULL);
117
118   gtk_show_about_dialog (GTK_WINDOW (window),
119                          "program-name", "GTK+ Code Demos",
120                          "version", g_strdup_printf ("%s,\nRunning against GTK+ %d.%d.%d",
121                                                      PACKAGE_VERSION,
122                                                      gtk_get_major_version (),
123                                                      gtk_get_minor_version (),
124                                                      gtk_get_micro_version ()),
125                          "copyright", "(C) 1997-2009 The GTK+ Team",
126                          "license-type", GTK_LICENSE_LGPL_2_1,
127                          "website", "http://www.gtk.org",
128                          "comments", "Program to demonstrate GTK+ functions.",
129                          "authors", authors,
130                          "documenters", documentors,
131                          "logo", pixbuf,
132                          "title", "About GTK+ Code Demos",
133                          NULL);
134   g_object_unref (pixbuf);
135 }
136
137 static void
138 activate_quit (GSimpleAction *action,
139                GVariant      *parameter,
140                gpointer       user_data)
141 {
142   GtkApplication *app = user_data;
143   GtkWidget *win;
144   GList *list, *next;
145
146   list = gtk_application_get_windows (app);
147   while (list)
148     {
149       win = list->data;
150       next = list->next;
151
152       gtk_widget_destroy (GTK_WIDGET (win));
153
154       list = next;
155     }
156 }
157
158 static void
159 register_stock_icons (void)
160 {
161   static gboolean registered = FALSE;
162
163   if (!registered)
164     {
165       GdkPixbuf *pixbuf;
166       GtkIconFactory *factory;
167       GtkIconSet *icon_set;
168
169       static GtkStockItem items[] = {
170         { "demo-gtk-logo", "_GTK!", 0, 0, NULL }
171       };
172
173       registered = TRUE;
174
175       gtk_stock_add (items, G_N_ELEMENTS (items));
176
177       factory = gtk_icon_factory_new ();
178       gtk_icon_factory_add_default (factory);
179
180       pixbuf = gdk_pixbuf_new_from_resource ("/application/logos/gtk-logo-24.png", NULL);
181
182       icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
183       gtk_icon_factory_add (factory, "demo-gtk-logo", icon_set);
184       gtk_icon_set_unref (icon_set);
185       g_object_unref (pixbuf);
186
187       /* Drop our reference to the factory, GTK will hold a reference. */
188       g_object_unref (factory);
189     }
190 }
191
192 static void
193 update_statusbar (GtkTextBuffer *buffer,
194                   GtkStatusbar  *statusbar)
195 {
196   gchar *msg;
197   gint row, col;
198   gint count;
199   GtkTextIter iter;
200
201   /* clear any previous message, underflow is allowed */
202   gtk_statusbar_pop (statusbar, 0);
203
204   count = gtk_text_buffer_get_char_count (buffer);
205
206   gtk_text_buffer_get_iter_at_mark (buffer,
207                                     &iter,
208                                     gtk_text_buffer_get_insert (buffer));
209
210   row = gtk_text_iter_get_line (&iter);
211   col = gtk_text_iter_get_line_offset (&iter);
212
213   msg = g_strdup_printf ("Cursor at row %d column %d - %d chars in document",
214                          row, col, count);
215
216   gtk_statusbar_push (statusbar, 0, msg);
217
218   g_free (msg);
219 }
220
221 static void
222 mark_set_callback (GtkTextBuffer     *buffer,
223                    const GtkTextIter *new_location,
224                    GtkTextMark       *mark,
225                    gpointer           data)
226 {
227   update_statusbar (buffer, GTK_STATUSBAR (data));
228 }
229
230 static void
231 change_theme_state (GSimpleAction *action,
232                     GVariant      *state,
233                     gpointer       user_data)
234 {
235   GtkSettings *settings = gtk_settings_get_default ();
236
237   g_object_set (G_OBJECT (settings),
238                 "gtk-application-prefer-dark-theme",
239                 g_variant_get_boolean (state),
240                 NULL);
241
242   g_simple_action_set_state (action, state);
243 }
244
245 static void
246 change_titlebar_state (GSimpleAction *action,
247                        GVariant      *state,
248                        gpointer       user_data)
249 {
250   GtkWindow *window = user_data;
251
252   gtk_window_set_hide_titlebar_when_maximized (GTK_WINDOW (window),
253                                                g_variant_get_boolean (state));
254
255   g_simple_action_set_state (action, state);
256 }
257
258 static void
259 change_radio_state (GSimpleAction *action,
260                     GVariant      *state,
261                     gpointer       user_data)
262 {
263   g_simple_action_set_state (action, state);
264 }
265
266 static GActionEntry app_entries[] = {
267   { "new", activate_action, NULL, NULL, NULL },
268   { "open", activate_action, NULL, NULL, NULL },
269   { "save", activate_action, NULL, NULL, NULL },
270   { "save-as", activate_action, NULL, NULL, NULL },
271   { "quit", activate_quit, NULL, NULL, NULL },
272   { "dark", activate_toggle, NULL, "false", change_theme_state }
273 };
274
275 static GActionEntry win_entries[] = {
276   { "titlebar", activate_toggle, NULL, "false", change_titlebar_state },
277   { "shape", activate_radio, "s", "'oval'", change_radio_state },
278   { "bold", activate_toggle, NULL, "false", NULL },
279   { "about", activate_about, NULL, NULL, NULL },
280   { "file1", activate_action, NULL, NULL, NULL },
281   { "logo", activate_action, NULL, NULL, NULL }
282 };
283
284 static void
285 clicked_cb (GtkWidget *widget, GtkWidget *info)
286 {
287   gtk_widget_hide (info);
288 }
289
290 static void
291 startup (GApplication *app)
292 {
293   GtkBuilder *builder;
294   GMenuModel *appmenu;
295   GMenuModel *menubar;
296
297   builder = gtk_builder_new ();
298   gtk_builder_add_from_resource (builder, "/application/ui/menus.ui", NULL);
299
300   appmenu = (GMenuModel *)gtk_builder_get_object (builder, "appmenu");
301   menubar = (GMenuModel *)gtk_builder_get_object (builder, "menubar");
302
303   gtk_application_set_app_menu (GTK_APPLICATION (app), appmenu);
304   gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
305
306   g_object_unref (builder);
307 }
308
309 static void
310 activate (GApplication *app)
311 {
312   GtkBuilder *builder;
313   GtkWidget *window;
314   GtkWidget *grid;
315   GtkWidget *contents;
316   GtkWidget *status;
317   GtkWidget *message;
318   GtkWidget *button;
319   GtkWidget *infobar;
320   GtkWidget *menutool;
321   GMenuModel *toolmenu;
322   GtkTextBuffer *buffer;
323
324   window = gtk_application_window_new (GTK_APPLICATION (app));
325   gtk_window_set_title (GTK_WINDOW (window), "Application Class");
326   gtk_window_set_icon_name (GTK_WINDOW (window), "document-open");
327   gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
328
329   g_action_map_add_action_entries (G_ACTION_MAP (window),
330                                    win_entries, G_N_ELEMENTS (win_entries),
331                                    window);
332
333   builder = gtk_builder_new ();
334   gtk_builder_add_from_resource (builder, "/application/ui/application.ui", NULL);
335
336   grid = (GtkWidget *)gtk_builder_get_object (builder, "grid");
337   contents = (GtkWidget *)gtk_builder_get_object (builder, "contents");
338   status = (GtkWidget *)gtk_builder_get_object (builder, "status");
339   message = (GtkWidget *)gtk_builder_get_object (builder, "message");
340   button = (GtkWidget *)gtk_builder_get_object (builder, "button");
341   infobar = (GtkWidget *)gtk_builder_get_object (builder, "infobar");
342   menutool = (GtkWidget *)gtk_builder_get_object (builder, "menutool");
343   toolmenu = (GMenuModel *)gtk_builder_get_object (builder, "toolmenu");
344
345   g_object_set_data (G_OBJECT (window), "message", message);
346   g_object_set_data (G_OBJECT (window), "infobar", infobar);
347
348   gtk_container_add (GTK_CONTAINER (window), grid);
349
350   gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (menutool),
351                                  gtk_menu_new_from_model (toolmenu));
352
353   gtk_widget_grab_focus (contents);
354   g_signal_connect (button, "clicked", G_CALLBACK (clicked_cb), infobar);
355
356   /* Show text widget info in the statusbar */
357   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (contents));
358   g_signal_connect_object (buffer, "changed",
359                            G_CALLBACK (update_statusbar), status, 0);
360   g_signal_connect_object (buffer, "mark-set",
361                            G_CALLBACK (mark_set_callback), status, 0);
362
363   update_statusbar (buffer, GTK_STATUSBAR (status));
364
365   gtk_widget_show_all (window);
366
367   g_object_unref (builder);
368 }
369
370 int
371 main (int argc, char *argv[])
372 {
373   GtkApplication *app;
374   GSettings *settings;
375   GAction *action;
376
377   gtk_init (NULL, NULL);
378
379   register_stock_icons ();
380
381   app = gtk_application_new ("org.gtk.Demo", 0);
382   settings = g_settings_new ("org.gtk.Demo");
383
384   g_action_map_add_action_entries (G_ACTION_MAP (app),
385                                    app_entries, G_N_ELEMENTS (app_entries),
386                                    app);
387
388   action = g_settings_create_action (settings, "color");
389
390   g_action_map_add_action (G_ACTION_MAP (app), action);
391
392   g_signal_connect (app, "startup", G_CALLBACK (startup), NULL);
393   g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
394
395   g_application_run (G_APPLICATION (app), 0, NULL);
396
397   return 0;
398 }
399
400 #else /* !STANDALONE */
401
402 static gboolean name_seen;
403 static GtkWidget *placeholder;
404
405 static void
406 on_name_appeared (GDBusConnection *connection,
407                   const gchar     *name,
408                   const gchar     *name_owner,
409                   gpointer         user_data)
410 {
411   name_seen = TRUE;
412 }
413
414 static void
415 on_name_vanished (GDBusConnection *connection,
416                   const gchar     *name,
417                   gpointer         user_data)
418 {
419   if (!name_seen)
420     return;
421
422   if (placeholder)
423     {
424       gtk_widget_destroy (placeholder);
425       g_object_unref (placeholder);
426       placeholder = NULL;
427     }
428 }
429
430 #ifdef G_OS_WIN32
431 #define APP_EXTENSION ".exe"
432 #else
433 #define APP_EXTENSION
434 #endif
435
436 GtkWidget *
437 do_application (GtkWidget *toplevel)
438 {
439   static guint watch = 0;
440
441   if (watch == 0)
442     watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
443                               "org.gtk.Demo",
444                               0,
445                               on_name_appeared,
446                               on_name_vanished,
447                               NULL, NULL);
448
449   if (placeholder == NULL)
450     {
451       const gchar *command;
452       GError *error = NULL;
453
454       if (g_file_test ("./gtk3-demo-application" APP_EXTENSION, G_FILE_TEST_IS_EXECUTABLE))
455         command = "./gtk3-demo-application" APP_EXTENSION;
456       else
457         command = "gtk3-demo-application";
458
459       if (!g_spawn_command_line_async (command, &error))
460         {
461           g_warning ("%s", error->message);
462           g_error_free (error);
463         }
464
465       placeholder = gtk_label_new ("");
466       g_object_ref_sink (placeholder);
467     }
468   else
469     {
470       g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
471                               "org.gtk.Demo",
472                               "/org/gtk/Demo",
473                               "org.gtk.Actions",
474                               "Activate",
475                               g_variant_new ("(sava{sv})", "quit", NULL, NULL),
476                               NULL,
477                               0,
478                               G_MAXINT,
479                               NULL, NULL);
480     }
481
482   return placeholder;
483 }
484
485 #endif