Codebase list xapp / 7e1126b
Add an icon chooser dialog (#51) * Add an icon chooser dialog * icon chooser dialog: switch from derivable type to final type * icon chooser dialog: Switch icon size property from int to enum * Add icon chooser dialog test script * icon chooser dialog: combine categories, make category name translatable and rework category code a bit to simplify * icon chooser dialog: only scroll the category list vertically * Fix not building on LMDE 3. The issue is that gnome.mkenums_simple() was added in meson 0.42.0 but LMDE 3 only has 0.37. When we no longer need to support pre-.42 meson, we can switch to mkenums_simple and remove the templates * fix some codacity warnings * Update the test script for the icon chooser dialog with more options * icon chooser dialog: on file search, check if the file is an image and make sure we have the right file permissions before trying to load the icon * icon chooser dialog: add option to only allow icon names Stephen Collins authored 5 years ago Clement Lefebvre committed 5 years ago
14 changed file(s) with 1534 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
00 usr/share/glib-2.0/schemas
11 usr/bin/
22 usr/share/icons
3
3 usr/share/locale
1515
1616 <chapter>
1717 <title>API reference</title>
18 <xi:include href="xml/xapp-gtk-window.xml"/>
19 <xi:include href="xml/xapp-icon-chooser-dialog.xml"/>
1820 <xi:include href="xml/xapp-kbd-layout-controller.xml"/>
1921 <xi:include href="xml/xapp-monitor-blanker.xml"/>
20 <xi:include href="xml/xapp-gtk-window.xml"/>
2122 <xi:include href="xml/xapp-preferences-window.xml"/>
2223 <xi:include href="xml/xapp-stack-sidebar.xml"/>
2324
1010
1111 xapp_headers = [
1212 'xapp-gtk-window.h',
13 'xapp-icon-chooser-dialog.h',
1314 'xapp-kbd-layout-controller.h',
1415 'xapp-monitor-blanker.h',
1516 'xapp-preferences-window.h',
1920 xapp_sources = [
2021 'xapp-glade-catalog.c',
2122 'xapp-gtk-window.c',
23 'xapp-icon-chooser-dialog.c',
2224 'xapp-kbd-layout-controller.c',
2325 'xapp-monitor-blanker.c',
2426 'xapp-preferences-window.c',
2527 'xapp-stack-sidebar.c',
2628 ]
2729
30 xapp_enums = gnome.mkenums('xapp-enums',
31 sources : xapp_headers,
32 c_template : 'xapp-enums.c.template',
33 h_template : 'xapp-enums.h.template',
34 identifier_prefix : 'XApp',
35 symbol_prefix : 'xapp'
36 )
37
2838 libxapp = library('xapp',
29 sources : xapp_headers + xapp_sources,
39 sources : xapp_headers + xapp_sources + xapp_enums,
3040 include_directories: [top_inc],
3141 version: meson.project_version(),
3242 soversion: '1',
7686 sources: gir[0],
7787 metadata_dirs: meson.current_source_dir(),
7888 install: true
79 )
89 )
0 /*** BEGIN file-header ***/
1
2 #include "config.h"
3 #include "xapp-enums.h"
4 #include "xapp-icon-chooser-dialog.h"
5
6 #define C_ENUM(v) ((gint) v)
7 #define C_FLAGS(v) ((guint) v)
8
9 /*** END file-header ***/
10
11 /*** BEGIN file-production ***/
12
13 /* enumerations from "@basename@" */
14
15 /*** END file-production ***/
16
17 /*** BEGIN value-header ***/
18 GType
19 @enum_name@_get_type (void)
20 {
21 static volatile gsize gtype_id = 0;
22 static const G@Type@Value values[] = {
23 /*** END value-header ***/
24
25 /*** BEGIN value-production ***/
26 { C_ENUM(@VALUENAME@), "@VALUENAME@", "@valuenick@" },
27 /*** END value-production ***/
28
29 /*** BEGIN value-tail ***/
30 { 0, NULL, NULL }
31 };
32 if (g_once_init_enter (&gtype_id)) {
33 GType new_type = g_@type@_register_static ("@EnumName@", values);
34 g_once_init_leave (&gtype_id, new_type);
35 }
36 return (GType) gtype_id;
37 }
38
39 /*** END value-tail ***/
40
41 /*** BEGIN file-tail ***/
42
43 /*** END file-tail ***/
0 /*** BEGIN file-header ***/
1 #ifndef __XAPP_ENUMS_H__
2 #define __XAPP_ENUMS_H__
3
4 #include <glib-object.h>
5
6 G_BEGIN_DECLS
7 /*** END file-header ***/
8
9 /*** BEGIN file-production ***/
10
11 /* enumerations from "@basename@" */
12 /*** END file-production ***/
13
14 /*** BEGIN value-header ***/
15 GType @enum_name@_get_type (void);
16 #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
17 /*** END value-header ***/
18
19 /*** BEGIN file-tail ***/
20 G_END_DECLS
21
22 #endif /* __XAPP_ENUMS_H__ */
23 /*** END file-tail ***/
0 #include <config.h>
1 #include <gdk/gdk.h>
2 #include "xapp-icon-chooser-dialog.h"
3 #include "xapp-stack-sidebar.h"
4 #include <glib/gi18n-lib.h>
5 #include <glib/gstdio.h>
6
7 /**
8 * SECTION:xapp-icon-chooser-dialog
9 * @Short_description: A dialog for selecting an icon
10 * @Title: XAppIconChooserDialog
11 *
12 * The XAppIconChooserDialog creates a dialog so that
13 * the user can select an icon. It provides the ability
14 * to browse by category, search by icon name, or select
15 * from a specific file.
16 */
17
18 typedef struct
19 {
20 GtkResponseType response;
21 XAppIconSize icon_size;
22 GCancellable *cancellable;
23 GtkListStore *category_list;
24 GtkListStore *icon_store;
25 GHashTable *categories;
26 GtkWidget *search_bar;
27 GtkWidget *icon_view;
28 GtkWidget *list_box;
29 GtkWidget *select_button;
30 GtkWidget *browse_button;
31 gchar *icon_string;
32 gboolean allow_paths;
33 } XAppIconChooserDialogPrivate;
34
35 struct _XAppIconChooserDialog
36 {
37 GtkWindow parent_instance;
38 };
39
40 typedef struct
41 {
42 GtkListStore *model;
43 const gchar *short_name;
44 const gchar *long_name;
45 } IconInfoLoadCallbackInfo;
46
47 typedef struct
48 {
49 gchar *name;
50 GList *contexts;
51 GList *icons;
52 GtkListStore *model;
53 gboolean is_loaded;
54 } IconCategoryInfo;
55
56 typedef struct
57 {
58 const gchar *name;
59 const gchar *contexts[5];
60 } IconCategoryDefinition;
61
62 static IconCategoryDefinition categories[] = {
63 // Category name context names
64 {
65 N_("Actions"), { "Actions", NULL }
66 },
67 {
68 N_("Applications"), { "Applications", "Apps", NULL }
69 },
70 {
71 N_("Categories"), { "Categories", NULL }
72 },
73 {
74 N_("Devices"), { "Devices", NULL }
75 },
76 {
77 N_("Emblems"), { "Emblems", NULL }
78 },
79 {
80 N_("Emoji"), { "Emotes", NULL }
81 },
82 {
83 N_("Mime types"), { "MimeTypes", "Mimetypes", NULL }
84 },
85 {
86 N_("Places"), { "Places", NULL }
87 },
88 {
89 N_("Status"), { "Status", "Notifications", NULL }
90 },
91 {
92 N_("Other"), { "Panel", NULL }
93 }
94 };
95
96 enum
97 {
98 CLOSE,
99 SELECT,
100 LAST_SIGNAL
101 };
102
103 enum
104 {
105 PROP_0,
106 PROP_ICON_SIZE,
107 PROP_ALLOW_PATHS,
108 N_PROPERTIES
109 };
110
111 enum
112 {
113 COLUMN_DISPLAY_NAME,
114 COLUMN_FULL_NAME,
115 COLUMN_PIXBUF,
116 };
117
118 static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
119
120 static guint signals[LAST_SIGNAL] = {0, };
121
122 G_DEFINE_TYPE_WITH_PRIVATE (XAppIconChooserDialog, xapp_icon_chooser_dialog, GTK_TYPE_WINDOW)
123
124 static void on_category_selected (GtkListBox *list_box,
125 XAppIconChooserDialog *dialog);
126
127 static void on_search (GtkSearchEntry *entry,
128 XAppIconChooserDialog *dialog);
129
130 static void on_icon_view_selection_changed (GtkIconView *icon_view,
131 gpointer user_data);
132
133 static void on_icon_store_icons_added (GtkTreeModel *tree_model,
134 GtkTreePath *path,
135 GtkTreeIter *iter,
136 gpointer user_data);
137
138 static void on_browse_button_clicked (GtkButton *button,
139 gpointer user_data);
140
141 static void on_select_button_clicked (GtkButton *button,
142 gpointer user_data);
143
144 static void on_cancel_button_clicked (GtkButton *button,
145 gpointer user_data);
146
147 static gboolean on_search_bar_key_pressed (GtkWidget *widget,
148 GdkEvent *event,
149 gpointer user_data);
150
151 static gboolean on_delete_event (GtkWidget *widget,
152 GdkEventAny *event);
153
154 static gboolean on_select_event (XAppIconChooserDialog *dialog,
155 GdkEventAny *event);
156
157 static void on_icon_view_item_activated (GtkIconView *iconview,
158 GtkTreePath *path,
159 gpointer user_data);
160
161 static void load_categories (XAppIconChooserDialog *dialog);
162
163 static gint list_box_sort (GtkListBoxRow *row1,
164 GtkListBoxRow *row2,
165 gpointer user_data);
166
167 void
168 xapp_icon_chooser_dialog_get_property (GObject *object,
169 guint prop_id,
170 GValue *value,
171 GParamSpec *pspec)
172 {
173 XAppIconChooserDialog *dialog;
174 XAppIconChooserDialogPrivate *priv;
175
176 dialog = XAPP_ICON_CHOOSER_DIALOG (object);
177 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
178
179 switch (prop_id)
180 {
181 case PROP_ICON_SIZE:
182 g_value_set_enum (value, priv->icon_size);
183 break;
184 case PROP_ALLOW_PATHS:
185 g_value_set_boolean (value, priv->allow_paths);
186 break;
187 default:
188 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
189 break;
190 }
191 }
192
193 void
194 xapp_icon_chooser_dialog_set_property (GObject *object,
195 guint prop_id,
196 const GValue *value,
197 GParamSpec *pspec)
198 {
199 XAppIconChooserDialog *dialog;
200 XAppIconChooserDialogPrivate *priv;
201
202 dialog = XAPP_ICON_CHOOSER_DIALOG (object);
203 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
204
205 switch (prop_id)
206 {
207 case PROP_ICON_SIZE:
208 priv->icon_size = g_value_get_enum (value);
209 break;
210 case PROP_ALLOW_PATHS:
211 priv->allow_paths = g_value_get_boolean (value);
212 if (priv->allow_paths)
213 {
214 gtk_widget_show (priv->browse_button);
215 gtk_widget_set_no_show_all (priv->browse_button, FALSE);
216 }
217 else
218 {
219 gtk_widget_hide (priv->browse_button);
220 gtk_widget_set_no_show_all (priv->browse_button, TRUE);
221 }
222 break;
223 default:
224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225 break;
226 }
227 }
228
229 static void
230 xapp_icon_chooser_dialog_init (XAppIconChooserDialog *dialog)
231 {
232 XAppIconChooserDialogPrivate *priv;
233 GtkWidget *main_box;
234 GtkWidget *secondary_box;
235 GtkWidget *right_box;
236 GtkWidget *search_bar_box;
237 GtkCellRenderer *renderer;
238 GtkTreeViewColumn *column;
239 GtkStyleContext *style;
240 GtkSizeGroup *button_size_group;
241 GtkWidget *cancel_button;
242 GtkWidget *button_area;
243 GtkWidget *selection;
244 GtkWidget *scrolled_window;
245
246 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
247
248 priv->icon_size = XAPP_ICON_SIZE_32;
249 priv->categories = g_hash_table_new (NULL, NULL);
250 priv->response = GTK_RESPONSE_NONE;
251 priv->icon_string = "";
252 priv->cancellable = NULL;
253
254 priv->icon_store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF);
255 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->icon_store), COLUMN_DISPLAY_NAME,
256 GTK_SORT_ASCENDING);
257 g_signal_connect (priv->icon_store, "row-inserted",
258 G_CALLBACK (on_icon_store_icons_added), dialog);
259
260 gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 400);
261 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE);
262 gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
263
264 main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
265 gtk_container_add (GTK_CONTAINER (dialog), main_box);
266
267 secondary_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
268 gtk_box_pack_start (GTK_BOX (main_box), secondary_box, TRUE, TRUE, 0);
269
270 // context list
271 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
272 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
273 gtk_box_pack_start (GTK_BOX (secondary_box), scrolled_window, FALSE, FALSE, 0);
274
275 priv->list_box = gtk_list_box_new ();
276 gtk_container_add(GTK_CONTAINER (scrolled_window), GTK_WIDGET (priv->list_box));
277 gtk_list_box_set_sort_func (GTK_LIST_BOX (priv->list_box), list_box_sort, NULL, NULL);
278 g_signal_connect (priv->list_box, "selected-rows-changed",
279 G_CALLBACK (on_category_selected), dialog);
280
281 style = gtk_widget_get_style_context (GTK_WIDGET (priv->list_box));
282 gtk_style_context_add_class (style, "sidebar");
283
284 right_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
285 gtk_box_pack_start (GTK_BOX (secondary_box), right_box, TRUE, TRUE, 8);
286
287 // search bar
288 search_bar_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
289 gtk_box_pack_start (GTK_BOX (right_box), search_bar_box, FALSE, FALSE, 0);
290 // gtk_box_set_spacing (GTK_BOX (search_bar_box), 8);
291 style = gtk_widget_get_style_context (GTK_WIDGET (search_bar_box));
292 gtk_style_context_add_class (style, "linked");
293
294 priv->search_bar = gtk_search_entry_new ();
295 gtk_box_pack_start (GTK_BOX (search_bar_box), priv->search_bar, TRUE, TRUE, 0);
296
297 g_signal_connect (priv->search_bar, "search-changed",
298 G_CALLBACK (on_search), dialog);
299 g_signal_connect (priv->search_bar, "key-press-event",
300 G_CALLBACK (on_search_bar_key_pressed), dialog);
301
302 priv->browse_button = gtk_button_new_with_label (_("Browse"));
303 gtk_box_pack_start (GTK_BOX (search_bar_box), priv->browse_button, FALSE, FALSE, 0);
304
305 g_signal_connect (priv->browse_button, "clicked",
306 G_CALLBACK (on_browse_button_clicked), dialog);
307
308 // icon view
309 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
310 gtk_box_pack_start (GTK_BOX (right_box), scrolled_window, TRUE, TRUE, 0);
311 // gtk_widget_set_margin_top (GTK_WIDGET (scrolled_window), 8);
312 // gtk_widget_set_margin_bottom (GTK_WIDGET (scrolled_window), 8);
313 // gtk_widget_set_margin_start (GTK_WIDGET (scrolled_window), 8);
314 // gtk_widget_set_margin_end (GTK_WIDGET (scrolled_window), 8);
315
316 priv->icon_view = gtk_icon_view_new ();
317 gtk_container_add(GTK_CONTAINER (scrolled_window), GTK_WIDGET (priv->icon_view));
318
319 gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (priv->icon_view), COLUMN_PIXBUF);
320 gtk_icon_view_set_text_column (GTK_ICON_VIEW (priv->icon_view), COLUMN_DISPLAY_NAME);
321 gtk_icon_view_set_tooltip_column (GTK_ICON_VIEW (priv->icon_view), COLUMN_FULL_NAME);
322
323 g_signal_connect (priv->icon_view, "selection-changed",
324 G_CALLBACK (on_icon_view_selection_changed), dialog);
325 g_signal_connect (priv->icon_view, "item-activated",
326 G_CALLBACK (on_icon_view_item_activated), dialog);
327
328 // buttons
329 button_area = gtk_action_bar_new ();
330 gtk_box_pack_start (GTK_BOX (main_box), button_area, FALSE, FALSE, 0);
331
332 button_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
333
334 priv->select_button = gtk_button_new_with_label (_("Select"));
335 style = gtk_widget_get_style_context (GTK_WIDGET (priv->select_button));
336 gtk_style_context_add_class (style, "text-button");
337 gtk_size_group_add_widget (button_size_group, priv->select_button);
338 gtk_action_bar_pack_end (GTK_ACTION_BAR (button_area), priv->select_button);
339
340 g_signal_connect (priv->select_button, "clicked",
341 G_CALLBACK (on_select_button_clicked), dialog);
342
343 cancel_button = gtk_button_new_with_label (_("Cancel"));
344 style = gtk_widget_get_style_context (GTK_WIDGET (cancel_button));
345 gtk_style_context_add_class (style, "text-button");
346 gtk_size_group_add_widget (button_size_group, cancel_button);
347 gtk_action_bar_pack_end (GTK_ACTION_BAR (button_area), cancel_button);
348
349 g_signal_connect (cancel_button, "clicked",
350 G_CALLBACK (on_cancel_button_clicked), dialog);
351
352 load_categories (dialog);
353 }
354
355 static void
356 xapp_icon_chooser_dialog_class_init (XAppIconChooserDialogClass *klass)
357 {
358 GtkBindingSet *binding_set;
359 GObjectClass *object_class = G_OBJECT_CLASS (klass);
360 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
361
362 object_class->get_property = xapp_icon_chooser_dialog_get_property;
363 object_class->set_property = xapp_icon_chooser_dialog_set_property;
364
365 widget_class->delete_event = on_delete_event;
366
367 /**
368 * XAppIconChooserDialog:icon-size:
369 *
370 * The preferred size to use when looking up icons. This only works with icon names.
371 * Additionally, there is no guarantee that a selected icon name will exist in a
372 * particular size.
373 */
374 obj_properties[PROP_ICON_SIZE] =
375 g_param_spec_enum ("icon-size",
376 _("Icon size"),
377 _("The preferred icon size."),
378 XAPP_TYPE_ICON_SIZE,
379 XAPP_ICON_SIZE_32,
380 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
381
382 /**
383 * XAppIconChooserDialog:allow-paths:
384 *
385 * Whether to allow paths to be searched and selected or only icon names.
386 */
387 obj_properties[PROP_ALLOW_PATHS] =
388 g_param_spec_boolean ("allow-paths",
389 _("Allow Paths"),
390 _("Whether to allow paths."),
391 TRUE,
392 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
393
394 g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);
395
396 // keybinding signals
397 signals[CLOSE] =
398 g_signal_new ("close",
399 G_TYPE_FROM_CLASS (klass),
400 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
401 G_STRUCT_OFFSET (GtkWidgetClass, delete_event),
402 NULL, NULL, NULL,
403 G_TYPE_NONE, 0);
404
405 signals[SELECT] =
406 g_signal_new ("select",
407 G_TYPE_FROM_CLASS (klass),
408 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
409 0,
410 NULL, NULL, NULL,
411 G_TYPE_NONE, 0);
412
413 binding_set = gtk_binding_set_by_class (klass);
414 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "close", 0);
415 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select", 0);
416 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select", 0);
417 }
418
419 /**
420 * xapp_icon_chooser_dialog_new:
421 *
422 * Creates a new #XAppIconChooserDialog.
423 *
424 * Returns: a newly created #XAppIconChooserDialog
425 */
426 XAppIconChooserDialog *
427 xapp_icon_chooser_dialog_new (void)
428 {
429 return g_object_new (XAPP_TYPE_ICON_CHOOSER_DIALOG, NULL);
430 }
431
432 /**
433 * xapp_icon_chooser_dialog_run:
434 * @dialog: a #XAppIconChooserDialog
435 *
436 * Shows the dialog and enters a separate main loop until an icon is chosen or the action is canceled.
437 *
438 * xapp_icon_chooser_dialog_run (), xapp_icon_chooser_dialog_run_with_icon(), and
439 * xapp_icon_chooser_dialog_run_with_category () may all be called multiple times. This is useful for
440 * applications which use this dialog multiple times, as it may improve performance for subsequent
441 * calls.
442 *
443 * Returns: GTK_RESPONSE_OK if the user selected an icon, or GTK_RESPONSE_CANCEL otherwise
444 */
445 gint
446 xapp_icon_chooser_dialog_run (XAppIconChooserDialog *dialog)
447 {
448 XAppIconChooserDialogPrivate *priv;
449
450 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
451
452 gtk_widget_show_all (GTK_WIDGET (dialog));
453 gtk_widget_grab_focus (priv->search_bar);
454
455 gtk_main ();
456
457 return priv->response;
458 }
459
460 /**
461 * xapp_icon_chooser_dialog_run_with_icon:
462 * @dialog: a #XAppIconChooserDialog
463 * @icon: a string representing the icon that should be selected
464 *
465 * Like xapp_icon_chooser_dialog_run but selects the icon specified by @icon. This can be either an
466 * icon name or a path. Passing an icon string or path that doesn't exist is accepted, but it may show
467 * multiple results, or none at all. This behavior is useful if, for example, you wish to have the
468 * user select an image file from a particular directory.
469 *
470 * If the property allow_paths is FALSE, setting a path will yield no results when the dialog is opened.
471 *
472 * xapp_icon_chooser_dialog_run (), xapp_icon_chooser_dialog_run_with_icon(), and
473 * xapp_icon_chooser_dialog_run_with_category () may all be called multiple times. This is useful for
474 * applications which use this dialog multiple times, as it may improve performance for subsequent
475 * calls.
476 *
477 * Returns: GTK_RESPONSE_OK if the user selected an icon, or GTK_RESPONSE_CANCEL otherwise
478 */
479 gint
480 xapp_icon_chooser_dialog_run_with_icon (XAppIconChooserDialog *dialog,
481 gchar *icon)
482 {
483 XAppIconChooserDialogPrivate *priv;
484
485 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
486
487 gtk_widget_show_all (GTK_WIDGET (dialog));
488 gtk_entry_set_text (GTK_ENTRY (priv->search_bar), icon);
489 gtk_widget_grab_focus (priv->search_bar);
490
491 gtk_main ();
492
493 return priv->response;
494 }
495
496 /**
497 * xapp_icon_chooser_dialog_run_with_category:
498 * @dialog: a #XAppIconChooserDialog
499 *
500 * Like xapp_icon_chooser_dialog_run but selects a particular category specified by @category.
501 * This is used when there is a particular category of icon that is more appropriate than the
502 * others. If the category does not exist, the first category in the list will be selected. To
503 * get a list of possible categories, use gtk_icon_theme_list_contexts ().
504 *
505 * xapp_icon_chooser_dialog_run (), xapp_icon_chooser_dialog_run_with_icon(), and
506 * xapp_icon_chooser_dialog_run_with_category () may all be called multiple times. This is useful for
507 * applications which use this dialog multiple times, as it may improve performance for subsequent
508 * calls.
509 *
510 * Returns: GTK_RESPONSE_OK if the user selected an icon, or GTK_RESPONSE_CANCEL otherwise
511 */
512 gint
513 xapp_icon_chooser_dialog_run_with_category (XAppIconChooserDialog *dialog,
514 gchar *category)
515 {
516 XAppIconChooserDialogPrivate *priv;
517 GList *children;
518
519 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
520
521 gtk_widget_show_all (GTK_WIDGET (dialog));
522 gtk_widget_grab_focus (priv->search_bar);
523
524 children = gtk_container_get_children (GTK_CONTAINER (priv->list_box));
525 for ( ; children; children = children->next)
526 {
527 GtkWidget *row;
528 GtkWidget *child;
529 const gchar *context;
530
531 row = children->data;
532 child = gtk_bin_get_child (GTK_BIN (row));
533 context = gtk_label_get_text (GTK_LABEL (child));
534 if (g_strcmp0 (context, category) == 0)
535 {
536 gtk_list_box_select_row (GTK_LIST_BOX (priv->list_box), GTK_LIST_BOX_ROW (row));
537 break;
538 }
539 }
540
541 gtk_main ();
542
543 return priv->response;
544 }
545
546 /**
547 * xapp_icon_chooser_dialog_get_icon_string:
548 * @dialog: a #XAppIconChooserDialog
549 *
550 * Gets the currently selected icon from the dialog. If allow-paths is TRUE, this function may return
551 * either an icon name or a path depending on what the user selects. Otherwise it will only return an
552 * icon name.
553 *
554 * Returns: the string representation of the currently selected icon or NULL
555 * if no icon is selected.
556 */
557 gchar *
558 xapp_icon_chooser_dialog_get_icon_string (XAppIconChooserDialog *dialog)
559 {
560 XAppIconChooserDialogPrivate *priv;
561
562 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
563 return priv->icon_string;
564 }
565
566 gboolean
567 xapp_icon_chooser_dialog_close (XAppIconChooserDialog *dialog,
568 gboolean cancelled)
569 {
570 XAppIconChooserDialogPrivate *priv;
571
572 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
573
574 priv->response = (cancelled) ? GTK_RESPONSE_CANCEL : GTK_RESPONSE_OK;
575 gtk_widget_hide (GTK_WIDGET (dialog));
576
577 gtk_main_quit ();
578 }
579
580 static gint
581 list_box_sort (GtkListBoxRow *row1,
582 GtkListBoxRow *row2,
583 gpointer user_data)
584 {
585 GtkWidget *item;
586 const gchar *label1;
587 const gchar *label2;
588
589 item = gtk_bin_get_child (GTK_BIN (row1));
590 label1 = gtk_label_get_text (GTK_LABEL (item));
591
592 item = gtk_bin_get_child (GTK_BIN (row2));
593 label2 = gtk_label_get_text (GTK_LABEL (item));
594
595 return g_strcmp0 (label1, label2);
596 }
597
598 static gint
599 search_model_sort (GtkTreeModel *model,
600 GtkTreeIter *a,
601 GtkTreeIter *b,
602 gpointer user_data)
603 {
604 gchar *a_value;
605 gchar *b_value;
606 gchar *search_str;
607 gboolean a_starts_with;
608 gboolean b_starts_with;
609
610 search_str = user_data;
611
612 gtk_tree_model_get (model, a, COLUMN_DISPLAY_NAME, &a_value, -1);
613 gtk_tree_model_get (model, b, COLUMN_DISPLAY_NAME, &b_value, -1);
614
615 if (g_strcmp0 (a_value, search_str) == 0)
616 {
617 return -1;
618 }
619
620 if (g_strcmp0 (b_value, search_str) == 0)
621 {
622 return 1;
623 }
624
625 a_starts_with = g_str_has_prefix (a_value, search_str);
626 b_starts_with = g_str_has_prefix (b_value, search_str);
627
628 if (a_starts_with && !b_starts_with)
629 {
630 return -1;
631 }
632
633 if (!a_starts_with && b_starts_with)
634 {
635 return 1;
636 }
637
638 return g_strcmp0 (a_value, b_value);
639 }
640
641 static gint
642 category_model_sort (GtkTreeModel *model,
643 GtkTreeIter *a,
644 GtkTreeIter *b,
645 gpointer user_data)
646 {
647 gchar *a_value;
648 gchar *b_value;
649
650 gtk_tree_model_get (model, a, COLUMN_DISPLAY_NAME, &a_value, -1);
651 gtk_tree_model_get (model, b, COLUMN_DISPLAY_NAME, &b_value, -1);
652
653 return g_strcmp0 (a_value, b_value);
654 }
655
656 static void
657 load_categories (XAppIconChooserDialog *dialog)
658 {
659 XAppIconChooserDialogPrivate *priv;
660 GtkIconTheme *theme;
661 gint i;
662 gint j;
663
664 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
665
666 theme = gtk_icon_theme_get_default ();
667
668 for (i = 0; i < G_N_ELEMENTS (categories); i++)
669 {
670 IconCategoryDefinition *category;
671 IconCategoryInfo *category_info;
672 GtkWidget *row;
673 GtkWidget *label;
674
675 category = &categories[i];
676
677 category_info = g_new (IconCategoryInfo, 1);
678
679 category_info->name = _(category->name);
680 category_info->is_loaded = FALSE;
681 category_info->contexts = NULL;
682 category_info->icons = NULL;
683
684 for (j = 0; category->contexts[j] != NULL; j++)
685 {
686 GList *context_icons;
687
688 category_info->contexts = g_list_prepend (category_info->contexts, g_strdup (category->contexts[j]));
689 context_icons = gtk_icon_theme_list_icons (theme, category->contexts[j]);
690 category_info->icons = g_list_concat (category_info->icons, context_icons);
691 }
692
693 if (g_list_length (category_info->icons) == 0)
694 {
695 g_list_free (category_info->contexts);
696 g_free (category_info);
697
698 continue;
699 }
700
701 category_info->model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF);
702 g_signal_connect (category_info->model, "row-inserted",
703 G_CALLBACK (on_icon_store_icons_added), dialog);
704
705 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (category_info->model), COLUMN_DISPLAY_NAME,
706 category_model_sort, NULL, NULL);
707 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (category_info->model), COLUMN_DISPLAY_NAME,
708 GTK_SORT_ASCENDING);
709
710 row = gtk_list_box_row_new ();
711 label = gtk_label_new (category_info->name);
712 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
713 gtk_widget_set_margin_top (GTK_WIDGET (label), 10);
714 gtk_widget_set_margin_bottom (GTK_WIDGET (label), 10);
715 gtk_widget_set_margin_start (GTK_WIDGET (label), 15);
716 gtk_widget_set_margin_end (GTK_WIDGET (label), 15);
717
718 gtk_container_add (GTK_CONTAINER (row), label);
719 gtk_container_add (GTK_CONTAINER (priv->list_box), row);
720
721 g_hash_table_insert (priv->categories, row, category_info);
722 }
723 }
724
725 static void
726 finish_pixbuf_load_from_file (GObject *stream,
727 GAsyncResult *res,
728 gpointer *user_data)
729 {
730 IconInfoLoadCallbackInfo *callback_info;
731 GdkPixbuf *pixbuf;
732 GError *error = NULL;
733 GtkTreeIter iter;
734
735 callback_info = (IconInfoLoadCallbackInfo*) user_data;
736
737 pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
738
739 g_input_stream_close (G_INPUT_STREAM (stream), NULL, NULL);
740
741 if (error == NULL)
742 {
743 gtk_list_store_append (callback_info->model, &iter);
744 gtk_list_store_set (callback_info->model, &iter,
745 COLUMN_DISPLAY_NAME, callback_info->short_name,
746 COLUMN_FULL_NAME, callback_info->long_name,
747 COLUMN_PIXBUF, pixbuf,
748 -1);
749 }
750 else if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_CANCELLED)
751 {
752 g_message ("%s\n", error->message);
753 }
754
755 g_free (callback_info);
756 g_clear_error (&error);
757 g_object_unref (pixbuf);
758 g_object_unref (stream);
759 }
760
761 static void
762 finish_pixbuf_load_from_name (GObject *info,
763 GAsyncResult *res,
764 gpointer *user_data)
765 {
766 IconInfoLoadCallbackInfo *callback_info;
767 GdkPixbuf *pixbuf;
768 GError *error = NULL;
769 GtkTreeIter iter;
770
771 callback_info = (IconInfoLoadCallbackInfo*) user_data;
772
773 pixbuf = gtk_icon_info_load_icon_finish (GTK_ICON_INFO (info), res, &error);
774
775 if (error == NULL)
776 {
777 gtk_list_store_append (callback_info->model, &iter);
778 gtk_list_store_set (callback_info->model, &iter,
779 COLUMN_DISPLAY_NAME, callback_info->short_name,
780 COLUMN_FULL_NAME, callback_info->long_name,
781 COLUMN_PIXBUF, pixbuf,
782 -1);
783
784 g_object_unref (pixbuf);
785 }
786 else if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_CANCELLED)
787 {
788 g_message ("%s\n", error->message);
789 }
790
791 g_free (callback_info);
792 g_clear_error (&error);
793 g_object_unref (info);
794 }
795
796 static void
797 load_icons_for_category (GtkListStore *model,
798 GList *icons,
799 guint icon_size)
800 {
801 GtkIconTheme *theme;
802
803 theme = gtk_icon_theme_get_default ();
804
805 for ( ; icons; icons = icons->next)
806 {
807 GtkIconInfo *info;
808 IconInfoLoadCallbackInfo *callback_info;
809
810 callback_info = g_new (IconInfoLoadCallbackInfo, 1);
811 callback_info->model = model;
812 callback_info->short_name = icons->data;
813 callback_info->long_name = icons->data;
814 info = gtk_icon_theme_lookup_icon (theme, callback_info->short_name, icon_size, GTK_ICON_LOOKUP_FORCE_SIZE);
815 gtk_icon_info_load_icon_async (info, NULL, (GAsyncReadyCallback) (finish_pixbuf_load_from_name), callback_info);
816 }
817 }
818
819 static void
820 on_category_selected (GtkListBox *list_box,
821 XAppIconChooserDialog *dialog)
822 {
823 XAppIconChooserDialogPrivate *priv;
824 GList *selection;
825 GtkWidget *selected;
826 IconCategoryInfo *category_info;
827 GList *contexts;
828 GtkTreePath *new_path;
829
830 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
831
832 if (priv->cancellable != NULL)
833 {
834 g_cancellable_cancel (priv->cancellable);
835 g_object_unref (priv->cancellable);
836 priv->cancellable = NULL;
837 }
838
839 gtk_entry_set_text (GTK_ENTRY (priv->search_bar), "");
840 selection = gtk_list_box_get_selected_rows (GTK_LIST_BOX (priv->list_box));
841 selected = selection->data;
842 category_info = g_hash_table_lookup (priv->categories, selected);
843 if (!category_info->is_loaded)
844 {
845 load_icons_for_category (category_info->model, category_info->icons, priv->icon_size);
846 category_info->is_loaded = TRUE;
847 }
848
849 gtk_icon_view_set_model (GTK_ICON_VIEW (priv->icon_view), GTK_TREE_MODEL (category_info->model));
850
851 new_path = gtk_tree_path_new_first ();
852 gtk_icon_view_select_path (GTK_ICON_VIEW (priv->icon_view), new_path);
853
854 g_list_free (selection);
855 }
856
857 static void
858 search_path (const gchar *path_string,
859 GtkListStore *icon_store,
860 GCancellable *cancellable)
861 {
862 const gchar *search_str = "";
863 GFile *dir;
864 GFileEnumerator *children;
865 GFileInfo *child_info;
866
867 if (g_file_test (path_string, G_FILE_TEST_IS_DIR))
868 {
869 dir = g_file_new_for_path (path_string);
870 }
871 else
872 {
873 GFile *file;
874
875 file = g_file_new_for_path (path_string);
876 dir = g_file_get_parent (file);
877 search_str = g_file_get_basename (file);
878 g_object_unref (file);
879 }
880
881 if (!g_file_query_exists (dir, NULL) ||
882 g_file_query_file_type (dir, G_FILE_QUERY_INFO_NONE, NULL) != G_FILE_TYPE_DIRECTORY)
883 {
884 g_object_unref (dir);
885 return;
886 }
887
888 children = g_file_enumerate_children (dir, "*", G_FILE_QUERY_INFO_NONE, NULL, NULL);
889 child_info = g_file_enumerator_next_file (children, NULL, NULL);
890
891 while (child_info != NULL)
892 {
893 const gchar *child_name;
894 const gchar *child_path;
895 GFile *child;
896 GError *error = NULL;
897
898 child_name = g_file_info_get_name (child_info);
899 child = g_file_enumerator_get_child (children, child_info);
900 child_path = g_file_get_path (child);
901
902 if (g_str_has_prefix (child_name, search_str) &&
903 g_file_query_file_type (child, G_FILE_QUERY_INFO_NONE, NULL) != G_FILE_TYPE_DIRECTORY &&
904 g_str_has_prefix (g_content_type_guess (child_name, NULL, 0, NULL), "image") &&
905 g_access (child_path, R_OK) == 0)
906 {
907 GFileInputStream *stream;
908 IconInfoLoadCallbackInfo *callback_info;
909
910 stream = g_file_read (child, NULL, &error);
911 if (stream == NULL)
912 {
913 g_message ("%s\n", error->message);
914 continue;
915 }
916
917 callback_info = g_new (IconInfoLoadCallbackInfo, 1);
918 callback_info->model = icon_store;
919 callback_info->short_name = child_name;
920 callback_info->long_name = child_path;
921 gdk_pixbuf_new_from_stream_async (G_INPUT_STREAM (stream), cancellable, (GAsyncReadyCallback) (finish_pixbuf_load_from_file), callback_info);
922
923 g_object_unref (child);
924 }
925
926 child_info = g_file_enumerator_next_file (children, NULL, NULL);
927
928 g_clear_error (&error);
929 }
930
931 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (icon_store), COLUMN_DISPLAY_NAME, search_model_sort,
932 (gpointer) search_str, NULL);
933
934 g_file_enumerator_close (children, NULL, NULL);
935 g_object_unref (children);
936 g_object_unref (dir);
937 }
938
939 static void
940 search_icon_name (const gchar *name_string,
941 GtkListStore *icon_store,
942 GCancellable *cancellable,
943 guint icon_size)
944 {
945 GtkIconTheme *theme;
946 GList *icons;
947 GtkIconInfo *info;
948 IconInfoLoadCallbackInfo *callback_info;
949
950 theme = gtk_icon_theme_get_default ();
951
952 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (icon_store), COLUMN_DISPLAY_NAME, search_model_sort,
953 (gpointer) name_string, NULL);
954
955 icons = gtk_icon_theme_list_icons (theme, NULL);
956
957 for ( ; icons; icons = icons->next)
958 {
959 if (g_strrstr (icons->data, name_string)) {
960 callback_info = g_new (IconInfoLoadCallbackInfo, 1);
961 callback_info->model = icon_store;
962 callback_info->short_name = icons->data;
963 callback_info->long_name = icons->data;
964 info = gtk_icon_theme_lookup_icon (theme, callback_info->short_name, icon_size, GTK_ICON_LOOKUP_FORCE_SIZE);
965 gtk_icon_info_load_icon_async (info, cancellable, (GAsyncReadyCallback) (finish_pixbuf_load_from_name), callback_info);
966 }
967 }
968 g_list_free_full (icons, g_free);
969 }
970
971 static void
972 on_search (GtkSearchEntry *entry,
973 XAppIconChooserDialog *dialog)
974 {
975 XAppIconChooserDialogPrivate *priv;
976 const gchar *search_text;
977
978 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
979
980 if (priv->cancellable != NULL)
981 {
982 g_cancellable_cancel (priv->cancellable);
983 g_object_unref (priv->cancellable);
984 }
985 priv->cancellable = g_cancellable_new ();
986
987 search_text = gtk_entry_get_text (GTK_ENTRY (entry));
988
989 if (g_strcmp0 (search_text, "") == 0)
990 {
991 on_category_selected (GTK_LIST_BOX (priv->list_box), dialog);
992 }
993 else
994 {
995 gtk_list_store_clear (GTK_LIST_STORE (priv->icon_store));
996 gtk_icon_view_set_model (GTK_ICON_VIEW (priv->icon_view), GTK_TREE_MODEL (priv->icon_store));
997 if (g_strrstr (search_text, "/"))
998 {
999 if (priv->allow_paths)
1000 {
1001 search_path (search_text, priv->icon_store, priv->cancellable);
1002 }
1003 }
1004 else
1005 {
1006 search_icon_name (search_text, priv->icon_store, priv->cancellable, priv->icon_size);
1007 }
1008 }
1009 }
1010
1011 static void
1012 on_icon_view_selection_changed (GtkIconView *icon_view,
1013 gpointer user_data)
1014 {
1015 XAppIconChooserDialogPrivate *priv;
1016 GList *selected_items;
1017 gchar *icon_string = "";
1018
1019 priv = xapp_icon_chooser_dialog_get_instance_private (user_data);
1020
1021 selected_items = gtk_icon_view_get_selected_items (icon_view);
1022 if (selected_items == NULL)
1023 {
1024 gtk_widget_set_sensitive (GTK_WIDGET (priv->select_button), FALSE);
1025 }
1026 else
1027 {
1028 GtkTreePath *tree_path;
1029 GtkTreeModel *model;
1030 GtkTreeIter iter;
1031
1032 gtk_widget_set_sensitive (GTK_WIDGET (priv->select_button), TRUE);
1033
1034 tree_path = selected_items->data;
1035 model = gtk_icon_view_get_model (icon_view);
1036 gtk_tree_model_get_iter (model, &iter, tree_path);
1037 gtk_tree_model_get (model, &iter, COLUMN_FULL_NAME, &icon_string, -1);
1038 }
1039
1040 priv->icon_string = icon_string;
1041
1042 g_list_free_full (selected_items, (GDestroyNotify) gtk_tree_path_free);
1043 }
1044
1045 static void
1046 on_icon_store_icons_added (GtkTreeModel *tree_model,
1047 GtkTreePath *path,
1048 GtkTreeIter *iter,
1049 gpointer user_data)
1050 {
1051 XAppIconChooserDialogPrivate *priv;
1052 GtkTreePath *new_path;
1053
1054 priv = xapp_icon_chooser_dialog_get_instance_private (user_data);
1055
1056 if (tree_model != gtk_icon_view_get_model (GTK_ICON_VIEW (priv->icon_view))) {
1057 return;
1058 }
1059
1060 new_path = gtk_tree_path_new_first ();
1061 gtk_icon_view_select_path (GTK_ICON_VIEW (priv->icon_view), new_path);
1062 }
1063
1064 static void
1065 on_browse_button_clicked (GtkButton *button,
1066 gpointer user_data)
1067 {
1068 XAppIconChooserDialog *dialog = user_data;
1069 XAppIconChooserDialogPrivate *priv;
1070 GtkWidget *file_dialog;
1071 const gchar *search_text;
1072 GtkFileFilter *file_filter;
1073 gint response;
1074
1075 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
1076
1077 file_dialog = gtk_file_chooser_dialog_new (_("Select image file"),
1078 GTK_WINDOW (dialog),
1079 GTK_FILE_CHOOSER_ACTION_OPEN,
1080 _("Cancel"),
1081 GTK_RESPONSE_CANCEL,
1082 _("Open"),
1083 GTK_RESPONSE_ACCEPT,
1084 NULL);
1085
1086 search_text = gtk_entry_get_text (GTK_ENTRY (priv->search_bar));
1087 if (g_strrstr (search_text, "/"))
1088 {
1089 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (file_dialog), search_text);
1090 }
1091 else
1092 {
1093 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (file_dialog), "/usr/share/icons/");
1094 }
1095
1096 file_filter = gtk_file_filter_new ();
1097 gtk_file_filter_set_name (file_filter, _("Image"));
1098 gtk_file_filter_add_pixbuf_formats (file_filter);
1099 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_dialog), file_filter);
1100
1101 response = gtk_dialog_run (GTK_DIALOG (file_dialog));
1102 if (response == GTK_RESPONSE_ACCEPT)
1103 {
1104 gchar *filename;
1105
1106 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_dialog));
1107 gtk_entry_set_text (GTK_ENTRY (priv->search_bar), filename);
1108 g_free (filename);
1109 }
1110
1111 gtk_widget_destroy (file_dialog);
1112 }
1113
1114 static void
1115 on_select_button_clicked (GtkButton *button,
1116 gpointer user_data)
1117 {
1118 xapp_icon_chooser_dialog_close (XAPP_ICON_CHOOSER_DIALOG (user_data), FALSE);
1119 }
1120
1121 static void
1122 on_cancel_button_clicked (GtkButton *button,
1123 gpointer user_data)
1124 {
1125 xapp_icon_chooser_dialog_close (XAPP_ICON_CHOOSER_DIALOG (user_data), TRUE);
1126 }
1127
1128 static gboolean
1129 on_delete_event (GtkWidget *widget,
1130 GdkEventAny *event)
1131 {
1132 xapp_icon_chooser_dialog_close (XAPP_ICON_CHOOSER_DIALOG (widget), TRUE);
1133 }
1134
1135 static gboolean
1136 on_select_event (XAppIconChooserDialog *dialog,
1137 GdkEventAny *event)
1138 {
1139 XAppIconChooserDialogPrivate *priv;
1140
1141 priv = xapp_icon_chooser_dialog_get_instance_private (dialog);
1142
1143 if (g_strcmp0 (priv->icon_string, "") != 0)
1144 {
1145 xapp_icon_chooser_dialog_close (dialog, FALSE);
1146 }
1147 }
1148
1149 static void
1150 on_icon_view_item_activated (GtkIconView *iconview,
1151 GtkTreePath *path,
1152 gpointer user_data)
1153 {
1154 xapp_icon_chooser_dialog_close (XAPP_ICON_CHOOSER_DIALOG (user_data), FALSE);
1155 }
1156
1157 static gboolean
1158 on_search_bar_key_pressed (GtkWidget *widget,
1159 GdkEvent *event,
1160 gpointer user_data)
1161 {
1162 XAppIconChooserDialogPrivate *priv;
1163 guint keyval;
1164
1165 priv = xapp_icon_chooser_dialog_get_instance_private (user_data);
1166
1167 gdk_event_get_keyval (event, &keyval);
1168 switch (keyval)
1169 {
1170 case GDK_KEY_Escape:
1171 xapp_icon_chooser_dialog_close (XAPP_ICON_CHOOSER_DIALOG (user_data), TRUE);
1172 return TRUE;
1173 case GDK_KEY_Return:
1174 case GDK_KEY_KP_Enter:
1175 if (g_strcmp0 (priv->icon_string, "") != 0)
1176 {
1177 xapp_icon_chooser_dialog_close (XAPP_ICON_CHOOSER_DIALOG (user_data), FALSE);
1178 }
1179 return TRUE;
1180 }
1181
1182 return FALSE;
1183 }
0 #ifndef _XAPP_ICON_CHOOSER_DIALOG_H_
1 #define _XAPP_ICON_CHOOSER_DIALOG_H_
2
3 #include <glib-object.h>
4 #include <gtk/gtk.h>
5 #include "xapp-enums.h"
6
7 G_BEGIN_DECLS
8
9 #define XAPP_TYPE_ICON_CHOOSER_DIALOG (xapp_icon_chooser_dialog_get_type ())
10
11 G_DECLARE_FINAL_TYPE (XAppIconChooserDialog, xapp_icon_chooser_dialog, XAPP, ICON_CHOOSER_DIALOG, GtkWindow)
12
13 typedef enum
14 {
15 XAPP_ICON_SIZE_16 = 16,
16 XAPP_ICON_SIZE_22 = 22,
17 XAPP_ICON_SIZE_24 = 24,
18 XAPP_ICON_SIZE_32 = 32,
19 XAPP_ICON_SIZE_48 = 48,
20 XAPP_ICON_SIZE_96 = 96
21 } XAppIconSize;
22
23 XAppIconChooserDialog * xapp_icon_chooser_dialog_new (void);
24
25 gint xapp_icon_chooser_dialog_run (XAppIconChooserDialog *dialog);
26
27 gint xapp_icon_chooser_dialog_run_with_icon (XAppIconChooserDialog *dialog,
28 gchar *icon);
29
30 gint xapp_icon_chooser_dialog_run_with_category (XAppIconChooserDialog *dialog,
31 gchar *category);
32
33 gchar * xapp_icon_chooser_dialog_get_icon_string (XAppIconChooserDialog *dialog);
34
35
36 G_END_DECLS
37
38 #endif /* _XAPP_ICON_CHOOSER_DIALOG_H_ */
2626 top_inc = include_directories('.')
2727
2828 subdir('libxapp')
29 # subdir('po')
29 subdir('po')
3030 subdir('pygobject')
3131 subdir('files')
3232 subdir('schemas')
0 es
01 fr
00 libxapp/xapp-gtk-window.c
1 libxapp/xapp-icon-chooser-dialog.c
12 libxapp/xapp-kbd-layout-controller.c
23 libxapp/xapp-monitor-blanker.c
34 libxapp/xapp-preferences-window.c
0 # SOME DESCRIPTIVE TITLE.
1 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
2 # This file is distributed under the same license as the PACKAGE package.
3 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
4 #
5 msgid ""
6 msgstr ""
7 "Project-Id-Version: \n"
8 "Report-Msgid-Bugs-To: \n"
9 "POT-Creation-Date: 2018-09-25 13:17-0600\n"
10 "PO-Revision-Date: 2018-09-25 13:42-0600\n"
11 "Language-Team: \n"
12 "MIME-Version: 1.0\n"
13 "Content-Type: text/plain; charset=UTF-8\n"
14 "Content-Transfer-Encoding: 8bit\n"
15 "X-Generator: Poedit 2.0.6\n"
16 "Last-Translator: \n"
17 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
18 "Language: es\n"
19
20 #: libxapp/xapp-icon-chooser-dialog.c:153
21 msgid "Browse"
22 msgstr "Ramonear"
23
24 #: libxapp/xapp-icon-chooser-dialog.c:192
25 #: libxapp/xapp-icon-chooser-dialog.c:674
26 msgid "Cancel"
27 msgstr "Cancelar"
28
29 #: libxapp/xapp-icon-chooser-dialog.c:691
30 msgid "Image"
31 msgstr "Archivos de imagen"
32
33 #: libxapp/xapp-icon-chooser-dialog.c:676
34 msgid "Open"
35 msgstr "Abrir"
36
37 #: libxapp/xapp-icon-chooser-dialog.c:183
38 msgid "Select"
39 msgstr "Elegir"
40
41 #: libxapp/xapp-icon-chooser-dialog.c:671
42 msgid "Select image file"
43 msgstr "Elegir un archivo de icono"
0 # SOME DESCRIPTIVE TITLE.
1 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
2 # This file is distributed under the same license as the PACKAGE package.
3 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
4 #
5 msgid ""
6 msgstr ""
7 "Project-Id-Version: \n"
8 "Report-Msgid-Bugs-To: \n"
9 "POT-Creation-Date: 2018-09-25 13:17-0600\n"
10 "PO-Revision-Date: 2018-09-25 13:43-0600\n"
11 "Language-Team: \n"
12 "MIME-Version: 1.0\n"
13 "Content-Type: text/plain; charset=UTF-8\n"
14 "Content-Transfer-Encoding: 8bit\n"
15 "X-Generator: Poedit 2.0.6\n"
16 "Last-Translator: \n"
17 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
18 "Language: fr\n"
19
20 #: libxapp/xapp-icon-chooser-dialog.c:153
21 msgid "Browse"
22 msgstr ""
23
24 #: libxapp/xapp-icon-chooser-dialog.c:192
25 #: libxapp/xapp-icon-chooser-dialog.c:674
26 msgid "Cancel"
27 msgstr ""
28
29 #: libxapp/xapp-icon-chooser-dialog.c:691
30 msgid "Image"
31 msgstr ""
32
33 #: libxapp/xapp-icon-chooser-dialog.c:676
34 msgid "Open"
35 msgstr ""
36
37 #: libxapp/xapp-icon-chooser-dialog.c:183
38 msgid "Select"
39 msgstr ""
40
41 #: libxapp/xapp-icon-chooser-dialog.c:671
42 msgid "Select image file"
43 msgstr ""
0 # SOME DESCRIPTIVE TITLE.
1 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
2 # This file is distributed under the same license as the PACKAGE package.
3 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
4 #
5 #, fuzzy
6 msgid ""
7 msgstr ""
8 "Project-Id-Version: PACKAGE VERSION\n"
9 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2018-10-04 23:04-0600\n"
11 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13 "Language-Team: LANGUAGE <LL@li.org>\n"
14 "Language: \n"
15 "MIME-Version: 1.0\n"
16 "Content-Type: text/plain; charset=CHARSET\n"
17 "Content-Transfer-Encoding: 8bit\n"
18
19 #: libxapp/xapp-icon-chooser-dialog.c:63
20 msgid "Actions"
21 msgstr ""
22
23 #: libxapp/xapp-icon-chooser-dialog.c:66
24 msgid "Applications"
25 msgstr ""
26
27 #: libxapp/xapp-icon-chooser-dialog.c:69
28 msgid "Categories"
29 msgstr ""
30
31 #: libxapp/xapp-icon-chooser-dialog.c:72
32 msgid "Devices"
33 msgstr ""
34
35 #: libxapp/xapp-icon-chooser-dialog.c:75
36 msgid "Emblems"
37 msgstr ""
38
39 #: libxapp/xapp-icon-chooser-dialog.c:78
40 msgid "Emoji"
41 msgstr ""
42
43 #: libxapp/xapp-icon-chooser-dialog.c:81
44 msgid "Mime types"
45 msgstr ""
46
47 #: libxapp/xapp-icon-chooser-dialog.c:84
48 msgid "Places"
49 msgstr ""
50
51 #: libxapp/xapp-icon-chooser-dialog.c:87
52 msgid "Status"
53 msgstr ""
54
55 #: libxapp/xapp-icon-chooser-dialog.c:90
56 msgid "Other"
57 msgstr ""
58
59 #: libxapp/xapp-icon-chooser-dialog.c:284
60 msgid "Browse"
61 msgstr ""
62
63 #: libxapp/xapp-icon-chooser-dialog.c:316
64 msgid "Select"
65 msgstr ""
66
67 #: libxapp/xapp-icon-chooser-dialog.c:325
68 #: libxapp/xapp-icon-chooser-dialog.c:1033
69 msgid "Cancel"
70 msgstr ""
71
72 #: libxapp/xapp-icon-chooser-dialog.c:358
73 msgid "Icon size"
74 msgstr ""
75
76 #: libxapp/xapp-icon-chooser-dialog.c:359
77 msgid "The preferred icon size."
78 msgstr ""
79
80 #: libxapp/xapp-icon-chooser-dialog.c:1030
81 msgid "Select image file"
82 msgstr ""
83
84 #: libxapp/xapp-icon-chooser-dialog.c:1035
85 msgid "Open"
86 msgstr ""
87
88 #: libxapp/xapp-icon-chooser-dialog.c:1050
89 msgid "Image"
90 msgstr ""
0 #!/usr/bin/python3
1
2 import gi
3 gi.require_version('Gtk', '3.0')
4 gi.require_version('XApp', '1.0')
5
6 from gi.repository import Gtk, XApp, Gdk
7
8 import argparse
9
10 if __name__ == '__main__':
11 parser = argparse.ArgumentParser()
12 group = parser.add_mutually_exclusive_group()
13 # if there are no arguments supplied, we should create a new launcher in the default location (usually ~/.local/share/applications/)
14 group.add_argument('-c', '--category', dest='category', metavar='CATEGORY',
15 help='The category to select when the dialog is opened.')
16 group.add_argument('-i', '--icon-string', dest='icon', metavar='ICON_STRING',
17 help='The icon to select when the dialog is opened. This can be an icon name or a path. '
18 'If the icon doesn\'t exist, it will not cause an error, but there may not be an icon '
19 'selected.')
20 parser.add_argument('-b', '--clipboard', dest='clipboard', action='store_true',
21 help='If this option is supplied, the result will be copied to the clipboard when an icon is '
22 'selected and the dialog closed.')
23 parser.add_argument('-p', '--disallow-paths', dest='paths', action='store_false',
24 help='causes the path.')
25
26 args = parser.parse_args()
27
28 dialog = XApp.IconChooserDialog(allow_paths=args.paths)
29 if args.category:
30 response = dialog.run_with_category(args.category)
31 elif args.icon:
32 response = dialog.run_with_icon(args.icon)
33 else:
34 response = dialog.run()
35
36 if response == Gtk.ResponseType.OK:
37 string = dialog.get_icon_string()
38 print(string)
39
40 if args.clipboard:
41 clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
42 clipboard.set_text(string, -1)
43 clipboard.store()
44 else:
45 print('Dialog canceled')