~ubuntu-branches/ubuntu/breezy/control-center/breezy

« back to all changes in this revision

Viewing changes to control-center/capplet-dir.c

  • Committer: Bazaar Package Importer
  • Author(s): Josselin Mouette
  • Date: 2005-03-17 22:28:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050317222832-r2cw3974bm9qjrva
Tags: upstream-2.8.2
ImportĀ upstreamĀ versionĀ 2.8.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vim: set sw=8: -*- mode: c; style: linux -*- */
 
2
 
 
3
/* capplet-dir.c
 
4
 * Copyright (C) 2000, 2001 Ximian, Inc.
 
5
 * Copyright (C) 1998 Red Hat Software, Inc.
 
6
 *
 
7
 * Written by Bradford Hovinen <hovinen@ximian.com>,
 
8
 *            Jonathan Blandford <jrb@redhat.com>
 
9
 *
 
10
 * This program is free software; you can redistribute it and/or modify
 
11
 * it under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation; either version 2, or (at your option)
 
13
 * any later version.
 
14
 *
 
15
 * This program is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 * GNU General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU General Public License
 
21
 * along with this program; if not, write to the Free Software
 
22
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
23
 * 02111-1307, USA.
 
24
 */
 
25
 
 
26
#include <config.h>
 
27
 
 
28
#include <string.h>
 
29
#include <glib.h>
 
30
 
 
31
#include <sys/stat.h>
 
32
#include <sys/types.h>
 
33
#include <dirent.h>
 
34
#include <errno.h>
 
35
 
 
36
#include "capplet-dir.h"
 
37
#include "capplet-dir-view.h"
 
38
 
 
39
static void capplet_activate     (Capplet *capplet);
 
40
static void capplet_dir_activate (CappletDir *capplet_dir,
 
41
                                  CappletDirView *launcher);
 
42
 
 
43
static void capplet_shutdown     (Capplet *capplet);
 
44
static void capplet_dir_shutdown (CappletDir *capplet_dir);
 
45
 
 
46
static GSList *read_entries (CappletDir *dir);
 
47
 
 
48
#ifdef USE_ROOT_MANAGER
 
49
static void start_capplet_through_root_manager (GnomeDesktopItem *gde);
 
50
#endif
 
51
 
 
52
CappletDirView *(*get_view_cb) (CappletDir *dir, CappletDirView *launcher);
 
53
 
 
54
/* nice global table for capplet lookup */
 
55
GHashTable *capplet_hash = NULL;
 
56
 
 
57
/********************************************************************
 
58
 *
 
59
 * Stolen from nautilus to keep control center and nautilus in sync
 
60
 */
 
61
static gboolean
 
62
eel_str_has_suffix (const char *haystack, const char *needle)
 
63
{
 
64
        const char *h, *n;
 
65
 
 
66
        if (needle == NULL) {
 
67
                return TRUE;
 
68
        }
 
69
        if (haystack == NULL) {
 
70
                return needle[0] == '\0';
 
71
        }
 
72
                
 
73
        /* Eat one character at a time. */
 
74
        h = haystack + strlen(haystack);
 
75
        n = needle + strlen(needle);
 
76
        do {
 
77
                if (n == needle) {
 
78
                        return TRUE;
 
79
                }
 
80
                if (h == haystack) {
 
81
                        return FALSE;
 
82
                }
 
83
        } while (*--h == *--n);
 
84
        return FALSE;
 
85
}
 
86
static char *   
 
87
eel_str_strip_trailing_str (const char *source, const char *remove_this)
 
88
{
 
89
        const char *end;
 
90
        if (source == NULL) {
 
91
                return NULL;
 
92
        }
 
93
        if (remove_this == NULL) {
 
94
                return g_strdup (source);
 
95
        }
 
96
        end = source + strlen (source);
 
97
        if (strcmp (end - strlen (remove_this), remove_this) != 0) {
 
98
                return g_strdup (source);
 
99
        }
 
100
        else {
 
101
                return g_strndup (source, strlen (source) - strlen(remove_this));
 
102
        }
 
103
        
 
104
}
 
105
static char *
 
106
nautilus_remove_icon_file_name_suffix (const char *icon_name)
 
107
{
 
108
        guint i;
 
109
        const char *suffix;
 
110
        static const char *icon_file_name_suffixes[] = { ".svg", ".svgz", ".png", ".jpg", ".xpm" };
 
111
 
 
112
        for (i = 0; i < G_N_ELEMENTS (icon_file_name_suffixes); i++) {
 
113
                suffix = icon_file_name_suffixes[i];
 
114
                if (eel_str_has_suffix (icon_name, suffix)) {
 
115
                        return eel_str_strip_trailing_str (icon_name, suffix);
 
116
                }
 
117
        }
 
118
        return g_strdup (icon_name);
 
119
}
 
120
/********************************************************************/
 
121
 
 
122
static GdkPixbuf * 
 
123
find_icon (GnomeDesktopItem *dentry) 
 
124
{
 
125
        GdkPixbuf *res;
 
126
        char const *icon;
 
127
        GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
 
128
 
 
129
        icon = gnome_desktop_item_get_string (dentry, GNOME_DESKTOP_ITEM_ICON);
 
130
 
 
131
        if (icon == NULL || icon[0] == 0)
 
132
                icon = "gnome-settings";
 
133
        else if (g_path_is_absolute (icon))
 
134
                res = gdk_pixbuf_new_from_file (icon, NULL);
 
135
        else  {
 
136
                char *no_suffix = nautilus_remove_icon_file_name_suffix (icon);
 
137
                res = gtk_icon_theme_load_icon (icon_theme, no_suffix, 48, 0, NULL);
 
138
                g_free (no_suffix);
 
139
                if (res == NULL) {
 
140
                        char *path = g_build_filename (GNOMECC_ICONS_DIR, icon, NULL);
 
141
                        res = gdk_pixbuf_new_from_file (path, NULL);
 
142
                        g_free (path);
 
143
                }
 
144
        }
 
145
        if (res == NULL)
 
146
                res = gtk_icon_theme_load_icon (icon_theme, "gnome-unknown", 48, 0, NULL);
 
147
        if (res == NULL)
 
148
                res = gtk_icon_theme_load_icon (icon_theme, "gtk-missing-image", 48, 0, NULL);
 
149
        return res;
 
150
}
 
151
 
 
152
CappletDirEntry *
 
153
capplet_new (CappletDir *dir, gchar *desktop_path) 
 
154
{
 
155
        Capplet *capplet;
 
156
        CappletDirEntry *entry;
 
157
        GnomeDesktopItem *dentry;
 
158
        gchar *path, **vec;
 
159
        const gchar *execstr;
 
160
 
 
161
        g_return_val_if_fail (desktop_path != NULL, NULL);
 
162
 
 
163
        entry = g_hash_table_lookup (capplet_hash, desktop_path);
 
164
        if (entry) {
 
165
                return entry;
 
166
        }
 
167
 
 
168
        dentry = gnome_desktop_item_new_from_uri (desktop_path,
 
169
                                                  GNOME_DESKTOP_ITEM_TYPE_NULL,
 
170
                                                  NULL);
 
171
        if (dentry == NULL)
 
172
                return NULL;
 
173
 
 
174
        execstr = gnome_desktop_item_get_string (dentry,
 
175
                        GNOME_DESKTOP_ITEM_EXEC);
 
176
        /* Perhaps use poptParseArgvString here */
 
177
        vec = g_strsplit (execstr, " ", 0);
 
178
        if (!(execstr && execstr[0]) || !(vec && (path = g_find_program_in_path (vec[0]))))
 
179
        {
 
180
                g_strfreev (vec);
 
181
                gnome_desktop_item_unref (dentry);
 
182
                return NULL;
 
183
        }
 
184
        g_free (path);
 
185
 
 
186
        capplet = g_new0 (Capplet, 1);
 
187
        capplet->launching = FALSE;
 
188
 
 
189
        entry = CAPPLET_DIR_ENTRY (capplet);
 
190
 
 
191
        entry->type = TYPE_CAPPLET;
 
192
        entry->entry = dentry;
 
193
 
 
194
        entry->label = g_strdup (gnome_desktop_item_get_localestring (dentry,
 
195
                        GNOME_DESKTOP_ITEM_NAME));
 
196
        entry->icon = find_icon (dentry);
 
197
        entry->uri = gnome_vfs_uri_new (desktop_path);
 
198
        entry->exec = vec;
 
199
        entry->dir = dir;
 
200
 
 
201
        g_hash_table_insert (capplet_hash, g_strdup (desktop_path), entry);
 
202
 
 
203
        return entry;
 
204
}
 
205
 
 
206
CappletDirEntry *
 
207
capplet_dir_new (CappletDir *dir, gchar *dir_path)
 
208
{
 
209
        CappletDir *capplet_dir;
 
210
        CappletDirEntry *entry;
 
211
        GnomeVFSURI *desktop_uri;
 
212
        GnomeVFSURI *dir_uri;
 
213
        char *desktop_uri_string;
 
214
 
 
215
        g_return_val_if_fail (dir_path != NULL, NULL);
 
216
 
 
217
        dir_uri = gnome_vfs_uri_new (dir_path);
 
218
 
 
219
        entry = g_hash_table_lookup (capplet_hash, dir_path);
 
220
        if (entry) {
 
221
                return entry;
 
222
        }
 
223
 
 
224
        desktop_uri = gnome_vfs_uri_append_file_name (dir_uri, ".directory");
 
225
        desktop_uri_string = gnome_vfs_uri_to_string (desktop_uri, GNOME_VFS_URI_HIDE_NONE);
 
226
 
 
227
        capplet_dir = g_new0 (CappletDir, 1);
 
228
        entry = CAPPLET_DIR_ENTRY (capplet_dir);
 
229
 
 
230
        entry->type = TYPE_CAPPLET_DIR;
 
231
        entry->entry = gnome_desktop_item_new_from_uri (desktop_uri_string,
 
232
                        GNOME_DESKTOP_ITEM_TYPE_NULL,
 
233
                        NULL);
 
234
        entry->dir = dir;
 
235
        entry->uri = dir_uri;
 
236
 
 
237
        gnome_vfs_uri_unref (desktop_uri);
 
238
        g_free (desktop_uri_string);
 
239
 
 
240
        if (entry->entry) {
 
241
                entry->label = g_strdup (gnome_desktop_item_get_localestring (
 
242
                                entry->entry,
 
243
                                GNOME_DESKTOP_ITEM_NAME));
 
244
                entry->icon = find_icon (entry->entry);
 
245
        } else {
 
246
                /* If the .directory file could not be found or read, abort */
 
247
                g_free (capplet_dir);
 
248
                return NULL;
 
249
        }
 
250
 
 
251
        entry->dir = dir;
 
252
 
 
253
        g_hash_table_insert (capplet_hash, g_strdup (dir_path), entry);
 
254
 
 
255
        capplet_dir_load (CAPPLET_DIR (entry));
 
256
 
 
257
        return entry;
 
258
}
 
259
 
 
260
CappletDirEntry *
 
261
capplet_lookup (const char *path)
 
262
{
 
263
        return g_hash_table_lookup (capplet_hash, path);
 
264
}
 
265
 
 
266
void 
 
267
capplet_dir_entry_destroy (CappletDirEntry *entry)
 
268
{
 
269
        if (entry->type == TYPE_CAPPLET) {
 
270
                capplet_shutdown (CAPPLET (entry));
 
271
        } else {
 
272
                capplet_dir_shutdown (CAPPLET_DIR (entry));
 
273
        }
 
274
 
 
275
        g_free (entry->label);
 
276
        g_object_unref (entry->icon);
 
277
        gnome_vfs_uri_unref (entry->uri);
 
278
        g_strfreev (entry->exec);
 
279
        gnome_desktop_item_unref (entry->entry);
 
280
        g_free (entry);
 
281
}
 
282
 
 
283
void 
 
284
capplet_dir_entry_activate (CappletDirEntry *entry, 
 
285
                            CappletDirView *launcher)
 
286
{
 
287
        g_return_if_fail (entry != NULL);
 
288
 
 
289
        if (entry->type == TYPE_CAPPLET)
 
290
                capplet_activate (CAPPLET (entry));
 
291
        else if (entry->type == TYPE_CAPPLET_DIR)
 
292
                capplet_dir_activate (CAPPLET_DIR (entry), launcher);
 
293
        else
 
294
                g_assert_not_reached ();
 
295
}
 
296
 
 
297
void 
 
298
capplet_dir_entry_shutdown (CappletDirEntry *entry)
 
299
{
 
300
        if (entry->type == TYPE_CAPPLET)
 
301
                capplet_shutdown (CAPPLET (entry));
 
302
        else if (entry->type == TYPE_CAPPLET_DIR)
 
303
                capplet_dir_shutdown (CAPPLET_DIR (entry));
 
304
        else
 
305
                g_assert_not_reached ();
 
306
}
 
307
 
 
308
static gint
 
309
capplet_reset_cb (Capplet *capplet) 
 
310
{
 
311
        capplet->launching = FALSE;
 
312
        return FALSE;
 
313
}
 
314
 
 
315
static void
 
316
capplet_activate (Capplet *capplet) 
 
317
{
 
318
        CappletDirEntry *entry;
 
319
 
 
320
        entry = CAPPLET_DIR_ENTRY (capplet);
 
321
 
 
322
        if (capplet->launching) {
 
323
                return;
 
324
        } else {
 
325
                capplet->launching = TRUE;
 
326
                gtk_timeout_add (1000, (GtkFunction) capplet_reset_cb, capplet);
 
327
                gnome_desktop_item_launch (entry->entry, NULL, 0, NULL);
 
328
        }
 
329
}
 
330
 
 
331
void
 
332
capplet_dir_load (CappletDir *capplet_dir) 
 
333
{
 
334
        if (capplet_dir->entries) return;
 
335
        capplet_dir->entries = read_entries (capplet_dir);
 
336
}
 
337
 
 
338
static void
 
339
capplet_dir_activate (CappletDir *capplet_dir, CappletDirView *launcher) 
 
340
{
 
341
        capplet_dir_load (capplet_dir);
 
342
        capplet_dir->view = get_view_cb (capplet_dir, launcher);
 
343
 
 
344
        capplet_dir_view_load_dir (capplet_dir->view, capplet_dir);
 
345
        capplet_dir_view_show (capplet_dir->view);
 
346
}
 
347
 
 
348
static void
 
349
capplet_shutdown (Capplet *capplet) 
 
350
{
 
351
        /* Can't do much here ... :-( */
 
352
}
 
353
 
 
354
static void
 
355
cde_destroy (CappletDirEntry *e, gpointer null)
 
356
{
 
357
        capplet_dir_entry_destroy (e);
 
358
}
 
359
 
 
360
static void
 
361
capplet_dir_shutdown (CappletDir *capplet_dir) 
 
362
{
 
363
        if (capplet_dir->view)
 
364
                g_object_unref (G_OBJECT (capplet_dir->view));
 
365
 
 
366
        g_slist_foreach (capplet_dir->entries, (GFunc) cde_destroy, NULL);
 
367
 
 
368
        g_slist_free (capplet_dir->entries);
 
369
}
 
370
 
 
371
static gint 
 
372
node_compare (gconstpointer a, gconstpointer b) 
 
373
{
 
374
        return strcmp (CAPPLET_DIR_ENTRY (a)->label, 
 
375
                       CAPPLET_DIR_ENTRY (b)->label);
 
376
}
 
377
 
 
378
/* Adapted from the original control center... */
 
379
 
 
380
static GSList *
 
381
read_entries (CappletDir *dir) 
 
382
{
 
383
        GSList *list = NULL;
 
384
        CappletDirEntry *entry;
 
385
        gchar *fullpath, *test;
 
386
        GnomeVFSURI *fulluri;
 
387
        GnomeVFSDirectoryHandle *parent_dir;
 
388
        GnomeVFSResult result;
 
389
 
 
390
        GnomeVFSFileInfo *child = gnome_vfs_file_info_new ();
 
391
 
 
392
        result = gnome_vfs_directory_open_from_uri (&parent_dir, CAPPLET_DIR_ENTRY (dir)->uri,
 
393
                                                    GNOME_VFS_FILE_INFO_DEFAULT);
 
394
 
 
395
        if (result != GNOME_VFS_OK) {
 
396
                gnome_vfs_file_info_unref (child);
 
397
                return NULL;
 
398
        }
 
399
                
 
400
        while ( gnome_vfs_directory_read_next (parent_dir, child) == GNOME_VFS_OK ) {
 
401
                if (child->name[0] == '.')
 
402
                        continue;
 
403
                 
 
404
                fulluri = gnome_vfs_uri_append_path (CAPPLET_DIR_ENTRY (dir)->uri, child->name);
 
405
                fullpath = gnome_vfs_uri_to_string (fulluri, GNOME_VFS_URI_HIDE_NONE);
 
406
 
 
407
                entry = NULL;
 
408
 
 
409
                if (child->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
 
410
                        entry = capplet_dir_new (dir, fullpath);
 
411
                } else {
 
412
                        test = strrchr(child->name, '.');
 
413
 
 
414
                        /* if it's a .desktop file, it's interesting for sure! */
 
415
                        if (test && !strcmp (".desktop", test))
 
416
                                entry = capplet_new (dir, fullpath);
 
417
                }
 
418
 
 
419
                if (entry)
 
420
                        list = g_slist_prepend (list, entry);
 
421
                
 
422
                g_free (fullpath);
 
423
        }
 
424
        
 
425
        gnome_vfs_file_info_unref (child);
 
426
        gnome_vfs_directory_close (parent_dir);
 
427
 
 
428
        list = g_slist_sort (list, node_compare);
 
429
 
 
430
        /* remove FALSE for parent entry */
 
431
        return FALSE && CAPPLET_DIR_ENTRY (dir)->dir 
 
432
                ? g_slist_prepend (list, CAPPLET_DIR_ENTRY (dir)->dir) 
 
433
                : list;
 
434
}
 
435
 
 
436
#ifdef USE_ROOT_MANAGER
 
437
static void
 
438
start_capplet_through_root_manager (GnomeDesktopItem *gde) 
 
439
{
 
440
        static FILE *output = NULL;
 
441
        pid_t pid;
 
442
        char *cmdline;
 
443
        char *oldexec;
 
444
 
 
445
        if (!output) {
 
446
                gint pipe_fd[2];
 
447
                pipe (pipe_fd);
 
448
 
 
449
                pid = fork ();
 
450
 
 
451
                if (pid == (pid_t) -1) {
 
452
                        g_error ("%s", g_strerror (errno));
 
453
                } else if (pid == 0) {
 
454
                        char *arg[2];
 
455
                        int i;
 
456
 
 
457
                        dup2 (pipe_fd[0], STDIN_FILENO);
 
458
      
 
459
                        for (i = 3; i < FOPEN_MAX; i++) close(i);
 
460
 
 
461
                        arg[0] = gnome_is_program_in_path ("root-manager-helper");
 
462
                        arg[1] = NULL;
 
463
                        execv (arg[0], arg);
 
464
                } else {
 
465
                        output = fdopen(pipe_fd[1], "a");
 
466
                }
 
467
 
 
468
                capplet_dir_views_set_authenticated (TRUE);
 
469
        }
 
470
 
 
471
 
 
472
        oldexec = gde->exec[1];
 
473
        gde->exec[1] = g_concat_dir_and_file (GNOME_SBINDIR, oldexec);
 
474
 
 
475
        cmdline = g_strjoinv (" ", gde->exec + 1);
 
476
 
 
477
        g_free (gde->exec[1]);
 
478
        gde->exec[1] = oldexec;
 
479
 
 
480
        fprintf (output, "%s\n", cmdline);
 
481
        fflush (output);
 
482
        g_free (cmdline);
 
483
}
 
484
#endif
 
485
 
 
486
void 
 
487
capplet_dir_init (CappletDirView *(*cb) (CappletDir *, CappletDirView *)) 
 
488
{
 
489
        get_view_cb = cb;
 
490
        capplet_hash = g_hash_table_new (g_str_hash, g_str_equal);
 
491
}
 
492
 
 
493
CappletDir *
 
494
get_root_capplet_dir (void)
 
495
{
 
496
        static CappletDir *root_dir = NULL;
 
497
 
 
498
        if (root_dir == NULL) {
 
499
                CappletDirEntry *entry;
 
500
 
 
501
                entry = capplet_dir_new (NULL, "preferences:///");
 
502
 
 
503
                if (entry)
 
504
                        root_dir = CAPPLET_DIR (entry);
 
505
                if (!root_dir)
 
506
                        g_warning ("Could not find directory of control panels [%s]", "preferences:///");
 
507
        }
 
508
 
 
509
        return root_dir;
 
510
}