~ubuntu-branches/debian/jessie/mate-control-center/jessie

« back to all changes in this revision

Viewing changes to capplets/appearance/theme-installer.c

  • Committer: Package Import Robot
  • Author(s): Mike Gabriel
  • Date: 2014-05-02 23:20:06 UTC
  • Revision ID: package-import@ubuntu.com-20140502232006-9626h14ggaz2hc9h
Tags: upstream-1.8.1+dfsg1
ImportĀ upstreamĀ versionĀ 1.8.1+dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2007 The GNOME Foundation
 
4
 * Written by Thomas Wood <thos@gnome.org>
 
5
 *            Jens Granseuer <jensgr@gmx.net>
 
6
 * All Rights Reserved
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation; either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License along
 
19
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
20
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
21
 */
 
22
 
 
23
#include "appearance.h"
 
24
 
 
25
#include <string.h>
 
26
#include <glib.h>
 
27
#include <glib/gi18n.h>
 
28
#include <gio/gio.h>
 
29
#include <glib/gstdio.h>
 
30
#include <unistd.h>
 
31
 
 
32
#include "capplet-util.h"
 
33
#include "file-transfer-dialog.h"
 
34
#include "theme-installer.h"
 
35
#include "theme-util.h"
 
36
 
 
37
enum {
 
38
        THEME_INVALID,
 
39
        THEME_ICON,
 
40
        THEME_MATE,
 
41
        THEME_GTK,
 
42
        THEME_ENGINE,
 
43
        THEME_MARCO,
 
44
        THEME_CURSOR,
 
45
        THEME_ICON_CURSOR
 
46
};
 
47
 
 
48
enum {
 
49
        TARGZ,
 
50
        TARBZ,
 
51
        DIRECTORY
 
52
};
 
53
 
 
54
static gboolean
 
55
cleanup_tmp_dir (GIOSchedulerJob *job,
 
56
                 GCancellable *cancellable,
 
57
                 const gchar *tmp_dir)
 
58
{
 
59
        GFile *directory;
 
60
 
 
61
        directory = g_file_new_for_path (tmp_dir);
 
62
        capplet_file_delete_recursive (directory, NULL);
 
63
        g_object_unref (directory);
 
64
 
 
65
        return FALSE;
 
66
}
 
67
 
 
68
static int
 
69
file_theme_type (const gchar *dir)
 
70
{
 
71
        gchar *filename = NULL;
 
72
        gboolean exists;
 
73
 
 
74
        if (!dir)
 
75
                return THEME_INVALID;
 
76
 
 
77
        filename = g_build_filename (dir, "index.theme", NULL);
 
78
        exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
 
79
 
 
80
        if (exists) {
 
81
                GPatternSpec *pattern;
 
82
                gchar *file_contents = NULL;
 
83
                gsize file_size;
 
84
                gboolean match;
 
85
 
 
86
                g_file_get_contents (filename, &file_contents, &file_size, NULL);
 
87
                g_free (filename);
 
88
 
 
89
                pattern = g_pattern_spec_new ("*[Icon Theme]*");
 
90
                match = g_pattern_match_string (pattern, file_contents);
 
91
                g_pattern_spec_free (pattern);
 
92
 
 
93
                if (match) {
 
94
                        pattern = g_pattern_spec_new ("*Directories=*");
 
95
                        match = g_pattern_match_string (pattern, file_contents);
 
96
                        g_pattern_spec_free (pattern);
 
97
                        g_free (file_contents);
 
98
 
 
99
                        if (match) {
 
100
                                /* check if we have a cursor, too */
 
101
                                filename = g_build_filename (dir, "cursors", NULL);
 
102
                                exists = g_file_test (filename, G_FILE_TEST_IS_DIR);
 
103
                                g_free (filename);
 
104
 
 
105
                                if (exists)
 
106
                                        return THEME_ICON_CURSOR;
 
107
                                else
 
108
                                        return THEME_ICON;
 
109
                        }
 
110
                        return THEME_CURSOR;
 
111
                }
 
112
 
 
113
                pattern = g_pattern_spec_new ("*[X-GNOME-Metatheme]*");
 
114
                match = g_pattern_match_string (pattern, file_contents);
 
115
                g_pattern_spec_free (pattern);
 
116
                g_free (file_contents);
 
117
 
 
118
                if (match)
 
119
                        return THEME_MATE;
 
120
        } else {
 
121
                g_free (filename);
 
122
        }
 
123
 
 
124
        filename = g_build_filename (dir, "gtk-2.0", "gtkrc", NULL);
 
125
        exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
 
126
        g_free (filename);
 
127
 
 
128
        if (exists)
 
129
                return THEME_GTK;
 
130
 
 
131
        filename = g_build_filename (dir, "metacity-1", "metacity-theme-1.xml", NULL);
 
132
        exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
 
133
        g_free (filename);
 
134
 
 
135
        if (exists)
 
136
                return THEME_MARCO;
 
137
 
 
138
        /* cursor themes don't necessarily have an index.theme */
 
139
        filename = g_build_filename (dir, "cursors", NULL);
 
140
        exists = g_file_test (filename, G_FILE_TEST_IS_DIR);
 
141
        g_free (filename);
 
142
 
 
143
        if (exists)
 
144
                return THEME_CURSOR;
 
145
 
 
146
        filename = g_build_filename (dir, "configure", NULL);
 
147
        exists = g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE);
 
148
        g_free (filename);
 
149
 
 
150
        if (exists)
 
151
                return THEME_ENGINE;
 
152
 
 
153
        return THEME_INVALID;
 
154
}
 
155
 
 
156
static void
 
157
transfer_cancel_cb (GtkWidget *dialog,
 
158
                    gchar *path)
 
159
{
 
160
        GFile *todelete;
 
161
 
 
162
        todelete = g_file_new_for_path (path);
 
163
        capplet_file_delete_recursive (todelete, NULL);
 
164
 
 
165
        g_object_unref (todelete);
 
166
        g_free (path);
 
167
        gtk_widget_destroy (dialog);
 
168
}
 
169
 
 
170
static void
 
171
missing_utility_message_dialog (GtkWindow *parent,
 
172
                                const gchar *utility)
 
173
{
 
174
        GtkWidget *dialog = gtk_message_dialog_new (parent,
 
175
                                                    GTK_DIALOG_MODAL,
 
176
                                                    GTK_MESSAGE_ERROR,
 
177
                                                    GTK_BUTTONS_OK,
 
178
                                                    _("Cannot install theme"));
 
179
        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
 
180
                                                  _("The %s utility is not installed."), utility);
 
181
        gtk_dialog_run (GTK_DIALOG (dialog));
 
182
        gtk_widget_destroy (dialog);
 
183
}
 
184
 
 
185
/* this works around problems when doing fork/exec in a threaded app
 
186
 * with some locks being held/waited on in different threads.
 
187
 *
 
188
 * we do the idle callback so that the async xfer has finished and
 
189
 * cleaned up its vfs job.  otherwise it seems the slave thread gets
 
190
 * woken up and it removes itself from the job queue before it is
 
191
 * supposed to.  very strange.
 
192
 *
 
193
 * see bugzilla.gnome.org #86141 for details
 
194
 */
 
195
static gboolean
 
196
process_local_theme_tgz_tbz (GtkWindow *parent,
 
197
                             const gchar *util,
 
198
                             const gchar *tmp_dir,
 
199
                             const gchar *archive)
 
200
{
 
201
        gboolean rc;
 
202
        int status;
 
203
        gchar *command, *filename, *zip, *tar;
 
204
 
 
205
        if (!(zip = g_find_program_in_path (util))) {
 
206
                missing_utility_message_dialog (parent, util);
 
207
                return FALSE;
 
208
        }
 
209
        if (!(tar = g_find_program_in_path ("tar"))) {
 
210
                missing_utility_message_dialog (parent, "tar");
 
211
                g_free (zip);
 
212
                return FALSE;
 
213
        }
 
214
 
 
215
        filename = g_shell_quote (archive);
 
216
 
 
217
        /* this should be something more clever and nonblocking */
 
218
        command = g_strdup_printf ("sh -c 'cd \"%s\"; %s -d -c < \"%s\" | %s xf - '",
 
219
                                   tmp_dir, zip, filename, tar);
 
220
        g_free (zip);
 
221
        g_free (tar);
 
222
        g_free (filename);
 
223
 
 
224
        rc = (g_spawn_command_line_sync (command, NULL, NULL, &status, NULL) && status == 0);
 
225
        g_free (command);
 
226
 
 
227
        if (rc == FALSE) {
 
228
                GtkWidget *dialog;
 
229
 
 
230
                dialog = gtk_message_dialog_new (parent,
 
231
                                                 GTK_DIALOG_MODAL,
 
232
                                                 GTK_MESSAGE_ERROR,
 
233
                                                 GTK_BUTTONS_OK,
 
234
                                                 _("Cannot install theme"));
 
235
                gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
 
236
                                                          _("There was a problem while extracting the theme."));
 
237
                gtk_dialog_run (GTK_DIALOG (dialog));
 
238
                gtk_widget_destroy (dialog);
 
239
        }
 
240
 
 
241
        return rc;
 
242
}
 
243
 
 
244
static gboolean
 
245
process_local_theme_archive (GtkWindow *parent,
 
246
                             gint filetype,
 
247
                             const gchar *tmp_dir,
 
248
                             const gchar *archive)
 
249
{
 
250
        if (filetype == TARGZ)
 
251
                return process_local_theme_tgz_tbz (parent, "gzip", tmp_dir, archive);
 
252
        else if (filetype == TARBZ)
 
253
                return process_local_theme_tgz_tbz (parent, "bzip2", tmp_dir, archive);
 
254
        else
 
255
                return FALSE;
 
256
}
 
257
 
 
258
static void
 
259
invalid_theme_dialog (GtkWindow *parent,
 
260
                      const gchar *filename,
 
261
                      gboolean maybe_theme_engine)
 
262
{
 
263
        GtkWidget *dialog;
 
264
        const gchar *primary = _("There was an error installing the selected file");
 
265
        const gchar *secondary = _("\"%s\" does not appear to be a valid theme.");
 
266
        const gchar *engine = _("\"%s\" does not appear to be a valid theme. It may be a theme engine which you need to compile.");
 
267
 
 
268
        dialog = gtk_message_dialog_new (parent,
 
269
                                         GTK_DIALOG_MODAL,
 
270
                                         GTK_MESSAGE_ERROR,
 
271
                                         GTK_BUTTONS_OK,
 
272
                                         "%s", primary);
 
273
        if (maybe_theme_engine)
 
274
                gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), engine, filename);
 
275
        else
 
276
                gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), secondary, filename);
 
277
        gtk_dialog_run (GTK_DIALOG (dialog));
 
278
        gtk_widget_destroy (dialog);
 
279
}
 
280
 
 
281
static gboolean
 
282
mate_theme_install_real (GtkWindow *parent,
 
283
                          gint filetype,
 
284
                          const gchar *tmp_dir,
 
285
                          const gchar *theme_name,
 
286
                          gboolean ask_user)
 
287
{
 
288
        gboolean success = TRUE;
 
289
        GtkWidget *dialog, *apply_button;
 
290
        GFile *theme_source_dir, *theme_dest_dir;
 
291
        GError *error = NULL;
 
292
        gint theme_type;
 
293
        gchar *target_dir = NULL;
 
294
 
 
295
        /* What type of theme is it? */
 
296
        theme_type = file_theme_type (tmp_dir);
 
297
        switch (theme_type) {
 
298
        case THEME_ICON:
 
299
        case THEME_CURSOR:
 
300
        case THEME_ICON_CURSOR:
 
301
                target_dir = g_build_path (G_DIR_SEPARATOR_S,
 
302
                                           g_get_home_dir (), ".icons",
 
303
                                           theme_name, NULL);
 
304
                break;
 
305
        case THEME_MATE:
 
306
                target_dir = g_build_path (G_DIR_SEPARATOR_S,
 
307
                                           g_get_home_dir (), ".themes",
 
308
                                           theme_name, NULL);
 
309
                break;
 
310
        case THEME_MARCO:
 
311
        case THEME_GTK:
 
312
                target_dir = g_build_path (G_DIR_SEPARATOR_S,
 
313
                                           g_get_home_dir (), ".themes",
 
314
                                           theme_name, NULL);
 
315
                break;
 
316
        case THEME_ENGINE:
 
317
                invalid_theme_dialog (parent, theme_name, TRUE);
 
318
                return FALSE;
 
319
        default:
 
320
                invalid_theme_dialog (parent, theme_name, FALSE);
 
321
                return FALSE;
 
322
        }
 
323
 
 
324
        /* see if there is an icon theme lurking in this package */
 
325
        if (theme_type == THEME_MATE) {
 
326
                gchar *path;
 
327
 
 
328
                path = g_build_path (G_DIR_SEPARATOR_S,
 
329
                                     tmp_dir, "icons", NULL);
 
330
                if (g_file_test (path, G_FILE_TEST_IS_DIR)
 
331
                    && (file_theme_type (path) == THEME_ICON)) {
 
332
                        gchar *new_path, *update_icon_cache;
 
333
                        GFile *new_file;
 
334
                        GFile *src_file;
 
335
 
 
336
                        src_file = g_file_new_for_path (path);
 
337
                        new_path = g_build_path (G_DIR_SEPARATOR_S,
 
338
                                                 g_get_home_dir (),
 
339
                                                 ".icons",
 
340
                                                 theme_name, NULL);
 
341
                        new_file = g_file_new_for_path (new_path);
 
342
 
 
343
                        if (!g_file_move (src_file, new_file, G_FILE_COPY_NONE,
 
344
                                          NULL, NULL, NULL, &error)) {
 
345
                                g_warning ("Error while moving from `%s' to `%s': %s",
 
346
                                           path, new_path, error->message);
 
347
                                g_error_free (error);
 
348
                                error = NULL;
 
349
                        }
 
350
                        g_object_unref (new_file);
 
351
                        g_object_unref (src_file);
 
352
 
 
353
                        /* update icon cache - shouldn't really matter if this fails */
 
354
                        update_icon_cache = g_strdup_printf ("gtk-update-icon-cache %s", new_path);
 
355
                        g_spawn_command_line_async (update_icon_cache, NULL);
 
356
                        g_free (update_icon_cache);
 
357
 
 
358
                        g_free (new_path);
 
359
                }
 
360
                g_free (path);
 
361
        }
 
362
 
 
363
        /* Move the dir to the target dir */
 
364
        theme_source_dir = g_file_new_for_path (tmp_dir);
 
365
        theme_dest_dir = g_file_new_for_path (target_dir);
 
366
 
 
367
        if (!g_file_move (theme_source_dir, theme_dest_dir,
 
368
                          G_FILE_COPY_OVERWRITE, NULL, NULL,
 
369
                          NULL, &error)) {
 
370
                gchar *str;
 
371
 
 
372
                str = g_strdup_printf (_("Installation for theme \"%s\" failed."), theme_name);
 
373
                dialog = gtk_message_dialog_new (parent,
 
374
                                                 GTK_DIALOG_MODAL,
 
375
                                                 GTK_MESSAGE_ERROR,
 
376
                                                 GTK_BUTTONS_OK,
 
377
                                                 "%s",
 
378
                                                 str);
 
379
                gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
 
380
                                                          "%s", error->message);
 
381
 
 
382
                g_free (str);
 
383
                g_error_free (error);
 
384
                error = NULL;
 
385
 
 
386
                gtk_dialog_run (GTK_DIALOG (dialog));
 
387
                gtk_widget_destroy (dialog);
 
388
                success = FALSE;
 
389
        } else {
 
390
                if (theme_type == THEME_ICON || theme_type == THEME_ICON_CURSOR)
 
391
                {
 
392
                        gchar *update_icon_cache;
 
393
 
 
394
                        /* update icon cache - shouldn't really matter if this fails */
 
395
                        update_icon_cache = g_strdup_printf ("gtk-update-icon-cache %s", target_dir);
 
396
                        g_spawn_command_line_async (update_icon_cache, NULL);
 
397
 
 
398
                        g_free (update_icon_cache);
 
399
                }
 
400
 
 
401
                if (ask_user) {
 
402
                        /* Ask to apply theme (if we can) */
 
403
                        if (theme_type == THEME_GTK
 
404
                            || theme_type == THEME_MARCO
 
405
                            || theme_type == THEME_ICON
 
406
                            || theme_type == THEME_CURSOR
 
407
                            || theme_type == THEME_ICON_CURSOR) {
 
408
                                /* TODO: currently cannot apply "mate themes" */
 
409
                                gchar *str;
 
410
 
 
411
                                str = g_strdup_printf (_("The theme \"%s\" has been installed."), theme_name);
 
412
                                dialog = gtk_message_dialog_new_with_markup (parent,
 
413
                                                                             GTK_DIALOG_MODAL,
 
414
                                                                             GTK_MESSAGE_INFO,
 
415
                                                                             GTK_BUTTONS_NONE,
 
416
                                                                             "<span weight=\"bold\" size=\"larger\">%s</span>",
 
417
                                                                             str);
 
418
                                g_free (str);
 
419
 
 
420
                                gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
 
421
                                                                          _("Would you like to apply it now, or keep your current theme?"));
 
422
 
 
423
                                gtk_dialog_add_button (GTK_DIALOG (dialog),
 
424
                                                       _("Keep Current Theme"),
 
425
                                                       GTK_RESPONSE_CLOSE);
 
426
 
 
427
                                apply_button = gtk_button_new_with_label (_("Apply New Theme"));
 
428
                                gtk_button_set_image (GTK_BUTTON (apply_button),
 
429
                                                      gtk_image_new_from_stock (GTK_STOCK_APPLY,
 
430
                                                                                GTK_ICON_SIZE_BUTTON));
 
431
                                gtk_dialog_add_action_widget (GTK_DIALOG (dialog), apply_button, GTK_RESPONSE_APPLY);
 
432
                                gtk_widget_set_can_default (apply_button, TRUE);
 
433
                                gtk_widget_show (apply_button);
 
434
 
 
435
                                gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_APPLY);
 
436
 
 
437
                                if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_APPLY) {
 
438
                                        /* apply theme here! */
 
439
                                        GSettings *settings;
 
440
 
 
441
                                        switch (theme_type) {
 
442
                                        case THEME_GTK:
 
443
                                                settings = g_settings_new (INTERFACE_SCHEMA);
 
444
                                                g_settings_set_string (settings, GTK_THEME_KEY, theme_name);
 
445
                                                g_object_unref (settings);
 
446
                                                break;
 
447
                                        case THEME_MARCO:
 
448
                                                settings = g_settings_new (MARCO_SCHEMA);
 
449
                                                g_settings_set_string (settings, MARCO_THEME_KEY, theme_name);
 
450
                                                g_object_unref (settings);
 
451
                                                break;
 
452
                                        case THEME_ICON:
 
453
                                                settings = g_settings_new (INTERFACE_SCHEMA);
 
454
                                                g_settings_set_string (settings, ICON_THEME_KEY, theme_name);
 
455
                                                g_object_unref (settings);
 
456
                                                break;
 
457
                                        case THEME_CURSOR:
 
458
                                                settings = g_settings_new (MOUSE_SCHEMA);
 
459
                                                g_settings_set_string (settings, CURSOR_THEME_KEY, theme_name);
 
460
                                                g_object_unref (settings);
 
461
                                                break;
 
462
                                        case THEME_ICON_CURSOR:
 
463
                                                settings = g_settings_new (INTERFACE_SCHEMA);
 
464
                                                g_settings_set_string (settings, ICON_THEME_KEY, theme_name);
 
465
                                                g_object_unref (settings);
 
466
                                                settings = g_settings_new (MOUSE_SCHEMA);
 
467
                                                g_settings_set_string (settings, CURSOR_THEME_KEY, theme_name);
 
468
                                                g_object_unref (settings);
 
469
                                                break;
 
470
                                        default:
 
471
                                                break;
 
472
                                        }
 
473
                                }
 
474
                        } else {
 
475
                                dialog = gtk_message_dialog_new (parent,
 
476
                                                                 GTK_DIALOG_MODAL,
 
477
                                                                 GTK_MESSAGE_INFO,
 
478
                                                                 GTK_BUTTONS_OK,
 
479
                                                                 _("MATE Theme %s correctly installed"),
 
480
                                                                 theme_name);
 
481
                                gtk_dialog_run (GTK_DIALOG (dialog));
 
482
                        }
 
483
                        gtk_widget_destroy (dialog);
 
484
                }
 
485
        }
 
486
 
 
487
        g_free (target_dir);
 
488
 
 
489
        return success;
 
490
}
 
491
 
 
492
static void
 
493
process_local_theme (GtkWindow  *parent,
 
494
                     const char *path)
 
495
{
 
496
        GtkWidget *dialog;
 
497
        gint filetype;
 
498
 
 
499
        if (g_str_has_suffix (path, ".tar.gz")
 
500
            || g_str_has_suffix (path, ".tgz")
 
501
            || g_str_has_suffix(path, ".gtp")) {
 
502
                filetype = TARGZ;
 
503
        } else if (g_str_has_suffix (path, ".tar.bz2")) {
 
504
                filetype = TARBZ;
 
505
        } else if (g_file_test (path, G_FILE_TEST_IS_DIR)) {
 
506
                filetype = DIRECTORY;
 
507
        } else {
 
508
                gchar *filename;
 
509
                filename = g_path_get_basename (path);
 
510
                invalid_theme_dialog (parent, filename, FALSE);
 
511
                g_free (filename);
 
512
                return;
 
513
        }
 
514
 
 
515
        if (filetype == DIRECTORY) {
 
516
                gchar *name = g_path_get_basename (path);
 
517
                mate_theme_install_real (parent,
 
518
                                          filetype,
 
519
                                          path,
 
520
                                          name,
 
521
                                          TRUE);
 
522
                g_free (name);
 
523
        } else {
 
524
                /* Create a temp directory and uncompress file there */
 
525
                GDir *dir;
 
526
                const gchar *name;
 
527
                gchar *tmp_dir;
 
528
                gboolean ok;
 
529
                gint n_themes;
 
530
                GFile *todelete;
 
531
 
 
532
                tmp_dir = g_strdup_printf ("%s/.themes/.theme-%u",
 
533
                                           g_get_home_dir (),
 
534
                                           g_random_int ());
 
535
 
 
536
                if ((g_mkdir (tmp_dir, 0700)) != 0) {
 
537
                        dialog = gtk_message_dialog_new (parent,
 
538
                                                         GTK_DIALOG_MODAL,
 
539
                                                         GTK_MESSAGE_ERROR,
 
540
                                                         GTK_BUTTONS_OK,
 
541
                                                         _("Failed to create temporary directory"));
 
542
                        gtk_dialog_run (GTK_DIALOG (dialog));
 
543
                        gtk_widget_destroy (dialog);
 
544
                        g_free (tmp_dir);
 
545
                        return;
 
546
                }
 
547
 
 
548
                if (!process_local_theme_archive (parent, filetype, tmp_dir, path)
 
549
                    || ((dir = g_dir_open (tmp_dir, 0, NULL)) == NULL)) {
 
550
                        g_io_scheduler_push_job ((GIOSchedulerJobFunc) cleanup_tmp_dir,
 
551
                                                 g_strdup (tmp_dir),
 
552
                                                 g_free,
 
553
                                                 G_PRIORITY_DEFAULT,
 
554
                                                 NULL);
 
555
                        g_free (tmp_dir);
 
556
                        return;
 
557
                }
 
558
 
 
559
                todelete = g_file_new_for_path (path);
 
560
                g_file_delete (todelete, NULL, NULL);
 
561
                g_object_unref (todelete);
 
562
 
 
563
                /* See whether we have multiple themes to install. If so,
 
564
                 * we won't ask the user whether to apply the new theme
 
565
                 * after installation. */
 
566
                n_themes = 0;
 
567
                for (name = g_dir_read_name (dir);
 
568
                     name && n_themes <= 1;
 
569
                     name = g_dir_read_name (dir)) {
 
570
                        gchar *theme_dir;
 
571
 
 
572
                        theme_dir = g_build_filename (tmp_dir, name, NULL);
 
573
 
 
574
                        if (g_file_test (theme_dir, G_FILE_TEST_IS_DIR))
 
575
                                ++n_themes;
 
576
 
 
577
                        g_free (theme_dir);
 
578
                }
 
579
                g_dir_rewind (dir);
 
580
 
 
581
                ok = TRUE;
 
582
                for (name = g_dir_read_name (dir); name && ok;
 
583
                     name = g_dir_read_name (dir)) {
 
584
                        gchar *theme_dir;
 
585
 
 
586
                        theme_dir = g_build_filename (tmp_dir, name, NULL);
 
587
 
 
588
                        if (g_file_test (theme_dir, G_FILE_TEST_IS_DIR))
 
589
                                ok = mate_theme_install_real (parent,
 
590
                                                               filetype,
 
591
                                                               theme_dir,
 
592
                                                               name,
 
593
                                                               n_themes == 1);
 
594
 
 
595
                        g_free (theme_dir);
 
596
                }
 
597
                g_dir_close (dir);
 
598
 
 
599
                if (ok && n_themes > 1) {
 
600
                        dialog = gtk_message_dialog_new (parent,
 
601
                                                         GTK_DIALOG_MODAL,
 
602
                                                         GTK_MESSAGE_INFO,
 
603
                                                         GTK_BUTTONS_OK,
 
604
                                                         _("New themes have been successfully installed."));
 
605
                        gtk_dialog_run (GTK_DIALOG (dialog));
 
606
                        gtk_widget_destroy (dialog);
 
607
                }
 
608
                g_io_scheduler_push_job ((GIOSchedulerJobFunc) cleanup_tmp_dir,
 
609
                                         tmp_dir, g_free,
 
610
                                         G_PRIORITY_DEFAULT, NULL);
 
611
        }
 
612
}
 
613
 
 
614
typedef struct
 
615
{
 
616
        GtkWindow *parent;
 
617
        char      *path;
 
618
} TransferData;
 
619
 
 
620
static void
 
621
transfer_done_cb (GtkWidget *dialog,
 
622
                  TransferData *tdata)
 
623
{
 
624
        gdk_threads_enter ();
 
625
        /* XXX: path should be on the local filesystem by now? */
 
626
 
 
627
        if (dialog != NULL) {
 
628
                gtk_widget_destroy (dialog);
 
629
        }
 
630
 
 
631
        process_local_theme (tdata->parent, tdata->path);
 
632
 
 
633
        g_free (tdata->path);
 
634
        g_free (tdata);
 
635
 
 
636
        gdk_threads_leave ();
 
637
}
 
638
 
 
639
void
 
640
mate_theme_install (GFile *file,
 
641
                     GtkWindow *parent)
 
642
{
 
643
        GtkWidget *dialog;
 
644
        gchar *path, *base;
 
645
        GList *src, *target;
 
646
        const gchar *template;
 
647
        TransferData *tdata;
 
648
 
 
649
        if (file == NULL) {
 
650
                dialog = gtk_message_dialog_new (parent,
 
651
                                                 GTK_DIALOG_MODAL,
 
652
                                                 GTK_MESSAGE_ERROR,
 
653
                                                 GTK_BUTTONS_OK,
 
654
                                                 _("No theme file location specified to install"));
 
655
                gtk_dialog_run (GTK_DIALOG (dialog));
 
656
                gtk_widget_destroy (dialog);
 
657
                return;
 
658
        }
 
659
 
 
660
        /* see if someone dropped a local directory */
 
661
        if (g_file_is_native (file)
 
662
            && g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL) == G_FILE_TYPE_DIRECTORY) {
 
663
                path = g_file_get_path (file);
 
664
                process_local_theme (parent, path);
 
665
                g_free (path);
 
666
                return;
 
667
        }
 
668
 
 
669
        /* we can't tell if this is an icon theme yet, so just make a
 
670
         * temporary copy in .themes */
 
671
        path = g_build_filename (g_get_home_dir (), ".themes", NULL);
 
672
 
 
673
        if (access (path, X_OK | W_OK) != 0) {
 
674
                dialog = gtk_message_dialog_new (parent,
 
675
                                                 GTK_DIALOG_MODAL,
 
676
                                                 GTK_MESSAGE_ERROR,
 
677
                                                 GTK_BUTTONS_OK,
 
678
                                                 _("Insufficient permissions to install the theme in:\n%s"), path);
 
679
                gtk_dialog_run (GTK_DIALOG (dialog));
 
680
                gtk_widget_destroy (dialog);
 
681
                g_free (path);
 
682
                return;
 
683
        }
 
684
 
 
685
        base = g_file_get_basename (file);
 
686
 
 
687
        if (g_str_has_suffix (base, ".tar.gz")
 
688
            || g_str_has_suffix (base, ".tgz")
 
689
            || g_str_has_suffix (base, ".gtp"))
 
690
                template = "mate-theme-%d.gtp";
 
691
        else if (g_str_has_suffix (base, ".tar.bz2"))
 
692
                template = "mate-theme-%d.tar.bz2";
 
693
        else {
 
694
                invalid_theme_dialog (parent, base, FALSE);
 
695
                g_free (base);
 
696
                return;
 
697
        }
 
698
        g_free (base);
 
699
 
 
700
        src = g_list_append (NULL, g_object_ref (file));
 
701
 
 
702
        path = NULL;
 
703
        do {
 
704
                gchar *file_tmp;
 
705
 
 
706
                g_free (path);
 
707
                file_tmp = g_strdup_printf (template, g_random_int ());
 
708
                path = g_build_filename (g_get_home_dir (), ".themes", file_tmp, NULL);
 
709
                g_free (file_tmp);
 
710
        } while (g_file_test (path, G_FILE_TEST_EXISTS));
 
711
 
 
712
        tdata = g_new0 (TransferData, 1);
 
713
        tdata->parent = parent;
 
714
        tdata->path = path;
 
715
 
 
716
        dialog = file_transfer_dialog_new_with_parent (parent);
 
717
        g_signal_connect (dialog,
 
718
                          "cancel",
 
719
                          (GCallback) transfer_cancel_cb, path);
 
720
        g_signal_connect (dialog,
 
721
                          "done",
 
722
                          (GCallback) transfer_done_cb, tdata);
 
723
 
 
724
        target = g_list_append (NULL, g_file_new_for_path (path));
 
725
        file_transfer_dialog_copy_async (FILE_TRANSFER_DIALOG (dialog),
 
726
                                         src,
 
727
                                         target,
 
728
                                         FILE_TRANSFER_DIALOG_DEFAULT,
 
729
                                         G_PRIORITY_DEFAULT);
 
730
        gtk_widget_show (dialog);
 
731
 
 
732
        /* don't free the path since we're using that for the signals */
 
733
        g_list_foreach (src, (GFunc) g_object_unref, NULL);
 
734
        g_list_free (src);
 
735
        g_list_foreach (target, (GFunc) g_object_unref, NULL);
 
736
        g_list_free (target);
 
737
}
 
738
 
 
739
void
 
740
mate_theme_installer_run (GtkWindow *parent,
 
741
                           const gchar *filename)
 
742
{
 
743
        static gboolean running_theme_install = FALSE;
 
744
        static gchar old_folder[512] = "";
 
745
        GtkWidget *dialog;
 
746
        GtkFileFilter *filter;
 
747
 
 
748
        if (running_theme_install)
 
749
                return;
 
750
 
 
751
        running_theme_install = TRUE;
 
752
 
 
753
        if (filename == NULL)
 
754
                filename = old_folder;
 
755
 
 
756
        dialog = gtk_file_chooser_dialog_new (_("Select Theme"),
 
757
                                              parent,
 
758
                                              GTK_FILE_CHOOSER_ACTION_OPEN,
 
759
                                              GTK_STOCK_CANCEL,
 
760
                                              GTK_RESPONSE_REJECT,
 
761
                                              GTK_STOCK_OPEN,
 
762
                                              GTK_RESPONSE_ACCEPT,
 
763
                                              NULL);
 
764
        gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
 
765
 
 
766
        filter = gtk_file_filter_new ();
 
767
        gtk_file_filter_set_name (filter, _("Theme Packages"));
 
768
        gtk_file_filter_add_mime_type (filter, "application/x-bzip-compressed-tar");
 
769
        gtk_file_filter_add_mime_type (filter, "application/x-compressed-tar");
 
770
        gtk_file_filter_add_mime_type (filter, "application/x-mate-theme-package");
 
771
        gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
 
772
 
 
773
        filter = gtk_file_filter_new ();
 
774
        gtk_file_filter_set_name (filter, _("All Files"));
 
775
        gtk_file_filter_add_pattern(filter, "*");
 
776
        gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
 
777
 
 
778
        if (strcmp (old_folder, ""))
 
779
                gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), old_folder);
 
780
 
 
781
        if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
 
782
                gchar *uri_selected, *folder;
 
783
 
 
784
                uri_selected = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
 
785
 
 
786
                folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
 
787
                g_strlcpy (old_folder, folder, 255);
 
788
                g_free (folder);
 
789
 
 
790
                gtk_widget_destroy (dialog);
 
791
 
 
792
                if (uri_selected != NULL) {
 
793
                        GFile *file = g_file_new_for_uri (uri_selected);
 
794
                        g_free (uri_selected);
 
795
 
 
796
                        mate_theme_install (file, parent);
 
797
                        g_object_unref (file);
 
798
                }
 
799
        } else {
 
800
                gtk_widget_destroy (dialog);
 
801
        }
 
802
 
 
803
        /*
 
804
         * we're relying on the mate theme info module to pick up changes
 
805
         * to the themes so we don't need to update the model here
 
806
         */
 
807
 
 
808
        running_theme_install = FALSE;
 
809
}