1#include "config.h"
2
3#include <gtk/gtk.h>
4
5typedef GtkApplication DemoApplication;
6typedef GtkApplicationClass DemoApplicationClass;
7
8static GType demo_application_get_type (void);
9G_DEFINE_TYPE (DemoApplication, demo_application, GTK_TYPE_APPLICATION)
10
11typedef struct {
12 GtkApplicationWindow parent_instance;
13
14 GtkWidget *message;
15 GtkWidget *infobar;
16 GtkWidget *status;
17 GtkWidget *menubutton;
18 GMenuModel *toolmenu;
19 GtkTextBuffer *buffer;
20
21 int width;
22 int height;
23 gboolean maximized;
24 gboolean fullscreen;
25} DemoApplicationWindow;
26typedef GtkApplicationWindowClass DemoApplicationWindowClass;
27
28static GType demo_application_window_get_type (void);
29G_DEFINE_TYPE (DemoApplicationWindow, demo_application_window, GTK_TYPE_APPLICATION_WINDOW)
30
31static void create_window (GApplication *app, const char *contents);
32
33static void
34show_action_dialog (GSimpleAction *action)
35{
36 const char *name;
37 GtkWidget *dialog;
38
39 name = g_action_get_name (G_ACTION (action));
40
41 dialog = gtk_message_dialog_new (NULL,
42 flags: GTK_DIALOG_DESTROY_WITH_PARENT,
43 type: GTK_MESSAGE_INFO,
44 buttons: GTK_BUTTONS_CLOSE,
45 message_format: "You activated action: \"%s\"",
46 name);
47
48 g_signal_connect (dialog, "response",
49 G_CALLBACK (gtk_window_destroy), NULL);
50
51 gtk_widget_show (widget: dialog);
52}
53
54static void
55show_action_infobar (GSimpleAction *action,
56 GVariant *parameter,
57 gpointer data)
58{
59 DemoApplicationWindow *window = data;
60 char *text;
61 const char *name;
62 const char *value;
63
64 name = g_action_get_name (G_ACTION (action));
65 value = g_variant_get_string (value: parameter, NULL);
66
67 text = g_strdup_printf (format: "You activated radio action: \"%s\".\n"
68 "Current value: %s", name, value);
69 gtk_label_set_text (GTK_LABEL (window->message), str: text);
70 gtk_widget_show (widget: window->infobar);
71 g_free (mem: text);
72}
73
74static void
75activate_action (GSimpleAction *action,
76 GVariant *parameter,
77 gpointer user_data)
78{
79 show_action_dialog (action);
80}
81
82static void
83activate_new (GSimpleAction *action,
84 GVariant *parameter,
85 gpointer user_data)
86{
87 GApplication *app = user_data;
88
89 create_window (app, NULL);
90}
91
92static void
93open_response_cb (GtkNativeDialog *dialog,
94 int response_id,
95 gpointer user_data)
96{
97 GtkFileChooserNative *native = user_data;
98 GApplication *app = g_object_get_data (G_OBJECT (native), key: "app");
99 GtkWidget *message_dialog;
100 GFile *file;
101 char *contents;
102 GError *error = NULL;
103
104 if (response_id == GTK_RESPONSE_ACCEPT)
105 {
106 file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
107
108 if (g_file_load_contents (file, NULL, contents: &contents, NULL, NULL, error: &error))
109 {
110 create_window (app, contents);
111 g_free (mem: contents);
112 }
113 else
114 {
115 message_dialog = gtk_message_dialog_new (NULL,
116 flags: GTK_DIALOG_DESTROY_WITH_PARENT,
117 type: GTK_MESSAGE_ERROR,
118 buttons: GTK_BUTTONS_CLOSE,
119 message_format: "Error loading file: \"%s\"",
120 error->message);
121 g_signal_connect (message_dialog, "response",
122 G_CALLBACK (gtk_window_destroy), NULL);
123 gtk_widget_show (widget: message_dialog);
124 g_error_free (error);
125 }
126 }
127
128 gtk_native_dialog_destroy (self: GTK_NATIVE_DIALOG (ptr: native));
129 g_object_unref (object: native);
130}
131
132
133static void
134activate_open (GSimpleAction *action,
135 GVariant *parameter,
136 gpointer user_data)
137{
138 GApplication *app = user_data;
139 GtkFileChooserNative *native;
140
141 native = gtk_file_chooser_native_new (title: "Open File",
142 NULL,
143 action: GTK_FILE_CHOOSER_ACTION_OPEN,
144 accept_label: "_Open",
145 cancel_label: "_Cancel");
146
147 g_object_set_data_full (G_OBJECT (native), key: "app", g_object_ref (app), destroy: g_object_unref);
148 g_signal_connect (native,
149 "response",
150 G_CALLBACK (open_response_cb),
151 native);
152
153 gtk_native_dialog_show (self: GTK_NATIVE_DIALOG (ptr: native));
154}
155
156static void
157activate_toggle (GSimpleAction *action,
158 GVariant *parameter,
159 gpointer user_data)
160{
161 GVariant *state;
162
163 show_action_dialog (action);
164
165 state = g_action_get_state (G_ACTION (action));
166 g_action_change_state (G_ACTION (action), value: g_variant_new_boolean (value: !g_variant_get_boolean (value: state)));
167 g_variant_unref (value: state);
168}
169
170static void
171activate_radio (GSimpleAction *action,
172 GVariant *parameter,
173 gpointer user_data)
174{
175 show_action_infobar (action, parameter, data: user_data);
176
177 g_action_change_state (G_ACTION (action), value: parameter);
178}
179
180static void
181activate_about (GSimpleAction *action,
182 GVariant *parameter,
183 gpointer user_data)
184{
185 GtkWidget *window = user_data;
186
187 const char *authors[] = {
188 "Peter Mattis",
189 "Spencer Kimball",
190 "Josh MacDonald",
191 "and many more...",
192 NULL
193 };
194
195 const char *documentors[] = {
196 "Owen Taylor",
197 "Tony Gale",
198 "Matthias Clasen <mclasen@redhat.com>",
199 "and many more...",
200 NULL
201 };
202
203 gtk_show_about_dialog (GTK_WINDOW (window),
204 first_property_name: "program-name", "GTK Code Demos",
205 "version", g_strdup_printf (format: "%s,\nRunning against GTK %d.%d.%d",
206 PACKAGE_VERSION,
207 gtk_get_major_version (),
208 gtk_get_minor_version (),
209 gtk_get_micro_version ()),
210 "copyright", "(C) 1997-2013 The GTK Team",
211 "license-type", GTK_LICENSE_LGPL_2_1,
212 "website", "http://www.gtk.org",
213 "comments", "Program to demonstrate GTK functions.",
214 "authors", authors,
215 "documenters", documentors,
216 "logo-icon-name", "org.gtk.Demo4",
217 "title", "About GTK Code Demos",
218 NULL);
219}
220
221static void
222activate_quit (GSimpleAction *action,
223 GVariant *parameter,
224 gpointer user_data)
225{
226 GtkApplication *app = user_data;
227 GtkWidget *win;
228 GList *list, *next;
229
230 list = gtk_application_get_windows (application: app);
231 while (list)
232 {
233 win = list->data;
234 next = list->next;
235
236 gtk_window_destroy (GTK_WINDOW (win));
237
238 list = next;
239 }
240}
241
242static void
243update_statusbar (GtkTextBuffer *buffer,
244 DemoApplicationWindow *window)
245{
246 char *msg;
247 int row, col;
248 int count;
249 GtkTextIter iter;
250
251 /* clear any previous message, underflow is allowed */
252 gtk_statusbar_pop (GTK_STATUSBAR (window->status), context_id: 0);
253
254 count = gtk_text_buffer_get_char_count (buffer);
255
256 gtk_text_buffer_get_iter_at_mark (buffer,
257 iter: &iter,
258 mark: gtk_text_buffer_get_insert (buffer));
259
260 row = gtk_text_iter_get_line (iter: &iter);
261 col = gtk_text_iter_get_line_offset (iter: &iter);
262
263 msg = g_strdup_printf (format: "Cursor at row %d column %d - %d chars in document",
264 row, col, count);
265
266 gtk_statusbar_push (GTK_STATUSBAR (window->status), context_id: 0, text: msg);
267
268 g_free (mem: msg);
269}
270
271static void
272mark_set_callback (GtkTextBuffer *buffer,
273 const GtkTextIter *new_location,
274 GtkTextMark *mark,
275 DemoApplicationWindow *window)
276{
277 update_statusbar (buffer, window);
278}
279
280static void
281change_theme_state (GSimpleAction *action,
282 GVariant *state,
283 gpointer user_data)
284{
285 GtkSettings *settings = gtk_settings_get_default ();
286
287 g_object_set (G_OBJECT (settings),
288 first_property_name: "gtk-application-prefer-dark-theme",
289 g_variant_get_boolean (value: state),
290 NULL);
291
292 g_simple_action_set_state (simple: action, value: state);
293}
294
295static void
296change_radio_state (GSimpleAction *action,
297 GVariant *state,
298 gpointer user_data)
299{
300 g_simple_action_set_state (simple: action, value: state);
301}
302
303static GActionEntry app_entries[] = {
304 { "new", activate_new, NULL, NULL, NULL },
305 { "open", activate_open, NULL, NULL, NULL },
306 { "save", activate_action, NULL, NULL, NULL },
307 { "save-as", activate_action, NULL, NULL, NULL },
308 { "quit", activate_quit, NULL, NULL, NULL },
309 { "dark", activate_toggle, NULL, "false", change_theme_state }
310};
311
312static GActionEntry win_entries[] = {
313 { "shape", activate_radio, "s", "'oval'", change_radio_state },
314 { "bold", activate_toggle, NULL, "false", NULL },
315 { "about", activate_about, NULL, NULL, NULL },
316 { "file1", activate_action, NULL, NULL, NULL },
317 { "logo", activate_action, NULL, NULL, NULL }
318};
319
320static void
321clicked_cb (GtkWidget *widget, DemoApplicationWindow *window)
322{
323 gtk_widget_hide (widget: window->infobar);
324}
325
326static void
327startup (GApplication *app)
328{
329 GtkBuilder *builder;
330
331 G_APPLICATION_CLASS (demo_application_parent_class)->startup (app);
332
333 builder = gtk_builder_new ();
334 gtk_builder_add_from_resource (builder, resource_path: "/application_demo/menus.ui", NULL);
335
336 gtk_application_set_menubar (GTK_APPLICATION (app),
337 G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")));
338
339 g_object_unref (object: builder);
340}
341
342static void
343create_window (GApplication *app,
344 const char *content)
345{
346 DemoApplicationWindow *window;
347
348 window = (DemoApplicationWindow *)g_object_new (object_type: demo_application_window_get_type (),
349 first_property_name: "application", app,
350 "show-menubar", TRUE,
351 NULL);
352 if (content)
353 gtk_text_buffer_set_text (buffer: window->buffer, text: content, len: -1);
354
355 gtk_window_present (GTK_WINDOW (window));
356}
357
358static void
359activate (GApplication *app)
360{
361 create_window (app, NULL);
362}
363
364static void
365demo_application_init (DemoApplication *app)
366{
367 GSettings *settings;
368 GAction *action;
369
370 settings = g_settings_new (schema_id: "org.gtk.Demo4");
371
372 g_action_map_add_action_entries (G_ACTION_MAP (app),
373 entries: app_entries, G_N_ELEMENTS (app_entries),
374 user_data: app);
375
376 action = g_settings_create_action (settings, key: "color");
377
378 g_action_map_add_action (G_ACTION_MAP (app), action);
379
380 g_object_unref (object: settings);
381}
382
383static void
384demo_application_class_init (DemoApplicationClass *class)
385{
386 GApplicationClass *app_class = G_APPLICATION_CLASS (class);
387
388 app_class->startup = startup;
389 app_class->activate = activate;
390}
391
392static void
393demo_application_window_store_state (DemoApplicationWindow *win)
394{
395 GSettings *settings;
396
397 settings = g_settings_new (schema_id: "org.gtk.Demo4");
398 g_settings_set (settings, key: "window-size", format: "(ii)", win->width, win->height);
399 g_settings_set_boolean (settings, key: "maximized", value: win->maximized);
400 g_settings_set_boolean (settings, key: "fullscreen", value: win->fullscreen);
401 g_object_unref (object: settings);
402}
403
404static void
405demo_application_window_load_state (DemoApplicationWindow *win)
406{
407 GSettings *settings;
408
409 settings = g_settings_new (schema_id: "org.gtk.Demo4");
410 g_settings_get (settings, key: "window-size", format: "(ii)", &win->width, &win->height);
411 win->maximized = g_settings_get_boolean (settings, key: "maximized");
412 win->fullscreen = g_settings_get_boolean (settings, key: "fullscreen");
413 g_object_unref (object: settings);
414}
415
416static void
417demo_application_window_init (DemoApplicationWindow *window)
418{
419 GtkWidget *popover;
420
421 window->width = -1;
422 window->height = -1;
423 window->maximized = FALSE;
424 window->fullscreen = FALSE;
425
426 gtk_widget_init_template (GTK_WIDGET (window));
427
428 popover = gtk_popover_menu_new_from_model (model: window->toolmenu);
429 gtk_menu_button_set_popover (GTK_MENU_BUTTON (window->menubutton), popover);
430
431 g_action_map_add_action_entries (G_ACTION_MAP (window),
432 entries: win_entries, G_N_ELEMENTS (win_entries),
433 user_data: window);
434}
435
436static void
437demo_application_window_constructed (GObject *object)
438{
439 DemoApplicationWindow *window = (DemoApplicationWindow *)object;
440
441 demo_application_window_load_state (win: window);
442
443 gtk_window_set_default_size (GTK_WINDOW (window), width: window->width, height: window->height);
444
445 if (window->maximized)
446 gtk_window_maximize (GTK_WINDOW (window));
447
448 if (window->fullscreen)
449 gtk_window_fullscreen (GTK_WINDOW (window));
450
451 G_OBJECT_CLASS (demo_application_window_parent_class)->constructed (object);
452}
453
454static void
455demo_application_window_size_allocate (GtkWidget *widget,
456 int width,
457 int height,
458 int baseline)
459{
460 DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
461
462 GTK_WIDGET_CLASS (demo_application_window_parent_class)->size_allocate (widget,
463 width,
464 height,
465 baseline);
466
467 if (!window->maximized && !window->fullscreen)
468 gtk_window_get_default_size (GTK_WINDOW (window), width: &window->width, height: &window->height);
469}
470
471static void
472surface_state_changed (GtkWidget *widget)
473{
474 DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
475 GdkToplevelState new_state;
476
477 new_state = gdk_toplevel_get_state (toplevel: GDK_TOPLEVEL (ptr: gtk_native_get_surface (self: GTK_NATIVE (ptr: widget))));
478 window->maximized = (new_state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0;
479 window->fullscreen = (new_state & GDK_TOPLEVEL_STATE_FULLSCREEN) != 0;
480}
481
482static void
483demo_application_window_realize (GtkWidget *widget)
484{
485 GTK_WIDGET_CLASS (demo_application_window_parent_class)->realize (widget);
486
487 g_signal_connect_swapped (gtk_native_get_surface (GTK_NATIVE (widget)), "notify::state",
488 G_CALLBACK (surface_state_changed), widget);
489}
490
491static void
492demo_application_window_unrealize (GtkWidget *widget)
493{
494 g_signal_handlers_disconnect_by_func (gtk_native_get_surface (GTK_NATIVE (widget)),
495 surface_state_changed, widget);
496
497 GTK_WIDGET_CLASS (demo_application_window_parent_class)->unrealize (widget);
498}
499
500static void
501demo_application_window_dispose (GObject *object)
502{
503 DemoApplicationWindow *window = (DemoApplicationWindow *)object;
504
505 demo_application_window_store_state (win: window);
506
507 G_OBJECT_CLASS (demo_application_window_parent_class)->dispose (object);
508}
509
510static void
511demo_application_window_class_init (DemoApplicationWindowClass *class)
512{
513 GObjectClass *object_class = G_OBJECT_CLASS (class);
514 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
515
516 object_class->constructed = demo_application_window_constructed;
517 object_class->dispose = demo_application_window_dispose;
518
519 widget_class->size_allocate = demo_application_window_size_allocate;
520 widget_class->realize = demo_application_window_realize;
521 widget_class->unrealize = demo_application_window_unrealize;
522
523 gtk_widget_class_set_template_from_resource (widget_class, resource_name: "/application_demo/application.ui");
524 gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, message);
525 gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, infobar);
526 gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, status);
527 gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, buffer);
528 gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, menubutton);
529 gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, toolmenu);
530 gtk_widget_class_bind_template_callback (widget_class, clicked_cb);
531 gtk_widget_class_bind_template_callback (widget_class, update_statusbar);
532 gtk_widget_class_bind_template_callback (widget_class, mark_set_callback);
533}
534
535int
536main (int argc, char *argv[])
537{
538 GtkApplication *app;
539
540 app = GTK_APPLICATION (g_object_new (demo_application_get_type (),
541 "application-id", "org.gtk.Demo4.App",
542 "flags", G_APPLICATION_HANDLES_OPEN,
543 NULL));
544
545 return g_application_run (G_APPLICATION (app), argc: 0, NULL);
546}
547

source code of gtk/demos/gtk-demo/application.c