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