1 /*
2  *  Copyright (c) 2012-2013 Andrzej Radecki <andrzejr@xfce.org>
3  *  Copyright (c) 2017      Viktor Odintsev <ninetls@xfce.org>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program 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
13  *  GNU Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #ifdef HAVE_STRING_H
26 #include <string.h>
27 #endif
28 
29 #include <libxfce4ui/libxfce4ui.h>
30 #include <libxfce4util/libxfce4util.h>
31 #include <libxfce4panel/libxfce4panel.h>
32 
33 #include "sn-dialog.h"
34 #include "sn-dialog-ui.h"
35 
36 
37 
38 #define DEFAULT_ICON_SIZE          22
39 
40 
41 
42 static gboolean              sn_dialog_build                         (SnDialog                *dialog);
43 
44 static void                  sn_dialog_finalize                      (GObject                 *object);
45 
46 
47 
48 struct _SnDialogClass
49 {
50   GObjectClass         __parent__;
51 };
52 
53 struct _SnDialog
54 {
55   GObject              __parent__;
56 
57   GtkBuilder          *builder;
58   GtkWidget           *dialog;
59   GtkWidget           *auto_size;
60   GtkWidget           *size_spinbutton;
61   GtkWidget           *size_revealer;
62   GObject             *store;
63   GObject             *legacy_store;
64   SnConfig            *config;
65 };
66 
67 G_DEFINE_TYPE (SnDialog, sn_dialog, G_TYPE_OBJECT)
68 
69 
70 
71 enum
72 {
73   COLUMN_PIXBUF,
74   COLUMN_TITLE,
75   COLUMN_HIDDEN,
76   COLUMN_TIP
77 };
78 
79 
80 
81 /* known applications to improve the icon and name */
82 static const gchar *known_applications[][3] =
83 {
84   /* application name, icon-name, understandable name */
85   { "blueman", "blueman", "Blueman Applet" },
86   { "nm-applet", "network-workgroup", "Network Manager Applet" },
87   { "Skype1", "skypeforlinux", "Skype" },
88   { "chrome_status_icon_1", "google-chrome", "Google Chrome" },
89   { "Telegram Desktop", "telegram", "Telegram Desktop" },
90   { "redshift", "redshift", "Redshift" },
91   { "vlc", "vlc", "VLC Player" },
92   { "zoom", "Zoom", "Zoom" },
93 };
94 
95 static const gchar *known_legacy_applications[][3] =
96 {
97   /* application name, icon-name, understandable name */
98   { "audacious2", "audacious", "Audacious" },
99   { "drop-down terminal", "utilities-terminal", "Xfce Dropdown Terminal" },
100   { "networkmanager applet", "network-workgroup", "Network Manager Applet" },
101   { "parole", "parole", "Parole Media Player" },
102   { "task manager", "org.xfce.taskmanager", "Xfce Taskmanager" },
103   { "thunar", "Thunar", "Thunar Progress Dialog" },
104   { "wicd-client.py", "wicd-gtk", "Wicd" },
105   { "workrave tray icon", NULL, "Workrave Applet" },
106   { "workrave", NULL, "Workrave" },
107   { "xfce terminal", "utilities-terminal", "Xfce Terminal" },
108   { "xfce4-power-manager", "xfpm-ac-adapter", "Xfce Power Manager" },
109   { "redshift-gtk", "redshift", "Redshift" },
110   { "skypeforlinux", "skypeforlinux", "Skype" },
111   { "blueman-applet", "blueman", "Blueman Applet" },
112   { "system-config-printer", "printer", "Printing Service" },
113   { "network", "network-workgroup", "Network Manager Applet" },
114 };
115 
116 
117 
118 static void
sn_dialog_class_init(SnDialogClass * klass)119 sn_dialog_class_init (SnDialogClass *klass)
120 {
121   GObjectClass *object_class;
122 
123   object_class = G_OBJECT_CLASS (klass);
124   object_class->finalize = sn_dialog_finalize;
125 }
126 
127 
128 
129 static void
sn_dialog_init(SnDialog * dialog)130 sn_dialog_init (SnDialog *dialog)
131 {
132   dialog->builder = NULL;
133   dialog->dialog = NULL;
134   dialog->store  = NULL;
135   dialog->legacy_store  = NULL;
136   dialog->config = NULL;
137 }
138 
139 
140 
141 static void
sn_dialog_add_item(SnDialog * dialog,GdkPixbuf * pixbuf,const gchar * name,const gchar * title,gboolean hidden)142 sn_dialog_add_item (SnDialog   *dialog,
143                     GdkPixbuf   *pixbuf,
144                     const gchar *name,
145                     const gchar *title,
146                     gboolean     hidden)
147 {
148   GtkTreeIter iter;
149 
150   g_return_if_fail (XFCE_IS_SN_DIALOG (dialog));
151   g_return_if_fail (GTK_IS_LIST_STORE (dialog->store));
152   g_return_if_fail (name == NULL || g_utf8_validate (name, -1, NULL));
153 
154   /* insert in the store */
155   gtk_list_store_append (GTK_LIST_STORE (dialog->store), &iter);
156   gtk_list_store_set (GTK_LIST_STORE (dialog->store), &iter,
157                       COLUMN_PIXBUF,  pixbuf,
158                       COLUMN_TITLE,   title,
159                       COLUMN_HIDDEN,  hidden,
160                       COLUMN_TIP,     name,
161                       -1);
162 }
163 
164 
165 
166 static void
sn_dialog_add_legacy_item(SnDialog * dialog,GdkPixbuf * pixbuf,const gchar * name,const gchar * title,gboolean hidden)167 sn_dialog_add_legacy_item(SnDialog *dialog,
168                    GdkPixbuf *pixbuf,
169                    const gchar *name,
170                    const gchar *title,
171                    gboolean hidden)
172 {
173   GtkTreeIter iter;
174 
175   g_return_if_fail(XFCE_IS_SN_DIALOG(dialog));
176   g_return_if_fail(GTK_IS_LIST_STORE(dialog->legacy_store));
177   g_return_if_fail(name == NULL || g_utf8_validate(name, -1, NULL));
178 
179   /* insert in the store */
180   gtk_list_store_append(GTK_LIST_STORE(dialog->legacy_store), &iter);
181   gtk_list_store_set(GTK_LIST_STORE(dialog->legacy_store), &iter,
182                      COLUMN_PIXBUF, pixbuf,
183                      COLUMN_TITLE, title,
184                      COLUMN_HIDDEN, hidden,
185                      COLUMN_TIP, name,
186                      -1);
187 }
188 
189 
190 
191 static void
sn_dialog_update_names(SnDialog * dialog)192 sn_dialog_update_names (SnDialog *dialog)
193 {
194   GList       *li;
195   const gchar *name;
196   const gchar *title;
197   const gchar *icon_name;
198   GdkPixbuf   *pixbuf;
199   guint        i;
200 
201   g_return_if_fail (XFCE_IS_SN_DIALOG (dialog));
202   g_return_if_fail (XFCE_IS_SN_CONFIG (dialog->config));
203   g_return_if_fail (GTK_IS_LIST_STORE (dialog->store));
204 
205   for (li = sn_config_get_known_items (dialog->config); li != NULL; li = li->next)
206     {
207       name = li->data;
208       title = name;
209       icon_name = name;
210 
211       /* check if we have a better name for the application */
212       for (i = 0; i < G_N_ELEMENTS (known_applications); i++)
213         {
214           if (strcmp (name, known_applications[i][0]) == 0)
215             {
216               icon_name = known_applications[i][1];
217               title = known_applications[i][2];
218               break;
219             }
220         }
221 
222       pixbuf = xfce_panel_pixbuf_from_source (icon_name, NULL, 22);
223 
224       /* insert item in the store */
225       sn_dialog_add_item (dialog, pixbuf, name, title,
226                           sn_config_is_hidden (dialog->config, name));
227 
228       if (pixbuf != NULL)
229         g_object_unref (G_OBJECT (pixbuf));
230     }
231 }
232 
233 
234 
235 static void
sn_dialog_update_legacy_names(SnDialog * dialog)236 sn_dialog_update_legacy_names(SnDialog *dialog)
237 {
238   GList *li;
239   const gchar *name;
240   const gchar *title;
241   const gchar *icon_name;
242   GdkPixbuf *pixbuf;
243   guint i;
244 
245   g_return_if_fail(XFCE_IS_SN_DIALOG(dialog));
246   g_return_if_fail(XFCE_IS_SN_CONFIG(dialog->config));
247   g_return_if_fail(GTK_IS_LIST_STORE(dialog->legacy_store));
248 
249   for (li = sn_config_get_known_legacy_items(dialog->config); li != NULL; li = li->next)
250   {
251     name = li->data;
252     title = name;
253     icon_name = name;
254 
255     /* check if we have a better name for the application */
256     for (i = 0; i < G_N_ELEMENTS(known_legacy_applications); i++)
257     {
258       if (strcmp(name, known_legacy_applications[i][0]) == 0)
259       {
260         icon_name = known_legacy_applications[i][1];
261         title = known_legacy_applications[i][2];
262         break;
263       }
264     }
265 
266     pixbuf = xfce_panel_pixbuf_from_source(icon_name, NULL, 22);
267 
268     /* insert item in the store */
269     sn_dialog_add_legacy_item(dialog, pixbuf, name, title,
270                        sn_config_is_legacy_hidden(dialog->config, name));
271 
272     if (pixbuf != NULL)
273       g_object_unref(G_OBJECT(pixbuf));
274   }
275 }
276 
277 
278 
279 static void
sn_dialog_selection_changed(GtkTreeSelection * selection,SnDialog * dialog)280 sn_dialog_selection_changed (GtkTreeSelection *selection,
281                              SnDialog         *dialog)
282 {
283   GtkTreeModel *model;
284   GtkTreeIter   iter;
285   GtkTreePath  *path;
286   gint         *indices;
287   gint          count = 0, position = -1, depth;
288   gboolean      item_up_sensitive, item_down_sensitive;
289   GObject      *object;
290 
291   if (gtk_tree_selection_get_selected (selection, &model, &iter))
292     {
293       path = gtk_tree_model_get_path (model, &iter);
294       indices = gtk_tree_path_get_indices_with_depth (path, &depth);
295 
296       if (indices != NULL && depth > 0)
297         position = indices[0];
298 
299       count = gtk_tree_model_iter_n_children (model, NULL);
300 
301       gtk_tree_path_free (path);
302     }
303 
304   item_up_sensitive = position > 0;
305   item_down_sensitive = position + 1 < count;
306 
307   object = gtk_builder_get_object (dialog->builder, "item-up");
308   if (GTK_IS_BUTTON (object))
309     gtk_widget_set_sensitive (GTK_WIDGET (object), item_up_sensitive);
310 
311   object = gtk_builder_get_object (dialog->builder, "item-down");
312   if (GTK_IS_BUTTON (object))
313     gtk_widget_set_sensitive (GTK_WIDGET (object), item_down_sensitive);
314 }
315 
316 
317 
318 static void
sn_dialog_legacy_selection_changed(GtkTreeSelection * selection,SnDialog * dialog)319 sn_dialog_legacy_selection_changed (GtkTreeSelection *selection,
320                                     SnDialog         *dialog)
321 {
322   GtkTreeModel *model;
323   GtkTreeIter   iter;
324   GtkTreePath  *path;
325   gint         *indices;
326   gint          count = 0, position = -1, depth;
327   gboolean      item_up_sensitive, item_down_sensitive;
328   GObject      *object;
329 
330   if (gtk_tree_selection_get_selected (selection, &model, &iter))
331     {
332       path = gtk_tree_model_get_path (model, &iter);
333       indices = gtk_tree_path_get_indices_with_depth (path, &depth);
334 
335       if (indices != NULL && depth > 0)
336         position = indices[0];
337 
338       count = gtk_tree_model_iter_n_children (model, NULL);
339 
340       gtk_tree_path_free (path);
341     }
342 
343   item_up_sensitive = position > 0;
344   item_down_sensitive = position + 1 < count;
345 
346   object = gtk_builder_get_object (dialog->builder, "item-up");
347   if (GTK_IS_BUTTON (object))
348     gtk_widget_set_sensitive (GTK_WIDGET (object), item_up_sensitive);
349 
350   object = gtk_builder_get_object (dialog->builder, "item-down");
351   if (GTK_IS_BUTTON (object))
352     gtk_widget_set_sensitive (GTK_WIDGET (object), item_down_sensitive);
353 }
354 
355 
356 
357 static void
sn_dialog_hidden_toggled(GtkCellRendererToggle * renderer,const gchar * path_string,SnDialog * dialog)358 sn_dialog_hidden_toggled (GtkCellRendererToggle *renderer,
359                           const gchar           *path_string,
360                           SnDialog              *dialog)
361 {
362   GtkTreeIter  iter;
363   gboolean     hidden;
364   gchar       *name;
365 
366   g_return_if_fail (XFCE_IS_SN_DIALOG (dialog));
367   g_return_if_fail (XFCE_IS_SN_CONFIG (dialog->config));
368   g_return_if_fail (GTK_IS_LIST_STORE (dialog->store));
369 
370   if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (dialog->store), &iter, path_string))
371     {
372       gtk_tree_model_get (GTK_TREE_MODEL (dialog->store), &iter,
373                           COLUMN_HIDDEN, &hidden,
374                           COLUMN_TIP, &name, -1);
375 
376       /* insert value (we need to update it) */
377       hidden = !hidden;
378 
379       /* update box and store with new state */
380       sn_config_set_hidden (dialog->config, name, hidden);
381       gtk_list_store_set (GTK_LIST_STORE (dialog->store), &iter, COLUMN_HIDDEN, hidden, -1);
382 
383       g_free (name);
384     }
385 }
386 
387 
388 
389 static void
sn_dialog_legacy_hidden_toggled(GtkCellRendererToggle * renderer,const gchar * path_string,SnDialog * dialog)390 sn_dialog_legacy_hidden_toggled (GtkCellRendererToggle *renderer,
391                                  const gchar           *path_string,
392                                  SnDialog              *dialog)
393 {
394   GtkTreeIter  iter;
395   gboolean     hidden;
396   gchar       *name;
397 
398   g_return_if_fail (XFCE_IS_SN_DIALOG (dialog));
399   g_return_if_fail (XFCE_IS_SN_CONFIG (dialog->config));
400   g_return_if_fail (GTK_IS_LIST_STORE (dialog->store));
401 
402   if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (dialog->legacy_store), &iter, path_string))
403     {
404       gtk_tree_model_get (GTK_TREE_MODEL (dialog->legacy_store), &iter,
405                           COLUMN_HIDDEN, &hidden,
406                           COLUMN_TIP, &name, -1);
407 
408       /* insert value (we need to update it) */
409       hidden = !hidden;
410 
411       /* update box and store with new state */
412       sn_config_set_legacy_hidden (dialog->config, name, hidden);
413       gtk_list_store_set (GTK_LIST_STORE (dialog->legacy_store), &iter, COLUMN_HIDDEN, hidden, -1);
414 
415       g_free (name);
416     }
417 }
418 
419 
420 
421 static void
sn_dialog_swap_rows(SnDialog * dialog,GtkTreeIter * iter_prev,GtkTreeIter * iter)422 sn_dialog_swap_rows (SnDialog   *dialog,
423                      GtkTreeIter *iter_prev,
424                      GtkTreeIter *iter)
425 {
426   GdkPixbuf *pixbuf1, *pixbuf2;
427   gchar     *title1, *title2;
428   gboolean   hidden1, hidden2;
429   gchar     *tip1, *tip2;
430 
431   g_return_if_fail (XFCE_IS_SN_DIALOG (dialog));
432   g_return_if_fail (XFCE_IS_SN_CONFIG (dialog->config));
433   g_return_if_fail (GTK_IS_LIST_STORE (dialog->store));
434 
435   gtk_tree_model_get (GTK_TREE_MODEL (dialog->store), iter_prev,
436                       COLUMN_PIXBUF,  &pixbuf1,
437                       COLUMN_TITLE,   &title1,
438                       COLUMN_HIDDEN,  &hidden1,
439                       COLUMN_TIP,     &tip1, -1);
440   gtk_tree_model_get (GTK_TREE_MODEL (dialog->store), iter,
441                       COLUMN_PIXBUF,  &pixbuf2,
442                       COLUMN_TITLE,   &title2,
443                       COLUMN_HIDDEN,  &hidden2,
444                       COLUMN_TIP,     &tip2, -1);
445   gtk_list_store_set (GTK_LIST_STORE (dialog->store), iter_prev,
446                       COLUMN_PIXBUF,  pixbuf2,
447                       COLUMN_TITLE,   title2,
448                       COLUMN_HIDDEN,  hidden2,
449                       COLUMN_TIP,     tip2, -1);
450   gtk_list_store_set (GTK_LIST_STORE (dialog->store), iter,
451                       COLUMN_PIXBUF,  pixbuf1,
452                       COLUMN_TITLE,   title1,
453                       COLUMN_HIDDEN,  hidden1,
454                       COLUMN_TIP,     tip1, -1);
455 
456   /* do a matching operation on SnConfig */
457   sn_config_swap_known_items (dialog->config, tip1, tip2);
458 }
459 
460 
461 
462 static void
sn_dialog_legacy_swap_rows(SnDialog * dialog,GtkTreeIter * iter_prev,GtkTreeIter * iter)463 sn_dialog_legacy_swap_rows(SnDialog *dialog,
464                            GtkTreeIter *iter_prev,
465                            GtkTreeIter *iter)
466 {
467   GdkPixbuf *pixbuf1, *pixbuf2;
468   gchar *title1, *title2;
469   gboolean hidden1, hidden2;
470   gchar *tip1, *tip2;
471 
472   g_return_if_fail(XFCE_IS_SN_DIALOG(dialog));
473   g_return_if_fail(XFCE_IS_SN_CONFIG(dialog->config));
474   g_return_if_fail(GTK_IS_LIST_STORE(dialog->legacy_store));
475 
476   gtk_tree_model_get(GTK_TREE_MODEL(dialog->legacy_store), iter_prev,
477                      COLUMN_PIXBUF, &pixbuf1,
478                      COLUMN_TITLE, &title1,
479                      COLUMN_HIDDEN, &hidden1,
480                      COLUMN_TIP, &tip1, -1);
481   gtk_tree_model_get(GTK_TREE_MODEL(dialog->legacy_store), iter,
482                      COLUMN_PIXBUF, &pixbuf2,
483                      COLUMN_TITLE, &title2,
484                      COLUMN_HIDDEN, &hidden2,
485                      COLUMN_TIP, &tip2, -1);
486   gtk_list_store_set(GTK_LIST_STORE(dialog->legacy_store), iter_prev,
487                      COLUMN_PIXBUF, pixbuf2,
488                      COLUMN_TITLE, title2,
489                      COLUMN_HIDDEN, hidden2,
490                      COLUMN_TIP, tip2, -1);
491   gtk_list_store_set(GTK_LIST_STORE(dialog->legacy_store), iter,
492                      COLUMN_PIXBUF, pixbuf1,
493                      COLUMN_TITLE, title1,
494                      COLUMN_HIDDEN, hidden1,
495                      COLUMN_TIP, tip1, -1);
496 
497   /* do a matching operation on SnConfig */
498   sn_config_swap_known_legacy_items(dialog->config, tip1, tip2);
499 }
500 
501 
502 
503 static gboolean
sn_dialog_iter_equal(GtkTreeIter * iter1,GtkTreeIter * iter2)504 sn_dialog_iter_equal (GtkTreeIter *iter1,
505                       GtkTreeIter *iter2)
506 {
507   return (iter1->user_data  == iter2->user_data  &&
508           iter1->user_data2 == iter2->user_data2 &&
509           iter1->user_data3 == iter2->user_data3);
510 }
511 
512 
513 
514 static void
sn_dialog_item_up_clicked(GtkWidget * button,SnDialog * dialog)515 sn_dialog_item_up_clicked (GtkWidget *button,
516                            SnDialog *dialog)
517 {
518   GObject          *treeview;
519   GtkTreeSelection *selection;
520   GtkTreeIter       iter, iter_prev, iter_tmp;
521 
522   g_return_if_fail (XFCE_IS_SN_DIALOG (dialog));
523   g_return_if_fail (GTK_IS_LIST_STORE (dialog->store));
524 
525   treeview = gtk_builder_get_object (dialog->builder, "items-treeview");
526   g_return_if_fail (GTK_IS_TREE_VIEW (treeview));
527 
528   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
529   if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
530     return;
531 
532   /* gtk_tree_model_iter_previous available from Gtk3 */
533   /* so we have to search for it starting from the first iter */
534   if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dialog->store), &iter_prev))
535     return;
536 
537   iter_tmp = iter_prev;
538   while (!sn_dialog_iter_equal (&iter_tmp, &iter))
539     {
540       iter_prev = iter_tmp;
541       if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (dialog->store), &iter_tmp))
542         return;
543     }
544 
545   sn_dialog_swap_rows (dialog, &iter_prev, &iter);
546   gtk_tree_selection_select_iter (selection, &iter_prev);
547 }
548 
549 
550 
551 static void
sn_dialog_legacy_item_up_clicked(GtkWidget * button,SnDialog * dialog)552 sn_dialog_legacy_item_up_clicked(GtkWidget *button,
553                                  SnDialog *dialog)
554 {
555   GObject *treeview;
556   GtkTreeSelection *selection;
557   GtkTreeIter iter, iter_prev, iter_tmp;
558 
559   g_return_if_fail(XFCE_IS_SN_DIALOG(dialog));
560   g_return_if_fail(GTK_IS_LIST_STORE(dialog->legacy_store));
561 
562   treeview = gtk_builder_get_object(dialog->builder, "legacy-items-treeview");
563   g_return_if_fail(GTK_IS_TREE_VIEW(treeview));
564 
565   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
566   if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
567     return;
568 
569   /* gtk_tree_model_iter_previous available from Gtk3 */
570   /* so we have to search for it starting from the first iter */
571   if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dialog->legacy_store), &iter_prev))
572     return;
573 
574   iter_tmp = iter_prev;
575   while (!sn_dialog_iter_equal(&iter_tmp, &iter))
576   {
577     iter_prev = iter_tmp;
578     if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(dialog->legacy_store), &iter_tmp))
579       return;
580   }
581 
582   sn_dialog_legacy_swap_rows(dialog, &iter_prev, &iter);
583   gtk_tree_selection_select_iter(selection, &iter_prev);
584 }
585 
586 
587 
588 static void
sn_dialog_item_down_clicked(GtkWidget * button,SnDialog * dialog)589 sn_dialog_item_down_clicked (GtkWidget *button,
590                              SnDialog *dialog)
591 {
592   GObject          *treeview;
593   GtkTreeSelection *selection;
594   GtkTreeIter       iter, iter_next;
595 
596   g_return_if_fail (XFCE_IS_SN_DIALOG (dialog));
597 
598   treeview = gtk_builder_get_object (dialog->builder, "items-treeview");
599   g_return_if_fail (GTK_IS_TREE_VIEW (treeview));
600 
601   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
602   if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
603     return;
604 
605   iter_next = iter;
606   if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (dialog->store), &iter_next))
607     return;
608 
609   sn_dialog_swap_rows (dialog, &iter, &iter_next);
610   gtk_tree_selection_select_iter (selection, &iter_next);
611 }
612 
613 
614 
615 static void
sn_dialog_legacy_item_down_clicked(GtkWidget * button,SnDialog * dialog)616 sn_dialog_legacy_item_down_clicked(GtkWidget *button,
617                             SnDialog *dialog)
618 {
619   GObject *treeview;
620   GtkTreeSelection *selection;
621   GtkTreeIter iter, iter_next;
622 
623   g_return_if_fail(XFCE_IS_SN_DIALOG(dialog));
624 
625   treeview = gtk_builder_get_object(dialog->builder, "legacy-items-treeview");
626   g_return_if_fail(GTK_IS_TREE_VIEW(treeview));
627 
628   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
629   if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
630     return;
631 
632   iter_next = iter;
633   if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(dialog->legacy_store), &iter_next))
634     return;
635 
636   sn_dialog_legacy_swap_rows(dialog, &iter, &iter_next);
637   gtk_tree_selection_select_iter(selection, &iter_next);
638 }
639 
640 
641 
642 static void
sn_dialog_clear_clicked(GtkWidget * button,SnDialog * dialog)643 sn_dialog_clear_clicked (GtkWidget *button,
644                          SnDialog *dialog)
645 {
646   g_return_if_fail (XFCE_IS_SN_DIALOG (dialog));
647 
648   if (xfce_dialog_confirm (GTK_WINDOW (gtk_widget_get_toplevel (button)),
649                            "edit-clear", _("Clear"), NULL,
650                            _("Are you sure you want to clear the list of "
651                              "known items?")))
652     {
653       if (sn_config_items_clear (dialog->config))
654         {
655           gtk_list_store_clear (GTK_LIST_STORE (dialog->store));
656           sn_dialog_update_names (dialog);
657         }
658       if (sn_config_legacy_items_clear (dialog->config))
659         {
660           gtk_list_store_clear (GTK_LIST_STORE (dialog->legacy_store));
661           sn_dialog_update_legacy_names (dialog);
662         }
663     }
664 }
665 
666 
667 
668 static void
sn_dialog_dialog_unref(gpointer data,GObject * where_the_object_was)669 sn_dialog_dialog_unref (gpointer  data,
670                         GObject  *where_the_object_was)
671 {
672   SnDialog *dialog = data;
673 
674   dialog->dialog = NULL;
675   g_object_unref (dialog);
676 }
677 
678 
679 
680 static void
reveal_icon_size(GtkWidget * widget,GParamSpec * pspec,SnDialog * dialog)681 reveal_icon_size (GtkWidget  *widget,
682                   GParamSpec *pspec,
683                   SnDialog   *dialog)
684 {
685   gboolean active;
686   gint     icon_size;
687 
688   g_return_if_fail (XFCE_IS_SN_DIALOG (dialog));
689 
690   active = gtk_switch_get_active (GTK_SWITCH (widget));
691 
692   if (active)
693     icon_size = 0;
694   else
695     icon_size = DEFAULT_ICON_SIZE;
696 
697   gtk_revealer_set_reveal_child (GTK_REVEALER (dialog->size_revealer), !active);
698   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->size_spinbutton), icon_size);
699 }
700 
701 
702 
703 static gboolean
sn_dialog_build(SnDialog * dialog)704 sn_dialog_build (SnDialog *dialog)
705 {
706   GObject          *object;
707   GError           *error = NULL;
708   GtkTreeSelection *selection;
709 
710   if (xfce_titled_dialog_get_type () == 0)
711     return FALSE;
712 
713   dialog->builder = gtk_builder_new ();
714 
715   /* load the builder data into the object */
716   if (gtk_builder_add_from_string (dialog->builder, sn_dialog_ui,
717                                    sn_dialog_ui_length, &error))
718     {
719       object = gtk_builder_get_object (dialog->builder, "dialog");
720       g_return_val_if_fail (XFCE_IS_TITLED_DIALOG (object), FALSE);
721       dialog->dialog = GTK_WIDGET (object);
722 
723       object = gtk_builder_get_object (dialog->builder, "close-button");
724       g_return_val_if_fail (GTK_IS_BUTTON (object), FALSE);
725       g_signal_connect_swapped (G_OBJECT (object), "clicked",
726                                 G_CALLBACK (gtk_widget_destroy),
727                                 dialog->dialog);
728 
729       object = gtk_builder_get_object (dialog->builder, "switch-auto-size");
730       g_return_val_if_fail (GTK_IS_WIDGET (object), FALSE);
731       dialog->auto_size = GTK_WIDGET (object);
732 
733       object = gtk_builder_get_object (dialog->builder, "spinbutton-icon-size");
734       g_return_val_if_fail (GTK_IS_WIDGET (object), FALSE);
735       g_object_bind_property (G_OBJECT (dialog->config), "icon-size",
736                               G_OBJECT (gtk_spin_button_get_adjustment
737                                         (GTK_SPIN_BUTTON (object))), "value",
738                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
739       dialog->size_spinbutton = GTK_WIDGET (object);
740 
741       object = gtk_builder_get_object (dialog->builder, "revealer-icon-size");
742       g_return_val_if_fail (GTK_IS_WIDGET (object), FALSE);
743       dialog->size_revealer = GTK_WIDGET (object);
744 
745       if (sn_config_get_icon_size_is_automatic (dialog->config))
746         {
747           gtk_switch_set_active (GTK_SWITCH (dialog->auto_size), TRUE);
748           gtk_revealer_set_reveal_child (GTK_REVEALER (dialog->size_revealer), FALSE);
749         }
750 
751       g_signal_connect (G_OBJECT (dialog->auto_size), "notify::active",
752                         G_CALLBACK (reveal_icon_size), dialog);
753 
754       object = gtk_builder_get_object (dialog->builder, "checkbutton-single-row");
755       g_return_val_if_fail (GTK_IS_WIDGET (object), FALSE);
756       g_object_bind_property (G_OBJECT (dialog->config), "single-row",
757                               G_OBJECT (object), "active",
758                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
759 
760       object = gtk_builder_get_object (dialog->builder, "checkbutton-square-icons");
761       g_return_val_if_fail (GTK_IS_WIDGET (object), FALSE);
762       g_object_bind_property (G_OBJECT (dialog->config), "square-icons",
763                               G_OBJECT (object), "active",
764                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
765 
766       object = gtk_builder_get_object (dialog->builder, "checkbutton-symbolic-icons");
767       g_return_val_if_fail (GTK_IS_WIDGET (object), FALSE);
768       g_object_bind_property (G_OBJECT (dialog->config), "symbolic-icons",
769                               G_OBJECT (object), "active",
770                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
771 
772       object = gtk_builder_get_object (dialog->builder, "checkbutton-menu-is-primary");
773       g_return_val_if_fail (GTK_IS_WIDGET (object), FALSE);
774       g_object_bind_property (G_OBJECT (dialog->config), "menu-is-primary",
775                               G_OBJECT (object), "active",
776                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
777 
778       object = gtk_builder_get_object (dialog->builder, "checkbutton-hide-new-items");
779       g_return_val_if_fail (GTK_IS_WIDGET (object), FALSE);
780       g_object_bind_property (G_OBJECT (dialog->config), "hide-new-items",
781                               G_OBJECT (object), "active",
782                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
783 
784       dialog->store = gtk_builder_get_object (dialog->builder, "items-store");
785       g_return_val_if_fail (GTK_IS_LIST_STORE (dialog->store), FALSE);
786       sn_dialog_update_names (dialog);
787 
788       object = gtk_builder_get_object (dialog->builder, "items-treeview");
789       g_return_val_if_fail (GTK_IS_TREE_VIEW (object), FALSE);
790       gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (object), COLUMN_TIP);
791 
792       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (object));
793       g_signal_connect (G_OBJECT (selection), "changed",
794                         G_CALLBACK (sn_dialog_selection_changed), dialog);
795       sn_dialog_selection_changed (selection, dialog);
796 
797       object = gtk_builder_get_object (dialog->builder, "hidden-toggle");
798       g_return_val_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (object), FALSE);
799       g_signal_connect (G_OBJECT (object), "toggled",
800                         G_CALLBACK (sn_dialog_hidden_toggled), dialog);
801 
802       object = gtk_builder_get_object (dialog->builder, "item-up");
803       g_return_val_if_fail (GTK_IS_BUTTON (object), FALSE);
804       g_signal_connect (G_OBJECT (object), "clicked",
805                         G_CALLBACK (sn_dialog_item_up_clicked), dialog);
806 
807       object = gtk_builder_get_object (dialog->builder, "item-down");
808       g_return_val_if_fail (GTK_IS_BUTTON (object), FALSE);
809       g_signal_connect (G_OBJECT (object), "clicked",
810                         G_CALLBACK (sn_dialog_item_down_clicked), dialog);
811 
812       dialog->legacy_store = gtk_builder_get_object (dialog->builder, "legacy-items-store");
813       g_return_val_if_fail (GTK_IS_LIST_STORE (dialog->legacy_store), FALSE);
814       sn_dialog_update_legacy_names (dialog);
815 
816       object = gtk_builder_get_object (dialog->builder, "legacy-items-treeview");
817       g_return_val_if_fail (GTK_IS_TREE_VIEW (object), FALSE);
818       gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (object), COLUMN_TIP);
819 
820       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (object));
821       g_signal_connect (G_OBJECT (selection), "changed",
822                         G_CALLBACK (sn_dialog_legacy_selection_changed), dialog);
823       sn_dialog_selection_changed (selection, dialog);
824 
825       object = gtk_builder_get_object (dialog->builder, "legacy-hidden-toggle");
826       g_return_val_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (object), FALSE);
827       g_signal_connect (G_OBJECT (object), "toggled",
828                         G_CALLBACK (sn_dialog_legacy_hidden_toggled), dialog);
829 
830       object = gtk_builder_get_object (dialog->builder, "legacy-item-up");
831       g_return_val_if_fail (GTK_IS_BUTTON (object), FALSE);
832       g_signal_connect (G_OBJECT (object), "clicked",
833                         G_CALLBACK (sn_dialog_legacy_item_up_clicked), dialog);
834 
835       object = gtk_builder_get_object (dialog->builder, "legacy-item-down");
836       g_return_val_if_fail (GTK_IS_BUTTON (object), FALSE);
837       g_signal_connect (G_OBJECT (object), "clicked",
838                         G_CALLBACK (sn_dialog_legacy_item_down_clicked), dialog);
839 
840       object = gtk_builder_get_object (dialog->builder, "items-clear");
841       g_return_val_if_fail (GTK_IS_BUTTON (object), FALSE);
842       g_signal_connect (G_OBJECT (object), "clicked",
843                         G_CALLBACK (sn_dialog_clear_clicked), dialog);
844 
845 #ifndef HAVE_DBUSMENU
846       object = gtk_builder_get_object (dialog->builder, "sn_box");
847       gtk_widget_hide (GTK_WIDGET (object));
848       object = gtk_builder_get_object (dialog->builder, "items_stack_switcher");
849       gtk_widget_hide (GTK_WIDGET (object));
850 #endif
851 
852       g_object_weak_ref (G_OBJECT (dialog->dialog), sn_dialog_dialog_unref, dialog);
853       return TRUE;
854     }
855   else
856     {
857       g_critical ("Failed to construct the builder: %s.",
858                   error->message);
859       g_error_free (error);
860       return FALSE;
861     }
862 }
863 
864 
865 
866 SnDialog *
sn_dialog_new(SnConfig * config,GdkScreen * screen)867 sn_dialog_new (SnConfig  *config,
868                GdkScreen *screen)
869 {
870   SnDialog *dialog;
871 
872   g_return_val_if_fail (XFCE_IS_SN_CONFIG (config), NULL);
873 
874   dialog = g_object_new (XFCE_TYPE_SN_DIALOG, NULL);
875   dialog->config = config;
876 
877   if (sn_dialog_build (dialog))
878     {
879       gtk_widget_show (dialog->dialog);
880       gtk_window_set_screen (GTK_WINDOW (dialog->dialog), screen);
881       return dialog;
882     }
883   else
884     {
885       g_object_unref (dialog);
886       return NULL;
887     }
888 }
889 
890 
891 
892 static void
sn_dialog_finalize(GObject * object)893 sn_dialog_finalize (GObject *object)
894 {
895   SnDialog *dialog = XFCE_SN_DIALOG (object);
896 
897   if (dialog->dialog != NULL)
898     gtk_widget_destroy (dialog->dialog);
899 
900   if (dialog->builder != NULL)
901     g_object_unref (dialog->builder);
902 
903   G_OBJECT_CLASS (sn_dialog_parent_class)->finalize (object);
904 }
905