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 <glib/gi18n.h>
24 #include <gtk/gtk.h>
25 
26 static void
change_theme_state(GSimpleAction * action,GVariant * state,gpointer user_data)27 change_theme_state (GSimpleAction *action,
28                     GVariant      *state,
29                     gpointer       user_data)
30 {
31   GtkSettings *settings = gtk_settings_get_default ();
32 
33   g_object_set (G_OBJECT (settings),
34                 "gtk-application-prefer-dark-theme",
35                 g_variant_get_boolean (state),
36                 NULL);
37 
38   g_simple_action_set_state (action, state);
39 }
40 
41 static GtkWidget *page_stack;
42 
43 static void
change_transition_state(GSimpleAction * action,GVariant * state,gpointer user_data)44 change_transition_state (GSimpleAction *action,
45                          GVariant      *state,
46                          gpointer       user_data)
47 {
48   GtkStackTransitionType transition;
49 
50   if (g_variant_get_boolean (state))
51     transition = GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT;
52   else
53     transition = GTK_STACK_TRANSITION_TYPE_NONE;
54 
55   gtk_stack_set_transition_type (GTK_STACK (page_stack), transition);
56 
57   g_simple_action_set_state (action, state);
58 }
59 
60 static gboolean
get_idle(gpointer data)61 get_idle (gpointer data)
62 {
63   GtkWidget *window = data;
64   GtkApplication *app = gtk_window_get_application (GTK_WINDOW (window));
65 
66   gtk_widget_set_sensitive (window, TRUE);
67   gdk_window_set_cursor (gtk_widget_get_window (window), NULL);
68   g_application_unmark_busy (G_APPLICATION (app));
69 
70   return G_SOURCE_REMOVE;
71 }
72 
73 static void
get_busy(GSimpleAction * action,GVariant * parameter,gpointer user_data)74 get_busy (GSimpleAction *action,
75           GVariant      *parameter,
76           gpointer       user_data)
77 {
78   GtkWidget *window = user_data;
79   GdkCursor *cursor;
80   GtkApplication *app = gtk_window_get_application (GTK_WINDOW (window));
81 
82   g_application_mark_busy (G_APPLICATION (app));
83   cursor = gdk_cursor_new_from_name (gtk_widget_get_display (window), "wait");
84   gdk_window_set_cursor (gtk_widget_get_window (window), cursor);
85   g_object_unref (cursor);
86   g_timeout_add (5000, get_idle, window);
87 
88   gtk_widget_set_sensitive (window, FALSE);
89 }
90 
91 static gint current_page = 0;
92 static gboolean
on_page(gint i)93 on_page (gint i)
94 {
95   return current_page == i;
96 }
97 
98 static void
activate_search(GSimpleAction * action,GVariant * parameter,gpointer user_data)99 activate_search (GSimpleAction *action,
100                  GVariant      *parameter,
101                  gpointer       user_data)
102 {
103   GtkWidget *window = user_data;
104   GtkWidget *searchbar;
105 
106   if (!on_page (2))
107     return;
108 
109   searchbar = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "searchbar"));
110   gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (searchbar), TRUE);
111 }
112 
113 static void
activate_delete(GSimpleAction * action,GVariant * parameter,gpointer user_data)114 activate_delete (GSimpleAction *action,
115                  GVariant      *parameter,
116                  gpointer       user_data)
117 {
118   GtkWidget *window = user_data;
119   GtkWidget *infobar;
120 
121   if (!on_page (2))
122     return;
123 
124   infobar = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "infobar"));
125   gtk_widget_show (infobar);
126 }
127 
128 static void populate_flowbox (GtkWidget *flowbox);
129 
130 static void
activate_background(GSimpleAction * action,GVariant * parameter,gpointer user_data)131 activate_background (GSimpleAction *action,
132                      GVariant      *parameter,
133                      gpointer       user_data)
134 {
135   GtkWidget *window = user_data;
136   GtkWidget *dialog;
137   GtkWidget *flowbox;
138 
139   if (!on_page (2))
140     return;
141 
142   dialog = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "selection_dialog"));
143   flowbox = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "selection_flowbox"));
144 
145   gtk_widget_show (dialog);
146   populate_flowbox (flowbox);
147 }
148 
149 static void
activate_open(GSimpleAction * action,GVariant * parameter,gpointer user_data)150 activate_open (GSimpleAction *action,
151                GVariant      *parameter,
152                gpointer       user_data)
153 {
154   GtkWidget *window = user_data;
155   GtkWidget *button;
156 
157   if (!on_page (3))
158     return;
159 
160   button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "open_menubutton"));
161   gtk_button_clicked (GTK_BUTTON (button));
162 }
163 
164 static void
activate_record(GSimpleAction * action,GVariant * parameter,gpointer user_data)165 activate_record (GSimpleAction *action,
166                  GVariant      *parameter,
167                  gpointer       user_data)
168 {
169   GtkWidget *window = user_data;
170   GtkWidget *button;
171 
172   if (!on_page (3))
173     return;
174 
175   button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "record_button"));
176   gtk_button_clicked (GTK_BUTTON (button));
177 }
178 
179 static void
activate_lock(GSimpleAction * action,GVariant * parameter,gpointer user_data)180 activate_lock (GSimpleAction *action,
181                GVariant      *parameter,
182                gpointer       user_data)
183 {
184   GtkWidget *window = user_data;
185   GtkWidget *button;
186 
187   if (!on_page (3))
188     return;
189 
190   button = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "lockbutton"));
191   gtk_button_clicked (GTK_BUTTON (button));
192 }
193 
194 static void
activate_about(GSimpleAction * action,GVariant * parameter,gpointer user_data)195 activate_about (GSimpleAction *action,
196                 GVariant      *parameter,
197                 gpointer       user_data)
198 {
199   GtkApplication *app = user_data;
200   const gchar *authors[] = {
201     "Andrea Cimitan",
202     "Cosimo Cecchi",
203     NULL
204   };
205   gchar *version;
206 
207   version = g_strdup_printf ("%s\nRunning against GTK+ %d.%d.%d",
208                              PACKAGE_VERSION,
209                              gtk_get_major_version (),
210                              gtk_get_minor_version (),
211                              gtk_get_micro_version ());
212 
213   gtk_show_about_dialog (GTK_WINDOW (gtk_application_get_active_window (app)),
214                          "program-name", "GTK Widget Factory",
215                          "version", version,
216                          "copyright", "© 1997—2019 The GTK Team",
217                          "license-type", GTK_LICENSE_LGPL_2_1,
218                          "website", "http://www.gtk.org",
219                          "comments", "Program to demonstrate GTK themes and widgets",
220                          "authors", authors,
221                          "logo-icon-name", "gtk3-widget-factory",
222                          "title", "About GTK Widget Factory",
223                          NULL);
224 
225   g_free (version);
226 }
227 
228 static void
activate_quit(GSimpleAction * action,GVariant * parameter,gpointer user_data)229 activate_quit (GSimpleAction *action,
230                GVariant      *parameter,
231                gpointer       user_data)
232 {
233   GtkApplication *app = user_data;
234   GtkWidget *win;
235   GList *list, *next;
236 
237   list = gtk_application_get_windows (app);
238   while (list)
239     {
240       win = list->data;
241       next = list->next;
242 
243       gtk_widget_destroy (GTK_WIDGET (win));
244 
245       list = next;
246     }
247 }
248 
249 static void
activate_inspector(GSimpleAction * action,GVariant * parameter,gpointer user_data)250 activate_inspector (GSimpleAction *action,
251                     GVariant      *parameter,
252                     gpointer       user_data)
253 {
254   gtk_window_set_interactive_debugging (TRUE);
255 }
256 
257 static void
spin_value_changed(GtkAdjustment * adjustment,GtkWidget * label)258 spin_value_changed (GtkAdjustment *adjustment, GtkWidget *label)
259 {
260   GtkWidget *w;
261   gint v;
262   gchar *text;
263 
264   v = (int)gtk_adjustment_get_value (adjustment);
265 
266   if ((v % 3) == 0)
267     {
268       text = g_strdup_printf ("%d is a multiple of 3", v);
269       gtk_label_set_label (GTK_LABEL (label), text);
270       g_free (text);
271     }
272 
273   w = gtk_widget_get_ancestor (label, GTK_TYPE_REVEALER);
274   gtk_revealer_set_reveal_child (GTK_REVEALER (w), (v % 3) == 0);
275 }
276 
277 static void
dismiss(GtkWidget * button)278 dismiss (GtkWidget *button)
279 {
280   GtkWidget *w;
281 
282   w = gtk_widget_get_ancestor (button, GTK_TYPE_REVEALER);
283   gtk_revealer_set_reveal_child (GTK_REVEALER (w), FALSE);
284 }
285 
286 static void
spin_value_reset(GtkWidget * button,GtkAdjustment * adjustment)287 spin_value_reset (GtkWidget *button, GtkAdjustment *adjustment)
288 {
289   gtk_adjustment_set_value (adjustment, 50.0);
290   dismiss (button);
291 }
292 
293 static gint pulse_time = 250;
294 static gint pulse_entry_mode = 0;
295 
296 static void
remove_pulse(gpointer pulse_id)297 remove_pulse (gpointer pulse_id)
298 {
299   g_source_remove (GPOINTER_TO_UINT (pulse_id));
300 }
301 
302 static gboolean
pulse_it(GtkWidget * widget)303 pulse_it (GtkWidget *widget)
304 {
305   guint pulse_id;
306 
307   if (GTK_IS_ENTRY (widget))
308     gtk_entry_progress_pulse (GTK_ENTRY (widget));
309   else
310     gtk_progress_bar_pulse (GTK_PROGRESS_BAR (widget));
311 
312   pulse_id = g_timeout_add (pulse_time, (GSourceFunc)pulse_it, widget);
313   g_object_set_data_full (G_OBJECT (widget), "pulse_id", GUINT_TO_POINTER (pulse_id), remove_pulse);
314 
315   return G_SOURCE_REMOVE;
316 }
317 
318 static void
update_pulse_time(GtkAdjustment * adjustment,GtkWidget * widget)319 update_pulse_time (GtkAdjustment *adjustment, GtkWidget *widget)
320 {
321   gdouble value;
322   guint pulse_id;
323 
324   value = gtk_adjustment_get_value (adjustment);
325 
326   pulse_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "pulse_id"));
327 
328   /* vary between 50 and 450 */
329   pulse_time = 50 + 4 * value;
330 
331   if (value == 100)
332     {
333       g_object_set_data (G_OBJECT (widget), "pulse_id", NULL);
334     }
335   else if (value < 100)
336     {
337       if (pulse_id == 0 && (GTK_IS_PROGRESS_BAR (widget) || pulse_entry_mode % 3 == 2))
338         {
339           pulse_id = g_timeout_add (pulse_time, (GSourceFunc)pulse_it, widget);
340           g_object_set_data_full (G_OBJECT (widget), "pulse_id", GUINT_TO_POINTER (pulse_id), remove_pulse);
341         }
342     }
343 }
344 
345 static void
on_entry_icon_release(GtkEntry * entry,GtkEntryIconPosition icon_pos,GdkEvent * event,gpointer user_data)346 on_entry_icon_release (GtkEntry            *entry,
347                        GtkEntryIconPosition icon_pos,
348                        GdkEvent            *event,
349                        gpointer             user_data)
350 {
351   if (icon_pos != GTK_ENTRY_ICON_SECONDARY)
352     return;
353 
354   pulse_entry_mode++;
355 
356   if (pulse_entry_mode % 3 == 0)
357     {
358       g_object_set_data (G_OBJECT (entry), "pulse_id", NULL);
359       gtk_entry_set_progress_fraction (entry, 0);
360     }
361   else if (pulse_entry_mode % 3 == 1)
362     gtk_entry_set_progress_fraction (entry, 0.25);
363   else if (pulse_entry_mode % 3 == 2)
364     {
365       if (pulse_time - 50 < 400)
366         {
367           gtk_entry_set_progress_pulse_step (entry, 0.1);
368           pulse_it (GTK_WIDGET (entry));
369         }
370     }
371 }
372 
373 #define EPSILON (1e-10)
374 
375 static gboolean
on_scale_button_query_tooltip(GtkWidget * button,gint x,gint y,gboolean keyboard_mode,GtkTooltip * tooltip,gpointer user_data)376 on_scale_button_query_tooltip (GtkWidget  *button,
377                                gint        x,
378                                gint        y,
379                                gboolean    keyboard_mode,
380                                GtkTooltip *tooltip,
381                                gpointer    user_data)
382 {
383   GtkScaleButton *scale_button = GTK_SCALE_BUTTON (button);
384   GtkAdjustment *adjustment;
385   gdouble val;
386   gchar *str;
387   AtkImage *image;
388 
389   image = ATK_IMAGE (gtk_widget_get_accessible (button));
390 
391   adjustment = gtk_scale_button_get_adjustment (scale_button);
392   val = gtk_scale_button_get_value (scale_button);
393 
394   if (val < (gtk_adjustment_get_lower (adjustment) + EPSILON))
395     {
396       str = g_strdup (_("Muted"));
397     }
398   else if (val >= (gtk_adjustment_get_upper (adjustment) - EPSILON))
399     {
400       str = g_strdup (_("Full Volume"));
401     }
402   else
403     {
404       gint percent;
405 
406       percent = (gint) (100. * val / (gtk_adjustment_get_upper (adjustment) - gtk_adjustment_get_lower (adjustment)) + .5);
407 
408       str = g_strdup_printf (C_("volume percentage", "%d %%"), percent);
409     }
410 
411   gtk_tooltip_set_text (tooltip, str);
412   atk_image_set_image_description (image, str);
413   g_free (str);
414 
415   return TRUE;
416 }
417 
418 static void
on_scale_button_value_changed(GtkScaleButton * button,gdouble value,gpointer user_data)419 on_scale_button_value_changed (GtkScaleButton *button,
420                                gdouble         value,
421                                gpointer        user_data)
422 {
423   gtk_widget_trigger_tooltip_query (GTK_WIDGET (button));
424 }
425 
426 static void
on_record_button_toggled(GtkToggleButton * button,gpointer user_data)427 on_record_button_toggled (GtkToggleButton *button,
428                           gpointer         user_data)
429 {
430   GtkStyleContext *context;
431 
432   context = gtk_widget_get_style_context (GTK_WIDGET (button));
433   if (gtk_toggle_button_get_active (button))
434     gtk_style_context_remove_class (context, "destructive-action");
435   else
436     gtk_style_context_add_class (context, "destructive-action");
437 }
438 
439 static void
on_page_combo_changed(GtkComboBox * combo,gpointer user_data)440 on_page_combo_changed (GtkComboBox *combo,
441                        gpointer     user_data)
442 {
443   GtkWidget *from;
444   GtkWidget *to;
445   GtkWidget *print;
446 
447   from = GTK_WIDGET (g_object_get_data (G_OBJECT (combo), "range_from_spin"));
448   to = GTK_WIDGET (g_object_get_data (G_OBJECT (combo), "range_to_spin"));
449   print = GTK_WIDGET (g_object_get_data (G_OBJECT (combo), "print_button"));
450 
451   switch (gtk_combo_box_get_active (combo))
452     {
453     case 0: /* Range */
454       gtk_widget_set_sensitive (from, TRUE);
455       gtk_widget_set_sensitive (to, TRUE);
456       gtk_widget_set_sensitive (print, TRUE);
457       break;
458     case 1: /* All */
459       gtk_widget_set_sensitive (from, FALSE);
460       gtk_widget_set_sensitive (to, FALSE);
461       gtk_spin_button_set_value (GTK_SPIN_BUTTON (from), 1);
462       gtk_spin_button_set_value (GTK_SPIN_BUTTON (to), 99);
463       gtk_widget_set_sensitive (print, TRUE);
464       break;
465     case 2: /* Current */
466       gtk_widget_set_sensitive (from, FALSE);
467       gtk_widget_set_sensitive (to, FALSE);
468       gtk_spin_button_set_value (GTK_SPIN_BUTTON (from), 7);
469       gtk_spin_button_set_value (GTK_SPIN_BUTTON (to), 7);
470       gtk_widget_set_sensitive (print, TRUE);
471       break;
472     case 4:
473       gtk_widget_set_sensitive (from, FALSE);
474       gtk_widget_set_sensitive (to, FALSE);
475       gtk_widget_set_sensitive (print, FALSE);
476       break;
477     default:;
478     }
479 }
480 
481 static void
on_range_from_changed(GtkSpinButton * from)482 on_range_from_changed (GtkSpinButton *from)
483 {
484   GtkSpinButton *to;
485   gint v1, v2;
486 
487   to = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (from), "range_to_spin"));
488 
489   v1 = gtk_spin_button_get_value_as_int (from);
490   v2 = gtk_spin_button_get_value_as_int (to);
491 
492   if (v1 > v2)
493     gtk_spin_button_set_value (to, v1);
494 }
495 
496 static void
on_range_to_changed(GtkSpinButton * to)497 on_range_to_changed (GtkSpinButton *to)
498 {
499   GtkSpinButton *from;
500   gint v1, v2;
501 
502   from = GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (to), "range_from_spin"));
503 
504   v1 = gtk_spin_button_get_value_as_int (from);
505   v2 = gtk_spin_button_get_value_as_int (to);
506 
507   if (v1 > v2)
508     gtk_spin_button_set_value (from, v2);
509 }
510 
511 static void
update_header(GtkListBoxRow * row,GtkListBoxRow * before,gpointer data)512 update_header (GtkListBoxRow *row,
513                GtkListBoxRow *before,
514                gpointer       data)
515 {
516   if (before != NULL &&
517       gtk_list_box_row_get_header (row) == NULL)
518     {
519       GtkWidget *separator;
520 
521       separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
522       gtk_widget_show (separator);
523       gtk_list_box_row_set_header (row, separator);
524     }
525 }
526 
527 static void
info_bar_response(GtkWidget * infobar,gint response_id)528 info_bar_response (GtkWidget *infobar, gint response_id)
529 {
530   if (response_id == GTK_RESPONSE_CLOSE)
531     gtk_widget_hide (infobar);
532 }
533 
534 static void
show_dialog(GtkWidget * button,GtkWidget * dialog)535 show_dialog (GtkWidget *button, GtkWidget *dialog)
536 {
537   gtk_widget_show (dialog);
538 }
539 
540 static void
close_dialog(GtkWidget * dialog)541 close_dialog (GtkWidget *dialog)
542 {
543   gtk_widget_hide (dialog);
544 }
545 
546 static void
set_needs_attention(GtkWidget * page,gboolean needs_attention)547 set_needs_attention (GtkWidget *page, gboolean needs_attention)
548 {
549   GtkWidget *stack;
550 
551   stack = gtk_widget_get_parent (page);
552   gtk_container_child_set (GTK_CONTAINER (stack), page,
553                            "needs-attention", needs_attention,
554                            NULL);
555 }
556 
557 static gboolean
demand_attention(gpointer stack)558 demand_attention (gpointer stack)
559 {
560   GtkWidget *page;
561 
562   page = gtk_stack_get_child_by_name (GTK_STACK (stack), "page3");
563   set_needs_attention (page, TRUE);
564 
565   return G_SOURCE_REMOVE;
566 }
567 
568 static void
action_dialog_button_clicked(GtkButton * button,GtkWidget * page)569 action_dialog_button_clicked (GtkButton *button, GtkWidget *page)
570 {
571   g_timeout_add (1000, demand_attention, page);
572 }
573 
574 static void
page_changed_cb(GtkWidget * stack,GParamSpec * pspec,gpointer data)575 page_changed_cb (GtkWidget *stack, GParamSpec *pspec, gpointer data)
576 {
577   const gchar *name;
578   GtkWidget *window;
579   GtkWidget *page;
580 
581   if (gtk_widget_in_destruction (stack))
582     return;
583 
584   name = gtk_stack_get_visible_child_name (GTK_STACK (stack));
585 
586   window = gtk_widget_get_ancestor (stack, GTK_TYPE_APPLICATION_WINDOW);
587   g_object_set (gtk_application_window_get_help_overlay (GTK_APPLICATION_WINDOW (window)),
588                 "view-name", name,
589                 NULL);
590 
591   if (g_str_equal (name, "page1"))
592     current_page = 1;
593   else if (g_str_equal (name, "page2"))
594     current_page = 2;
595   if (g_str_equal (name, "page3"))
596     {
597       current_page = 3;
598       page = gtk_stack_get_visible_child (GTK_STACK (stack));
599       set_needs_attention (GTK_WIDGET (page), FALSE);
600     }
601 }
602 
603 static void
populate_model(GtkTreeStore * store)604 populate_model (GtkTreeStore *store)
605 {
606   GtkTreeIter iter, parent0, parent1, parent2, parent3;
607 
608   gtk_tree_store_append (store, &iter, NULL);
609   gtk_tree_store_set (store, &iter,
610                       0, "Charlemagne",
611                       1, "742",
612                       2, "814",
613                       -1);
614   parent0 = iter;
615   gtk_tree_store_append (store, &iter, &parent0);
616   gtk_tree_store_set (store, &iter,
617                       0, "Pepin the Short",
618                       1, "714",
619                       2, "768",
620                       -1);
621   parent1 = iter;
622   gtk_tree_store_append (store, &iter, &parent1);
623   gtk_tree_store_set (store, &iter,
624                       0, "Charles Martel",
625                       1, "688",
626                       2, "741",
627                       -1);
628   parent2 = iter;
629   gtk_tree_store_append (store, &iter, &parent2);
630   gtk_tree_store_set (store, &iter,
631                       0, "Pepin of Herstal",
632                       1, "635",
633                       2, "714",
634                       -1);
635   parent3 = iter;
636   gtk_tree_store_append (store, &iter, &parent3);
637   gtk_tree_store_set (store, &iter,
638                       0, "Ansegisel",
639                       1, "602 or 610",
640                       2, "murdered before 679",
641                       -1);
642   gtk_tree_store_append (store, &iter, &parent3);
643   gtk_tree_store_set (store, &iter,
644                       0, "Begga",
645                       1, "615",
646                       2, "693",
647                       -1);
648   gtk_tree_store_append (store, &iter, &parent2);
649   gtk_tree_store_set (store, &iter,
650                       0, "Alpaida",
651                       -1);
652   gtk_tree_store_append (store, &iter, &parent1);
653   gtk_tree_store_set (store, &iter,
654                       0, "Rotrude",
655                       -1);
656   parent2 = iter;
657   gtk_tree_store_append (store, &iter, &parent2);
658   gtk_tree_store_set (store, &iter,
659                       0, "Liévin de Trèves",
660                       -1);
661   parent3 = iter;
662   gtk_tree_store_append (store, &iter, &parent3);
663   gtk_tree_store_set (store, &iter,
664                       0, "Guérin",
665                       -1);
666   gtk_tree_store_append (store, &iter, &parent3);
667   gtk_tree_store_set (store, &iter,
668                       0, "Gunza",
669                       -1);
670   gtk_tree_store_append (store, &iter, &parent2);
671   gtk_tree_store_set (store, &iter,
672                       0, "Willigarde de Bavière",
673                       -1);
674   gtk_tree_store_append (store, &iter, &parent0);
675   gtk_tree_store_set (store, &iter,
676                       0, "Bertrada of Laon",
677                       1, "710",
678                       2, "783",
679                       -1);
680   parent1 = iter;
681   gtk_tree_store_append (store, &iter, &parent1);
682   gtk_tree_store_set (store, &iter,
683                       0, "Caribert of Laon",
684                       2, "before 762",
685                       -1);
686   parent2 = iter;
687   gtk_tree_store_append (store, &iter, &parent2);
688   gtk_tree_store_set (store, &iter,
689                       0, "Unknown",
690                       -1);
691   gtk_tree_store_append (store, &iter, &parent2);
692   gtk_tree_store_set (store, &iter,
693                       0, "Bertrada of Prüm",
694                       1, "ca. 670",
695                       2, "after 721",
696                       -1);
697   gtk_tree_store_append (store, &iter, &parent1);
698   gtk_tree_store_set (store, &iter,
699                       0, "Gisele of Aquitaine",
700                       -1);
701   gtk_tree_store_append (store, &iter, NULL);
702   gtk_tree_store_set (store, &iter, 3, TRUE, -1);
703   gtk_tree_store_append (store, &iter, NULL);
704   gtk_tree_store_set (store, &iter,
705                       0, "Attila the Hun",
706                       1, "ca. 390",
707                       2, "453",
708                       -1);
709 }
710 
711 static gboolean
row_separator_func(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)712 row_separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
713 {
714   gboolean is_sep;
715 
716   gtk_tree_model_get (model, iter, 3, &is_sep, -1);
717 
718   return is_sep;
719 }
720 
721 static void
update_title_header(GtkListBoxRow * row,GtkListBoxRow * before,gpointer data)722 update_title_header (GtkListBoxRow *row,
723                      GtkListBoxRow *before,
724                      gpointer       data)
725 {
726   GtkWidget *header;
727   gchar *title;
728 
729   header = gtk_list_box_row_get_header (row);
730   title = (gchar *)g_object_get_data (G_OBJECT (row), "title");
731   if (!header && title)
732     {
733       title = g_strdup_printf ("<b>%s</b>", title);
734 
735       header = gtk_label_new (title);
736       gtk_label_set_use_markup (GTK_LABEL (header), TRUE);
737       gtk_widget_set_halign (header, GTK_ALIGN_START);
738       gtk_widget_set_margin_top (header, 12);
739       gtk_widget_set_margin_start (header, 6);
740       gtk_widget_set_margin_end (header, 6);
741       gtk_widget_set_margin_bottom (header, 6);
742       gtk_widget_show (header);
743 
744       gtk_list_box_row_set_header (row, header);
745 
746       g_free (title);
747     }
748 }
749 
750 static void
overshot(GtkScrolledWindow * sw,GtkPositionType pos,GtkWidget * widget)751 overshot (GtkScrolledWindow *sw, GtkPositionType pos, GtkWidget *widget)
752 {
753   GtkWidget *box, *row, *label, *swatch;
754   GdkRGBA rgba;
755   const gchar *color;
756   gchar *text;
757   GtkWidget *silver;
758   GtkWidget *gold;
759 
760   silver = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "Silver"));
761   gold = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "Gold"));
762 
763   if (pos == GTK_POS_TOP)
764     {
765       if (silver)
766         {
767           gtk_container_remove (GTK_CONTAINER (widget), silver);
768           g_object_set_data (G_OBJECT (widget), "Silver", NULL);
769         }
770       if (gold)
771         {
772           gtk_container_remove (GTK_CONTAINER (widget), gold);
773           g_object_set_data (G_OBJECT (widget), "Gold", NULL);
774         }
775 
776       return;
777     }
778 
779 
780   if (gold)
781     return;
782   else if (silver)
783     color = "Gold";
784   else
785     color = "Silver";
786 
787   row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 20);
788   text = g_strconcat ("<b>", color, "</b>", NULL);
789   label = gtk_label_new (text);
790   g_free (text);
791   g_object_set (label,
792                 "use-markup", TRUE,
793                 "halign", GTK_ALIGN_START,
794                 "valign", GTK_ALIGN_CENTER,
795                 "margin", 6,
796                 "xalign", 0.0,
797                 NULL);
798   gtk_box_pack_start (GTK_BOX (row), label, TRUE, TRUE, 0);
799   gdk_rgba_parse (&rgba, color);
800   swatch = g_object_new (g_type_from_name ("GtkColorSwatch"),
801                          "rgba", &rgba,
802                          "selectable", FALSE,
803                          "halign", GTK_ALIGN_END,
804                          "valign", GTK_ALIGN_CENTER,
805                          "margin", 6,
806                          "height-request", 24,
807                          NULL);
808   box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
809   gtk_container_add (GTK_CONTAINER (box), swatch);
810   gtk_box_pack_start (GTK_BOX (row), box, FALSE, FALSE, 0);
811   gtk_widget_show_all (row);
812   gtk_list_box_insert (GTK_LIST_BOX (widget), row, -1);
813   row = gtk_widget_get_parent (row);
814   gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
815   g_object_set_data (G_OBJECT (widget), color, row);
816   g_object_set_data (G_OBJECT (row), "color", (gpointer)color);
817 }
818 
819 static void
rgba_changed(GtkColorChooser * chooser,GParamSpec * pspec,GtkListBox * box)820 rgba_changed (GtkColorChooser *chooser, GParamSpec *pspec, GtkListBox *box)
821 {
822   gtk_list_box_select_row (box, NULL);
823 }
824 
825 static void
set_color(GtkListBox * box,GtkListBoxRow * row,GtkColorChooser * chooser)826 set_color (GtkListBox *box, GtkListBoxRow *row, GtkColorChooser *chooser)
827 {
828   const char *color;
829   GdkRGBA rgba;
830 
831   if (!row)
832     return;
833 
834   color = (const char *)g_object_get_data (G_OBJECT (row), "color");
835 
836   if (!color)
837     return;
838 
839   if (gdk_rgba_parse (&rgba, color))
840     {
841       g_signal_handlers_block_by_func (chooser, rgba_changed, box);
842       gtk_color_chooser_set_rgba (chooser, &rgba);
843       g_signal_handlers_unblock_by_func (chooser, rgba_changed, box);
844     }
845 }
846 
847 static void
populate_colors(GtkWidget * widget,GtkWidget * chooser)848 populate_colors (GtkWidget *widget, GtkWidget *chooser)
849 {
850   struct { const gchar *name; const gchar *color; const gchar *title; } colors[] = {
851     { "2.5", "#C8828C", "Red" },
852     { "5", "#C98286", NULL },
853     { "7.5", "#C9827F", NULL },
854     { "10", "#C98376", NULL },
855     { "2.5", "#C8856D", "Red/Yellow" },
856     { "5", "#C58764", NULL },
857     { "7.5", "#C1895E", NULL },
858     { "10", "#BB8C56", NULL },
859     { "2.5", "#B58F4F", "Yellow" },
860     { "5", "#AD924B", NULL },
861     { "7.5", "#A79548", NULL },
862     { "10", "#A09749", NULL },
863     { "2.5", "#979A4E", "Yellow/Green" },
864     { "5", "#8D9C55", NULL },
865     { "7.5", "#7F9F62", NULL },
866     { "10", "#73A06E", NULL },
867     { "2.5", "#65A27C", "Green" },
868     { "5", "#5CA386", NULL },
869     { "7.5", "#57A38D", NULL },
870     { "10", "#52A394", NULL },
871     { "2.5", "#4EA39A", "Green/Blue" },
872     { "5", "#49A3A2", NULL },
873     { "7.5", "#46A2AA", NULL },
874     { "10", "#46A1B1", NULL },
875     { "2.5", "#49A0B8", "Blue" },
876     { "5", "#529EBD", NULL },
877     { "7.5", "#5D9CC1", NULL },
878     { "10", "#689AC3", NULL },
879     { "2.5", "#7597C5", "Blue/Purple" },
880     { "5", "#8095C6", NULL },
881     { "7.5", "#8D91C6", NULL },
882     { "10", "#988EC4", NULL },
883     { "2.5", "#A08CC1", "Purple" },
884     { "5", "#A88ABD", NULL },
885     { "7.5", "#B187B6", NULL },
886     { "10", "#B786B0", NULL },
887     { "2.5", "#BC84A9", "Purple/Red" },
888     { "5", "#C183A0", NULL },
889     { "7.5", "#C48299", NULL },
890     { "10", "#C68292", NULL }
891   };
892   gint i;
893   GtkWidget *row, *box, *label, *swatch;
894   GtkWidget *sw;
895   GdkRGBA rgba;
896 
897   gtk_list_box_set_header_func (GTK_LIST_BOX (widget), update_title_header, NULL, NULL);
898 
899   for (i = 0; i < G_N_ELEMENTS (colors); i++)
900     {
901       row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 20);
902       label = gtk_label_new (colors[i].name);
903       g_object_set (label,
904                     "halign", GTK_ALIGN_START,
905                     "valign", GTK_ALIGN_CENTER,
906                     "margin", 6,
907                     "xalign", 0.0,
908                     NULL);
909       gtk_box_pack_start (GTK_BOX (row), label, TRUE, TRUE, 0);
910       gdk_rgba_parse (&rgba, colors[i].color);
911       swatch = g_object_new (g_type_from_name ("GtkColorSwatch"),
912                              "rgba", &rgba,
913                              "selectable", FALSE,
914                              "halign", GTK_ALIGN_END,
915                              "valign", GTK_ALIGN_CENTER,
916                              "margin", 6,
917                              "height-request", 24,
918                              NULL);
919       box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
920       gtk_container_add (GTK_CONTAINER (box), swatch);
921       gtk_box_pack_start (GTK_BOX (row), box, FALSE, FALSE, 0);
922       gtk_widget_show_all (row);
923       gtk_list_box_insert (GTK_LIST_BOX (widget), row, -1);
924       row = gtk_widget_get_parent (row);
925       gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
926       g_object_set_data (G_OBJECT (row), "color", (gpointer)colors[i].color);
927       if (colors[i].title)
928         g_object_set_data (G_OBJECT (row), "title", (gpointer)colors[i].title);
929     }
930 
931   g_signal_connect (widget, "row-selected", G_CALLBACK (set_color), chooser);
932 
933   gtk_list_box_invalidate_headers (GTK_LIST_BOX (widget));
934 
935   sw = gtk_widget_get_ancestor (widget, GTK_TYPE_SCROLLED_WINDOW);
936   g_signal_connect (sw, "edge-overshot", G_CALLBACK (overshot), widget);
937 }
938 
939 typedef struct {
940   GtkWidget *flowbox;
941   gchar *filename;
942 } BackgroundData;
943 
944 static void
background_loaded_cb(GObject * source,GAsyncResult * res,gpointer data)945 background_loaded_cb (GObject      *source,
946                       GAsyncResult *res,
947                       gpointer      data)
948 {
949   BackgroundData *bd = data;
950   GtkWidget *child;
951   GdkPixbuf *pixbuf;
952   GError *error = NULL;
953 
954   pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
955   if (error)
956     {
957       g_warning ("Error loading '%s': %s", bd->filename, error->message);
958       g_error_free (error);
959       return;
960     }
961 
962   child = gtk_image_new_from_pixbuf (pixbuf);
963   gtk_widget_show (child);
964   gtk_flow_box_insert (GTK_FLOW_BOX (bd->flowbox), child, -1);
965   child = gtk_widget_get_parent (child);
966   g_object_set_data_full (G_OBJECT (child), "filename", bd->filename, g_free);
967   g_free (bd);
968 }
969 
970 static void
populate_flowbox(GtkWidget * flowbox)971 populate_flowbox (GtkWidget *flowbox)
972 {
973   const gchar *location;
974   GDir *dir;
975   GError *error = NULL;
976   const gchar *name;
977   gchar *filename;
978   GFile *file;
979   GInputStream *stream;
980   BackgroundData *bd;
981   GdkPixbuf *pixbuf;
982   GtkWidget *child;
983 
984   if (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (flowbox), "populated")))
985     return;
986 
987   g_object_set_data (G_OBJECT (flowbox), "populated", GUINT_TO_POINTER (1));
988 
989   pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 110, 70);
990   gdk_pixbuf_fill (pixbuf, 0xffffffff);
991   child = gtk_image_new_from_pixbuf (pixbuf);
992   gtk_widget_show (child);
993   gtk_flow_box_insert (GTK_FLOW_BOX (flowbox), child, -1);
994 
995   location = "/usr/share/backgrounds/gnome";
996   dir = g_dir_open (location, 0, &error);
997   if (error)
998     {
999       g_warning ("%s", error->message);
1000       g_error_free (error);
1001       return;
1002     }
1003 
1004   while ((name = g_dir_read_name (dir)) != NULL)
1005     {
1006       filename = g_build_filename (location, name, NULL);
1007       file = g_file_new_for_path (filename);
1008       stream = G_INPUT_STREAM (g_file_read (file, NULL, &error));
1009       if (error)
1010         {
1011           g_warning ("%s", error->message);
1012           g_clear_error (&error);
1013           g_free (filename);
1014         }
1015       else
1016         {
1017           bd = g_new (BackgroundData, 1);
1018           bd->flowbox = flowbox;
1019           bd->filename = filename;
1020           gdk_pixbuf_new_from_stream_at_scale_async (stream, 110, 110, TRUE, NULL,
1021                                                      background_loaded_cb, bd);
1022         }
1023 
1024       g_object_unref (file);
1025       g_object_unref (stream);
1026     }
1027 
1028   g_dir_close (dir);
1029 }
1030 
1031 static void
row_activated(GtkListBox * box,GtkListBoxRow * row)1032 row_activated (GtkListBox *box, GtkListBoxRow *row)
1033 {
1034   GtkWidget *image;
1035   GtkWidget *dialog;
1036 
1037   image = (GtkWidget *)g_object_get_data (G_OBJECT (row), "image");
1038   dialog = (GtkWidget *)g_object_get_data (G_OBJECT (row), "dialog");
1039 
1040   if (image)
1041     {
1042       if (gtk_widget_get_opacity (image) > 0)
1043         gtk_widget_set_opacity (image, 0);
1044       else
1045         gtk_widget_set_opacity (image, 1);
1046     }
1047   else if (dialog)
1048     {
1049       gtk_window_present (GTK_WINDOW (dialog));
1050     }
1051 }
1052 
1053 static void
set_accel(GtkApplication * app,GtkWidget * widget)1054 set_accel (GtkApplication *app, GtkWidget *widget)
1055 {
1056   GtkWidget *accel_label;
1057   const gchar *action;
1058   gchar **accels;
1059   guint key;
1060   GdkModifierType mods;
1061 
1062   accel_label = gtk_bin_get_child (GTK_BIN (widget));
1063   g_assert (GTK_IS_ACCEL_LABEL (accel_label));
1064 
1065   action = gtk_actionable_get_action_name (GTK_ACTIONABLE (widget));
1066   accels = gtk_application_get_accels_for_action (app, action);
1067 
1068   gtk_accelerator_parse (accels[0], &key, &mods);
1069   gtk_accel_label_set_accel (GTK_ACCEL_LABEL (accel_label), key, mods);
1070 
1071   g_strfreev (accels);
1072 }
1073 
1074 typedef struct
1075 {
1076   GtkTextView tv;
1077   cairo_surface_t *surface;
1078 } MyTextView;
1079 
1080 typedef GtkTextViewClass MyTextViewClass;
1081 
G_DEFINE_TYPE(MyTextView,my_text_view,GTK_TYPE_TEXT_VIEW)1082 G_DEFINE_TYPE (MyTextView, my_text_view, GTK_TYPE_TEXT_VIEW)
1083 
1084 static void
1085 my_text_view_init (MyTextView *tv)
1086 {
1087 }
1088 
1089 static void
my_tv_draw_layer(GtkTextView * widget,GtkTextViewLayer layer,cairo_t * cr)1090 my_tv_draw_layer (GtkTextView      *widget,
1091                   GtkTextViewLayer  layer,
1092                   cairo_t          *cr)
1093 {
1094   MyTextView *tv = (MyTextView *)widget;
1095 
1096   if (layer == GTK_TEXT_VIEW_LAYER_BELOW_TEXT && tv->surface)
1097     {
1098       cairo_save (cr);
1099       cairo_set_source_surface (cr, tv->surface, 0.0, 0.0);
1100       cairo_paint_with_alpha (cr, 0.333);
1101       cairo_restore (cr);
1102     }
1103 }
1104 
1105 static void
my_tv_finalize(GObject * object)1106 my_tv_finalize (GObject *object)
1107 {
1108   MyTextView *tv = (MyTextView *)object;
1109 
1110   if (tv->surface)
1111     cairo_surface_destroy (tv->surface);
1112 
1113   G_OBJECT_CLASS (my_text_view_parent_class)->finalize (object);
1114 }
1115 
1116 static void
my_text_view_class_init(MyTextViewClass * class)1117 my_text_view_class_init (MyTextViewClass *class)
1118 {
1119   GtkTextViewClass *tv_class = GTK_TEXT_VIEW_CLASS (class);
1120   GObjectClass *o_class = G_OBJECT_CLASS (class);
1121 
1122   o_class->finalize = my_tv_finalize;
1123   tv_class->draw_layer = my_tv_draw_layer;
1124 }
1125 
1126 static void
my_text_view_set_background(MyTextView * tv,const gchar * filename)1127 my_text_view_set_background (MyTextView *tv, const gchar *filename)
1128 {
1129   GdkPixbuf *pixbuf;
1130   GError *error = NULL;
1131 
1132   if (tv->surface)
1133     cairo_surface_destroy (tv->surface);
1134 
1135   tv->surface = NULL;
1136 
1137   if (filename == NULL)
1138     return;
1139 
1140   pixbuf = gdk_pixbuf_new_from_file (filename, &error);
1141   if (error)
1142     {
1143       g_warning ("%s", error->message);
1144       g_error_free (error);
1145       return;
1146     }
1147 
1148   tv->surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL);
1149 
1150   g_object_unref (pixbuf);
1151 
1152   gtk_widget_queue_draw (GTK_WIDGET (tv));
1153 }
1154 
1155 static void
close_selection_dialog(GtkWidget * dialog,gint response,GtkWidget * tv)1156 close_selection_dialog (GtkWidget *dialog, gint response, GtkWidget *tv)
1157 {
1158   GtkWidget *box;
1159   GtkWidget *child;
1160   GList *children;
1161   const gchar *filename;
1162 
1163   gtk_widget_hide (dialog);
1164 
1165   if (response == GTK_RESPONSE_CANCEL)
1166     return;
1167 
1168   box = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
1169   children = gtk_container_get_children (GTK_CONTAINER (box));
1170   box = children->data;
1171   g_list_free (children);
1172   g_assert (GTK_IS_FLOW_BOX (box));
1173   children = gtk_flow_box_get_selected_children (GTK_FLOW_BOX (box));
1174 
1175   if (!children)
1176     return;
1177 
1178   child = children->data;
1179   filename = (const gchar *)g_object_get_data (G_OBJECT (child), "filename");
1180 
1181   g_list_free (children);
1182 
1183   my_text_view_set_background ((MyTextView *)tv, filename);
1184 }
1185 
1186 static void
toggle_selection_mode(GtkSwitch * sw,GParamSpec * pspec,GtkListBox * listbox)1187 toggle_selection_mode (GtkSwitch  *sw,
1188                        GParamSpec *pspec,
1189                        GtkListBox *listbox)
1190 {
1191   if (gtk_switch_get_active (sw))
1192     gtk_list_box_set_selection_mode (listbox, GTK_SELECTION_SINGLE);
1193   else
1194     gtk_list_box_set_selection_mode (listbox, GTK_SELECTION_NONE);
1195 
1196   gtk_list_box_set_activate_on_single_click (listbox, !gtk_switch_get_active (sw));
1197 }
1198 
1199 static void
handle_insert(GtkWidget * button,GtkWidget * textview)1200 handle_insert (GtkWidget *button, GtkWidget *textview)
1201 {
1202   GtkTextBuffer *buffer;
1203   const gchar *id;
1204   const gchar *text;
1205 
1206   id = gtk_buildable_get_name (GTK_BUILDABLE (button));
1207 
1208   if (strcmp (id, "toolbutton1") == 0)
1209     text = "⌘";
1210   else if (strcmp (id, "toolbutton2") == 0)
1211     text = "⚽";
1212   else if (strcmp (id, "toolbutton3") == 0)
1213     text = "⤢";
1214   else if (strcmp (id, "toolbutton4") == 0)
1215     text = "☆";
1216   else
1217     text = "";
1218 
1219   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
1220   gtk_text_buffer_insert_at_cursor (buffer, text, -1);
1221 }
1222 
1223 static void
handle_cutcopypaste(GtkWidget * button,GtkWidget * textview)1224 handle_cutcopypaste (GtkWidget *button, GtkWidget *textview)
1225 {
1226   GtkTextBuffer *buffer;
1227   GtkClipboard *clipboard;
1228   const gchar *id;
1229 
1230   clipboard = gtk_widget_get_clipboard (textview, GDK_SELECTION_CLIPBOARD);
1231   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
1232   id = gtk_buildable_get_name (GTK_BUILDABLE (button));
1233 
1234   if (strcmp (id, "cutbutton") == 0)
1235     gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
1236   else if (strcmp (id, "copybutton") == 0)
1237     gtk_text_buffer_copy_clipboard (buffer, clipboard);
1238   else if (strcmp (id, "pastebutton") == 0)
1239     gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
1240   else if (strcmp (id, "deletebutton") == 0)
1241     gtk_text_buffer_delete_selection (buffer, TRUE, TRUE);
1242 }
1243 
1244 static void
clipboard_owner_change(GtkClipboard * clipboard,GdkEvent * event,GtkWidget * button)1245 clipboard_owner_change (GtkClipboard *clipboard, GdkEvent *event, GtkWidget *button)
1246 {
1247   const gchar *id;
1248   gboolean has_text;
1249 
1250   id = gtk_buildable_get_name (GTK_BUILDABLE (button));
1251   has_text = gtk_clipboard_wait_is_text_available (clipboard);
1252 
1253   if (strcmp (id, "pastebutton") == 0)
1254     gtk_widget_set_sensitive (button, has_text);
1255 }
1256 
1257 static void
textbuffer_notify_selection(GObject * object,GParamSpec * pspec,GtkWidget * button)1258 textbuffer_notify_selection (GObject *object, GParamSpec *pspec, GtkWidget *button)
1259 {
1260   const gchar *id;
1261   gboolean has_selection;
1262 
1263   id = gtk_buildable_get_name (GTK_BUILDABLE (button));
1264   has_selection = gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (object));
1265 
1266   if (strcmp (id, "cutbutton") == 0 ||
1267       strcmp (id, "copybutton") == 0 ||
1268       strcmp (id, "deletebutton") == 0)
1269     gtk_widget_set_sensitive (button, has_selection);
1270 }
1271 
1272 static gboolean
osd_frame_button_press(GtkWidget * frame,GdkEventButton * event,gpointer data)1273 osd_frame_button_press (GtkWidget *frame, GdkEventButton *event, gpointer data)
1274 {
1275   GtkWidget *osd;
1276   gboolean visible;
1277 
1278   osd = g_object_get_data (G_OBJECT (frame), "osd");
1279   visible = gtk_widget_get_visible (osd);
1280   gtk_widget_set_visible (osd, !visible);
1281 
1282   return GDK_EVENT_STOP;
1283 }
1284 
1285 static gboolean
page_combo_separator_func(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)1286 page_combo_separator_func (GtkTreeModel *model,
1287                            GtkTreeIter  *iter,
1288                            gpointer      data)
1289 {
1290   gchar *text;
1291   gboolean res;
1292 
1293   gtk_tree_model_get (model, iter, 0, &text, -1);
1294   res = g_strcmp0 (text, "-") == 0;
1295   g_free (text);
1296 
1297   return res;
1298 }
1299 
1300 static void
activate_item(GtkWidget * item,GtkTextView * tv)1301 activate_item (GtkWidget *item, GtkTextView *tv)
1302 {
1303   const gchar *tag;
1304   GtkTextIter start, end;
1305   gboolean active;
1306 
1307   g_object_get (item, "active", &active, NULL);
1308   tag = (const gchar *)g_object_get_data (G_OBJECT (item), "tag");
1309   gtk_text_buffer_get_selection_bounds (gtk_text_view_get_buffer (tv), &start, &end);
1310   if (active)
1311     gtk_text_buffer_apply_tag_by_name (gtk_text_view_get_buffer (tv), tag, &start, &end);
1312   else
1313     gtk_text_buffer_remove_tag_by_name (gtk_text_view_get_buffer (tv), tag, &start, &end);
1314 }
1315 
1316 static void
add_item(GtkTextView * tv,GtkWidget * popup,const gchar * text,const gchar * tag,gboolean set)1317 add_item (GtkTextView *tv,
1318           GtkWidget   *popup,
1319           const gchar *text,
1320           const gchar *tag,
1321           gboolean     set)
1322 {
1323   GtkWidget *item, *label;
1324 
1325   if (GTK_IS_MENU (popup))
1326     {
1327       item = gtk_check_menu_item_new ();
1328       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), set);
1329       g_signal_connect (item, "toggled", G_CALLBACK (activate_item), tv);
1330     }
1331   else
1332     {
1333       item = gtk_check_button_new ();
1334       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), set);
1335       gtk_widget_set_focus_on_click (item, FALSE);
1336       g_signal_connect (item, "clicked", G_CALLBACK (activate_item), tv);
1337     }
1338 
1339   label = gtk_label_new ("");
1340   gtk_label_set_xalign (GTK_LABEL (label), 0);
1341   gtk_label_set_markup (GTK_LABEL (label), text);
1342   gtk_widget_show (label);
1343   gtk_container_add (GTK_CONTAINER (item), label);
1344   g_object_set_data (G_OBJECT (item), "tag", (gpointer)tag);
1345   gtk_widget_show (item);
1346   gtk_container_add (GTK_CONTAINER (popup), item);
1347 }
1348 
1349 static void
populate_popup(GtkTextView * tv,GtkWidget * popup)1350 populate_popup (GtkTextView *tv,
1351                 GtkWidget   *popup)
1352 {
1353   gboolean has_selection;
1354   GtkWidget *item;
1355   GtkTextIter start, end, iter;
1356   GtkTextTagTable *tags;
1357   GtkTextTag *bold, *italic, *underline;
1358   gboolean all_bold, all_italic, all_underline;
1359 
1360   has_selection = gtk_text_buffer_get_selection_bounds (gtk_text_view_get_buffer (tv), &start, &end);
1361 
1362   if (!has_selection)
1363     return;
1364 
1365   tags = gtk_text_buffer_get_tag_table (gtk_text_view_get_buffer (tv));
1366   bold = gtk_text_tag_table_lookup (tags, "bold");
1367   italic = gtk_text_tag_table_lookup (tags, "italic");
1368   underline = gtk_text_tag_table_lookup (tags, "underline");
1369   all_bold = TRUE;
1370   all_italic = TRUE;
1371   all_underline = TRUE;
1372   gtk_text_iter_assign (&iter, &start);
1373   while (!gtk_text_iter_equal (&iter, &end))
1374     {
1375       all_bold &= gtk_text_iter_has_tag (&iter, bold);
1376       all_italic &= gtk_text_iter_has_tag (&iter, italic);
1377       all_underline &= gtk_text_iter_has_tag (&iter, underline);
1378       gtk_text_iter_forward_char (&iter);
1379     }
1380 
1381   if (GTK_IS_MENU (popup))
1382     {
1383       item = gtk_separator_menu_item_new ();
1384       gtk_widget_show (item);
1385       gtk_container_add (GTK_CONTAINER (popup), item);
1386     }
1387 
1388   add_item (tv, popup, "<b>Bold</b>", "bold", all_bold);
1389   add_item (tv, popup, "<i>Italics</i>", "italic", all_italic);
1390   add_item (tv, popup, "<u>Underline</u>", "underline", all_underline);
1391 }
1392 
1393 static void
open_popover_text_changed(GtkEntry * entry,GParamSpec * pspec,GtkWidget * button)1394 open_popover_text_changed (GtkEntry *entry, GParamSpec *pspec, GtkWidget *button)
1395 {
1396   const gchar *text;
1397 
1398   text = gtk_entry_get_text (entry);
1399   gtk_widget_set_sensitive (button, strlen (text) > 0);
1400 }
1401 
1402 static gboolean
show_page_again(gpointer data)1403 show_page_again (gpointer data)
1404 {
1405   gtk_widget_show (GTK_WIDGET (data));
1406   return G_SOURCE_REMOVE;
1407 }
1408 
1409 static void
tab_close_cb(GtkWidget * page)1410 tab_close_cb (GtkWidget *page)
1411 {
1412   gtk_widget_hide (page);
1413   g_timeout_add (2500, show_page_again, page);
1414 }
1415 
1416 typedef struct _GTestPermission GTestPermission;
1417 typedef struct _GTestPermissionClass GTestPermissionClass;
1418 
1419 struct _GTestPermission
1420 {
1421   GPermission parent;
1422 };
1423 
1424 struct _GTestPermissionClass
1425 {
1426   GPermissionClass parent_class;
1427 };
1428 
G_DEFINE_TYPE(GTestPermission,g_test_permission,G_TYPE_PERMISSION)1429 G_DEFINE_TYPE (GTestPermission, g_test_permission, G_TYPE_PERMISSION)
1430 
1431 static void
1432 g_test_permission_init (GTestPermission *test)
1433 {
1434   g_permission_impl_update (G_PERMISSION (test), TRUE, TRUE, TRUE);
1435 }
1436 
1437 static gboolean
update_allowed(GPermission * permission,gboolean allowed)1438 update_allowed (GPermission *permission,
1439                 gboolean     allowed)
1440 {
1441   g_permission_impl_update (permission, allowed, TRUE, TRUE);
1442 
1443   return TRUE;
1444 }
1445 
1446 static gboolean
acquire(GPermission * permission,GCancellable * cancellable,GError ** error)1447 acquire (GPermission   *permission,
1448          GCancellable  *cancellable,
1449          GError       **error)
1450 {
1451   return update_allowed (permission, TRUE);
1452 }
1453 
1454 static void
acquire_async(GPermission * permission,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1455 acquire_async (GPermission         *permission,
1456                GCancellable        *cancellable,
1457                GAsyncReadyCallback  callback,
1458                gpointer             user_data)
1459 {
1460   GTask *task;
1461 
1462   task = g_task_new ((GObject*)permission, NULL, callback, user_data);
1463   g_task_return_boolean (task, update_allowed (permission, TRUE));
1464   g_object_unref (task);
1465 }
1466 
1467 gboolean
acquire_finish(GPermission * permission,GAsyncResult * res,GError ** error)1468 acquire_finish (GPermission   *permission,
1469                 GAsyncResult  *res,
1470                 GError       **error)
1471 {
1472   return g_task_propagate_boolean (G_TASK (res), error);
1473 }
1474 
1475 static gboolean
release(GPermission * permission,GCancellable * cancellable,GError ** error)1476 release (GPermission   *permission,
1477          GCancellable  *cancellable,
1478          GError       **error)
1479 {
1480   return update_allowed (permission, FALSE);
1481 }
1482 
1483 static void
release_async(GPermission * permission,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1484 release_async (GPermission         *permission,
1485                GCancellable        *cancellable,
1486                GAsyncReadyCallback  callback,
1487                gpointer             user_data)
1488 {
1489   GTask *task;
1490 
1491   task = g_task_new ((GObject*)permission, NULL, callback, user_data);
1492   g_task_return_boolean (task, update_allowed (permission, FALSE));
1493   g_object_unref (task);
1494 }
1495 
1496 gboolean
release_finish(GPermission * permission,GAsyncResult * result,GError ** error)1497 release_finish (GPermission   *permission,
1498                 GAsyncResult  *result,
1499                 GError       **error)
1500 {
1501   return g_task_propagate_boolean (G_TASK (result), error);
1502 }
1503 
1504 static void
g_test_permission_class_init(GTestPermissionClass * class)1505 g_test_permission_class_init (GTestPermissionClass *class)
1506 {
1507   GPermissionClass *permission_class = G_PERMISSION_CLASS (class);
1508 
1509   permission_class->acquire = acquire;
1510   permission_class->acquire_async = acquire_async;
1511   permission_class->acquire_finish = acquire_finish;
1512 
1513   permission_class->release = release;
1514   permission_class->release_async = release_async;
1515   permission_class->release_finish = release_finish;
1516 }
1517 
1518 static int icon_sizes[5];
1519 
1520 static void
register_icon_sizes(void)1521 register_icon_sizes (void)
1522 {
1523   static gboolean registered;
1524 
1525   if (registered)
1526     return;
1527 
1528   registered = TRUE;
1529 
1530 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1531   icon_sizes[0] = gtk_icon_size_register ("a", 16, 16);
1532   icon_sizes[1] = gtk_icon_size_register ("b", 24, 24);
1533   icon_sizes[2] = gtk_icon_size_register ("c", 32, 32);
1534   icon_sizes[3] = gtk_icon_size_register ("d", 48, 48);
1535   icon_sizes[4] = gtk_icon_size_register ("e", 64, 64);
1536 G_GNUC_END_IGNORE_DEPRECATIONS
1537 }
1538 
1539 static int
find_icon_size(GtkIconSize size)1540 find_icon_size (GtkIconSize size)
1541 {
1542   gint w, h, w2, h2;
1543   gint i;
1544 
1545 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1546   gtk_icon_size_lookup (size, &w, &h);
1547   for (i = 0; i < G_N_ELEMENTS (icon_sizes); i++)
1548     {
1549       gtk_icon_size_lookup (icon_sizes[i], &w2, &h2);
1550       if (w == w2)
1551         return i;
1552     }
1553 G_GNUC_END_IGNORE_DEPRECATIONS
1554 
1555   return 2;
1556 }
1557 
1558 static void
update_buttons(GtkWidget * iv,int pos)1559 update_buttons (GtkWidget *iv, int pos)
1560 {
1561   GtkWidget *button;
1562 
1563   button = GTK_WIDGET (g_object_get_data (G_OBJECT (iv), "increase_button"));
1564   gtk_widget_set_sensitive (button, pos + 1 < G_N_ELEMENTS (icon_sizes));
1565   button = GTK_WIDGET (g_object_get_data (G_OBJECT (iv), "decrease_button"));
1566   gtk_widget_set_sensitive (button, pos > 0);
1567 }
1568 
1569 static void
increase_icon_size(GtkWidget * iv)1570 increase_icon_size (GtkWidget *iv)
1571 {
1572   GList *cells;
1573   GtkCellRendererPixbuf *cell;
1574   GtkIconSize size;
1575   int i;
1576 
1577   cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (iv));
1578   cell = cells->data;
1579   g_list_free (cells);
1580 
1581   g_object_get (cell, "stock-size", &size, NULL);
1582 
1583   i = find_icon_size (size);
1584   i = CLAMP (i + 1, 0, G_N_ELEMENTS (icon_sizes) - 1);
1585   size = icon_sizes[i];
1586 
1587   g_object_set (cell, "stock-size", size, NULL);
1588 
1589   update_buttons (iv, i);
1590 
1591   gtk_widget_queue_resize (iv);
1592 }
1593 
1594 static void
decrease_icon_size(GtkWidget * iv)1595 decrease_icon_size (GtkWidget *iv)
1596 {
1597   GList *cells;
1598   GtkCellRendererPixbuf *cell;
1599   GtkIconSize size;
1600   int i;
1601 
1602   cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (iv));
1603   cell = cells->data;
1604   g_list_free (cells);
1605 
1606   g_object_get (cell, "stock-size", &size, NULL);
1607 
1608   i = find_icon_size (size);
1609   i = CLAMP (i - 1, 0, G_N_ELEMENTS (icon_sizes) - 1);
1610   size = icon_sizes[i];
1611 
1612   g_object_set (cell, "stock-size", size, NULL);
1613 
1614   update_buttons (iv, i);
1615 
1616   gtk_widget_queue_resize (iv);
1617 }
1618 
1619 static void
reset_icon_size(GtkWidget * iv)1620 reset_icon_size (GtkWidget *iv)
1621 {
1622   GList *cells;
1623   GtkCellRendererPixbuf *cell;
1624 
1625   cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (iv));
1626   cell = cells->data;
1627   g_list_free (cells);
1628 
1629   g_object_set (cell, "stock-size", icon_sizes[2], NULL);
1630 
1631   update_buttons (iv, 2);
1632 
1633   gtk_widget_queue_resize (iv);
1634 }
1635 
1636 static gchar *
scale_format_value_blank(GtkScale * scale,gdouble value)1637 scale_format_value_blank (GtkScale *scale, gdouble value)
1638 {
1639   return g_strdup (" ");
1640 }
1641 
1642 static gchar *
scale_format_value(GtkScale * scale,gdouble value)1643 scale_format_value (GtkScale *scale, gdouble value)
1644 {
1645   return g_strdup_printf ("%0.*f", 1, value);
1646 }
1647 
1648 static void
adjustment3_value_changed(GtkAdjustment * adj,GtkProgressBar * pbar)1649 adjustment3_value_changed (GtkAdjustment *adj, GtkProgressBar *pbar)
1650 {
1651   double fraction;
1652 
1653   fraction = gtk_adjustment_get_value (adj) / (gtk_adjustment_get_upper (adj) - gtk_adjustment_get_lower (adj));
1654 
1655   gtk_progress_bar_set_fraction (pbar, fraction);
1656 }
1657 
1658 static void
validate_more_details(GtkEntry * entry,GParamSpec * pspec,GtkEntry * details)1659 validate_more_details (GtkEntry   *entry,
1660                        GParamSpec *pspec,
1661                        GtkEntry   *details)
1662 {
1663   if (strlen (gtk_entry_get_text (entry)) > 0 &&
1664       strlen (gtk_entry_get_text (details)) == 0)
1665     {
1666       gtk_widget_set_tooltip_text (GTK_WIDGET (entry), "Must have details first");
1667       gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (entry)), "error");
1668     }
1669   else
1670     {
1671       gtk_widget_set_tooltip_text (GTK_WIDGET (entry), "");
1672       gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (entry)), "error");
1673     }
1674 }
1675 
1676 static gboolean
mode_switch_state_set(GtkSwitch * sw,gboolean state)1677 mode_switch_state_set (GtkSwitch *sw, gboolean state)
1678 {
1679   GtkWidget *dialog = gtk_widget_get_ancestor (GTK_WIDGET (sw), GTK_TYPE_DIALOG);
1680   GtkWidget *scale = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "level_scale"));
1681   GtkWidget *label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "error_label"));
1682 
1683   if (!state ||
1684       (gtk_range_get_value (GTK_RANGE (scale)) > 50))
1685     {
1686       gtk_widget_hide (label);
1687       gtk_switch_set_state (sw, state);
1688     }
1689   else
1690     {
1691       gtk_widget_show (label);
1692     }
1693 
1694   return TRUE;
1695 }
1696 
1697 static void
level_scale_value_changed(GtkRange * range)1698 level_scale_value_changed (GtkRange *range)
1699 {
1700   GtkWidget *dialog = gtk_widget_get_ancestor (GTK_WIDGET (range), GTK_TYPE_DIALOG);
1701   GtkWidget *sw = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "mode_switch"));
1702   GtkWidget *label = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "error_label"));
1703 
1704   if (gtk_switch_get_active (GTK_SWITCH (sw)) &&
1705       !gtk_switch_get_state (GTK_SWITCH (sw)) &&
1706       (gtk_range_get_value (range) > 50))
1707     {
1708       gtk_widget_hide (label);
1709       gtk_switch_set_state (GTK_SWITCH (sw), TRUE);
1710     }
1711   else if (gtk_switch_get_state (GTK_SWITCH (sw)) &&
1712           (gtk_range_get_value (range) <= 50))
1713     {
1714       gtk_switch_set_state (GTK_SWITCH (sw), FALSE);
1715     }
1716 }
1717 
1718 static void
activate(GApplication * app)1719 activate (GApplication *app)
1720 {
1721   GtkBuilder *builder;
1722   GtkWindow *window;
1723   GtkWidget *widget;
1724   GtkWidget *widget2;
1725   GtkWidget *widget3;
1726   GtkWidget *widget4;
1727   GtkWidget *stack;
1728   GtkWidget *dialog;
1729   GtkAdjustment *adj;
1730   GtkCssProvider *provider;
1731   static GActionEntry win_entries[] = {
1732     { "dark", NULL, NULL, "false", change_theme_state },
1733     { "transition", NULL, NULL, "false", change_transition_state },
1734     { "search", activate_search, NULL, NULL, NULL },
1735     { "delete", activate_delete, NULL, NULL, NULL },
1736     { "busy", get_busy, NULL, NULL, NULL },
1737     { "background", activate_background, NULL, NULL, NULL },
1738     { "open", activate_open, NULL, NULL, NULL },
1739     { "record", activate_record, NULL, NULL, NULL },
1740     { "lock", activate_lock, NULL, NULL, NULL },
1741   };
1742   struct {
1743     const gchar *action_and_target;
1744     const gchar *accelerators[2];
1745   } accels[] = {
1746     { "app.about", { "F1", NULL } },
1747     { "app.quit", { "<Primary>q", NULL } },
1748     { "win.dark", { "<Primary>d", NULL } },
1749     { "win.search", { "<Primary>s", NULL } },
1750     { "win.delete", { "Delete", NULL } },
1751     { "win.background", { "<Primary>b", NULL } },
1752     { "win.open", { "<Primary>o", NULL } },
1753     { "win.record", { "<Primary>r", NULL } },
1754     { "win.lock", { "<Primary>l", NULL } },
1755   };
1756   gint i;
1757   GPermission *permission;
1758   GAction *action;
1759 
1760   g_type_ensure (my_text_view_get_type ());
1761   register_icon_sizes ();
1762 
1763   provider = gtk_css_provider_new ();
1764   gtk_css_provider_load_from_resource (provider, "/org/gtk/WidgetFactory/widget-factory.css");
1765   gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
1766                                              GTK_STYLE_PROVIDER (provider),
1767                                              GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1768   g_object_unref (provider);
1769 
1770   builder = gtk_builder_new_from_resource ("/org/gtk/WidgetFactory/widget-factory.ui");
1771   gtk_builder_add_callback_symbol (builder, "on_entry_icon_release", (GCallback)on_entry_icon_release);
1772   gtk_builder_add_callback_symbol (builder, "on_scale_button_value_changed", (GCallback)on_scale_button_value_changed);
1773   gtk_builder_add_callback_symbol (builder, "on_scale_button_query_tooltip", (GCallback)on_scale_button_query_tooltip);
1774   gtk_builder_add_callback_symbol (builder, "on_record_button_toggled", (GCallback)on_record_button_toggled);
1775   gtk_builder_add_callback_symbol (builder, "on_page_combo_changed", (GCallback)on_page_combo_changed);
1776   gtk_builder_add_callback_symbol (builder, "on_range_from_changed", (GCallback)on_range_from_changed);
1777   gtk_builder_add_callback_symbol (builder, "on_range_to_changed", (GCallback)on_range_to_changed);
1778   gtk_builder_add_callback_symbol (builder, "osd_frame_button_press", (GCallback)osd_frame_button_press);
1779   gtk_builder_add_callback_symbol (builder, "tab_close_cb", (GCallback)tab_close_cb);
1780   gtk_builder_add_callback_symbol (builder, "increase_icon_size", (GCallback)increase_icon_size);
1781   gtk_builder_add_callback_symbol (builder, "decrease_icon_size", (GCallback)decrease_icon_size);
1782   gtk_builder_add_callback_symbol (builder, "reset_icon_size", (GCallback)reset_icon_size);
1783   gtk_builder_add_callback_symbol (builder, "scale_format_value", (GCallback)scale_format_value);
1784   gtk_builder_add_callback_symbol (builder, "scale_format_value_blank", (GCallback)scale_format_value_blank);
1785   gtk_builder_add_callback_symbol (builder, "validate_more_details", (GCallback)validate_more_details);
1786   gtk_builder_add_callback_symbol (builder, "mode_switch_state_set", (GCallback)mode_switch_state_set);
1787   gtk_builder_add_callback_symbol (builder, "level_scale_value_changed", (GCallback)level_scale_value_changed);
1788 
1789   gtk_builder_connect_signals (builder, NULL);
1790 
1791   window = (GtkWindow *)gtk_builder_get_object (builder, "window");
1792   gtk_application_add_window (GTK_APPLICATION (app), window);
1793   g_action_map_add_action_entries (G_ACTION_MAP (window),
1794                                    win_entries, G_N_ELEMENTS (win_entries),
1795                                    window);
1796 
1797   for (i = 0; i < G_N_ELEMENTS (accels); i++)
1798     gtk_application_set_accels_for_action (GTK_APPLICATION (app), accels[i].action_and_target, accels[i].accelerators);
1799 
1800   widget = (GtkWidget *)gtk_builder_get_object (builder, "statusbar");
1801   gtk_statusbar_push (GTK_STATUSBAR (widget), 0, "All systems are operating normally.");
1802   action = G_ACTION (g_property_action_new ("statusbar", widget, "visible"));
1803   g_action_map_add_action (G_ACTION_MAP (window), action);
1804   g_object_unref (G_OBJECT (action));
1805 
1806   widget = (GtkWidget *)gtk_builder_get_object (builder, "toolbar");
1807   action = G_ACTION (g_property_action_new ("toolbar", widget, "visible"));
1808   g_action_map_add_action (G_ACTION_MAP (window), action);
1809   g_object_unref (G_OBJECT (action));
1810 
1811   adj = (GtkAdjustment *)gtk_builder_get_object (builder, "adjustment1");
1812 
1813   widget = (GtkWidget *)gtk_builder_get_object (builder, "progressbar3");
1814   g_signal_connect (adj, "value-changed", G_CALLBACK (update_pulse_time), widget);
1815   update_pulse_time (adj, widget);
1816 
1817   widget = (GtkWidget *)gtk_builder_get_object (builder, "entry1");
1818   g_signal_connect (adj, "value-changed", G_CALLBACK (update_pulse_time), widget);
1819   update_pulse_time (adj, widget);
1820 
1821   widget = (GtkWidget *)gtk_builder_get_object (builder, "page2reset");
1822   adj = (GtkAdjustment *) gtk_builder_get_object (builder, "adjustment2");
1823   g_signal_connect (widget, "clicked", G_CALLBACK (spin_value_reset), adj);
1824 
1825   widget = (GtkWidget *)gtk_builder_get_object (builder, "page2dismiss");
1826   g_signal_connect (widget, "clicked", G_CALLBACK (dismiss), NULL);
1827 
1828   widget = (GtkWidget *)gtk_builder_get_object (builder, "page2note");
1829   adj = (GtkAdjustment *) gtk_builder_get_object (builder, "adjustment2");
1830   g_signal_connect (adj, "value-changed", G_CALLBACK (spin_value_changed), widget);
1831 
1832   widget = (GtkWidget *)gtk_builder_get_object (builder, "listbox");
1833   gtk_list_box_set_header_func (GTK_LIST_BOX (widget), update_header, NULL, NULL);
1834   g_signal_connect (widget, "row-activated", G_CALLBACK (row_activated), NULL);
1835 
1836   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "listboxrow1switch");
1837   g_signal_connect (widget2, "notify::active", G_CALLBACK (toggle_selection_mode), widget);
1838 
1839   widget = (GtkWidget *)gtk_builder_get_object (builder, "listboxrow3");
1840   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "listboxrow3image");
1841   g_object_set_data (G_OBJECT (widget), "image", widget2);
1842 
1843   widget = (GtkWidget *)gtk_builder_get_object (builder, "listboxrow4");
1844   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "info_dialog");
1845   g_object_set_data (G_OBJECT (widget), "dialog", widget2);
1846 
1847   widget = (GtkWidget *)gtk_builder_get_object (builder, "listboxrow5button");
1848   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "action_dialog");
1849   g_signal_connect_swapped (widget, "clicked", G_CALLBACK (gtk_window_present), widget2);
1850 
1851   widget = (GtkWidget *)gtk_builder_get_object (builder, "toolbar");
1852   g_object_set_data (G_OBJECT (window), "toolbar", widget);
1853 
1854   widget = (GtkWidget *)gtk_builder_get_object (builder, "searchbar");
1855   g_object_set_data (G_OBJECT (window), "searchbar", widget);
1856 
1857   widget = (GtkWidget *)gtk_builder_get_object (builder, "infobar");
1858   g_signal_connect (widget, "response", G_CALLBACK (info_bar_response), NULL);
1859   g_object_set_data (G_OBJECT (window), "infobar", widget);
1860 
1861   dialog = (GtkWidget *)gtk_builder_get_object (builder, "info_dialog");
1862   g_signal_connect (dialog, "response", G_CALLBACK (close_dialog), NULL);
1863   widget = (GtkWidget *)gtk_builder_get_object (builder, "info_dialog_button");
1864   g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
1865 
1866   dialog = (GtkWidget *)gtk_builder_get_object (builder, "action_dialog");
1867   g_signal_connect (dialog, "response", G_CALLBACK (close_dialog), NULL);
1868   widget = (GtkWidget *)gtk_builder_get_object (builder, "action_dialog_button");
1869   g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
1870 
1871   widget = (GtkWidget *)gtk_builder_get_object (builder, "act_action_dialog");
1872   stack = (GtkWidget *)gtk_builder_get_object (builder, "toplevel_stack");
1873   g_signal_connect (widget, "clicked", G_CALLBACK (action_dialog_button_clicked), stack);
1874   g_signal_connect (stack, "notify::visible-child-name", G_CALLBACK (page_changed_cb), NULL);
1875   page_changed_cb (stack, NULL, NULL);
1876 
1877   page_stack = stack;
1878 
1879   dialog = (GtkWidget *)gtk_builder_get_object (builder, "preference_dialog");
1880   g_signal_connect (dialog, "response", G_CALLBACK (close_dialog), NULL);
1881   widget = (GtkWidget *)gtk_builder_get_object (builder, "preference_dialog_button");
1882   g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
1883   widget = (GtkWidget *)gtk_builder_get_object (builder, "circular_button");
1884   g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
1885 
1886   widget = (GtkWidget *)gtk_builder_get_object (builder, "level_scale");
1887   g_object_set_data (G_OBJECT (dialog), "level_scale", widget);
1888   widget = (GtkWidget *)gtk_builder_get_object (builder, "mode_switch");
1889   g_object_set_data (G_OBJECT (dialog), "mode_switch", widget);
1890   widget = (GtkWidget *)gtk_builder_get_object (builder, "error_label");
1891   g_object_set_data (G_OBJECT (dialog), "error_label", widget);
1892 
1893   dialog = (GtkWidget *)gtk_builder_get_object (builder, "selection_dialog");
1894   g_object_set_data (G_OBJECT (window), "selection_dialog", dialog);
1895   widget = (GtkWidget *)gtk_builder_get_object (builder, "text3");
1896   g_signal_connect (dialog, "response", G_CALLBACK (close_selection_dialog), widget);
1897   widget = (GtkWidget *)gtk_builder_get_object (builder, "selection_dialog_button");
1898   g_signal_connect (widget, "clicked", G_CALLBACK (show_dialog), dialog);
1899 
1900   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "selection_flowbox");
1901   g_object_set_data (G_OBJECT (window), "selection_flowbox", widget2);
1902   g_signal_connect_swapped (widget, "clicked", G_CALLBACK (populate_flowbox), widget2);
1903 
1904   widget = (GtkWidget *)gtk_builder_get_object (builder, "charletree");
1905   populate_model ((GtkTreeStore *)gtk_tree_view_get_model (GTK_TREE_VIEW (widget)));
1906   gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (widget), row_separator_func, NULL, NULL);
1907   gtk_tree_view_expand_all (GTK_TREE_VIEW (widget));
1908 
1909   widget = GTK_WIDGET (gtk_builder_get_object (builder, "munsell"));
1910   widget2 = GTK_WIDGET (gtk_builder_get_object (builder, "cchooser"));
1911 
1912   populate_colors (widget, widget2);
1913   g_signal_connect (widget2, "notify::rgba", G_CALLBACK (rgba_changed), widget);
1914 
1915   widget = (GtkWidget *)gtk_builder_get_object (builder, "page_combo");
1916   gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (widget), page_combo_separator_func, NULL, NULL);
1917   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "range_from_spin");
1918   widget3 = (GtkWidget *)gtk_builder_get_object (builder, "range_to_spin");
1919   widget4 = (GtkWidget *)gtk_builder_get_object (builder, "print_button");
1920   g_object_set_data (G_OBJECT (widget), "range_from_spin", widget2);
1921   g_object_set_data (G_OBJECT (widget3), "range_from_spin", widget2);
1922   g_object_set_data (G_OBJECT (widget), "range_to_spin", widget3);
1923   g_object_set_data (G_OBJECT (widget2), "range_to_spin", widget3);
1924   g_object_set_data (G_OBJECT (widget), "print_button", widget4);
1925 
1926   set_accel (GTK_APPLICATION (app), GTK_WIDGET (gtk_builder_get_object (builder, "quitmenuitem")));
1927   set_accel (GTK_APPLICATION (app), GTK_WIDGET (gtk_builder_get_object (builder, "deletemenuitem")));
1928   set_accel (GTK_APPLICATION (app), GTK_WIDGET (gtk_builder_get_object (builder, "searchmenuitem")));
1929   set_accel (GTK_APPLICATION (app), GTK_WIDGET (gtk_builder_get_object (builder, "darkmenuitem")));
1930   set_accel (GTK_APPLICATION (app), GTK_WIDGET (gtk_builder_get_object (builder, "aboutmenuitem")));
1931   set_accel (GTK_APPLICATION (app), GTK_WIDGET (gtk_builder_get_object (builder, "bgmenuitem")));
1932 
1933   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "tooltextview");
1934 
1935   widget = (GtkWidget *)gtk_builder_get_object (builder, "toolbutton1");
1936   g_signal_connect (widget, "clicked", G_CALLBACK (handle_insert), widget2);
1937   widget = (GtkWidget *)gtk_builder_get_object (builder, "toolbutton2");
1938   g_signal_connect (widget, "clicked", G_CALLBACK (handle_insert), widget2);
1939   widget = (GtkWidget *)gtk_builder_get_object (builder, "toolbutton3");
1940   g_signal_connect (widget, "clicked", G_CALLBACK (handle_insert), widget2);
1941   widget = (GtkWidget *)gtk_builder_get_object (builder, "toolbutton4");
1942   g_signal_connect (widget, "clicked", G_CALLBACK (handle_insert), widget2);
1943   widget = (GtkWidget *)gtk_builder_get_object (builder, "cutbutton");
1944   g_signal_connect (widget, "clicked", G_CALLBACK (handle_cutcopypaste), widget2);
1945   g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget2)), "notify::has-selection",
1946                     G_CALLBACK (textbuffer_notify_selection), widget);
1947   widget = (GtkWidget *)gtk_builder_get_object (builder, "copybutton");
1948   g_signal_connect (widget, "clicked", G_CALLBACK (handle_cutcopypaste), widget2);
1949   g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget2)), "notify::has-selection",
1950                     G_CALLBACK (textbuffer_notify_selection), widget);
1951   widget = (GtkWidget *)gtk_builder_get_object (builder, "deletebutton");
1952   g_signal_connect (widget, "clicked", G_CALLBACK (handle_cutcopypaste), widget2);
1953   g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget2)), "notify::has-selection",
1954                     G_CALLBACK (textbuffer_notify_selection), widget);
1955   widget = (GtkWidget *)gtk_builder_get_object (builder, "pastebutton");
1956   g_signal_connect (widget, "clicked", G_CALLBACK (handle_cutcopypaste), widget2);
1957   g_signal_connect_object (gtk_widget_get_clipboard (widget2, GDK_SELECTION_CLIPBOARD), "owner-change",
1958                            G_CALLBACK (clipboard_owner_change), widget, 0);
1959 
1960   widget = (GtkWidget *)gtk_builder_get_object (builder, "osd_frame");
1961   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "totem_like_osd");
1962   g_object_set_data (G_OBJECT (widget), "osd", widget2);
1963 
1964   widget = (GtkWidget *)gtk_builder_get_object (builder, "textview1");
1965   g_signal_connect (widget, "populate-popup",
1966                     G_CALLBACK (populate_popup), NULL);
1967 
1968   widget = (GtkWidget *)gtk_builder_get_object (builder, "open_popover");
1969   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "open_popover_entry");
1970   widget3 = (GtkWidget *)gtk_builder_get_object (builder, "open_popover_button");
1971   gtk_popover_set_default_widget (GTK_POPOVER (widget), widget3);
1972   g_signal_connect (widget2, "notify::text", G_CALLBACK (open_popover_text_changed), widget3);
1973   g_signal_connect_swapped (widget3, "clicked", G_CALLBACK (gtk_widget_hide), widget);
1974   widget = (GtkWidget *)gtk_builder_get_object (builder, "open_menubutton");
1975   g_object_set_data (G_OBJECT (window), "open_menubutton", widget);
1976   widget = (GtkWidget *)gtk_builder_get_object (builder, "record_button");
1977   g_object_set_data (G_OBJECT (window), "record_button", widget);
1978 
1979   widget = (GtkWidget *)gtk_builder_get_object (builder, "lockbox");
1980   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "lockbutton");
1981   g_object_set_data (G_OBJECT (window), "lockbutton", widget2);
1982   permission = g_object_new (g_test_permission_get_type (), NULL);
1983   g_object_bind_property (permission, "allowed",
1984                           widget, "sensitive",
1985                           G_BINDING_SYNC_CREATE);
1986   action = g_action_map_lookup_action (G_ACTION_MAP (window), "open");
1987   g_object_bind_property (permission, "allowed",
1988                           action, "enabled",
1989                           G_BINDING_SYNC_CREATE);
1990   action = g_action_map_lookup_action (G_ACTION_MAP (window), "record");
1991   g_object_bind_property (permission, "allowed",
1992                           action, "enabled",
1993                           G_BINDING_SYNC_CREATE);
1994   gtk_lock_button_set_permission (GTK_LOCK_BUTTON (widget2), permission);
1995   g_object_unref (permission);
1996 
1997   widget = (GtkWidget *)gtk_builder_get_object (builder, "iconview1");
1998   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "increase_button");
1999   g_object_set_data (G_OBJECT (widget), "increase_button", widget2);
2000   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "decrease_button");
2001   g_object_set_data (G_OBJECT (widget), "decrease_button", widget2);
2002 
2003   adj = (GtkAdjustment *)gtk_builder_get_object (builder, "adjustment3");
2004   widget = (GtkWidget *)gtk_builder_get_object (builder, "progressbar1");
2005   widget2 = (GtkWidget *)gtk_builder_get_object (builder, "progressbar2");
2006   g_signal_connect (adj, "value-changed", G_CALLBACK (adjustment3_value_changed), widget);
2007   g_signal_connect (adj, "value-changed", G_CALLBACK (adjustment3_value_changed), widget2);
2008 
2009   gtk_widget_show_all (GTK_WIDGET (window));
2010 
2011   g_object_unref (builder);
2012 }
2013 
2014 static void
print_version(void)2015 print_version (void)
2016 {
2017   g_print ("gtk3-widget-factory %d.%d.%d\n",
2018            gtk_get_major_version (),
2019            gtk_get_minor_version (),
2020            gtk_get_micro_version ());
2021 }
2022 
2023 static int
local_options(GApplication * app,GVariantDict * options,gpointer data)2024 local_options (GApplication *app,
2025                GVariantDict *options,
2026                gpointer      data)
2027 {
2028   gboolean version = FALSE;
2029 
2030   g_variant_dict_lookup (options, "version", "b", &version);
2031 
2032   if (version)
2033     {
2034       print_version ();
2035       return 0;
2036     }
2037 
2038   return -1;
2039 }
2040 
2041 int
main(int argc,char * argv[])2042 main (int argc, char *argv[])
2043 {
2044   GtkApplication *app;
2045   GAction *action;
2046   static GActionEntry app_entries[] = {
2047     { "about", activate_about, NULL, NULL, NULL },
2048     { "quit", activate_quit, NULL, NULL, NULL },
2049     { "inspector", activate_inspector, NULL, NULL, NULL },
2050     { "main", NULL, "s", "'steak'", NULL },
2051     { "wine", NULL, NULL, "false", NULL },
2052     { "beer", NULL, NULL, "false", NULL },
2053     { "water", NULL, NULL, "true", NULL },
2054     { "dessert", NULL, "s", "'bars'", NULL },
2055     { "pay", NULL, "s", NULL, NULL }
2056   };
2057   gint status;
2058 
2059   app = gtk_application_new ("org.gtk.WidgetFactory", G_APPLICATION_NON_UNIQUE);
2060 
2061   g_action_map_add_action_entries (G_ACTION_MAP (app),
2062                                    app_entries, G_N_ELEMENTS (app_entries),
2063                                    app);
2064   action = g_action_map_lookup_action (G_ACTION_MAP (app), "wine");
2065   g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
2066 
2067   g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
2068 
2069   g_application_add_main_option (G_APPLICATION (app), "version", 0, 0, G_OPTION_ARG_NONE, "Show program version", NULL);
2070 
2071   g_signal_connect (app, "handle-local-options", G_CALLBACK (local_options), NULL);
2072   status = g_application_run (G_APPLICATION (app), argc, argv);
2073   g_object_unref (app);
2074 
2075   return status;
2076 }
2077