1#include <stdlib.h>
2#include <gtk/gtk.h>
3
4typedef struct
5{
6 GtkApplication parent_instance;
7
8 guint quit_inhibit;
9 GMenu *time;
10 guint timeout;
11} BloatPad;
12
13typedef GtkApplicationClass BloatPadClass;
14
15GType bloat_pad_get_type (void);
16G_DEFINE_TYPE (BloatPad, bloat_pad, GTK_TYPE_APPLICATION)
17
18static void
19activate_toggle (GSimpleAction *action,
20 GVariant *parameter,
21 gpointer user_data)
22{
23 GVariant *state;
24
25 state = g_action_get_state (G_ACTION (action));
26 g_action_change_state (G_ACTION (action), value: g_variant_new_boolean (value: !g_variant_get_boolean (value: state)));
27 g_variant_unref (value: state);
28}
29
30static void
31activate_radio (GSimpleAction *action,
32 GVariant *parameter,
33 gpointer user_data)
34{
35 g_action_change_state (G_ACTION (action), value: parameter);
36}
37
38static void
39change_fullscreen_state (GSimpleAction *action,
40 GVariant *state,
41 gpointer user_data)
42{
43 if (g_variant_get_boolean (value: state))
44 gtk_window_fullscreen (window: user_data);
45 else
46 gtk_window_unfullscreen (window: user_data);
47
48 g_simple_action_set_state (simple: action, value: state);
49}
50
51static void
52change_busy_state (GSimpleAction *action,
53 GVariant *state,
54 gpointer user_data)
55{
56 GtkWindow *window = user_data;
57 GApplication *application = G_APPLICATION (gtk_window_get_application (window));
58
59 /* do this twice to test multiple busy counter increases */
60 if (g_variant_get_boolean (value: state))
61 {
62 g_application_mark_busy (application);
63 g_application_mark_busy (application);
64 }
65 else
66 {
67 g_application_unmark_busy (application);
68 g_application_unmark_busy (application);
69 }
70
71 g_simple_action_set_state (simple: action, value: state);
72}
73
74static void
75change_justify_state (GSimpleAction *action,
76 GVariant *state,
77 gpointer user_data)
78{
79 GtkTextView *text = g_object_get_data (object: user_data, key: "bloatpad-text");
80 const char *str;
81
82 str = g_variant_get_string (value: state, NULL);
83
84 if (g_str_equal (v1: str, v2: "left"))
85 gtk_text_view_set_justification (text_view: text, justification: GTK_JUSTIFY_LEFT);
86 else if (g_str_equal (v1: str, v2: "center"))
87 gtk_text_view_set_justification (text_view: text, justification: GTK_JUSTIFY_CENTER);
88 else if (g_str_equal (v1: str, v2: "right"))
89 gtk_text_view_set_justification (text_view: text, justification: GTK_JUSTIFY_RIGHT);
90 else
91 /* ignore this attempted change */
92 return;
93
94 g_simple_action_set_state (simple: action, value: state);
95}
96
97static void
98window_copy (GSimpleAction *action,
99 GVariant *parameter,
100 gpointer user_data)
101{
102 GtkWindow *window = GTK_WINDOW (user_data);
103 GtkTextView *text = g_object_get_data (object: (GObject*)window, key: "bloatpad-text");
104
105 gtk_text_buffer_copy_clipboard (buffer: gtk_text_view_get_buffer (text_view: text),
106 clipboard: gtk_widget_get_clipboard (GTK_WIDGET (text)));
107}
108
109static void
110window_paste (GSimpleAction *action,
111 GVariant *parameter,
112 gpointer user_data)
113{
114 GtkWindow *window = GTK_WINDOW (user_data);
115 GtkTextView *text = g_object_get_data (object: (GObject*)window, key: "bloatpad-text");
116
117 gtk_text_buffer_paste_clipboard (buffer: gtk_text_view_get_buffer (text_view: text),
118 clipboard: gtk_widget_get_clipboard (GTK_WIDGET (text)),
119 NULL,
120 TRUE);
121
122}
123
124static void
125activate_clear (GSimpleAction *action,
126 GVariant *parameter,
127 gpointer user_data)
128{
129 GtkWindow *window = GTK_WINDOW (user_data);
130 GtkTextView *text = g_object_get_data (object: (GObject*)window, key: "bloatpad-text");
131
132 gtk_text_buffer_set_text (buffer: gtk_text_view_get_buffer (text_view: text), text: "", len: -1);
133}
134
135static void
136activate_clear_all (GSimpleAction *action,
137 GVariant *parameter,
138 gpointer user_data)
139{
140 GtkApplication *app = GTK_APPLICATION (user_data);
141 GList *iter;
142
143 for (iter = gtk_application_get_windows (application: app); iter; iter = iter->next)
144 g_action_group_activate_action (action_group: iter->data, action_name: "clear", NULL);
145}
146
147static void
148text_buffer_changed_cb (GtkTextBuffer *buffer,
149 gpointer user_data)
150{
151 GtkWindow *window = user_data;
152 BloatPad *app;
153 int old_n, n;
154
155 app = (BloatPad *) gtk_window_get_application (window);
156
157 n = gtk_text_buffer_get_char_count (buffer);
158 if (n > 0)
159 {
160 if (!app->quit_inhibit)
161 app->quit_inhibit = gtk_application_inhibit (GTK_APPLICATION (app),
162 window: gtk_application_get_active_window (GTK_APPLICATION (app)),
163 flags: GTK_APPLICATION_INHIBIT_LOGOUT,
164 reason: "bloatpad can't save, so you can't logout; erase your text");
165 }
166 else
167 {
168 if (app->quit_inhibit)
169 {
170 gtk_application_uninhibit (GTK_APPLICATION (app), cookie: app->quit_inhibit);
171 app->quit_inhibit = 0;
172 }
173 }
174
175 g_simple_action_set_enabled (G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (window), "clear")), enabled: n > 0);
176
177 if (n > 0)
178 {
179 GSimpleAction *spellcheck;
180 spellcheck = g_simple_action_new (name: "spell-check", NULL);
181 g_action_map_add_action (G_ACTION_MAP (window), G_ACTION (spellcheck));
182 }
183 else
184 g_action_map_remove_action (G_ACTION_MAP (window), action_name: "spell-check");
185
186 old_n = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (buffer), "line-count"));
187 n = gtk_text_buffer_get_line_count (buffer);
188 g_object_set_data (G_OBJECT (buffer), key: "line-count", GINT_TO_POINTER (n));
189
190 if (old_n < 3 && n == 3)
191 {
192 GNotification *notification = g_notification_new (title: "Three lines of text");
193 g_notification_set_body (notification, body: "Keep up the good work!");
194 g_notification_add_button (notification, label: "Start over", detailed_action: "app.clear-all");
195 g_application_send_notification (G_APPLICATION (app), id: "three-lines", notification);
196 g_object_unref (object: notification);
197 }
198}
199
200static void
201fullscreen_changed (GObject *object,
202 GParamSpec *pspec,
203 gpointer user_data)
204{
205 if (gtk_window_is_fullscreen (GTK_WINDOW (object)))
206 gtk_button_set_icon_name (GTK_BUTTON (user_data), icon_name: "view-restore-symbolic");
207 else
208 gtk_button_set_icon_name (GTK_BUTTON (user_data), icon_name: "view-fullscreen-symbolic");
209}
210
211static GActionEntry win_entries[] = {
212 { "copy", window_copy, NULL, NULL, NULL },
213 { "paste", window_paste, NULL, NULL, NULL },
214 { "fullscreen", activate_toggle, NULL, "false", change_fullscreen_state },
215 { "busy", activate_toggle, NULL, "false", change_busy_state },
216 { "justify", activate_radio, "s", "'left'", change_justify_state },
217 { "clear", activate_clear, NULL, NULL, NULL }
218
219};
220
221static void
222new_window (GApplication *app,
223 GFile *file)
224{
225 GtkWidget *window, *grid, *scrolled, *view;
226 GtkWidget *toolbar;
227 GtkWidget *button;
228
229 window = gtk_application_window_new (GTK_APPLICATION (app));
230 gtk_window_set_default_size (window: (GtkWindow*)window, width: 640, height: 480);
231 g_action_map_add_action_entries (G_ACTION_MAP (window), entries: win_entries, G_N_ELEMENTS (win_entries), user_data: window);
232 gtk_window_set_title (GTK_WINDOW (window), title: "Bloatpad");
233 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (window), TRUE);
234
235 grid = gtk_grid_new ();
236 gtk_window_set_child (GTK_WINDOW (window), child: grid);
237
238 toolbar = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0);
239 gtk_widget_add_css_class (widget: toolbar, css_class: "toolbar");
240 button = gtk_toggle_button_new ();
241 gtk_button_set_icon_name (GTK_BUTTON (button), icon_name: "format-justify-left");
242 gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), detailed_action_name: "win.justify::left");
243 gtk_box_append (GTK_BOX (toolbar), child: button);
244
245 button = gtk_toggle_button_new ();
246 gtk_button_set_icon_name (GTK_BUTTON (button), icon_name: "format-justify-center");
247 gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), detailed_action_name: "win.justify::center");
248 gtk_box_append (GTK_BOX (toolbar), child: button);
249
250 button = gtk_toggle_button_new ();
251 gtk_button_set_icon_name (GTK_BUTTON (button), icon_name: "format-justify-right");
252 gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (button), detailed_action_name: "win.justify::right");
253 gtk_box_append (GTK_BOX (toolbar), child: button);
254
255 button = gtk_toggle_button_new ();
256 gtk_button_set_icon_name (GTK_BUTTON (button), icon_name: "view-fullscreen-symbolic");
257 gtk_actionable_set_action_name (GTK_ACTIONABLE (button), action_name: "win.fullscreen");
258 gtk_box_append (GTK_BOX (toolbar), child: button);
259 g_signal_connect (window, "notify::fullscreened", G_CALLBACK (fullscreen_changed), button);
260
261 gtk_grid_attach (GTK_GRID (grid), child: toolbar, column: 0, row: 0, width: 1, height: 1);
262
263 scrolled = gtk_scrolled_window_new ();
264 gtk_widget_set_hexpand (widget: scrolled, TRUE);
265 gtk_widget_set_vexpand (widget: scrolled, TRUE);
266 gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (scrolled), TRUE);
267 view = gtk_text_view_new ();
268
269 g_object_set_data (object: (GObject*)window, key: "bloatpad-text", data: view);
270
271 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), child: view);
272
273 gtk_grid_attach (GTK_GRID (grid), child: scrolled, column: 0, row: 1, width: 1, height: 1);
274
275 if (file != NULL)
276 {
277 char *contents;
278 gsize length;
279
280 if (g_file_load_contents (file, NULL, contents: &contents, length: &length, NULL, NULL))
281 {
282 GtkTextBuffer *buffer;
283
284 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
285 gtk_text_buffer_set_text (buffer, text: contents, len: length);
286 g_free (mem: contents);
287 }
288 }
289 g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)), "changed",
290 G_CALLBACK (text_buffer_changed_cb), window);
291 text_buffer_changed_cb (buffer: gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)), user_data: window);
292
293 gtk_widget_show (GTK_WIDGET (window));
294}
295
296static void
297bloat_pad_activate (GApplication *application)
298{
299 new_window (app: application, NULL);
300}
301
302static void
303bloat_pad_open (GApplication *application,
304 GFile **files,
305 int n_files,
306 const char *hint)
307{
308 int i;
309
310 for (i = 0; i < n_files; i++)
311 new_window (app: application, file: files[i]);
312}
313
314static void
315bloat_pad_finalize (GObject *object)
316{
317 G_OBJECT_CLASS (bloat_pad_parent_class)->finalize (object);
318}
319
320static void
321new_activated (GSimpleAction *action,
322 GVariant *parameter,
323 gpointer user_data)
324{
325 GApplication *app = user_data;
326
327 g_application_activate (application: app);
328}
329
330static void
331about_activated (GSimpleAction *action,
332 GVariant *parameter,
333 gpointer user_data)
334{
335 gtk_show_about_dialog (NULL,
336 first_property_name: "program-name", "Bloatpad",
337 "title", "About Bloatpad",
338 "comments", "Not much to say, really.",
339 NULL);
340}
341
342static void
343quit_activated (GSimpleAction *action,
344 GVariant *parameter,
345 gpointer user_data)
346{
347 GApplication *app = user_data;
348
349 g_application_quit (application: app);
350}
351
352static void
353combo_changed (GtkComboBox *combo,
354 gpointer user_data)
355{
356 GtkDialog *dialog = user_data;
357 GtkEntry *entry = g_object_get_data (object: user_data, key: "entry");
358 const char *action;
359 char **accels;
360 char *str;
361
362 action = gtk_combo_box_get_active_id (combo_box: combo);
363
364 if (!action)
365 return;
366
367 accels = gtk_application_get_accels_for_action (application: gtk_window_get_application (window: user_data), detailed_action_name: action);
368 str = g_strjoinv (separator: ",", str_array: accels);
369 g_strfreev (str_array: accels);
370
371 gtk_editable_set_text (GTK_EDITABLE (entry), text: str);
372 gtk_dialog_set_response_sensitive (dialog, response_id: GTK_RESPONSE_APPLY, FALSE);
373}
374
375static void
376entry_changed (GtkEntry *entry,
377 GParamSpec *pspec,
378 gpointer user_data)
379{
380 GtkDialog *dialog = user_data;
381
382 gtk_dialog_set_response_sensitive (dialog, response_id: GTK_RESPONSE_APPLY, TRUE);
383}
384
385static void
386response (GtkDialog *dialog,
387 guint response_id,
388 gpointer user_data)
389{
390 GtkEntry *entry = g_object_get_data (object: user_data, key: "entry");
391 GtkComboBox *combo = g_object_get_data (object: user_data, key: "combo");
392 const char *action;
393 const char *str;
394 char **accels;
395
396 if (response_id == GTK_RESPONSE_CANCEL)
397 {
398 gtk_window_destroy (GTK_WINDOW (dialog));
399 return;
400 }
401
402 action = gtk_combo_box_get_active_id (combo_box: combo);
403
404 if (!action)
405 return;
406
407 str = gtk_editable_get_text (GTK_EDITABLE (entry));
408 accels = g_strsplit (string: str, delimiter: ",", max_tokens: 0);
409
410 gtk_application_set_accels_for_action (application: gtk_window_get_application (window: user_data), detailed_action_name: action, accels: (const char **) accels);
411 g_strfreev (str_array: accels);
412
413 gtk_dialog_set_response_sensitive (dialog, response_id: GTK_RESPONSE_APPLY, FALSE);
414}
415
416static void
417edit_accels (GSimpleAction *action,
418 GVariant *parameter,
419 gpointer user_data)
420{
421 GtkApplication *app = user_data;
422 GtkWidget *combo;
423 GtkWidget *entry;
424 char **actions;
425 GtkWidget *dialog;
426 int i;
427
428 dialog = gtk_dialog_new_with_buttons (title: "Accelerators",
429 NULL,
430 flags: GTK_DIALOG_USE_HEADER_BAR,
431 first_button_text: "Close", GTK_RESPONSE_CANCEL,
432 "Set", GTK_RESPONSE_APPLY,
433 NULL);
434
435 gtk_window_set_application (GTK_WINDOW (dialog), application: app);
436 actions = gtk_application_list_action_descriptions (application: app);
437
438 combo = gtk_combo_box_text_new ();
439 g_object_set (object: gtk_dialog_get_content_area (GTK_DIALOG (dialog)),
440 first_property_name: "margin-top", 10,
441 "margin-bottom", 10,
442 "margin-start", 10,
443 "margin-end", 10,
444 "spacing", 10,
445 NULL);
446
447 gtk_box_append (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), child: combo);
448 for (i = 0; actions[i]; i++)
449 gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: actions[i], text: actions[i]);
450 g_signal_connect (combo, "changed", G_CALLBACK (combo_changed), dialog);
451
452 entry = gtk_entry_new ();
453 gtk_widget_set_hexpand (widget: entry, TRUE);
454 g_signal_connect (entry, "notify::text", G_CALLBACK (entry_changed), dialog);
455
456 gtk_box_append (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), child: entry);
457 g_signal_connect (dialog, "response", G_CALLBACK (response), dialog);
458 g_object_set_data (G_OBJECT (dialog), key: "combo", data: combo);
459 g_object_set_data (G_OBJECT (dialog), key: "entry", data: entry);
460
461 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), index_: 0);
462
463 gtk_widget_show (widget: dialog);
464}
465
466static gboolean
467update_time (gpointer user_data)
468{
469 BloatPad *bloatpad = user_data;
470 GDateTime *now;
471 char *time;
472
473 while (g_menu_model_get_n_items (G_MENU_MODEL (bloatpad->time)))
474 g_menu_remove (menu: bloatpad->time, position: 0);
475
476 g_message ("Updating the time menu (which should be open now)...");
477
478 now = g_date_time_new_now_local ();
479 time = g_date_time_format (datetime: now, format: "%c");
480 g_menu_append (menu: bloatpad->time, label: time, NULL);
481 g_date_time_unref (datetime: now);
482 g_free (mem: time);
483
484 return G_SOURCE_CONTINUE;
485}
486
487static void
488time_active_changed (GSimpleAction *action,
489 GVariant *state,
490 gpointer user_data)
491{
492 BloatPad *bloatpad = user_data;
493
494 if (g_variant_get_boolean (value: state))
495 {
496 if (!bloatpad->timeout)
497 {
498 bloatpad->timeout = g_timeout_add (interval: 1000, function: update_time, data: bloatpad);
499 update_time (user_data: bloatpad);
500 }
501 }
502 else
503 {
504 if (bloatpad->timeout)
505 {
506 g_source_remove (tag: bloatpad->timeout);
507 bloatpad->timeout = 0;
508 }
509 }
510
511 g_simple_action_set_state (simple: action, value: state);
512}
513
514static GActionEntry app_entries[] = {
515 { "new", new_activated, NULL, NULL, NULL },
516 { "about", about_activated, NULL, NULL, NULL },
517 { "quit", quit_activated, NULL, NULL, NULL },
518 { "edit-accels", edit_accels },
519 { "time-active", NULL, NULL, "false", time_active_changed },
520 { "clear-all", activate_clear_all }
521};
522
523static void
524dump_accels (GtkApplication *app)
525{
526 char **actions;
527 int i;
528
529 actions = gtk_application_list_action_descriptions (application: app);
530 for (i = 0; actions[i]; i++)
531 {
532 char **accels;
533 char *str;
534
535 accels = gtk_application_get_accels_for_action (application: app, detailed_action_name: actions[i]);
536
537 str = g_strjoinv (separator: ",", str_array: accels);
538 g_print (format: "%s -> %s\n", actions[i], str);
539 g_strfreev (str_array: accels);
540 g_free (mem: str);
541 }
542 g_strfreev (str_array: actions);
543}
544
545static void
546bloat_pad_startup (GApplication *application)
547{
548 BloatPad *bloatpad = (BloatPad*) application;
549 GtkApplication *app = GTK_APPLICATION (application);
550 GMenu *menu;
551 GMenuItem *item;
552 GBytes *bytes;
553 GIcon *icon;
554 GIcon *icon2;
555 GEmblem *emblem;
556 GFile *file;
557 int i;
558 struct {
559 const char *action_and_target;
560 const char *accelerators[2];
561 } accels[] = {
562 { "app.new", { "<Control>n", NULL } },
563 { "app.quit", { "<Control>q", NULL } },
564 { "win.copy", { "<Control>c", NULL } },
565 { "win.paste", { "<Control>p", NULL } },
566 { "win.justify::left", { "<Control>l", NULL } },
567 { "win.justify::center", { "<Control>m", NULL } },
568 { "win.justify::right", { "<Control>r", NULL } }
569 };
570
571 G_APPLICATION_CLASS (bloat_pad_parent_class)
572 ->startup (application);
573
574 g_action_map_add_action_entries (G_ACTION_MAP (application), entries: app_entries, G_N_ELEMENTS (app_entries), user_data: application);
575
576 for (i = 0; i < G_N_ELEMENTS (accels); i++)
577 gtk_application_set_accels_for_action (application: app, detailed_action_name: accels[i].action_and_target, accels: accels[i].accelerators);
578
579 menu = gtk_application_get_menu_by_id (GTK_APPLICATION (application), id: "icon-menu");
580
581 file = g_file_new_for_uri (uri: "resource:///org/gtk/libgtk/icons/16x16/actions/insert-image.png");
582 icon = g_file_icon_new (file);
583 item = g_menu_item_new (label: "File Icon", NULL);
584 g_menu_item_set_icon (menu_item: item, icon);
585 g_menu_append_item (menu, item);
586 g_object_unref (object: item);
587 g_object_unref (object: icon);
588 g_object_unref (object: file);
589
590 icon = g_themed_icon_new (iconname: "edit-find");
591 item = g_menu_item_new (label: "Themed Icon", NULL);
592 g_menu_item_set_icon (menu_item: item, icon);
593 g_menu_append_item (menu, item);
594 g_object_unref (object: item);
595 g_object_unref (object: icon);
596
597 bytes = g_resources_lookup_data (path: "/org/gtk/libgtk/icons/16x16/actions/media-eject.png", lookup_flags: 0, NULL);
598 icon = g_bytes_icon_new (bytes);
599 item = g_menu_item_new (label: "Bytes Icon", NULL);
600 g_menu_item_set_icon (menu_item: item, icon);
601 g_menu_append_item (menu, item);
602 g_object_unref (object: item);
603 g_object_unref (object: icon);
604 g_bytes_unref (bytes);
605
606 icon = G_ICON (gdk_texture_new_from_resource ("/org/gtk/libgtk/icons/16x16/actions/folder-new.png"));
607 item = g_menu_item_new (label: "Texture", NULL);
608 g_menu_item_set_icon (menu_item: item, icon);
609 g_menu_append_item (menu, item);
610 g_object_unref (object: item);
611 g_object_unref (object: icon);
612
613 file = g_file_new_for_uri (uri: "resource:///org/gtk/libgtk/icons/16x16/actions/bookmark-new.png");
614 icon = g_file_icon_new (file);
615 emblem = g_emblem_new (icon);
616 g_object_unref (object: icon);
617 g_object_unref (object: file);
618 file = g_file_new_for_uri (uri: "resource:///org/gtk/libgtk/icons/16x16/actions/dialog-warning.png");
619 icon2 = g_file_icon_new (file);
620 icon = g_emblemed_icon_new (icon: icon2, emblem);
621 item = g_menu_item_new (label: "Emblemed Icon", NULL);
622 g_menu_item_set_icon (menu_item: item, icon);
623 g_menu_append_item (menu, item);
624 g_object_unref (object: item);
625 g_object_unref (object: icon);
626 g_object_unref (object: icon2);
627 g_object_unref (object: file);
628 g_object_unref (object: emblem);
629
630 icon = g_themed_icon_new (iconname: "weather-severe-alert-symbolic");
631 item = g_menu_item_new (label: "Symbolic Icon", NULL);
632 g_menu_item_set_icon (menu_item: item, icon);
633 g_menu_append_item (menu, item);
634 g_object_unref (object: item);
635 g_object_unref (object: icon);
636
637 const char *new_accels[] = { "<Control>n", "<Control>t", NULL };
638 gtk_application_set_accels_for_action (GTK_APPLICATION (application), detailed_action_name: "app.new", accels: new_accels);
639
640 dump_accels (GTK_APPLICATION (application));
641 //gtk_application_set_menubar (GTK_APPLICATION (application), G_MENU_MODEL (gtk_builder_get_object (builder, "app-menu")));
642 bloatpad->time = gtk_application_get_menu_by_id (GTK_APPLICATION (application), id: "time-menu");
643}
644
645static void
646bloat_pad_shutdown (GApplication *application)
647{
648 BloatPad *bloatpad = (BloatPad *) application;
649
650 if (bloatpad->timeout)
651 {
652 g_source_remove (tag: bloatpad->timeout);
653 bloatpad->timeout = 0;
654 }
655
656 G_APPLICATION_CLASS (bloat_pad_parent_class)
657 ->shutdown (application);
658}
659
660static void
661bloat_pad_init (BloatPad *app)
662{
663}
664
665static void
666bloat_pad_class_init (BloatPadClass *class)
667{
668 GApplicationClass *application_class = G_APPLICATION_CLASS (class);
669 GObjectClass *object_class = G_OBJECT_CLASS (class);
670
671 application_class->startup = bloat_pad_startup;
672 application_class->shutdown = bloat_pad_shutdown;
673 application_class->activate = bloat_pad_activate;
674 application_class->open = bloat_pad_open;
675
676 object_class->finalize = bloat_pad_finalize;
677
678}
679
680static BloatPad *
681bloat_pad_new (void)
682{
683 BloatPad *bloat_pad;
684
685 g_set_application_name (application_name: "Bloatpad");
686
687 bloat_pad = g_object_new (object_type: bloat_pad_get_type (),
688 first_property_name: "application-id", "org.gtk.bloatpad",
689 "flags", G_APPLICATION_HANDLES_OPEN,
690 "inactivity-timeout", 30000,
691 "register-session", TRUE,
692 NULL);
693
694 return bloat_pad;
695}
696
697int
698main (int argc, char **argv)
699{
700 BloatPad *bloat_pad;
701 int status;
702 const char *accels[] = { "F11", NULL };
703
704 bloat_pad = bloat_pad_new ();
705
706 gtk_application_set_accels_for_action (GTK_APPLICATION (bloat_pad),
707 detailed_action_name: "win.fullscreen", accels);
708
709 status = g_application_run (G_APPLICATION (bloat_pad), argc, argv);
710
711 g_object_unref (object: bloat_pad);
712
713 return status;
714}
715

source code of gtk/examples/bp/bloatpad.c