2
* panel-icon-chooser.c: An icon chooser widget
4
* Copyright (C) 2010 Novell, Inc.
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License as
8
* published by the Free Software Foundation; either version 2 of the
9
* License, or (at your option) any later version.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22
* Vincent Untz <vuntz@gnome.org>
25
#include <glib/gi18n.h>
28
#include "panel-gtk.h"
29
#include "panel-xdg.h"
31
#include "panel-icon-chooser.h"
33
#define PANEL_ICON_CHOOSER_ICON_SIZE GTK_ICON_SIZE_DIALOG
35
struct _PanelIconChooserPrivate
37
char *fallback_icon_name;
44
GtkWidget *filechooser;
58
static guint panel_icon_chooser_signals[LAST_SIGNAL] = { 0 };
60
#define PANEL_ICON_CHOOSER_GET_PRIVATE(o) (PANEL_ICON_CHOOSER (o)->priv)
62
G_DEFINE_TYPE (PanelIconChooser, panel_icon_chooser, GTK_TYPE_BUTTON)
64
static void _panel_icon_chooser_clicked (GtkButton *button);
65
static void _panel_icon_chooser_style_set (GtkWidget *widget,
66
GtkStyle *prev_style);
67
static void _panel_icon_chooser_screen_changed (GtkWidget *widget,
68
GdkScreen *prev_screen);
73
panel_icon_chooser_constructor (GType type,
74
guint n_construct_properties,
75
GObjectConstructParam *construct_properties)
78
PanelIconChooser *chooser;
80
obj = G_OBJECT_CLASS (panel_icon_chooser_parent_class)->constructor (type,
81
n_construct_properties,
82
construct_properties);
84
chooser = PANEL_ICON_CHOOSER (obj);
85
gtk_container_add (GTK_CONTAINER (chooser), chooser->priv->image);
86
gtk_widget_show (chooser->priv->image);
92
panel_icon_chooser_get_property (GObject *object,
97
PanelIconChooser *chooser;
99
g_return_if_fail (PANEL_IS_ICON_CHOOSER (object));
101
chooser = PANEL_ICON_CHOOSER (object);
104
case PROP_FALLBACK_ICON:
105
g_value_set_string (value, panel_icon_chooser_get_fallback_icon_name (chooser));
108
g_value_set_string (value, panel_icon_chooser_get_icon (chooser));
111
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
117
panel_icon_chooser_set_property (GObject *object,
122
PanelIconChooser *chooser;
124
g_return_if_fail (PANEL_IS_ICON_CHOOSER (object));
126
chooser = PANEL_ICON_CHOOSER (object);
129
case PROP_FALLBACK_ICON:
130
panel_icon_chooser_set_fallback_icon_name (chooser,
131
g_value_get_string (value));
134
panel_icon_chooser_set_icon (chooser,
135
g_value_get_string (value));
138
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
144
panel_icon_chooser_destroy (GtkObject *object)
146
PanelIconChooser *chooser;
148
chooser = PANEL_ICON_CHOOSER (object);
150
if (chooser->priv->filechooser) {
151
gtk_widget_destroy (chooser->priv->filechooser);
152
chooser->priv->filechooser = NULL;
155
/* remember, destroy can be run multiple times! */
157
if (chooser->priv->fallback_icon_name != NULL)
158
g_free (chooser->priv->fallback_icon_name);
159
chooser->priv->fallback_icon_name = NULL;
161
if (chooser->priv->icon != NULL)
162
g_free (chooser->priv->icon);
163
chooser->priv->icon = NULL;
165
if (chooser->priv->icon_theme_dir != NULL)
166
g_free (chooser->priv->icon_theme_dir);
167
chooser->priv->icon_theme_dir = NULL;
169
GTK_OBJECT_CLASS (panel_icon_chooser_parent_class)->destroy (object);
173
panel_icon_chooser_class_init (PanelIconChooserClass *class)
175
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
176
GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (class);
177
GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (class);
178
GtkButtonClass *gtkbutton_class = GTK_BUTTON_CLASS (class);
180
gobject_class->constructor = panel_icon_chooser_constructor;
181
gobject_class->get_property = panel_icon_chooser_get_property;
182
gobject_class->set_property = panel_icon_chooser_set_property;
184
gtkobject_class->destroy = panel_icon_chooser_destroy;
186
gtkwidget_class->style_set = _panel_icon_chooser_style_set;
187
gtkwidget_class->screen_changed = _panel_icon_chooser_screen_changed;
189
gtkbutton_class->clicked = _panel_icon_chooser_clicked;
191
g_type_class_add_private (class,
192
sizeof (PanelIconChooserPrivate));
194
panel_icon_chooser_signals[CHANGED] =
195
g_signal_new ("changed",
196
G_TYPE_FROM_CLASS (gobject_class),
198
G_STRUCT_OFFSET (PanelIconChooserClass,
202
g_cclosure_marshal_VOID__STRING,
206
g_object_class_install_property (
209
g_param_spec_string ("fallback-icon-name",
210
"Fallback Icon Name",
211
"Icon name of the icon displayed (but not returned) if the current icon does not exit",
213
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
215
g_object_class_install_property (
218
g_param_spec_string ("icon",
222
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
226
panel_icon_chooser_init (PanelIconChooser *chooser)
228
PanelIconChooserPrivate *priv;
230
priv = G_TYPE_INSTANCE_GET_PRIVATE (chooser,
231
PANEL_TYPE_ICON_CHOOSER,
232
PanelIconChooserPrivate);
234
chooser->priv = priv;
236
priv->fallback_icon_name = g_strdup ("gtk-missing-image");
238
priv->icon_theme_dir = NULL;
240
priv->image = gtk_image_new_from_icon_name (priv->fallback_icon_name,
241
PANEL_ICON_CHOOSER_ICON_SIZE);
243
priv->filechooser = NULL;
249
_panel_icon_chooser_update (PanelIconChooser *chooser)
251
if (!chooser->priv->icon) {
252
gtk_image_set_from_icon_name (GTK_IMAGE (chooser->priv->image),
253
chooser->priv->fallback_icon_name,
254
PANEL_ICON_CHOOSER_ICON_SIZE);
256
} else if (g_path_is_absolute (chooser->priv->icon)) {
261
if (g_file_test (chooser->priv->icon, G_FILE_TEST_EXISTS)) {
262
/* we pass via a pixbuf to force the size we want */
266
gtk_icon_size_lookup (PANEL_ICON_CHOOSER_ICON_SIZE,
268
pixbuf = gdk_pixbuf_new_from_file_at_size (chooser->priv->icon,
273
gtk_image_set_from_pixbuf (GTK_IMAGE (chooser->priv->image),
275
g_object_unref (pixbuf);
281
gtk_image_set_from_icon_name (GTK_IMAGE (chooser->priv->image),
282
chooser->priv->fallback_icon_name,
283
PANEL_ICON_CHOOSER_ICON_SIZE);
287
/* Note: using GThemedIcon doesn't work well, see bug #606752.
288
* When we'll remove the alternative code, we won't need the
289
* style_set/screen_changed handlers anymore.
295
names[0] = panel_xdg_icon_remove_extension (chooser->priv->icon);
296
names[1] = chooser->priv->fallback_icon_name;
297
icon = g_themed_icon_new_from_names (names, 2);
299
gtk_image_set_from_gicon (GTK_IMAGE (chooser->priv->image),
301
PANEL_ICON_CHOOSER_ICON_SIZE);
305
GtkIconTheme *icon_theme;
309
no_ext = panel_xdg_icon_remove_extension (chooser->priv->icon);
311
icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (chooser)));
312
if (gtk_icon_theme_has_icon (icon_theme, no_ext))
315
icon = chooser->priv->fallback_icon_name;
317
gtk_image_set_from_icon_name (GTK_IMAGE (chooser->priv->image),
319
PANEL_ICON_CHOOSER_ICON_SIZE);
326
_panel_icon_chooser_find_icon_from_path (PanelIconChooser *chooser,
332
screen = gtk_widget_get_screen (GTK_WIDGET (chooser));
334
icon = panel_xdg_icon_name_from_icon_path (path, screen);
336
icon = g_strdup (path);
342
_panel_icon_chooser_file_chooser_response (GtkFileChooser *filechooser,
344
PanelIconChooser *chooser)
346
if (response_id == GTK_RESPONSE_ACCEPT) {
350
path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
351
icon = _panel_icon_chooser_find_icon_from_path (chooser, path);
354
panel_icon_chooser_set_icon (chooser, icon);
358
gtk_widget_destroy (GTK_WIDGET (filechooser));
362
_panel_icon_chooser_clicked (GtkButton *button)
364
PanelIconChooser *chooser = PANEL_ICON_CHOOSER (button);
365
GtkWidget *filechooser;
369
gboolean filechooser_path_set;
371
if (chooser->priv->filechooser) {
372
gtk_window_present (GTK_WINDOW (chooser->priv->filechooser));
376
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
377
if (GTK_WIDGET_TOPLEVEL (toplevel))
378
parent = GTK_WINDOW (toplevel);
382
filechooser = gtk_file_chooser_dialog_new (_("Choose an icon"),
384
GTK_FILE_CHOOSER_ACTION_OPEN,
390
panel_gtk_file_chooser_add_image_preview (GTK_FILE_CHOOSER (filechooser));
392
path = g_build_filename (DATADIR, "icons", NULL);
393
gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (filechooser),
397
path = g_build_filename (DATADIR, "pixmaps", NULL);
398
gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (filechooser),
402
filechooser_path_set = FALSE;
404
if (chooser->priv->icon) {
406
if (g_path_is_absolute (chooser->priv->icon)) {
407
path = g_strdup (chooser->priv->icon);
409
GtkIconTheme *icon_theme;
414
icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (chooser)));
415
no_ext = panel_xdg_icon_remove_extension (chooser->priv->icon);
416
gtk_icon_size_lookup (PANEL_ICON_CHOOSER_ICON_SIZE,
419
info = gtk_icon_theme_lookup_icon (icon_theme, no_ext,
424
path = g_strdup (gtk_icon_info_get_filename (info));
425
gtk_icon_info_free (info);
430
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filechooser),
433
filechooser_path_set = TRUE;
437
if (!filechooser_path_set) {
439
// FIXME? Use current icon theme? But there might not be a lot
441
path = g_build_filename (DATADIR, "icons", NULL);
442
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser),
446
gtk_window_set_destroy_with_parent (GTK_WINDOW (filechooser), TRUE);
448
g_signal_connect (filechooser, "response",
449
G_CALLBACK (_panel_icon_chooser_file_chooser_response),
452
chooser->priv->filechooser = filechooser;
454
g_signal_connect (G_OBJECT (filechooser), "destroy",
455
G_CALLBACK (gtk_widget_destroyed),
456
&chooser->priv->filechooser);
458
gtk_widget_show (filechooser);
462
_panel_icon_chooser_style_set (GtkWidget *widget,
463
GtkStyle *prev_style)
465
PanelIconChooser *chooser;
467
chooser = PANEL_ICON_CHOOSER (widget);
469
GTK_WIDGET_CLASS (panel_icon_chooser_parent_class)->style_set (widget, prev_style);
471
_panel_icon_chooser_update (chooser);
475
_panel_icon_chooser_screen_changed (GtkWidget *widget,
476
GdkScreen *prev_screen)
478
PanelIconChooser *chooser;
480
chooser = PANEL_ICON_CHOOSER (widget);
482
if (GTK_WIDGET_CLASS (panel_icon_chooser_parent_class)->screen_changed)
483
GTK_WIDGET_CLASS (panel_icon_chooser_parent_class)->screen_changed (widget, prev_screen);
485
_panel_icon_chooser_update (chooser);
491
panel_icon_chooser_new (const char *icon)
495
chooser = g_object_new (PANEL_TYPE_ICON_CHOOSER,
503
panel_icon_chooser_get_fallback_icon_name (PanelIconChooser *chooser)
505
g_return_val_if_fail (PANEL_IS_ICON_CHOOSER (chooser), NULL);
507
return chooser->priv->fallback_icon_name;
511
panel_icon_chooser_set_fallback_icon_name (PanelIconChooser *chooser,
512
const char *fallback_icon_name)
514
g_return_if_fail (PANEL_IS_ICON_CHOOSER (chooser));
516
if (g_strcmp0 (chooser->priv->fallback_icon_name, fallback_icon_name) == 0)
519
if (chooser->priv->fallback_icon_name)
520
g_free (chooser->priv->fallback_icon_name);
521
chooser->priv->fallback_icon_name = g_strdup (fallback_icon_name);
523
_panel_icon_chooser_update (chooser);
525
g_object_notify (G_OBJECT (chooser), "fallback-icon-name");
529
panel_icon_chooser_get_icon (PanelIconChooser *chooser)
531
g_return_val_if_fail (PANEL_IS_ICON_CHOOSER (chooser), NULL);
533
return chooser->priv->icon;
537
panel_icon_chooser_set_icon (PanelIconChooser *chooser,
540
g_return_if_fail (PANEL_IS_ICON_CHOOSER (chooser));
542
if (g_strcmp0 (chooser->priv->icon, icon) == 0)
545
if (chooser->priv->icon)
546
g_free (chooser->priv->icon);
547
chooser->priv->icon = g_strdup (icon);
549
_panel_icon_chooser_update (chooser);
551
g_object_notify (G_OBJECT (chooser), "icon");
553
g_signal_emit (G_OBJECT (chooser),
554
panel_icon_chooser_signals[CHANGED], 0, icon);