~ubuntu-branches/ubuntu/oneiric/gnome-panel/oneiric

« back to all changes in this revision

Viewing changes to gnome-panel/libpanel-util/panel-icon-chooser.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2010-01-14 22:20:05 UTC
  • mto: (2.1.6 squeeze) (1.3.3 upstream)
  • mto: This revision was merged to the branch mainline in revision 171.
  • Revision ID: james.westby@ubuntu.com-20100114222005-rll7tw9fojl3ac6z
Tags: upstream-2.29.5.1
ImportĀ upstreamĀ versionĀ 2.29.5.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * panel-icon-chooser.c: An icon chooser widget
 
3
 *
 
4
 * Copyright (C) 2010 Novell, Inc.
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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
 
19
 * 02111-1307, USA.
 
20
 *
 
21
 * Authors:
 
22
 *      Vincent Untz <vuntz@gnome.org>
 
23
 */
 
24
 
 
25
#include <glib/gi18n.h>
 
26
#include <gtk/gtk.h>
 
27
 
 
28
#include "panel-gtk.h"
 
29
#include "panel-xdg.h"
 
30
 
 
31
#include "panel-icon-chooser.h"
 
32
 
 
33
#define PANEL_ICON_CHOOSER_ICON_SIZE GTK_ICON_SIZE_DIALOG
 
34
 
 
35
struct _PanelIconChooserPrivate
 
36
{
 
37
        char *fallback_icon_name;
 
38
        char *icon;
 
39
 
 
40
        char *icon_theme_dir;
 
41
 
 
42
        GtkWidget *image;
 
43
 
 
44
        GtkWidget *filechooser;
 
45
};
 
46
 
 
47
enum {
 
48
        CHANGED,
 
49
        LAST_SIGNAL
 
50
};
 
51
 
 
52
enum {
 
53
        PROP_0,
 
54
        PROP_FALLBACK_ICON,
 
55
        PROP_ICON
 
56
};
 
57
 
 
58
static guint panel_icon_chooser_signals[LAST_SIGNAL] = { 0 };
 
59
 
 
60
#define PANEL_ICON_CHOOSER_GET_PRIVATE(o)  (PANEL_ICON_CHOOSER (o)->priv)
 
61
 
 
62
G_DEFINE_TYPE (PanelIconChooser, panel_icon_chooser, GTK_TYPE_BUTTON)
 
63
 
 
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);
 
69
 
 
70
/* gobject stuff */
 
71
 
 
72
static GObject *
 
73
panel_icon_chooser_constructor (GType                  type,
 
74
                                guint                  n_construct_properties,
 
75
                                GObjectConstructParam *construct_properties)
 
76
{
 
77
        GObject          *obj;
 
78
        PanelIconChooser *chooser;
 
79
 
 
80
        obj = G_OBJECT_CLASS (panel_icon_chooser_parent_class)->constructor (type,
 
81
                                                                             n_construct_properties,
 
82
                                                                             construct_properties);
 
83
 
 
84
        chooser = PANEL_ICON_CHOOSER (obj);
 
85
        gtk_container_add (GTK_CONTAINER (chooser), chooser->priv->image);
 
86
        gtk_widget_show (chooser->priv->image);
 
87
 
 
88
        return obj;
 
89
}
 
90
 
 
91
static void
 
92
panel_icon_chooser_get_property (GObject    *object,
 
93
                                 guint       prop_id,
 
94
                                 GValue     *value,
 
95
                                 GParamSpec *pspec)
 
96
{
 
97
        PanelIconChooser *chooser;
 
98
 
 
99
        g_return_if_fail (PANEL_IS_ICON_CHOOSER (object));
 
100
 
 
101
        chooser = PANEL_ICON_CHOOSER (object);
 
102
 
 
103
        switch (prop_id) {
 
104
        case PROP_FALLBACK_ICON:
 
105
                g_value_set_string (value, panel_icon_chooser_get_fallback_icon_name (chooser));
 
106
                break;
 
107
        case PROP_ICON:
 
108
                g_value_set_string (value, panel_icon_chooser_get_icon (chooser));
 
109
                break;
 
110
        default:
 
111
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
112
                break;
 
113
        }
 
114
}
 
115
 
 
116
static void
 
117
panel_icon_chooser_set_property (GObject      *object,
 
118
                                 guint         prop_id,
 
119
                                 const GValue *value,
 
120
                                 GParamSpec   *pspec)
 
121
{
 
122
        PanelIconChooser *chooser;
 
123
 
 
124
        g_return_if_fail (PANEL_IS_ICON_CHOOSER (object));
 
125
 
 
126
        chooser = PANEL_ICON_CHOOSER (object);
 
127
 
 
128
        switch (prop_id) {
 
129
        case PROP_FALLBACK_ICON:
 
130
                panel_icon_chooser_set_fallback_icon_name (chooser,
 
131
                                                           g_value_get_string (value));
 
132
                break;
 
133
        case PROP_ICON:
 
134
                panel_icon_chooser_set_icon (chooser,
 
135
                                             g_value_get_string (value));
 
136
                break;
 
137
        default:
 
138
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
139
                break;
 
140
        }
 
141
}
 
142
 
 
143
static void
 
144
panel_icon_chooser_destroy (GtkObject *object)
 
145
{
 
146
        PanelIconChooser *chooser;
 
147
 
 
148
        chooser = PANEL_ICON_CHOOSER (object);
 
149
 
 
150
        if (chooser->priv->filechooser) {
 
151
                gtk_widget_destroy (chooser->priv->filechooser);
 
152
                chooser->priv->filechooser = NULL;
 
153
        }
 
154
 
 
155
        /* remember, destroy can be run multiple times! */
 
156
 
 
157
        if (chooser->priv->fallback_icon_name != NULL)
 
158
                g_free (chooser->priv->fallback_icon_name);
 
159
        chooser->priv->fallback_icon_name = NULL;
 
160
 
 
161
        if (chooser->priv->icon != NULL)
 
162
                g_free (chooser->priv->icon);
 
163
        chooser->priv->icon = NULL;
 
164
 
 
165
        if (chooser->priv->icon_theme_dir != NULL)
 
166
                g_free (chooser->priv->icon_theme_dir);
 
167
        chooser->priv->icon_theme_dir = NULL;
 
168
 
 
169
        GTK_OBJECT_CLASS (panel_icon_chooser_parent_class)->destroy (object);
 
170
}
 
171
 
 
172
static void
 
173
panel_icon_chooser_class_init (PanelIconChooserClass *class)
 
174
{
 
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);
 
179
 
 
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;
 
183
 
 
184
        gtkobject_class->destroy = panel_icon_chooser_destroy;
 
185
 
 
186
        gtkwidget_class->style_set = _panel_icon_chooser_style_set;
 
187
        gtkwidget_class->screen_changed = _panel_icon_chooser_screen_changed;
 
188
 
 
189
        gtkbutton_class->clicked = _panel_icon_chooser_clicked;
 
190
 
 
191
        g_type_class_add_private (class,
 
192
                                  sizeof (PanelIconChooserPrivate));
 
193
 
 
194
        panel_icon_chooser_signals[CHANGED] =
 
195
                g_signal_new ("changed",
 
196
                              G_TYPE_FROM_CLASS (gobject_class),
 
197
                              G_SIGNAL_RUN_LAST,
 
198
                              G_STRUCT_OFFSET (PanelIconChooserClass,
 
199
                                               changed),
 
200
                              NULL,
 
201
                              NULL,
 
202
                              g_cclosure_marshal_VOID__STRING,
 
203
                              G_TYPE_NONE, 1,
 
204
                              G_TYPE_STRING);
 
205
 
 
206
        g_object_class_install_property (
 
207
                gobject_class,
 
208
                PROP_FALLBACK_ICON,
 
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",
 
212
                                     NULL,
 
213
                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
214
 
 
215
        g_object_class_install_property (
 
216
                gobject_class,
 
217
                PROP_ICON,
 
218
                g_param_spec_string ("icon",
 
219
                                     "Icon",
 
220
                                     "Icon name or path",
 
221
                                     NULL,
 
222
                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
223
}
 
224
 
 
225
static void
 
226
panel_icon_chooser_init (PanelIconChooser *chooser)
 
227
{
 
228
        PanelIconChooserPrivate *priv;
 
229
 
 
230
        priv = G_TYPE_INSTANCE_GET_PRIVATE (chooser,
 
231
                                            PANEL_TYPE_ICON_CHOOSER,
 
232
                                            PanelIconChooserPrivate);
 
233
 
 
234
        chooser->priv = priv;
 
235
 
 
236
        priv->fallback_icon_name = g_strdup ("gtk-missing-image");
 
237
        priv->icon = NULL;
 
238
        priv->icon_theme_dir = NULL;
 
239
 
 
240
        priv->image = gtk_image_new_from_icon_name (priv->fallback_icon_name,
 
241
                                                    PANEL_ICON_CHOOSER_ICON_SIZE);
 
242
 
 
243
        priv->filechooser = NULL;
 
244
}
 
245
 
 
246
/* internal code */
 
247
 
 
248
static void
 
249
_panel_icon_chooser_update (PanelIconChooser *chooser)
 
250
{
 
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);
 
255
 
 
256
        } else if (g_path_is_absolute (chooser->priv->icon)) {
 
257
                gboolean fallback;
 
258
 
 
259
                fallback = TRUE;
 
260
 
 
261
                if (g_file_test (chooser->priv->icon, G_FILE_TEST_EXISTS)) {
 
262
                        /* we pass via a pixbuf to force the size we want */
 
263
                        GdkPixbuf *pixbuf;
 
264
                        int        width, height;
 
265
 
 
266
                        gtk_icon_size_lookup (PANEL_ICON_CHOOSER_ICON_SIZE,
 
267
                                              &width, &height);
 
268
                        pixbuf = gdk_pixbuf_new_from_file_at_size (chooser->priv->icon,
 
269
                                                                   width, height,
 
270
                                                                   NULL);
 
271
 
 
272
                        if (pixbuf) {
 
273
                                gtk_image_set_from_pixbuf (GTK_IMAGE (chooser->priv->image),
 
274
                                                           pixbuf);
 
275
                                g_object_unref (pixbuf);
 
276
                                fallback = FALSE;
 
277
                        }
 
278
                }
 
279
 
 
280
                if (fallback) {
 
281
                        gtk_image_set_from_icon_name (GTK_IMAGE (chooser->priv->image),
 
282
                                                      chooser->priv->fallback_icon_name,
 
283
                                                      PANEL_ICON_CHOOSER_ICON_SIZE);
 
284
                }
 
285
 
 
286
        } else {
 
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.
 
290
                 */
 
291
#if 0
 
292
                GIcon *icon;
 
293
                char  *names[2];
 
294
 
 
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);
 
298
 
 
299
                gtk_image_set_from_gicon (GTK_IMAGE (chooser->priv->image),
 
300
                                          icon,
 
301
                                          PANEL_ICON_CHOOSER_ICON_SIZE);
 
302
 
 
303
                g_free (names[0]);
 
304
#endif
 
305
                GtkIconTheme *icon_theme;
 
306
                const char   *icon;
 
307
                char         *no_ext;
 
308
 
 
309
                no_ext = panel_xdg_icon_remove_extension (chooser->priv->icon);
 
310
 
 
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))
 
313
                        icon = no_ext;
 
314
                else
 
315
                        icon = chooser->priv->fallback_icon_name;
 
316
 
 
317
                gtk_image_set_from_icon_name (GTK_IMAGE (chooser->priv->image),
 
318
                                              icon,
 
319
                                              PANEL_ICON_CHOOSER_ICON_SIZE);
 
320
 
 
321
                g_free (no_ext);
 
322
        }
 
323
}
 
324
 
 
325
static char *
 
326
_panel_icon_chooser_find_icon_from_path (PanelIconChooser *chooser,
 
327
                                         const char       *path)
 
328
{
 
329
        GdkScreen *screen;
 
330
        char      *icon;
 
331
 
 
332
        screen = gtk_widget_get_screen (GTK_WIDGET (chooser));
 
333
 
 
334
        icon = panel_xdg_icon_name_from_icon_path (path, screen);
 
335
        if (!icon)
 
336
                icon = g_strdup (path);
 
337
 
 
338
        return icon;
 
339
}
 
340
 
 
341
static void
 
342
_panel_icon_chooser_file_chooser_response (GtkFileChooser   *filechooser,
 
343
                                           gint              response_id,
 
344
                                           PanelIconChooser *chooser)
 
345
{
 
346
        if (response_id == GTK_RESPONSE_ACCEPT) {
 
347
                char *path;
 
348
                char *icon;
 
349
 
 
350
                path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
 
351
                icon = _panel_icon_chooser_find_icon_from_path (chooser, path);
 
352
                g_free (path);
 
353
 
 
354
                panel_icon_chooser_set_icon (chooser, icon);
 
355
                g_free (icon);
 
356
        }
 
357
 
 
358
        gtk_widget_destroy (GTK_WIDGET (filechooser));
 
359
}
 
360
 
 
361
static void
 
362
_panel_icon_chooser_clicked (GtkButton *button)
 
363
{
 
364
        PanelIconChooser *chooser = PANEL_ICON_CHOOSER (button);
 
365
        GtkWidget        *filechooser;
 
366
        GtkWidget        *toplevel;
 
367
        GtkWindow        *parent;
 
368
        char             *path;
 
369
        gboolean          filechooser_path_set;
 
370
 
 
371
        if (chooser->priv->filechooser) {
 
372
                gtk_window_present (GTK_WINDOW (chooser->priv->filechooser));
 
373
                return;
 
374
        }
 
375
 
 
376
        toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
 
377
        if (GTK_WIDGET_TOPLEVEL (toplevel))
 
378
                parent = GTK_WINDOW (toplevel);
 
379
        else
 
380
                parent = NULL;
 
381
 
 
382
        filechooser = gtk_file_chooser_dialog_new (_("Choose an icon"),
 
383
                                                   parent,
 
384
                                                   GTK_FILE_CHOOSER_ACTION_OPEN,
 
385
                                                   GTK_STOCK_CANCEL,
 
386
                                                   GTK_RESPONSE_CANCEL,
 
387
                                                   GTK_STOCK_OPEN,
 
388
                                                   GTK_RESPONSE_ACCEPT,
 
389
                                                   NULL);
 
390
        panel_gtk_file_chooser_add_image_preview (GTK_FILE_CHOOSER (filechooser));
 
391
 
 
392
        path = g_build_filename (DATADIR, "icons", NULL);
 
393
        gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (filechooser),
 
394
                                              path, NULL);
 
395
        g_free (path);
 
396
 
 
397
        path = g_build_filename (DATADIR, "pixmaps", NULL);
 
398
        gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (filechooser),
 
399
                                              path, NULL);
 
400
        g_free (path);
 
401
 
 
402
        filechooser_path_set = FALSE;
 
403
 
 
404
        if (chooser->priv->icon) {
 
405
                char *path = NULL;
 
406
                if (g_path_is_absolute (chooser->priv->icon)) {
 
407
                        path = g_strdup (chooser->priv->icon);
 
408
                } else {
 
409
                        GtkIconTheme *icon_theme;
 
410
                        GtkIconInfo  *info;
 
411
                        char         *no_ext;
 
412
                        int           size;
 
413
 
 
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,
 
417
                                              &size, NULL);
 
418
 
 
419
                        info = gtk_icon_theme_lookup_icon (icon_theme, no_ext,
 
420
                                                           size, 0);
 
421
                        g_free (no_ext);
 
422
 
 
423
                        if (info) {
 
424
                                path = g_strdup (gtk_icon_info_get_filename (info));
 
425
                                gtk_icon_info_free (info);
 
426
                        }
 
427
                }
 
428
 
 
429
                if (path) {
 
430
                        gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filechooser),
 
431
                                                       path);
 
432
                        g_free (path);
 
433
                        filechooser_path_set = TRUE;
 
434
                }
 
435
        }
 
436
 
 
437
        if (!filechooser_path_set) {
 
438
                char *path;
 
439
                // FIXME? Use current icon theme? But there might not be a lot
 
440
                // of icons there...
 
441
                path = g_build_filename (DATADIR, "icons", NULL);
 
442
                gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser),
 
443
                                                     path);
 
444
        }
 
445
 
 
446
        gtk_window_set_destroy_with_parent (GTK_WINDOW (filechooser), TRUE);
 
447
 
 
448
        g_signal_connect (filechooser, "response",
 
449
                          G_CALLBACK (_panel_icon_chooser_file_chooser_response),
 
450
                          chooser);
 
451
 
 
452
        chooser->priv->filechooser = filechooser;
 
453
 
 
454
        g_signal_connect (G_OBJECT (filechooser), "destroy",
 
455
                          G_CALLBACK (gtk_widget_destroyed),
 
456
                          &chooser->priv->filechooser);
 
457
 
 
458
        gtk_widget_show (filechooser);
 
459
}
 
460
 
 
461
static void
 
462
_panel_icon_chooser_style_set (GtkWidget *widget,
 
463
                               GtkStyle  *prev_style)
 
464
{
 
465
        PanelIconChooser *chooser;
 
466
 
 
467
        chooser = PANEL_ICON_CHOOSER (widget);
 
468
 
 
469
        GTK_WIDGET_CLASS (panel_icon_chooser_parent_class)->style_set (widget, prev_style);
 
470
 
 
471
        _panel_icon_chooser_update (chooser);
 
472
}
 
473
 
 
474
static void
 
475
_panel_icon_chooser_screen_changed (GtkWidget *widget,
 
476
                                    GdkScreen *prev_screen)
 
477
{
 
478
        PanelIconChooser *chooser;
 
479
 
 
480
        chooser = PANEL_ICON_CHOOSER (widget);
 
481
 
 
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);
 
484
 
 
485
        _panel_icon_chooser_update (chooser);
 
486
}
 
487
 
 
488
/* public methods */
 
489
 
 
490
GtkWidget  *
 
491
panel_icon_chooser_new (const char  *icon)
 
492
{
 
493
        GtkWidget *chooser;
 
494
 
 
495
        chooser = g_object_new (PANEL_TYPE_ICON_CHOOSER,
 
496
                               "icon", icon,
 
497
                               NULL);
 
498
 
 
499
        return chooser;
 
500
}
 
501
 
 
502
const char *
 
503
panel_icon_chooser_get_fallback_icon_name (PanelIconChooser *chooser)
 
504
{
 
505
        g_return_val_if_fail (PANEL_IS_ICON_CHOOSER (chooser), NULL);
 
506
 
 
507
        return chooser->priv->fallback_icon_name;
 
508
}
 
509
 
 
510
void
 
511
panel_icon_chooser_set_fallback_icon_name (PanelIconChooser *chooser,
 
512
                                           const char       *fallback_icon_name)
 
513
{
 
514
        g_return_if_fail (PANEL_IS_ICON_CHOOSER (chooser));
 
515
 
 
516
        if (g_strcmp0 (chooser->priv->fallback_icon_name, fallback_icon_name) == 0)
 
517
                return;
 
518
 
 
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);
 
522
 
 
523
        _panel_icon_chooser_update (chooser);
 
524
 
 
525
        g_object_notify (G_OBJECT (chooser), "fallback-icon-name");
 
526
}
 
527
 
 
528
const char *
 
529
panel_icon_chooser_get_icon (PanelIconChooser *chooser)
 
530
{
 
531
        g_return_val_if_fail (PANEL_IS_ICON_CHOOSER (chooser), NULL);
 
532
 
 
533
        return chooser->priv->icon;
 
534
}
 
535
 
 
536
void
 
537
panel_icon_chooser_set_icon (PanelIconChooser *chooser,
 
538
                             const char       *icon)
 
539
{
 
540
        g_return_if_fail (PANEL_IS_ICON_CHOOSER (chooser));
 
541
 
 
542
        if (g_strcmp0 (chooser->priv->icon, icon) == 0)
 
543
                return;
 
544
 
 
545
        if (chooser->priv->icon)
 
546
                g_free (chooser->priv->icon);
 
547
        chooser->priv->icon = g_strdup (icon);
 
548
 
 
549
        _panel_icon_chooser_update (chooser);
 
550
 
 
551
        g_object_notify (G_OBJECT (chooser), "icon");
 
552
 
 
553
        g_signal_emit (G_OBJECT (chooser),
 
554
                       panel_icon_chooser_signals[CHANGED], 0, icon);
 
555
}