1/* widget-factory: a collection of widgets, for easy theme testing
2 *
3 * Copyright (C) 2011 Canonical Ltd
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authored by Andrea Cimitan <andrea.cimitan@canonical.com>
19 */
20
21#include "config.h"
22
23#include <stdlib.h>
24
25#include <glib/gi18n.h>
26#include <gtk/gtk.h>
27
28#include "demo_conf.h"
29
30static void
31change_dark_state (GSimpleAction *action,
32 GVariant *state,
33 gpointer user_data)
34{
35 GtkSettings *settings = gtk_settings_get_default ();
36
37 g_object_set (G_OBJECT (settings),
38 first_property_name: "gtk-application-prefer-dark-theme",
39 g_variant_get_boolean (value: state),
40 NULL);
41
42 g_simple_action_set_state (simple: action, value: state);
43}
44
45static void
46change_theme_state (GSimpleAction *action,
47 GVariant *state,
48 gpointer user_data)
49{
50 GtkSettings *settings = gtk_settings_get_default ();
51 const char *s;
52 const char *theme;
53
54 g_simple_action_set_state (simple: action, value: state);
55
56 s = g_variant_get_string (value: state, NULL);
57
58 if (strcmp (s1: s, s2: "default") == 0)
59 theme = "Default";
60 else if (strcmp (s1: s, s2: "dark") == 0)
61 theme = "Default-dark";
62 else if (strcmp (s1: s, s2: "hc") == 0)
63 theme = "Default-hc";
64 else if (strcmp (s1: s, s2: "hc-dark") == 0)
65 theme = "Default-hc-dark";
66 else if (strcmp (s1: s, s2: "current") == 0)
67 {
68 gtk_settings_reset_property (settings, name: "gtk-theme-name");
69 gtk_settings_reset_property (settings, name: "gtk-application-prefer-dark-theme");
70 return;
71 }
72 else
73 return;
74
75 g_object_set (G_OBJECT (settings),
76 first_property_name: "gtk-theme-name", theme,
77 "gtk-application-prefer-dark-theme", FALSE,
78 NULL);
79}
80
81static void
82change_fullscreen (GSimpleAction *action,
83 GVariant *state,
84 gpointer user_data)
85{
86 GtkWindow *window = user_data;
87
88 if (g_variant_get_boolean (value: state))
89 gtk_window_fullscreen (window);
90 else
91 gtk_window_unfullscreen (window);
92
93 g_simple_action_set_state (simple: action, value: state);
94}
95
96static GtkWidget *page_stack;
97
98static void
99transition_speed_changed (GtkRange *range,
100 gpointer data)
101{
102 double value;
103
104 value = gtk_range_get_value (range);
105 gtk_stack_set_transition_duration (GTK_STACK (page_stack), duration: (int)value);
106}
107
108static void
109change_transition_state (GSimpleAction *action,
110 GVariant *state,
111 gpointer user_data)
112{
113 GtkStackTransitionType transition;
114
115 if (g_variant_get_boolean (value: state))
116 transition = GTK_STACK_TRANSITION_TYPE_CROSSFADE;
117 else
118 transition = GTK_STACK_TRANSITION_TYPE_NONE;
119
120 gtk_stack_set_transition_type (GTK_STACK (page_stack), transition);
121
122 g_simple_action_set_state (simple: action, value: state);
123}
124
125static gboolean
126get_idle (gpointer data)
127{
128 GtkWidget *window = data;
129 GtkApplication *app = gtk_window_get_application (GTK_WINDOW (window));
130
131 gtk_widget_set_sensitive (widget: window, TRUE);
132 gdk_surface_set_cursor (surface: gtk_native_get_surface (self: GTK_NATIVE (ptr: window)), NULL);
133 g_application_unmark_busy (G_APPLICATION (app));
134
135 return G_SOURCE_REMOVE;
136}
137
138static void
139get_busy (GSimpleAction *action,
140 GVariant *parameter,
141 gpointer user_data)
142{
143 GtkWidget *window = user_data;
144 GdkCursor *cursor;
145 GtkApplication *app = gtk_window_get_application (GTK_WINDOW (window));
146
147 g_application_mark_busy (G_APPLICATION (app));
148 cursor = gdk_cursor_new_from_name (name: "wait", NULL);
149 gdk_surface_set_cursor (surface: gtk_native_get_surface (self: GTK_NATIVE (ptr: window)), cursor);
150 g_object_unref (object: cursor);
151 g_timeout_add (interval: 5000, function: get_idle, data: window);
152
153 gtk_widget_set_sensitive (widget: window, FALSE);
154}
155
156static int current_page = 0;
157static gboolean
158on_page (int i)
159{
160 return current_page == i;
161}
162
163static void
164activate_search (GSimpleAction *action,
165 GVariant *parameter,
166 gpointer user_data)
167{
168 GtkWidget *window = user_data;
169 GtkWidget *searchbar;
170
171 if (!on_page (i: 2))
172 return;
173
174 searchbar = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "searchbar"));
175 gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (searchbar), TRUE);
176}
177
178static void
179activate_delete (GSimpleAction *action,
180 GVariant *parameter,
181 gpointer user_data)
182{
183 GtkWidget *window = user_data;
184 GtkWidget *infobar;
185
186 g_print (format: "Activate action delete\n");
187
188 if (!on_page (i: 2))
189 return;
190
191 infobar = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "infobar"));
192 gtk_widget_show (widget: infobar);
193}
194
195static void populate_flowbox (GtkWidget *flowbox);
196
197static void
198activate_background (GSimpleAction *action,
199 GVariant *parameter,
200 gpointer user_data)
201{
202 GtkWidget *window = user_data;
203 GtkWidget *dialog;
204 GtkWidget *flowbox;
205
206 if (!on_page (i: 2))
207 return;
208
209 dialog = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "selection_dialog"));
210 flowbox = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "selection_flowbox"));
211
212 gtk_widget_show (widget: dialog);
213 populate_flowbox (flowbox);
214}
215
216static void
217activate_open (GSimpleAction *action,
218 GVariant *parameter,
219 gpointer user_data)
220{
221 GtkWidget *window = user_data;
222 GtkWidget *button;
223
224 if (!on_page (i: 3))
225 return;
226
227 button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "open_menubutton"));
228 g_signal_emit_by_name (instance: button, detailed_signal: "clicked");
229}
230
231static void
232activate_record (GSimpleAction *action,
233 GVariant *parameter,
234 gpointer user_data)
235{
236 GtkWidget *window = user_data;
237 GtkWidget *button;
238
239 if (!on_page (i: 3))
240 return;
241
242 button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "record_button"));
243 g_signal_emit_by_name (instance: button, detailed_signal: "clicked");
244}
245
246static void
247activate_lock (GSimpleAction *action,
248 GVariant *parameter,
249 gpointer user_data)
250{
251 GtkWidget *window = user_data;
252 GtkWidget *button;
253
254 if (!on_page (i: 3))
255 return;
256
257 button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "lockbutton"));
258 g_signal_emit_by_name (instance: button, detailed_signal: "clicked");
259}
260
261static void
262activate_about (GSimpleAction *action,
263 GVariant *parameter,
264 gpointer user_data)
265{
266 GtkApplication *app = user_data;
267 GtkWindow *window;
268 GtkWidget *button;
269 const char *authors[] = {
270 "Andrea Cimitan",
271 "Cosimo Cecchi",
272 NULL
273 };
274 const char *maintainers[] = {
275 "The GTK Team",
276 NULL
277 };
278 char *version;
279 char *os_name;
280 char *os_version;
281 GString *s;
282 GtkWidget *dialog;
283
284 s = g_string_new (init: "");
285
286 window = gtk_application_get_active_window (application: app);
287 button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "open_menubutton"));
288 gtk_menu_button_popdown (GTK_MENU_BUTTON (button));
289
290 os_name = g_get_os_info (G_OS_INFO_KEY_NAME);
291 os_version = g_get_os_info (G_OS_INFO_KEY_VERSION_ID);
292 if (os_name && os_version)
293 g_string_append_printf (string: s, format: "OS\t%s %s\n\n", os_name, os_version);
294 g_string_append (string: s, val: "System libraries\n");
295 g_string_append_printf (string: s, format: "\tGLib\t%d.%d.%d\n",
296 glib_major_version,
297 glib_minor_version,
298 glib_micro_version);
299 g_string_append_printf (string: s, format: "\tPango\t%s\n",
300 pango_version_string ());
301 g_string_append_printf (string: s, format: "\tGTK \t%d.%d.%d\n",
302 gtk_get_major_version (),
303 gtk_get_minor_version (),
304 gtk_get_micro_version ());
305 g_string_append_printf (string: s, format: "\nA link can appear here: <http://www.gtk.org>");
306
307 version = g_strdup_printf (format: "%s%s%s\nRunning against GTK %d.%d.%d",
308 PACKAGE_VERSION,
309 g_strcmp0 (str1: PROFILE, str2: "devel") == 0 ? "-" : "",
310 g_strcmp0 (str1: PROFILE, str2: "devel") == 0 ? VCS_TAG : "",
311 gtk_get_major_version (),
312 gtk_get_minor_version (),
313 gtk_get_micro_version ());
314
315 dialog = g_object_new (GTK_TYPE_ABOUT_DIALOG,
316 first_property_name: "transient-for", gtk_application_get_active_window (application: app),
317 "modal", TRUE,
318 "program-name", g_strcmp0 (str1: PROFILE, str2: "devel") == 0
319 ? "GTK Widget Factory (Development)"
320 : "GTK Widget Factory",
321 "version", version,
322 "copyright", "© 1997—2021 The GTK Team",
323 "license-type", GTK_LICENSE_LGPL_2_1,
324 "website", "http://www.gtk.org",
325 "comments", "Program to demonstrate GTK themes and widgets",
326 "authors", authors,
327 "logo-icon-name", "org.gtk.WidgetFactory4",
328 "title", "About GTK Widget Factory",
329 "system-information", s->str,
330 NULL);
331
332 gtk_about_dialog_add_credit_section (GTK_ABOUT_DIALOG (dialog),
333 _("Maintained by"), people: maintainers);
334
335 gtk_window_present (GTK_WINDOW (dialog));
336
337 g_string_free (string: s, TRUE);
338 g_free (mem: version);
339 g_free (mem: os_name);
340 g_free (mem: os_version);
341}
342
343static void
344activate_shortcuts_window (GSimpleAction *action,
345 GVariant *parameter,
346 gpointer user_data)
347{
348 GtkApplication *app = user_data;
349 GtkWindow *window;
350 GtkWidget *button;
351
352 window = gtk_application_get_active_window (application: app);
353 button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "open_menubutton"));
354 gtk_menu_button_popdown (GTK_MENU_BUTTON (button));
355 gtk_widget_activate_action (GTK_WIDGET (window), name: "win.show-help-overlay", NULL);
356}
357
358static void
359activate_quit (GSimpleAction *action,
360 GVariant *parameter,
361 gpointer user_data)
362{
363 GtkApplication *app = user_data;
364 GtkWidget *win;
365 GList *list, *next;
366
367 list = gtk_application_get_windows (application: app);
368 while (list)
369 {
370 win = list->data;
371 next = list->next;
372
373 gtk_window_destroy (GTK_WINDOW (win));
374
375 list = next;
376 }
377}
378
379static void
380activate_inspector (GSimpleAction *action,
381 GVariant *parameter,
382 gpointer user_data)
383{
384 gtk_window_set_interactive_debugging (TRUE);
385}
386
387static void
388print_operation_done (GtkPrintOperation *op,
389 GtkPrintOperationResult res,
390 gpointer data)
391{
392 GError *error = NULL;
393
394 switch (res)
395 {
396 case GTK_PRINT_OPERATION_RESULT_ERROR:
397 gtk_print_operation_get_error (op, error: &error);
398 g_print (format: "Printing failed: %s\n", error->message);
399 g_clear_error (err: &error);
400 break;
401 case GTK_PRINT_OPERATION_RESULT_APPLY:
402 break;
403 case GTK_PRINT_OPERATION_RESULT_CANCEL:
404 g_print (format: "Printing was canceled\n");
405 break;
406 case GTK_PRINT_OPERATION_RESULT_IN_PROGRESS:
407 return;
408 default:
409 g_assert_not_reached ();
410 break;
411 }
412
413 g_object_unref (object: op);
414}
415
416static void
417print_operation_begin (GtkPrintOperation *op,
418 GtkPrintContext *context,
419 gpointer data)
420{
421 gtk_print_operation_set_n_pages (op, n_pages: 1);
422}
423
424static void
425print_operation_page (GtkPrintOperation *op,
426 GtkPrintContext *context,
427 int page,
428 gpointer data)
429{
430 cairo_t *cr;
431 double width;
432 double aspect_ratio;
433 GdkSnapshot *snapshot;
434 GdkPaintable *paintable;
435 GskRenderNode *node;
436
437 g_print (format: "Save the trees!\n");
438
439 cr = gtk_print_context_get_cairo_context (context);
440 width = gtk_print_context_get_width (context);
441
442 snapshot = gtk_snapshot_new ();
443 paintable = gtk_widget_paintable_new (GTK_WIDGET (data));
444 aspect_ratio = gdk_paintable_get_intrinsic_aspect_ratio (paintable);
445 gdk_paintable_snapshot (paintable, snapshot, width, height: width / aspect_ratio);
446 node = gtk_snapshot_free_to_node (snapshot);
447
448 gsk_render_node_draw (node, cr);
449
450 gsk_render_node_unref (node);
451
452 g_object_unref (object: paintable);
453}
454
455static void
456activate_print (GSimpleAction *action,
457 GVariant *parameter,
458 gpointer user_data)
459{
460 GtkWindow *window = GTK_WINDOW (user_data);
461 GtkPrintOperation *op;
462 GtkPrintOperationResult res;
463
464 op = gtk_print_operation_new ();
465 gtk_print_operation_set_allow_async (op, TRUE);
466 g_signal_connect (op, "begin-print", G_CALLBACK (print_operation_begin), NULL);
467 g_signal_connect (op, "draw-page", G_CALLBACK (print_operation_page), window);
468 g_signal_connect (op, "done", G_CALLBACK (print_operation_done), NULL);
469
470 gtk_print_operation_set_embed_page_setup (op, TRUE);
471
472 res = gtk_print_operation_run (op, action: GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, parent: window, NULL);
473
474 if (res == GTK_PRINT_OPERATION_RESULT_IN_PROGRESS)
475 return;
476
477 print_operation_done (op, res, NULL);
478}
479
480static void
481spin_value_changed (GtkAdjustment *adjustment, GtkWidget *label)
482{
483 GtkWidget *w;
484 int v;
485 char *text;
486
487 v = (int)gtk_adjustment_get_value (adjustment);
488
489 if ((v % 3) == 0)
490 {
491 text = g_strdup_printf (format: "%d is a multiple of 3", v);
492 gtk_label_set_label (GTK_LABEL (label), str: text);
493 g_free (mem: text);
494 }
495
496 w = gtk_widget_get_ancestor (widget: label, GTK_TYPE_REVEALER);
497 gtk_revealer_set_reveal_child (GTK_REVEALER (w), reveal_child: (v % 3) == 0);
498}
499
500static void
501dismiss (GtkWidget *button)
502{
503 GtkWidget *w;
504
505 w = gtk_widget_get_ancestor (widget: button, GTK_TYPE_REVEALER);
506 gtk_revealer_set_reveal_child (GTK_REVEALER (w), FALSE);
507}
508
509static void
510spin_value_reset (GtkWidget *button, GtkAdjustment *adjustment)
511{
512 gtk_adjustment_set_value (adjustment, value: 50.0);
513 dismiss (button);
514}
515
516static int pulse_time = 250;
517static int pulse_entry_mode = 0;
518
519static void
520remove_pulse (gpointer pulse_id)
521{
522 g_source_remove (GPOINTER_TO_UINT (pulse_id));
523}
524
525static gboolean
526pulse_it (GtkWidget *widget)
527{
528 guint pulse_id;
529
530 if (GTK_IS_ENTRY (widget))
531 gtk_entry_progress_pulse (GTK_ENTRY (widget));
532 else
533 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (widget));
534
535 pulse_id = g_timeout_add (interval: pulse_time, function: (GSourceFunc)pulse_it, data: widget);
536 g_object_set_data_full (G_OBJECT (widget), key: "pulse_id", GUINT_TO_POINTER (pulse_id), destroy: remove_pulse);
537
538 return G_SOURCE_REMOVE;
539}
540
541static void
542update_pulse_time (GtkAdjustment *adjustment, GtkWidget *widget)
543{
544 double value;
545 guint pulse_id;
546
547 value = gtk_adjustment_get_value (adjustment);
548
549 pulse_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "pulse_id"));
550
551 /* vary between 50 and 450 */
552 pulse_time = 50 + 4 * value;
553
554 if (value == 100)
555 {
556 g_object_set_data (G_OBJECT (widget), key: "pulse_id", NULL);
557 }
558 else if (value < 100)
559 {
560 if (pulse_id == 0 && (GTK_IS_PROGRESS_BAR (widget) || pulse_entry_mode % 3 == 2))
561 {
562 pulse_id = g_timeout_add (interval: pulse_time, function: (GSourceFunc)pulse_it, data: widget);
563 g_object_set_data_full (G_OBJECT (widget), key: "pulse_id", GUINT_TO_POINTER (pulse_id), destroy: remove_pulse);
564 }
565 }
566}
567
568static void
569on_entry_icon_release (GtkEntry *entry,
570 GtkEntryIconPosition icon_pos,
571 gpointer user_data)
572{
573 if (icon_pos != GTK_ENTRY_ICON_SECONDARY)
574 return;
575
576 pulse_entry_mode++;
577
578 if (pulse_entry_mode % 3 == 0)
579 {
580 g_object_set_data (G_OBJECT (entry), key: "pulse_id", NULL);
581 gtk_entry_set_progress_fraction (entry, fraction: 0);
582 }
583 else if (pulse_entry_mode % 3 == 1)
584 gtk_entry_set_progress_fraction (entry, fraction: 0.25);
585 else if (pulse_entry_mode % 3 == 2)
586 {
587 if (pulse_time - 50 < 400)
588 {
589 gtk_entry_set_progress_pulse_step (entry, fraction: 0.1);
590 pulse_it (GTK_WIDGET (entry));
591 }
592 }
593}
594
595#define EPSILON (1e-10)
596
597static void
598on_scale_button_value_changed (GtkScaleButton *button,
599 double value,
600 gpointer user_data)
601{
602 GtkAdjustment *adjustment;
603 double val;
604 char *str;
605
606 adjustment = gtk_scale_button_get_adjustment (button);
607 val = gtk_scale_button_get_value (button);
608
609 if (val < (gtk_adjustment_get_lower (adjustment) + EPSILON))
610 {
611 str = g_strdup (_("Muted"));
612 }
613 else if (val >= (gtk_adjustment_get_upper (adjustment) - EPSILON))
614 {
615 str = g_strdup (_("Full Volume"));
616 }
617 else
618 {
619 int percent;
620
621 percent = (int) (100. * val / (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment)) + .5);
622
623 str = g_strdup_printf (C_("volume percentage", "%d %%"), percent);
624 }
625
626 gtk_widget_set_tooltip_text (GTK_WIDGET (button), text: str);
627
628 g_free (mem: str);
629}
630
631static void
632on_record_button_toggled (GtkToggleButton *button,
633 gpointer user_data)
634{
635
636 if (gtk_toggle_button_get_active (toggle_button: button))
637 gtk_widget_remove_css_class (GTK_WIDGET (button), css_class: "destructive-action");
638 else
639 gtk_widget_add_css_class (GTK_WIDGET (button), css_class: "destructive-action");
640}
641
642static void
643on_page_combo_changed (GtkComboBox *combo,
644 gpointer user_data)
645{
646 GtkWidget *from;
647 GtkWidget *to;
648 GtkWidget *print;
649
650 from = GTK_WIDGET (g_object_get_data (G_OBJECT (combo), "range_from_spin"));
651 to = GTK_WIDGET (g_object_get_data (G_OBJECT (combo), "range_to_spin"));
652 print = GTK_WIDGET (g_object_get_data (G_OBJECT (combo), "print_button"));
653
654 switch (gtk_combo_box_get_active (combo_box: combo))
655 {
656 case 0: /* Range */
657 gtk_widget_set_sensitive (widget: from, TRUE);
658 gtk_widget_set_sensitive (widget: to, TRUE);
659 gtk_widget_set_sensitive (widget: print, TRUE);
660 break;
661 case 1: /* All */
662 gtk_widget_set_sensitive (widget: from, FALSE);
663 gtk_widget_set_sensitive (widget: to, FALSE);
664 gtk_spin_button_set_value (GTK_SPIN_BUTTON (from), value: 1);
665 gtk_spin_button_set_value (GTK_SPIN_BUTTON (to), value: 99);
666 gtk_widget_set_sensitive (widget: print, TRUE);
667 break;
668 case 2: /* Current */
669 gtk_widget_set_sensitive (widget: from, FALSE);
670 gtk_widget_set_sensitive (widget: to, FALSE);
671 gtk_spin_button_set_value (GTK_SPIN_BUTTON (from), value: 7);
672 gtk_spin_button_set_value (GTK_SPIN_BUTTON (to), value: 7);
673 gtk_widget_set_sensitive (widget: print, TRUE);
674 break;
675 case 4:
676 gtk_widget_set_sensitive (widget: from, FALSE);
677 gtk_widget_set_sensitive (widget: to, FALSE);
678 gtk_widget_set_sensitive (widget: print, FALSE);
679 break;
680 default:;
681 }
682}
683
684static void
685on_range_from_changed (GtkSpinButton *from)
686{
687 GtkSpinButton *to;
688 int v1, v2;
689
690 to = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (from), "range_to_spin"));
691
692 v1 = gtk_spin_button_get_value_as_int (spin_button: from);
693 v2 = gtk_spin_button_get_value_as_int (spin_button: to);
694
695 if (v1 > v2)
696 gtk_spin_button_set_value (spin_button: to, value: v1);
697}
698
699static void
700on_range_to_changed (GtkSpinButton *to)
701{
702 GtkSpinButton *from;
703 int v1, v2;
704
705 from = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (to), "range_from_spin"));
706
707 v1 = gtk_spin_button_get_value_as_int (spin_button: from);
708 v2 = gtk_spin_button_get_value_as_int (spin_button: to);
709
710 if (v1 > v2)
711 gtk_spin_button_set_value (spin_button: from, value: v2);
712}
713
714static GdkContentProvider *
715on_picture_drag_prepare (GtkDragSource *source,
716 double x,
717 double y,
718 gpointer unused)
719{
720 GtkWidget *picture;
721
722 picture = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
723
724 return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, gtk_picture_get_paintable (self: GTK_PICTURE (ptr: picture)));
725}
726
727static gboolean
728on_picture_drop (GtkDropTarget *dest,
729 const GValue *value,
730 double x,
731 double y,
732 gpointer unused)
733{
734 GtkWidget *picture;
735 GdkPaintable *paintable;
736
737 picture = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
738 paintable = g_value_get_object (value);
739
740 gtk_picture_set_paintable (self: GTK_PICTURE (ptr: picture), paintable);
741
742 return TRUE;
743}
744
745static void
746info_bar_response (GtkWidget *infobar, int response_id)
747{
748 if (response_id == GTK_RESPONSE_CLOSE)
749 gtk_widget_hide (widget: infobar);
750}
751
752static void
753show_dialog (GtkWidget *button, GtkWidget *dialog)
754{
755 gtk_widget_show (widget: dialog);
756}
757
758static void
759close_dialog (GtkWidget *dialog)
760{
761 gtk_widget_hide (widget: dialog);
762}
763
764static void
765set_needs_attention (GtkWidget *page, gboolean needs_attention)
766{
767 GtkWidget *stack;
768
769 stack = gtk_widget_get_parent (widget: page);
770 g_object_set (object: gtk_stack_get_page (GTK_STACK (stack), child: page),
771 first_property_name: "needs-attention", needs_attention,
772 NULL);
773}
774
775static gboolean
776demand_attention (gpointer stack)
777{
778 GtkWidget *page;
779
780 page = gtk_stack_get_child_by_name (GTK_STACK (stack), name: "page3");
781 set_needs_attention (page, TRUE);
782
783 return G_SOURCE_REMOVE;
784}
785
786static void
787action_dialog_button_clicked (GtkButton *button, GtkWidget *page)
788{
789 g_timeout_add (interval: 1000, function: demand_attention, data: page);
790}
791
792static void
793page_changed_cb (GtkWidget *stack, GParamSpec *pspec, gpointer data)
794{
795 const char *name;
796 GtkWidget *window;
797 GtkWidget *page;
798
799 if (gtk_widget_in_destruction (widget: stack))
800 return;
801
802 name = gtk_stack_get_visible_child_name (GTK_STACK (stack));
803
804 window = gtk_widget_get_ancestor (widget: stack, GTK_TYPE_APPLICATION_WINDOW);
805 g_object_set (object: gtk_application_window_get_help_overlay (GTK_APPLICATION_WINDOW (window)),
806 first_property_name: "view-name", name,
807 NULL);
808
809 if (g_str_equal (v1: name, v2: "page1"))
810 current_page = 1;
811 else if (g_str_equal (v1: name, v2: "page2"))
812 current_page = 2;
813 if (g_str_equal (v1: name, v2: "page3"))
814 {
815 current_page = 3;
816 page = gtk_stack_get_visible_child (GTK_STACK (stack));
817 set_needs_attention (GTK_WIDGET (page), FALSE);
818 }
819}
820
821static void
822populate_model (GtkTreeStore *store)
823{
824 GtkTreeIter iter, parent0, parent1, parent2, parent3;
825
826 gtk_tree_store_append (tree_store: store, iter: &iter, NULL);
827 gtk_tree_store_set (tree_store: store, iter: &iter,
828 0, "Charlemagne",
829 1, "742",
830 2, "814",
831 -1);
832 parent0 = iter;
833 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent0);
834 gtk_tree_store_set (tree_store: store, iter: &iter,
835 0, "Pepin the Short",
836 1, "714",
837 2, "768",
838 -1);
839 parent1 = iter;
840 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent1);
841 gtk_tree_store_set (tree_store: store, iter: &iter,
842 0, "Charles Martel",
843 1, "688",
844 2, "741",
845 -1);
846 parent2 = iter;
847 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent2);
848 gtk_tree_store_set (tree_store: store, iter: &iter,
849 0, "Pepin of Herstal",
850 1, "635",
851 2, "714",
852 -1);
853 parent3 = iter;
854 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent3);
855 gtk_tree_store_set (tree_store: store, iter: &iter,
856 0, "Ansegisel",
857 1, "602 or 610",
858 2, "murdered before 679",
859 -1);
860 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent3);
861 gtk_tree_store_set (tree_store: store, iter: &iter,
862 0, "Begga",
863 1, "615",
864 2, "693",
865 -1);
866 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent2);
867 gtk_tree_store_set (tree_store: store, iter: &iter,
868 0, "Alpaida",
869 -1);
870 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent1);
871 gtk_tree_store_set (tree_store: store, iter: &iter,
872 0, "Rotrude",
873 -1);
874 parent2 = iter;
875 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent2);
876 gtk_tree_store_set (tree_store: store, iter: &iter,
877 0, "Liévin de Trèves",
878 -1);
879 parent3 = iter;
880 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent3);
881 gtk_tree_store_set (tree_store: store, iter: &iter,
882 0, "Guérin",
883 -1);
884 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent3);
885 gtk_tree_store_set (tree_store: store, iter: &iter,
886 0, "Gunza",
887 -1);
888 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent2);
889 gtk_tree_store_set (tree_store: store, iter: &iter,
890 0, "Willigarde de Bavière",
891 -1);
892 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent0);
893 gtk_tree_store_set (tree_store: store, iter: &iter,
894 0, "Bertrada of Laon",
895 1, "710",
896 2, "783",
897 -1);
898 parent1 = iter;
899 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent1);
900 gtk_tree_store_set (tree_store: store, iter: &iter,
901 0, "Caribert of Laon",
902 2, "before 762",
903 -1);
904 parent2 = iter;
905 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent2);
906 gtk_tree_store_set (tree_store: store, iter: &iter,
907 0, "Unknown",
908 -1);
909 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent2);
910 gtk_tree_store_set (tree_store: store, iter: &iter,
911 0, "Bertrada of Prüm",
912 1, "ca. 670",
913 2, "after 721",
914 -1);
915 gtk_tree_store_append (tree_store: store, iter: &iter, parent: &parent1);
916 gtk_tree_store_set (tree_store: store, iter: &iter,
917 0, "Gisele of Aquitaine",
918 -1);
919 gtk_tree_store_append (tree_store: store, iter: &iter, NULL);
920 gtk_tree_store_set (tree_store: store, iter: &iter, 3, TRUE, -1);
921 gtk_tree_store_append (tree_store: store, iter: &iter, NULL);
922 gtk_tree_store_set (tree_store: store, iter: &iter,
923 0, "Attila the Hun",
924 1, "ca. 390",
925 2, "453",
926 -1);
927}
928
929static gboolean
930row_separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
931{
932 gboolean is_sep;
933
934 gtk_tree_model_get (tree_model: model, iter, 3, &is_sep, -1);
935
936 return is_sep;
937}
938
939static void
940update_title_header (GtkListBoxRow *row,
941 GtkListBoxRow *before,
942 gpointer data)
943{
944 GtkWidget *header;
945 char *title;
946
947 header = gtk_list_box_row_get_header (row);
948 title = (char *)g_object_get_data (G_OBJECT (row), key: "title");
949 if (!header && title)
950 {
951 title = g_strdup_printf (format: "<b>%s</b>", title);
952
953 header = gtk_label_new (str: title);
954 gtk_label_set_use_markup (GTK_LABEL (header), TRUE);
955 gtk_widget_set_halign (widget: header, align: GTK_ALIGN_START);
956 gtk_widget_set_margin_top (widget: header, margin: 12);
957 gtk_widget_set_margin_start (widget: header, margin: 6);
958 gtk_widget_set_margin_end (widget: header, margin: 6);
959 gtk_widget_set_margin_bottom (widget: header, margin: 6);
960 gtk_widget_show (widget: header);
961
962 gtk_list_box_row_set_header (row, header);
963
964 g_free (mem: title);
965 }
966}
967
968static void
969overshot (GtkScrolledWindow *sw, GtkPositionType pos, GtkWidget *widget)
970{
971 GtkWidget *box, *row, *label, *swatch;
972 GdkRGBA rgba;
973 const char *color;
974 char *text;
975 GtkWidget *silver;
976 GtkWidget *gold;
977
978 silver = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "Silver"));
979 gold = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "Gold"));
980
981 if (pos == GTK_POS_TOP)
982 {
983 if (silver)
984 {
985 gtk_list_box_remove (GTK_LIST_BOX (widget), child: silver);
986 g_object_set_data (G_OBJECT (widget), key: "Silver", NULL);
987 }
988 if (gold)
989 {
990 gtk_list_box_remove (GTK_LIST_BOX (widget), child: gold);
991 g_object_set_data (G_OBJECT (widget), key: "Gold", NULL);
992 }
993
994 return;
995 }
996
997
998 if (gold)
999 return;
1000 else if (silver)
1001 color = "Gold";
1002 else
1003 color = "Silver";
1004
1005 row = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 20);
1006 text = g_strconcat (string1: "<b>", color, "</b>", NULL);
1007 label = gtk_label_new (str: text);
1008 g_free (mem: text);
1009 g_object_set (object: label,
1010 first_property_name: "use-markup", TRUE,
1011 "halign", GTK_ALIGN_START,
1012 "valign", GTK_ALIGN_CENTER,
1013 "hexpand", TRUE,
1014 "margin-start", 6,
1015 "margin-end", 6,
1016 "margin-top", 6,
1017 "margin-bottom", 6,
1018 "xalign", 0.0,
1019 NULL);
1020 gtk_box_append (GTK_BOX (row), child: label);
1021 gdk_rgba_parse (rgba: &rgba, spec: color);
1022 swatch = g_object_new (object_type: g_type_from_name (name: "GtkColorSwatch"),
1023 first_property_name: "rgba", &rgba,
1024 "can-focus", FALSE,
1025 "selectable", FALSE,
1026 "halign", GTK_ALIGN_END,
1027 "valign", GTK_ALIGN_CENTER,
1028 "margin-start", 6,
1029 "margin-end", 6,
1030 "margin-top", 6,
1031 "margin-bottom", 6,
1032 "height-request", 24,
1033 NULL);
1034 box = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0);
1035 gtk_box_append (GTK_BOX (box), child: swatch);
1036 gtk_box_append (GTK_BOX (row), child: box);
1037 gtk_list_box_insert (GTK_LIST_BOX (widget), child: row, position: -1);
1038 row = gtk_widget_get_parent (widget: row);
1039 gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
1040 g_object_set_data (G_OBJECT (widget), key: color, data: row);
1041 g_object_set_data (G_OBJECT (row), key: "color", data: (gpointer)color);
1042}
1043
1044static void
1045rgba_changed (GtkColorChooser *chooser, GParamSpec *pspec, GtkListBox *box)
1046{
1047 gtk_list_box_select_row (box, NULL);
1048}
1049
1050static void
1051set_color (GtkListBox *box, GtkListBoxRow *row, GtkColorChooser *chooser)
1052{
1053 const char *color;
1054 GdkRGBA rgba;
1055
1056 if (!row)
1057 return;
1058
1059 color = (const char *)g_object_get_data (G_OBJECT (row), key: "color");
1060
1061 if (!color)
1062 return;
1063
1064 if (gdk_rgba_parse (rgba: &rgba, spec: color))
1065 {
1066 g_signal_handlers_block_by_func (chooser, rgba_changed, box);
1067 gtk_color_chooser_set_rgba (chooser, color: &rgba);
1068 g_signal_handlers_unblock_by_func (chooser, rgba_changed, box);
1069 }
1070}
1071
1072static void
1073populate_colors (GtkWidget *widget, GtkWidget *chooser)
1074{
1075 struct { const char *name; const char *color; const char *title; } colors[] = {
1076 { "2.5", "#C8828C", "Red" },
1077 { "5", "#C98286", NULL },
1078 { "7.5", "#C9827F", NULL },
1079 { "10", "#C98376", NULL },
1080 { "2.5", "#C8856D", "Red/Yellow" },
1081 { "5", "#C58764", NULL },
1082 { "7.5", "#C1895E", NULL },
1083 { "10", "#BB8C56", NULL },
1084 { "2.5", "#B58F4F", "Yellow" },
1085 { "5", "#AD924B", NULL },
1086 { "7.5", "#A79548", NULL },
1087 { "10", "#A09749", NULL },
1088 { "2.5", "#979A4E", "Yellow/Green" },
1089 { "5", "#8D9C55", NULL },
1090 { "7.5", "#7F9F62", NULL },
1091 { "10", "#73A06E", NULL },
1092 { "2.5", "#65A27C", "Green" },
1093 { "5", "#5CA386", NULL },
1094 { "7.5", "#57A38D", NULL },
1095 { "10", "#52A394", NULL },
1096 { "2.5", "#4EA39A", "Green/Blue" },
1097 { "5", "#49A3A2", NULL },
1098 { "7.5", "#46A2AA", NULL },
1099 { "10", "#46A1B1", NULL },
1100 { "2.5", "#49A0B8", "Blue" },
1101 { "5", "#529EBD", NULL },
1102 { "7.5", "#5D9CC1", NULL },
1103 { "10", "#689AC3", NULL },
1104 { "2.5", "#7597C5", "Blue/Purple" },
1105 { "5", "#8095C6", NULL },
1106 { "7.5", "#8D91C6", NULL },
1107 { "10", "#988EC4", NULL },
1108 { "2.5", "#A08CC1", "Purple" },
1109 { "5", "#A88ABD", NULL },
1110 { "7.5", "#B187B6", NULL },
1111 { "10", "#B786B0", NULL },
1112 { "2.5", "#BC84A9", "Purple/Red" },
1113 { "5", "#C183A0", NULL },
1114 { "7.5", "#C48299", NULL },
1115 { "10", "#C68292", NULL }
1116 };
1117 int i;
1118 GtkWidget *row, *box, *label, *swatch;
1119 GtkWidget *sw;
1120 GdkRGBA rgba;
1121
1122 gtk_list_box_set_header_func (GTK_LIST_BOX (widget), update_header: update_title_header, NULL, NULL);
1123
1124 for (i = 0; i < G_N_ELEMENTS (colors); i++)
1125 {
1126 row = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 20);
1127 label = gtk_label_new (str: colors[i].name);
1128 g_object_set (object: label,
1129 first_property_name: "halign", GTK_ALIGN_START,
1130 "valign", GTK_ALIGN_CENTER,
1131 "margin-start", 6,
1132 "margin-end", 6,
1133 "margin-top", 6,
1134 "margin-bottom", 6,
1135 "hexpand", TRUE,
1136 "xalign", 0.0,
1137 NULL);
1138 gtk_box_append (GTK_BOX (row), child: label);
1139 gdk_rgba_parse (rgba: &rgba, spec: colors[i].color);
1140 swatch = g_object_new (object_type: g_type_from_name (name: "GtkColorSwatch"),
1141 first_property_name: "rgba", &rgba,
1142 "selectable", FALSE,
1143 "can-focus", FALSE,
1144 "halign", GTK_ALIGN_END,
1145 "valign", GTK_ALIGN_CENTER,
1146 "margin-start", 6,
1147 "margin-end", 6,
1148 "margin-top", 6,
1149 "margin-bottom", 6,
1150 "height-request", 24,
1151 NULL);
1152 box = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0);
1153 gtk_box_append (GTK_BOX (box), child: swatch);
1154 gtk_box_append (GTK_BOX (row), child: box);
1155 gtk_list_box_insert (GTK_LIST_BOX (widget), child: row, position: -1);
1156 row = gtk_widget_get_parent (widget: row);
1157 gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
1158 g_object_set_data (G_OBJECT (row), key: "color", data: (gpointer)colors[i].color);
1159 if (colors[i].title)
1160 g_object_set_data (G_OBJECT (row), key: "title", data: (gpointer)colors[i].title);
1161 }
1162
1163 g_signal_connect (widget, "row-selected", G_CALLBACK (set_color), chooser);
1164
1165 gtk_list_box_invalidate_headers (GTK_LIST_BOX (widget));
1166
1167 sw = gtk_widget_get_ancestor (widget, GTK_TYPE_SCROLLED_WINDOW);
1168 g_signal_connect (sw, "edge-overshot", G_CALLBACK (overshot), widget);
1169}
1170
1171typedef struct {
1172 GtkWidget *flowbox;
1173 char *filename;
1174} BackgroundData;
1175
1176static void
1177add_background (GtkWidget *flowbox,
1178 const char *filename,
1179 GdkPixbuf *pixbuf,
1180 gboolean is_resource)
1181{
1182 GtkWidget *child;
1183
1184 child = gtk_picture_new_for_pixbuf (pixbuf);
1185 gtk_widget_set_size_request (widget: child, width: 110, height: 70);
1186 gtk_flow_box_insert (GTK_FLOW_BOX (flowbox), widget: child, position: -1);
1187 child = gtk_widget_get_parent (widget: child);
1188 g_object_set_data_full (G_OBJECT (child), key: "filename", data: g_strdup (str: filename), destroy: g_free);
1189 if (is_resource)
1190 g_object_set_data (G_OBJECT (child), key: "is-resource", GINT_TO_POINTER (1));
1191}
1192
1193static void
1194background_loaded_cb (GObject *source,
1195 GAsyncResult *res,
1196 gpointer data)
1197{
1198 BackgroundData *bd = data;
1199 GdkPixbuf *pixbuf;
1200 GError *error = NULL;
1201
1202 pixbuf = gdk_pixbuf_new_from_stream_finish (async_result: res, error: &error);
1203 if (error)
1204 {
1205 g_warning ("Error loading '%s': %s", bd->filename, error->message);
1206 g_error_free (error);
1207 return;
1208 }
1209
1210 add_background (flowbox: bd->flowbox, filename: bd->filename, pixbuf, FALSE);
1211
1212 g_free (mem: bd->filename);
1213 g_free (mem: bd);
1214}
1215
1216static void
1217populate_flowbox (GtkWidget *flowbox)
1218{
1219 const char *location;
1220 GDir *dir;
1221 GError *error = NULL;
1222 const char *name;
1223 char *filename;
1224 GFile *file;
1225 GInputStream *stream;
1226 BackgroundData *bd;
1227 GdkPixbuf *pixbuf;
1228 GtkWidget *child;
1229 int i;
1230 const char *resources[] = {
1231 "sunset.jpg", "portland-rose.jpg", "beach.jpg", "nyc.jpg"
1232 };
1233
1234 if (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (flowbox), "populated")))
1235 return;
1236
1237 g_object_set_data (G_OBJECT (flowbox), key: "populated", GUINT_TO_POINTER (1));
1238
1239 pixbuf = gdk_pixbuf_new (colorspace: GDK_COLORSPACE_RGB, FALSE, bits_per_sample: 8, width: 110, height: 70);
1240 gdk_pixbuf_fill (pixbuf, pixel: 0xffffffff);
1241 child = gtk_picture_new_for_pixbuf (pixbuf);
1242 gtk_widget_add_css_class (widget: child, css_class: "frame");
1243 gtk_flow_box_insert (GTK_FLOW_BOX (flowbox), widget: child, position: -1);
1244
1245 for (i = 0; i < G_N_ELEMENTS (resources); i++)
1246 {
1247 filename = g_strconcat (string1: "/org/gtk/WidgetFactory4/", resources[i], NULL);
1248 pixbuf = gdk_pixbuf_new_from_resource_at_scale (resource_path: filename, width: 110, height: 110, TRUE, NULL);
1249 add_background (flowbox, filename, pixbuf, TRUE);
1250 }
1251
1252 location = "/usr/share/backgrounds/gnome";
1253 dir = g_dir_open (path: location, flags: 0, error: &error);
1254 if (error)
1255 {
1256 g_warning ("%s", error->message);
1257 g_error_free (error);
1258 return;
1259 }
1260
1261 while ((name = g_dir_read_name (dir)) != NULL)
1262 {
1263 if (g_str_has_suffix (str: name, suffix: ".xml"))
1264 continue;
1265
1266 filename = g_build_filename (first_element: location, name, NULL);
1267 file = g_file_new_for_path (path: filename);
1268 stream = G_INPUT_STREAM (g_file_read (file, NULL, &error));
1269 if (error)
1270 {
1271 g_warning ("%s", error->message);
1272 g_clear_error (err: &error);
1273 g_free (mem: filename);
1274 }
1275 else
1276 {
1277 bd = g_new (BackgroundData, 1);
1278 bd->flowbox = flowbox;
1279 bd->filename = filename;
1280 gdk_pixbuf_new_from_stream_at_scale_async (stream, width: 110, height: 110, TRUE, NULL,
1281 callback: background_loaded_cb, user_data: bd);
1282 }
1283
1284 g_object_unref (object: file);
1285 g_object_unref (object: stream);
1286 }
1287
1288 g_dir_close (dir);
1289
1290}
1291
1292static void
1293row_activated (GtkListBox *box, GtkListBoxRow *row)
1294{
1295 GtkWidget *image;
1296 GtkWidget *dialog;
1297
1298 image = (GtkWidget *)g_object_get_data (G_OBJECT (row), key: "image");
1299 dialog = (GtkWidget *)g_object_get_data (G_OBJECT (row), key: "dialog");
1300
1301 if (image)
1302 {
1303 if (gtk_widget_get_opacity (widget: image) > 0)
1304 gtk_widget_set_opacity (widget: image, opacity: 0);
1305 else
1306 gtk_widget_set_opacity (widget: image, opacity: 1);
1307 }
1308 else if (dialog)
1309 {
1310 gtk_window_present (GTK_WINDOW (dialog));
1311 }
1312}
1313
1314typedef struct
1315{
1316 GtkTextView tv;
1317 GdkTexture *texture;
1318 GtkAdjustment *adjustment;
1319} MyTextView;
1320
1321typedef GtkTextViewClass MyTextViewClass;
1322
1323static GType my_text_view_get_type (void);
1324G_DEFINE_TYPE (MyTextView, my_text_view, GTK_TYPE_TEXT_VIEW)
1325
1326static void
1327my_text_view_init (MyTextView *tv)
1328{
1329}
1330
1331static void
1332my_tv_snapshot_layer (GtkTextView *widget,
1333 GtkTextViewLayer layer,
1334 GtkSnapshot *snapshot)
1335{
1336 MyTextView *tv = (MyTextView *)widget;
1337 double opacity;
1338 double scale;
1339
1340 opacity = gtk_adjustment_get_value (adjustment: tv->adjustment) / 100.0;
1341
1342 if (layer == GTK_TEXT_VIEW_LAYER_BELOW_TEXT && tv->texture)
1343 {
1344 scale = gtk_widget_get_width (GTK_WIDGET (widget)) / (double)gdk_texture_get_width (texture: tv->texture);
1345 gtk_snapshot_push_opacity (snapshot, opacity);
1346 gtk_snapshot_scale (snapshot, factor_x: scale, factor_y: scale);
1347 gtk_snapshot_append_texture (snapshot,
1348 texture: tv->texture,
1349 bounds: &GRAPHENE_RECT_INIT(
1350 0, 0,
1351 gdk_texture_get_width (tv->texture),
1352 gdk_texture_get_height (tv->texture)
1353 ));
1354 gtk_snapshot_scale (snapshot, factor_x: 1/scale, factor_y: 1/scale);
1355 gtk_snapshot_pop (snapshot);
1356 }
1357}
1358
1359static void
1360my_tv_finalize (GObject *object)
1361{
1362 MyTextView *tv = (MyTextView *)object;
1363
1364 g_clear_object (&tv->texture);
1365
1366 G_OBJECT_CLASS (my_text_view_parent_class)->finalize (object);
1367}
1368
1369static void
1370my_text_view_class_init (MyTextViewClass *class)
1371{
1372 GtkTextViewClass *tv_class = GTK_TEXT_VIEW_CLASS (class);
1373 GObjectClass *o_class = G_OBJECT_CLASS (class);
1374
1375 o_class->finalize = my_tv_finalize;
1376 tv_class->snapshot_layer = my_tv_snapshot_layer;
1377}
1378
1379static void
1380my_text_view_set_background (MyTextView *tv, const char *filename, gboolean is_resource)
1381{
1382 GError *error = NULL;
1383 GFile *file;
1384
1385 g_clear_object (&tv->texture);
1386
1387 if (filename == NULL)
1388 return;
1389
1390 if (is_resource)
1391 tv->texture = gdk_texture_new_from_resource (resource_path: filename);
1392 else
1393 {
1394 file = g_file_new_for_path (path: filename);
1395 tv->texture = gdk_texture_new_from_file (file, error: &error);
1396 g_object_unref (object: file);
1397 }
1398
1399 if (error)
1400 {
1401 g_warning ("%s", error->message);
1402 g_error_free (error);
1403 return;
1404 }
1405
1406 gtk_widget_queue_draw (GTK_WIDGET (tv));
1407}
1408
1409static void
1410value_changed (GtkAdjustment *adjustment, MyTextView *tv)
1411{
1412 gtk_widget_queue_draw (GTK_WIDGET (tv));
1413}
1414
1415static void
1416my_text_view_set_adjustment (MyTextView *tv, GtkAdjustment *adjustment)
1417{
1418 g_set_object (&tv->adjustment, adjustment);
1419 g_signal_connect (tv->adjustment, "value-changed", G_CALLBACK (value_changed), tv);
1420}
1421
1422static void
1423close_selection_dialog (GtkWidget *dialog, int response, GtkWidget *tv)
1424{
1425 GtkWidget *box;
1426 GtkWidget *child;
1427 GList *children;
1428 const char *filename;
1429 gboolean is_resource;
1430
1431 gtk_widget_hide (widget: dialog);
1432
1433 if (response == GTK_RESPONSE_CANCEL)
1434 return;
1435
1436 box = gtk_widget_get_first_child (widget: gtk_dialog_get_content_area (GTK_DIALOG (dialog)));
1437 g_assert (GTK_IS_FLOW_BOX (box));
1438 children = gtk_flow_box_get_selected_children (GTK_FLOW_BOX (box));
1439
1440 if (!children)
1441 return;
1442
1443 child = children->data;
1444 filename = (const char *)g_object_get_data (G_OBJECT (child), key: "filename");
1445 is_resource = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (child), "is-resource"));
1446
1447 g_list_free (list: children);
1448
1449 my_text_view_set_background (tv: (MyTextView *)tv, filename, is_resource);
1450}
1451
1452static void
1453toggle_selection_mode (GtkSwitch *sw,
1454 GParamSpec *pspec,
1455 GtkListBox *listbox)
1456{
1457 if (gtk_switch_get_active (self: sw))
1458 gtk_list_box_set_selection_mode (box: listbox, mode: GTK_SELECTION_SINGLE);
1459 else
1460 gtk_list_box_set_selection_mode (box: listbox, mode: GTK_SELECTION_NONE);
1461
1462 gtk_list_box_set_activate_on_single_click (box: listbox, single: !gtk_switch_get_active (self: sw));
1463}
1464
1465static void
1466handle_insert (GtkWidget *button, GtkWidget *textview)
1467{
1468 GtkTextBuffer *buffer;
1469 const char *id;
1470 const char *text;
1471
1472 id = gtk_buildable_get_buildable_id (GTK_BUILDABLE (button));
1473
1474 if (strcmp (s1: id, s2: "toolbutton1") == 0)
1475 text = "⌘";
1476 else if (strcmp (s1: id, s2: "toolbutton2") == 0)
1477 text = "âš½";
1478 else if (strcmp (s1: id, s2: "toolbutton3") == 0)
1479 text = "⤢";
1480 else if (strcmp (s1: id, s2: "toolbutton4") == 0)
1481 text = "☆";
1482 else
1483 text = "";
1484
1485 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
1486 gtk_text_buffer_insert_at_cursor (buffer, text, len: -1);
1487}
1488
1489static void
1490handle_cutcopypaste (GtkWidget *button, GtkWidget *textview)
1491{
1492 GtkTextBuffer *buffer;
1493 GdkClipboard *clipboard;
1494 const char *id;
1495
1496 clipboard = gtk_widget_get_clipboard (widget: textview);
1497 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
1498 id = gtk_buildable_get_buildable_id (GTK_BUILDABLE (button));
1499
1500 if (strcmp (s1: id, s2: "cutbutton") == 0)
1501 gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
1502 else if (strcmp (s1: id, s2: "copybutton") == 0)
1503 gtk_text_buffer_copy_clipboard (buffer, clipboard);
1504 else if (strcmp (s1: id, s2: "pastebutton") == 0)
1505 gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
1506 else if (strcmp (s1: id, s2: "deletebutton") == 0)
1507 gtk_text_buffer_delete_selection (buffer, TRUE, TRUE);
1508}
1509
1510static void
1511clipboard_formats_notify (GdkClipboard *clipboard, GdkEvent *event, GtkWidget *button)
1512{
1513 const char *id;
1514 gboolean has_text;
1515
1516 id = gtk_buildable_get_buildable_id (GTK_BUILDABLE (button));
1517 has_text = gdk_content_formats_contain_gtype (formats: gdk_clipboard_get_formats (clipboard), GTK_TYPE_TEXT_BUFFER);
1518
1519 if (strcmp (s1: id, s2: "pastebutton") == 0)
1520 gtk_widget_set_sensitive (widget: button, sensitive: has_text);
1521}
1522
1523static void
1524textbuffer_notify_selection (GObject *object, GParamSpec *pspec, GtkWidget *button)
1525{
1526 const char *id;
1527 gboolean has_selection;
1528
1529 id = gtk_buildable_get_buildable_id (GTK_BUILDABLE (button));
1530 has_selection = gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (object));
1531
1532 if (strcmp (s1: id, s2: "cutbutton") == 0 ||
1533 strcmp (s1: id, s2: "copybutton") == 0 ||
1534 strcmp (s1: id, s2: "deletebutton") == 0)
1535 gtk_widget_set_sensitive (widget: button, sensitive: has_selection);
1536}
1537
1538static gboolean
1539osd_frame_pressed (GtkGestureClick *gesture,
1540 int press,
1541 double x,
1542 double y,
1543 gpointer data)
1544{
1545 GtkWidget *frame = data;
1546 GtkWidget *osd;
1547 gboolean visible;
1548
1549 osd = g_object_get_data (G_OBJECT (frame), key: "osd");
1550 visible = gtk_widget_get_visible (widget: osd);
1551 gtk_widget_set_visible (widget: osd, visible: !visible);
1552
1553 return GDK_EVENT_STOP;
1554}
1555
1556static gboolean
1557page_combo_separator_func (GtkTreeModel *model,
1558 GtkTreeIter *iter,
1559 gpointer data)
1560{
1561 char *text;
1562 gboolean res;
1563
1564 gtk_tree_model_get (tree_model: model, iter, 0, &text, -1);
1565 res = g_strcmp0 (str1: text, str2: "-") == 0;
1566 g_free (mem: text);
1567
1568 return res;
1569}
1570
1571static void
1572toggle_format (GSimpleAction *action,
1573 GVariant *value,
1574 gpointer user_data)
1575{
1576 GtkTextView *text_view = user_data;
1577 GtkTextIter start, end;
1578 const char *name;
1579
1580 name = g_action_get_name (G_ACTION (action));
1581
1582 g_simple_action_set_state (simple: action, value);
1583
1584 gtk_text_buffer_get_selection_bounds (buffer: gtk_text_view_get_buffer (text_view), start: &start, end: &end);
1585 if (g_variant_get_boolean (value))
1586 gtk_text_buffer_apply_tag_by_name (buffer: gtk_text_view_get_buffer (text_view), name, start: &start, end: &end);
1587 else
1588 gtk_text_buffer_remove_tag_by_name (buffer: gtk_text_view_get_buffer (text_view), name, start: &start, end: &end);
1589}
1590
1591static GActionGroup *actions;
1592
1593static void
1594text_changed (GtkTextBuffer *buffer)
1595{
1596 GAction *bold;
1597 GAction *italic;
1598 GAction *underline;
1599 GtkTextIter iter;
1600 GtkTextTagTable *tags;
1601 GtkTextTag *bold_tag, *italic_tag, *underline_tag;
1602 gboolean all_bold, all_italic, all_underline;
1603 GtkTextIter start, end;
1604 gboolean has_selection;
1605
1606 bold = g_action_map_lookup_action (G_ACTION_MAP (actions), action_name: "bold");
1607 italic = g_action_map_lookup_action (G_ACTION_MAP (actions), action_name: "italic");
1608 underline = g_action_map_lookup_action (G_ACTION_MAP (actions), action_name: "underline");
1609
1610 has_selection = gtk_text_buffer_get_selection_bounds (buffer, start: &start, end: &end);
1611 g_simple_action_set_enabled (G_SIMPLE_ACTION (bold), enabled: has_selection);
1612 g_simple_action_set_enabled (G_SIMPLE_ACTION (italic), enabled: has_selection);
1613 g_simple_action_set_enabled (G_SIMPLE_ACTION (underline), enabled: has_selection);
1614 if (!has_selection)
1615 return;
1616
1617 tags = gtk_text_buffer_get_tag_table (buffer);
1618 bold_tag = gtk_text_tag_table_lookup (table: tags, name: "bold");
1619 italic_tag = gtk_text_tag_table_lookup (table: tags, name: "italic");
1620 underline_tag = gtk_text_tag_table_lookup (table: tags, name: "underline");
1621 all_bold = TRUE;
1622 all_italic = TRUE;
1623 all_underline = TRUE;
1624 gtk_text_iter_assign (iter: &iter, other: &start);
1625 while (!gtk_text_iter_equal (lhs: &iter, rhs: &end))
1626 {
1627 all_bold &= gtk_text_iter_has_tag (iter: &iter, tag: bold_tag);
1628 all_italic &= gtk_text_iter_has_tag (iter: &iter, tag: italic_tag);
1629 all_underline &= gtk_text_iter_has_tag (iter: &iter, tag: underline_tag);
1630 gtk_text_iter_forward_char (iter: &iter);
1631 }
1632
1633 g_simple_action_set_state (G_SIMPLE_ACTION (bold), value: g_variant_new_boolean (value: all_bold));
1634 g_simple_action_set_state (G_SIMPLE_ACTION (italic), value: g_variant_new_boolean (value: all_italic));
1635 g_simple_action_set_state (G_SIMPLE_ACTION (underline), value: g_variant_new_boolean (value: all_underline));
1636}
1637
1638static void
1639text_view_add_to_context_menu (GtkTextView *text_view)
1640{
1641 GMenu *menu;
1642 GActionEntry entries[] = {
1643 { "bold", NULL, NULL, "false", toggle_format },
1644 { "italic", NULL, NULL, "false", toggle_format },
1645 { "underline", NULL, NULL, "false", toggle_format },
1646 };
1647 GMenuItem *item;
1648 GAction *action;
1649
1650 actions = G_ACTION_GROUP (g_simple_action_group_new ());
1651 g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), user_data: text_view);
1652
1653 action = g_action_map_lookup_action (G_ACTION_MAP (actions), action_name: "bold");
1654 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
1655 action = g_action_map_lookup_action (G_ACTION_MAP (actions), action_name: "italic");
1656 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
1657 action = g_action_map_lookup_action (G_ACTION_MAP (actions), action_name: "underline");
1658 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
1659
1660 gtk_widget_insert_action_group (GTK_WIDGET (text_view), name: "format", G_ACTION_GROUP (actions));
1661
1662 menu = g_menu_new ();
1663 item = g_menu_item_new (_("Bold"), detailed_action: "format.bold");
1664 g_menu_item_set_attribute (menu_item: item, attribute: "touch-icon", format_string: "s", "format-text-bold-symbolic");
1665 g_menu_append_item (G_MENU (menu), item);
1666 g_object_unref (object: item);
1667 item = g_menu_item_new (_("Italics"), detailed_action: "format.italic");
1668 g_menu_item_set_attribute (menu_item: item, attribute: "touch-icon", format_string: "s", "format-text-italic-symbolic");
1669 g_menu_append_item (G_MENU (menu), item);
1670 g_object_unref (object: item);
1671 item = g_menu_item_new (_("Underline"), detailed_action: "format.underline");
1672 g_menu_item_set_attribute (menu_item: item, attribute: "touch-icon", format_string: "s", "format-text-underline-symbolic");
1673 g_menu_append_item (G_MENU (menu), item);
1674 g_object_unref (object: item);
1675
1676 gtk_text_view_set_extra_menu (text_view, G_MENU_MODEL (menu));
1677 g_object_unref (object: menu);
1678
1679 g_signal_connect (gtk_text_view_get_buffer (text_view), "changed", G_CALLBACK (text_changed), NULL);
1680 g_signal_connect (gtk_text_view_get_buffer (text_view), "mark-set", G_CALLBACK (text_changed), NULL);
1681}
1682
1683static void
1684open_popover_text_changed (GtkEntry *entry, GParamSpec *pspec, GtkWidget *button)
1685{
1686 const char *text;
1687
1688 text = gtk_editable_get_text (GTK_EDITABLE (entry));
1689 gtk_widget_set_sensitive (widget: button, sensitive: strlen (s: text) > 0);
1690}
1691
1692static gboolean
1693show_page_again (gpointer data)
1694{
1695 gtk_widget_show (GTK_WIDGET (data));
1696 return G_SOURCE_REMOVE;
1697}
1698
1699static void
1700tab_close_cb (GtkWidget *page)
1701{
1702 gtk_widget_hide (widget: page);
1703 g_timeout_add (interval: 2500, function: show_page_again, data: page);
1704}
1705
1706typedef struct _GTestPermission GTestPermission;
1707typedef struct _GTestPermissionClass GTestPermissionClass;
1708
1709struct _GTestPermission
1710{
1711 GPermission parent;
1712};
1713
1714struct _GTestPermissionClass
1715{
1716 GPermissionClass parent_class;
1717};
1718
1719static GType g_test_permission_get_type (void);
1720G_DEFINE_TYPE (GTestPermission, g_test_permission, G_TYPE_PERMISSION)
1721
1722static void
1723g_test_permission_init (GTestPermission *test)
1724{
1725 g_permission_impl_update (G_PERMISSION (test), TRUE, TRUE, TRUE);
1726}
1727
1728static gboolean
1729update_allowed (GPermission *permission,
1730 gboolean allowed)
1731{
1732 g_permission_impl_update (permission, allowed, TRUE, TRUE);
1733
1734 return TRUE;
1735}
1736
1737static gboolean
1738acquire (GPermission *permission,
1739 GCancellable *cancellable,
1740 GError **error)
1741{
1742 return update_allowed (permission, TRUE);
1743}
1744
1745static void
1746acquire_async (GPermission *permission,
1747 GCancellable *cancellable,
1748 GAsyncReadyCallback callback,
1749 gpointer user_data)
1750{
1751 GTask *task;
1752
1753 task = g_task_new (source_object: (GObject*)permission, NULL, callback, callback_data: user_data);
1754 g_task_return_boolean (task, result: update_allowed (permission, TRUE));
1755 g_object_unref (object: task);
1756}
1757
1758static gboolean
1759acquire_finish (GPermission *permission,
1760 GAsyncResult *res,
1761 GError **error)
1762{
1763 return g_task_propagate_boolean (G_TASK (res), error);
1764}
1765
1766static gboolean
1767release (GPermission *permission,
1768 GCancellable *cancellable,
1769 GError **error)
1770{
1771 return update_allowed (permission, FALSE);
1772}
1773
1774static void
1775release_async (GPermission *permission,
1776 GCancellable *cancellable,
1777 GAsyncReadyCallback callback,
1778 gpointer user_data)
1779{
1780 GTask *task;
1781
1782 task = g_task_new (source_object: (GObject*)permission, NULL, callback, callback_data: user_data);
1783 g_task_return_boolean (task, result: update_allowed (permission, FALSE));
1784 g_object_unref (object: task);
1785}
1786
1787static gboolean
1788release_finish (GPermission *permission,
1789 GAsyncResult *result,
1790 GError **error)
1791{
1792 return g_task_propagate_boolean (G_TASK (result), error);
1793}
1794
1795static void
1796g_test_permission_class_init (GTestPermissionClass *class)
1797{
1798 GPermissionClass *permission_class = G_PERMISSION_CLASS (class);
1799
1800 permission_class->acquire = acquire;
1801 permission_class->acquire_async = acquire_async;
1802 permission_class->acquire_finish = acquire_finish;
1803
1804 permission_class->release = release;
1805 permission_class->release_async = release_async;
1806 permission_class->release_finish = release_finish;
1807}
1808
1809static void
1810update_buttons (GtkWidget *iv, GtkIconSize size)
1811{
1812 GtkWidget *button;
1813
1814 button = GTK_WIDGET (g_object_get_data (G_OBJECT (iv), "increase_button"));
1815 gtk_widget_set_sensitive (widget: button, sensitive: size != GTK_ICON_SIZE_LARGE);
1816 button = GTK_WIDGET (g_object_get_data (G_OBJECT (iv), "decrease_button"));
1817 gtk_widget_set_sensitive (widget: button, sensitive: size != GTK_ICON_SIZE_NORMAL);
1818 button = GTK_WIDGET (g_object_get_data (G_OBJECT (iv), "reset_button"));
1819 gtk_widget_set_sensitive (widget: button, sensitive: size != GTK_ICON_SIZE_INHERIT);
1820}
1821
1822static void
1823increase_icon_size (GtkWidget *iv)
1824{
1825 GList *cells;
1826 GtkCellRendererPixbuf *cell;
1827
1828 cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (iv));
1829 cell = cells->data;
1830 g_list_free (list: cells);
1831
1832 g_object_set (object: cell, first_property_name: "icon-size", GTK_ICON_SIZE_LARGE, NULL);
1833
1834 update_buttons (iv, size: GTK_ICON_SIZE_LARGE);
1835
1836 gtk_widget_queue_resize (widget: iv);
1837}
1838
1839static void
1840decrease_icon_size (GtkWidget *iv)
1841{
1842 GList *cells;
1843 GtkCellRendererPixbuf *cell;
1844
1845 cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (iv));
1846 cell = cells->data;
1847 g_list_free (list: cells);
1848
1849 g_object_set (object: cell, first_property_name: "icon-size", GTK_ICON_SIZE_NORMAL, NULL);
1850
1851 update_buttons (iv, size: GTK_ICON_SIZE_NORMAL);
1852
1853 gtk_widget_queue_resize (widget: iv);
1854}
1855
1856static void
1857reset_icon_size (GtkWidget *iv)
1858{
1859 GList *cells;
1860 GtkCellRendererPixbuf *cell;
1861
1862 cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (iv));
1863 cell = cells->data;
1864 g_list_free (list: cells);
1865
1866 g_object_set (object: cell, first_property_name: "icon-size", GTK_ICON_SIZE_INHERIT, NULL);
1867
1868 update_buttons (iv, size: GTK_ICON_SIZE_INHERIT);
1869
1870 gtk_widget_queue_resize (widget: iv);
1871}
1872
1873static char *
1874scale_format_value_blank (GtkScale *scale, double value, gpointer user_data)
1875{
1876 return g_strdup (str: " ");
1877}
1878
1879static char *
1880scale_format_value (GtkScale *scale, double value, gpointer user_data)
1881{
1882 return g_strdup_printf (format: "%0.*f", 1, value);
1883}
1884
1885static void
1886adjustment3_value_changed (GtkAdjustment *adj, GtkProgressBar *pbar)
1887{
1888 double fraction;
1889
1890 fraction = gtk_adjustment_get_value (adjustment: adj) / (gtk_adjustment_get_upper (adjustment: adj) - gtk_adjustment_get_lower (adjustment: adj));
1891
1892 gtk_progress_bar_set_fraction (pbar, fraction);
1893}
1894
1895static void
1896clicked_cb (GtkGesture *gesture,
1897 int n_press,
1898 double x,
1899 double y,
1900 GtkPopover *popover)
1901{
1902 GdkRectangle rect;
1903
1904 rect.x = x;
1905 rect.y = y;
1906 rect.width = 1;
1907 rect.height = 1;
1908 gtk_popover_set_pointing_to (popover, rect: &rect);
1909 gtk_popover_popup (popover);
1910}
1911
1912static void
1913set_up_context_popover (GtkWidget *widget,
1914 GMenuModel *model)
1915{
1916 GtkWidget *popover = gtk_popover_menu_new_from_model (model);
1917 GtkGesture *gesture;
1918
1919 gtk_widget_set_parent (widget: popover, parent: widget);
1920 gtk_popover_set_has_arrow (GTK_POPOVER (popover), FALSE);
1921 gesture = gtk_gesture_click_new ();
1922 gtk_event_controller_set_name (GTK_EVENT_CONTROLLER (gesture), name: "widget-factory-context-click");
1923 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
1924 g_signal_connect (gesture, "pressed", G_CALLBACK (clicked_cb), popover);
1925 gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (gesture));
1926}
1927
1928static void
1929age_entry_changed (GtkEntry *entry,
1930 GParamSpec *pspec,
1931 gpointer data)
1932{
1933 const char *text;
1934 guint64 age;
1935 GError *error = NULL;
1936
1937 text = gtk_editable_get_text (GTK_EDITABLE (entry));
1938
1939 if (strlen (s: text) > 0 &&
1940 !g_ascii_string_to_unsigned (str: text, base: 10, min: 16, max: 666, out_num: &age, error: &error))
1941 {
1942 gtk_widget_set_tooltip_text (GTK_WIDGET (entry), text: error->message);
1943 gtk_widget_add_css_class (GTK_WIDGET (entry), css_class: "error");
1944 g_error_free (error);
1945 }
1946 else
1947 {
1948 gtk_widget_set_tooltip_text (GTK_WIDGET (entry), text: "");
1949 gtk_widget_remove_css_class (GTK_WIDGET (entry), css_class: "error");
1950 }
1951}
1952
1953static void
1954validate_more_details (GtkEntry *entry,
1955 GParamSpec *pspec,
1956 GtkEntry *details)
1957{
1958 if (strlen (s: gtk_editable_get_text (GTK_EDITABLE (entry))) > 0 &&
1959 strlen (s: gtk_editable_get_text (GTK_EDITABLE (details))) == 0)
1960 {
1961 gtk_widget_set_tooltip_text (GTK_WIDGET (entry), text: "Must have details first");
1962 gtk_widget_add_css_class (GTK_WIDGET (entry), css_class: "error");
1963 }
1964 else
1965 {
1966 gtk_widget_set_tooltip_text (GTK_WIDGET (entry), text: "");
1967 gtk_widget_remove_css_class (GTK_WIDGET (entry), css_class: "error");
1968 }
1969}
1970
1971static gboolean
1972mode_switch_state_set (GtkSwitch *sw, gboolean state)
1973{
1974 GtkWidget *dialog = gtk_widget_get_ancestor (GTK_WIDGET (sw), GTK_TYPE_DIALOG);
1975 GtkWidget *scale = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "level_scale"));
1976 GtkWidget *label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "error_label"));
1977
1978 if (!state ||
1979 (gtk_range_get_value (GTK_RANGE (scale)) > 50))
1980 {
1981 gtk_widget_hide (widget: label);
1982 gtk_switch_set_state (self: sw, state);
1983 }
1984 else
1985 {
1986 gtk_widget_show (widget: label);
1987 }
1988
1989 return TRUE;
1990}
1991
1992static void
1993level_scale_value_changed (GtkRange *range)
1994{
1995 GtkWidget *dialog = gtk_widget_get_ancestor (GTK_WIDGET (range), GTK_TYPE_DIALOG);
1996 GtkWidget *sw = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "mode_switch"));
1997 GtkWidget *label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "error_label"));
1998
1999 if (gtk_switch_get_active (GTK_SWITCH (sw)) &&
2000 !gtk_switch_get_state (GTK_SWITCH (sw)) &&
2001 (gtk_range_get_value (range) > 50))
2002 {
2003 gtk_widget_hide (widget: label);
2004 gtk_switch_set_state (GTK_SWITCH (sw), TRUE);
2005 }
2006 else if (gtk_switch_get_state (GTK_SWITCH (sw)) &&
2007 (gtk_range_get_value (range) <= 50))
2008 {
2009 gtk_switch_set_state (GTK_SWITCH (sw), FALSE);
2010 }
2011}
2012
2013static void
2014activate (GApplication *app)
2015{
2016 GtkBuilder *builder;
2017 GtkBuilderScope *scope;
2018 GtkWindow *window;
2019 GtkWidget *widget;
2020 GtkWidget *widget2;
2021 GtkWidget *widget3;
2022 GtkWidget *widget4;
2023 GtkWidget *stack;
2024 GtkWidget *dialog;
2025 GtkAdjustment *adj;
2026 GtkCssProvider *provider;
2027 GMenuModel *model;
2028 static GActionEntry win_entries[] = {
2029 { "dark", NULL, NULL, "false", change_dark_state },
2030 { "theme", NULL, "s", "'current'", change_theme_state },
2031 { "transition", NULL, NULL, "true", change_transition_state },
2032 { "search", activate_search, NULL, NULL, NULL },
2033 { "delete", activate_delete, NULL, NULL, NULL },
2034 { "busy", get_busy, NULL, NULL, NULL },
2035 { "fullscreen", NULL, NULL, "false", change_fullscreen },
2036 { "background", activate_background, NULL, NULL, NULL },
2037 { "open", activate_open, NULL, NULL, NULL },
2038 { "record", activate_record, NULL, NULL, NULL },
2039 { "lock", activate_lock, NULL, NULL, NULL },
2040 { "print", activate_print, NULL, NULL, NULL },
2041 };
2042 struct {
2043 const char *action_and_target;
2044 const char *accelerators[2];
2045 } accels[] = {
2046 { "app.about", { "F1", NULL } },
2047 { "app.shortcuts", { "<Control>question", NULL } },
2048 { "app.quit", { "<Control>q", NULL } },
2049 { "app.open-in", { "<Control>n", NULL } },
2050 { "win.dark", { "<Control>d", NULL } },
2051 { "win.search", { "<Control>s", NULL } },
2052 { "win.background", { "<Control>b", NULL } },
2053 { "win.open", { "<Control>o", NULL } },
2054 { "win.record", { "<Control>r", NULL } },
2055 { "win.lock", { "<Control>l", NULL } },
2056 { "win.fullscreen", { "F11", NULL } },
2057 };
2058 struct {
2059 const char *action_and_target;
2060 const char *accelerators[2];
2061 } late_accels[] = {
2062 { "app.cut", { "<Control>x", NULL } },
2063 { "app.copy", { "<Control>c", NULL } },
2064 { "app.paste", { "<Control>v", NULL } },
2065 { "win.delete", { "Delete", NULL } },
2066 };
2067 int i;
2068 GPermission *permission;
2069 GAction *action;
2070 GError *error = NULL;
2071 GtkEventController *controller;
2072
2073 g_type_ensure (type: my_text_view_get_type ());
2074
2075 provider = gtk_css_provider_new ();
2076 gtk_css_provider_load_from_resource (css_provider: provider, resource_path: "/org/gtk/WidgetFactory4/widget-factory.css");
2077 gtk_style_context_add_provider_for_display (display: gdk_display_get_default (),
2078 GTK_STYLE_PROVIDER (provider),
2079 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
2080 g_object_unref (object: provider);
2081
2082 builder = gtk_builder_new ();
2083 scope = gtk_builder_cscope_new ();
2084 gtk_builder_cscope_add_callback_symbols (self: GTK_BUILDER_CSCOPE (ptr: scope),
2085 first_callback_name: "on_entry_icon_release", first_callback_symbol: (GCallback)on_entry_icon_release,
2086 "on_scale_button_value_changed", (GCallback)on_scale_button_value_changed,
2087 "on_record_button_toggled", (GCallback)on_record_button_toggled,
2088 "on_page_combo_changed", (GCallback)on_page_combo_changed,
2089 "on_range_from_changed", (GCallback)on_range_from_changed,
2090 "on_range_to_changed", (GCallback)on_range_to_changed,
2091 "on_picture_drag_prepare", (GCallback)on_picture_drag_prepare,
2092 "on_picture_drop", (GCallback)on_picture_drop,
2093 "tab_close_cb", (GCallback)tab_close_cb,
2094 "increase_icon_size", (GCallback)increase_icon_size,
2095 "decrease_icon_size", (GCallback)decrease_icon_size,
2096 "reset_icon_size", (GCallback)reset_icon_size,
2097 "osd_frame_pressed", (GCallback)osd_frame_pressed,
2098 "age_entry_changed", (GCallback)age_entry_changed,
2099 "validate_more_details", (GCallback)validate_more_details,
2100 "mode_switch_state_set", (GCallback)mode_switch_state_set,
2101 "level_scale_value_changed", (GCallback)level_scale_value_changed,
2102 "transition_speed_changed", (GCallback)transition_speed_changed,
2103 NULL);
2104 gtk_builder_set_scope (builder, scope);
2105 g_object_unref (object: scope);
2106 if (!gtk_builder_add_from_resource (builder, resource_path: "/org/gtk/WidgetFactory4/widget-factory.ui", error: &error))
2107 {
2108 g_critical ("%s", error->message);
2109 g_clear_error (err: &error);
2110 }
2111
2112 window = (GtkWindow *)gtk_builder_get_object (builder, name: "window");
2113
2114 if (g_strcmp0 (str1: PROFILE, str2: "devel") == 0)
2115 gtk_widget_add_css_class (GTK_WIDGET (window), css_class: "devel");
2116
2117 gtk_application_add_window (GTK_APPLICATION (app), window);
2118 g_action_map_add_action_entries (G_ACTION_MAP (window),
2119 entries: win_entries, G_N_ELEMENTS (win_entries),
2120 user_data: window);
2121
2122 controller = gtk_shortcut_controller_new ();
2123 gtk_event_controller_set_propagation_phase (controller, phase: GTK_PHASE_BUBBLE);
2124
2125 for (i = 0; i < G_N_ELEMENTS (late_accels); i++)
2126 {
2127 guint key;
2128 GdkModifierType mods;
2129 GtkShortcutTrigger *trigger;
2130 GtkShortcutAction *ac;
2131
2132 gtk_accelerator_parse (accelerator: late_accels[i].accelerators[0], accelerator_key: &key, accelerator_mods: &mods);
2133 trigger = gtk_keyval_trigger_new (keyval: key, modifiers: mods);
2134 ac = gtk_named_action_new (name: late_accels[i].action_and_target);
2135 gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
2136 shortcut: gtk_shortcut_new (trigger, action: ac));
2137 }
2138 gtk_widget_add_controller (GTK_WIDGET (window), controller);
2139
2140 for (i = 0; i < G_N_ELEMENTS (accels); i++)
2141 gtk_application_set_accels_for_action (GTK_APPLICATION (app), detailed_action_name: accels[i].action_and_target, accels: accels[i].accelerators);
2142
2143 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "statusbar");
2144 gtk_statusbar_push (GTK_STATUSBAR (widget), context_id: 0, text: "All systems are operating normally.");
2145 action = G_ACTION (g_property_action_new ("statusbar", widget, "visible"));
2146 g_action_map_add_action (G_ACTION_MAP (window), action);
2147 g_object_unref (G_OBJECT (action));
2148
2149 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "toolbar");
2150 action = G_ACTION (g_property_action_new ("toolbar", widget, "visible"));
2151 g_action_map_add_action (G_ACTION_MAP (window), action);
2152 g_object_unref (G_OBJECT (action));
2153
2154 adj = (GtkAdjustment *)gtk_builder_get_object (builder, name: "adjustment1");
2155
2156 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "progressbar3");
2157 g_signal_connect (adj, "value-changed", G_CALLBACK (update_pulse_time), widget);
2158 update_pulse_time (adjustment: adj, widget);
2159
2160 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "entry1");
2161 g_signal_connect (adj, "value-changed", G_CALLBACK (update_pulse_time), widget);
2162 update_pulse_time (adjustment: adj, widget);
2163
2164 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "page2reset");
2165 adj = (GtkAdjustment *) gtk_builder_get_object (builder, name: "adjustment2");
2166 g_signal_connect (widget, "clicked", G_CALLBACK (spin_value_reset), adj);
2167
2168 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "page2dismiss");
2169 g_signal_connect (widget, "clicked", G_CALLBACK (dismiss), NULL);
2170
2171 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "page2note");
2172 adj = (GtkAdjustment *) gtk_builder_get_object (builder, name: "adjustment2");
2173 g_signal_connect (adj, "value-changed", G_CALLBACK (spin_value_changed), widget);
2174
2175 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "listbox");
2176 g_signal_connect (widget, "row-activated", G_CALLBACK (row_activated), NULL);
2177
2178 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "listboxrow1switch");
2179 g_signal_connect (widget2, "notify::active", G_CALLBACK (toggle_selection_mode), widget);
2180
2181 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "listboxrow3");
2182 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "listboxrow3image");
2183 g_object_set_data (G_OBJECT (widget), key: "image", data: widget2);
2184
2185 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "info_dialog");
2186 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "listboxrow7");
2187 g_object_set_data (G_OBJECT (widget), key: "dialog", data: widget2);
2188 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "listboxrow8");
2189 g_object_set_data (G_OBJECT (widget), key: "dialog", data: widget2);
2190
2191 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "listboxrow5button");
2192 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "action_dialog");
2193 g_signal_connect_swapped (widget, "clicked", G_CALLBACK (gtk_window_present), widget2);
2194
2195 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "toolbar");
2196 g_object_set_data (G_OBJECT (window), key: "toolbar", data: widget);
2197
2198 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "searchbar");
2199 g_object_set_data (G_OBJECT (window), key: "searchbar", data: widget);
2200
2201 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "infobar");
2202 g_signal_connect (widget, "response", G_CALLBACK (info_bar_response), NULL);
2203 g_object_set_data (G_OBJECT (window), key: "infobar", data: widget);
2204
2205 dialog = (GtkWidget *)gtk_builder_get_object (builder, name: "info_dialog");
2206 g_signal_connect (dialog, "response", G_CALLBACK (close_dialog), NULL);
2207 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "info_dialog_button");
2208 g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
2209
2210 dialog = (GtkWidget *)gtk_builder_get_object (builder, name: "action_dialog");
2211 g_signal_connect (dialog, "response", G_CALLBACK (close_dialog), NULL);
2212 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "action_dialog_button");
2213 g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
2214
2215 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "act_action_dialog");
2216 stack = (GtkWidget *)gtk_builder_get_object (builder, name: "toplevel_stack");
2217 g_signal_connect (widget, "clicked", G_CALLBACK (action_dialog_button_clicked), stack);
2218 g_signal_connect (stack, "notify::visible-child-name", G_CALLBACK (page_changed_cb), NULL);
2219 page_changed_cb (stack, NULL, NULL);
2220
2221 page_stack = stack;
2222
2223 dialog = (GtkWidget *)gtk_builder_get_object (builder, name: "preference_dialog");
2224 g_signal_connect (dialog, "response", G_CALLBACK (close_dialog), NULL);
2225 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "preference_dialog_button");
2226 g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
2227 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "circular_button");
2228 g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
2229
2230 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "level_scale");
2231 g_object_set_data (G_OBJECT (dialog), key: "level_scale", data: widget);
2232 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "mode_switch");
2233 g_object_set_data (G_OBJECT (dialog), key: "mode_switch", data: widget);
2234 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "error_label");
2235 g_object_set_data (G_OBJECT (dialog), key: "error_label", data: widget);
2236
2237 dialog = (GtkWidget *)gtk_builder_get_object (builder, name: "selection_dialog");
2238 g_object_set_data (G_OBJECT (window), key: "selection_dialog", data: dialog);
2239 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "text3");
2240 g_signal_connect (dialog, "response", G_CALLBACK (close_selection_dialog), widget);
2241 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "opacity");
2242 my_text_view_set_adjustment (tv: (MyTextView *)widget, adjustment: gtk_range_get_adjustment (GTK_RANGE (widget2)));
2243 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "selection_dialog_button");
2244 g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
2245
2246 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "selection_flowbox");
2247 g_object_set_data (G_OBJECT (window), key: "selection_flowbox", data: widget2);
2248 g_signal_connect_swapped (widget, "clicked", G_CALLBACK (populate_flowbox), widget2);
2249
2250 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "charletree");
2251 populate_model (store: (GtkTreeStore *)gtk_tree_view_get_model (GTK_TREE_VIEW (widget)));
2252 gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (widget), func: row_separator_func, NULL, NULL);
2253 gtk_tree_view_expand_all (GTK_TREE_VIEW (widget));
2254
2255 widget = GTK_WIDGET (gtk_builder_get_object (builder, "munsell"));
2256 widget2 = GTK_WIDGET (gtk_builder_get_object (builder, "cchooser"));
2257
2258 populate_colors (widget, chooser: widget2);
2259 g_signal_connect (widget2, "notify::rgba", G_CALLBACK (rgba_changed), widget);
2260
2261 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "page_combo");
2262 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (widget), func: page_combo_separator_func, NULL, NULL);
2263 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "range_from_spin");
2264 widget3 = (GtkWidget *)gtk_builder_get_object (builder, name: "range_to_spin");
2265 widget4 = (GtkWidget *)gtk_builder_get_object (builder, name: "print_button");
2266 g_object_set_data (G_OBJECT (widget), key: "range_from_spin", data: widget2);
2267 g_object_set_data (G_OBJECT (widget3), key: "range_from_spin", data: widget2);
2268 g_object_set_data (G_OBJECT (widget), key: "range_to_spin", data: widget3);
2269 g_object_set_data (G_OBJECT (widget2), key: "range_to_spin", data: widget3);
2270 g_object_set_data (G_OBJECT (widget), key: "print_button", data: widget4);
2271
2272 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "tooltextview");
2273
2274 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "toolbutton1");
2275 g_signal_connect (widget, "clicked", G_CALLBACK (handle_insert), widget2);
2276 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "toolbutton2");
2277 g_signal_connect (widget, "clicked", G_CALLBACK (handle_insert), widget2);
2278 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "toolbutton3");
2279 g_signal_connect (widget, "clicked", G_CALLBACK (handle_insert), widget2);
2280 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "toolbutton4");
2281 g_signal_connect (widget, "clicked", G_CALLBACK (handle_insert), widget2);
2282 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "cutbutton");
2283 g_signal_connect (widget, "clicked", G_CALLBACK (handle_cutcopypaste), widget2);
2284 g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget2)), "notify::has-selection",
2285 G_CALLBACK (textbuffer_notify_selection), widget);
2286 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "copybutton");
2287 g_signal_connect (widget, "clicked", G_CALLBACK (handle_cutcopypaste), widget2);
2288 g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget2)), "notify::has-selection",
2289 G_CALLBACK (textbuffer_notify_selection), widget);
2290 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "deletebutton");
2291 g_signal_connect (widget, "clicked", G_CALLBACK (handle_cutcopypaste), widget2);
2292 g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget2)), "notify::has-selection",
2293 G_CALLBACK (textbuffer_notify_selection), widget);
2294 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "pastebutton");
2295 g_signal_connect (widget, "clicked", G_CALLBACK (handle_cutcopypaste), widget2);
2296 g_signal_connect_object (instance: gtk_widget_get_clipboard (widget: widget2), detailed_signal: "notify::formats",
2297 G_CALLBACK (clipboard_formats_notify), gobject: widget, connect_flags: 0);
2298
2299 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "osd_frame");
2300 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "totem_like_osd");
2301 g_object_set_data (G_OBJECT (widget), key: "osd", data: widget2);
2302
2303 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "textview1");
2304 text_view_add_to_context_menu (GTK_TEXT_VIEW (widget));
2305
2306 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "open_popover");
2307 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "open_popover_entry");
2308 widget3 = (GtkWidget *)gtk_builder_get_object (builder, name: "open_popover_button");
2309 gtk_popover_set_default_widget (GTK_POPOVER (widget), widget: widget3);
2310 g_signal_connect (widget2, "notify::text", G_CALLBACK (open_popover_text_changed), widget3);
2311 g_signal_connect_swapped (widget3, "clicked", G_CALLBACK (gtk_widget_hide), widget);
2312 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "open_menubutton");
2313 g_object_set_data (G_OBJECT (window), key: "open_menubutton", data: widget);
2314 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "record_button");
2315 g_object_set_data (G_OBJECT (window), key: "record_button", data: widget);
2316
2317 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "lockbox");
2318 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "lockbutton");
2319 g_object_set_data (G_OBJECT (window), key: "lockbutton", data: widget2);
2320 permission = g_object_new (object_type: g_test_permission_get_type (), NULL);
2321 g_object_bind_property (source: permission, source_property: "allowed",
2322 target: widget, target_property: "sensitive",
2323 flags: G_BINDING_SYNC_CREATE);
2324 action = g_action_map_lookup_action (G_ACTION_MAP (window), action_name: "open");
2325 g_object_bind_property (source: permission, source_property: "allowed",
2326 target: action, target_property: "enabled",
2327 flags: G_BINDING_SYNC_CREATE);
2328 action = g_action_map_lookup_action (G_ACTION_MAP (window), action_name: "record");
2329 g_object_bind_property (source: permission, source_property: "allowed",
2330 target: action, target_property: "enabled",
2331 flags: G_BINDING_SYNC_CREATE);
2332 gtk_lock_button_set_permission (GTK_LOCK_BUTTON (widget2), permission);
2333 g_object_unref (object: permission);
2334
2335 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "iconview1");
2336 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "increase_button");
2337 g_object_set_data (G_OBJECT (widget), key: "increase_button", data: widget2);
2338 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "decrease_button");
2339 g_object_set_data (G_OBJECT (widget), key: "decrease_button", data: widget2);
2340 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "reset_button");
2341 g_object_set_data (G_OBJECT (widget), key: "reset_button", data: widget2);
2342 reset_icon_size (iv: widget);
2343
2344 adj = (GtkAdjustment *)gtk_builder_get_object (builder, name: "adjustment3");
2345 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "progressbar1");
2346 widget2 = (GtkWidget *)gtk_builder_get_object (builder, name: "progressbar2");
2347 g_signal_connect (adj, "value-changed", G_CALLBACK (adjustment3_value_changed), widget);
2348 g_signal_connect (adj, "value-changed", G_CALLBACK (adjustment3_value_changed), widget2);
2349
2350 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "extra_info_entry");
2351 g_timeout_add (interval: 100, function: (GSourceFunc)pulse_it, data: widget);
2352
2353 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "scale3");
2354 gtk_scale_set_format_value_func (GTK_SCALE (widget), func: scale_format_value, NULL, NULL);
2355
2356 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "scale4");
2357 gtk_scale_set_format_value_func (GTK_SCALE (widget), func: scale_format_value_blank, NULL, NULL);
2358
2359 widget = (GtkWidget *)gtk_builder_get_object (builder, name: "box_for_context");
2360 model = (GMenuModel *)gtk_builder_get_object (builder, name: "new_style_context_menu_model");
2361 set_up_context_popover (widget, model);
2362
2363 gtk_window_present (window);
2364
2365 g_object_unref (object: builder);
2366}
2367
2368static void
2369print_version (void)
2370{
2371 g_print (format: "gtk4-widget-factory %s%s%s\n",
2372 PACKAGE_VERSION,
2373 g_strcmp0 (str1: PROFILE, str2: "devel") == 0 ? "-" : "",
2374 g_strcmp0 (str1: PROFILE, str2: "devel") == 0 ? VCS_TAG : "");
2375}
2376
2377static int
2378local_options (GApplication *app,
2379 GVariantDict *options,
2380 gpointer data)
2381{
2382 gboolean version = FALSE;
2383
2384 g_variant_dict_lookup (dict: options, key: "version", format_string: "b", &version);
2385
2386 if (version)
2387 {
2388 print_version ();
2389 return 0;
2390 }
2391
2392 return -1;
2393}
2394
2395static void
2396activate_action (GSimpleAction *action,
2397 GVariant *parameter,
2398 gpointer user_data)
2399{
2400 g_print (format: "Activate action %s\n", g_action_get_name (G_ACTION (action)));
2401}
2402
2403static void
2404select_action (GSimpleAction *action,
2405 GVariant *parameter,
2406 gpointer user_data)
2407{
2408 g_print (format: "Select action %s value %s\n",
2409 g_action_get_name (G_ACTION (action)),
2410 g_variant_get_string (value: parameter, NULL));
2411
2412 g_simple_action_set_state (simple: action, value: parameter);
2413}
2414
2415static void
2416toggle_action (GSimpleAction *action,
2417 GVariant *parameter,
2418 gpointer user_data)
2419{
2420 GVariant *state = g_action_get_state (G_ACTION (action));
2421
2422 g_print (format: "Toggle action %s to %s\n",
2423 g_action_get_name (G_ACTION (action)),
2424 g_variant_get_boolean (value: state) ? "false" : "true");
2425
2426 g_simple_action_set_state (simple: action,
2427 value: g_variant_new_boolean (value: !g_variant_get_boolean (value: state)));
2428}
2429
2430static gboolean
2431quit_timeout (gpointer data)
2432{
2433 exit (status: 0);
2434 return G_SOURCE_REMOVE;
2435}
2436
2437int
2438main (int argc, char *argv[])
2439{
2440 GtkApplication *app;
2441 GAction *action;
2442 static GActionEntry app_entries[] = {
2443 { "about", activate_about, NULL, NULL, NULL },
2444 { "shortcuts", activate_shortcuts_window, NULL, NULL, NULL },
2445 { "quit", activate_quit, NULL, NULL, NULL },
2446 { "inspector", activate_inspector, NULL, NULL, NULL },
2447 { "main", NULL, "s", "'steak'", NULL },
2448 { "wine", NULL, NULL, "false", NULL },
2449 { "beer", NULL, NULL, "false", NULL },
2450 { "water", NULL, NULL, "true", NULL },
2451 { "dessert", NULL, "s", "'bars'", NULL },
2452 { "pay", NULL, "s", NULL, NULL },
2453 { "share", activate_action, NULL, NULL, NULL },
2454 { "labels", activate_action, NULL, NULL, NULL },
2455 { "new", activate_action, NULL, NULL, NULL },
2456 { "open", activate_action, NULL, NULL, NULL },
2457 { "open-in", activate_action, NULL, NULL, NULL },
2458 { "open-tab", activate_action, NULL, NULL, NULL },
2459 { "open-window", activate_action, NULL, NULL, NULL },
2460 { "save", activate_action, NULL, NULL, NULL },
2461 { "save-as", activate_action, NULL, NULL, NULL },
2462 { "cut", activate_action, NULL, NULL, NULL },
2463 { "copy", activate_action, NULL, NULL, NULL },
2464 { "paste", activate_action, NULL, NULL, NULL },
2465 { "pin", toggle_action, NULL, "true", NULL },
2466 { "size", select_action, "s", "'medium'", NULL },
2467 { "berk", toggle_action, NULL, "true", NULL },
2468 { "broni", toggle_action, NULL, "true", NULL },
2469 { "drutt", toggle_action, NULL, "true", NULL },
2470 { "upstairs", toggle_action, NULL, "true", NULL },
2471 { "option-a", activate_action, NULL, NULL, NULL },
2472 { "option-b", activate_action, NULL, NULL, NULL },
2473 { "option-c", activate_action, NULL, NULL, NULL },
2474 { "option-d", activate_action, NULL, NULL, NULL },
2475 { "check-on", NULL, NULL, "true", NULL },
2476 { "check-off", NULL, NULL, "false", NULL },
2477 { "radio-x", NULL, "s", "'x'", NULL },
2478 { "check-on-disabled", NULL, NULL, "true", NULL },
2479 { "check-off-disabled", NULL, NULL, "false", NULL },
2480 { "radio-x-disabled", NULL, "s", "'x'", NULL },
2481 };
2482 int status;
2483
2484 app = gtk_application_new (application_id: "org.gtk.WidgetFactory4", flags: G_APPLICATION_NON_UNIQUE);
2485
2486 g_action_map_add_action_entries (G_ACTION_MAP (app),
2487 entries: app_entries, G_N_ELEMENTS (app_entries),
2488 user_data: app);
2489 action = g_action_map_lookup_action (G_ACTION_MAP (app), action_name: "wine");
2490 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
2491 action = g_action_map_lookup_action (G_ACTION_MAP (app), action_name: "check-on-disabled");
2492 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
2493 action = g_action_map_lookup_action (G_ACTION_MAP (app), action_name: "check-off-disabled");
2494 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
2495 action = g_action_map_lookup_action (G_ACTION_MAP (app), action_name: "radio-x-disabled");
2496 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
2497
2498 g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
2499
2500 g_application_add_main_option (G_APPLICATION (app), long_name: "version", short_name: 0, flags: 0, arg: G_OPTION_ARG_NONE, description: "Show program version", NULL);
2501
2502 if (g_getenv (variable: "GTK_DEBUG_AUTO_QUIT"))
2503 g_timeout_add (interval: 500, function: quit_timeout, NULL);
2504
2505 g_signal_connect (app, "handle-local-options", G_CALLBACK (local_options), NULL);
2506 status = g_application_run (G_APPLICATION (app), argc, argv);
2507 g_object_unref (object: app);
2508
2509 return status;
2510}
2511

source code of gtk/demos/widget-factory/widget-factory.c