main.c 46.4 KB
Newer Older
1 2
/*
 *  Copyright (c) 2008 Stephan Arts <stephan@xfce.org>
3
 *  Copyright (c) 2008 Jannis Pohlmann <jannis@xfce.org>
4 5 6 7 8 9 10 11 12 13 14
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
Nick Schermer's avatar
Nick Schermer committed
15 16 17
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 19
 */

20
#ifdef HAVE_CONFIG_H
21
#include <config.h>
22
#endif
23

24 25 26 27 28
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
29
#endif
30 31 32
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
33

34
#include <unistd.h>
35
#include <glib.h>
36 37
#include <glib/gstdio.h>
#include <fcntl.h>
38
#include <gtk/gtk.h>
39 40 41
#include <gtk/gtkx.h>

#include <gdk/gdkx.h>
42

43
#include <libxfce4ui/libxfce4ui.h>
44
#include <libxfce4util/libxfce4util.h>
45
#include <xfconf/xfconf.h>
46

Stephan Arts's avatar
Stephan Arts committed
47
#include "appearance-dialog_ui.h"
48
#include "images.h"
49

50 51 52 53 54 55
#define INCH_MM      25.4

/* Use a fallback DPI of 96 which should be ok-ish on most systems
 * and is only applied on rare occasions */
#define FALLBACK_DPI 96

56
/* Increase this number if new gtk settings have been added */
57 58
#define INITIALIZE_UINT (1)

59 60
enum
{
61
    COLUMN_THEME_PREVIEW,
62 63 64
    COLUMN_THEME_NAME,
    COLUMN_THEME_DISPLAY_NAME,
    COLUMN_THEME_COMMENT,
65
    COLUMN_THEME_NO_CACHE,
66 67 68 69 70 71 72 73
    N_THEME_COLUMNS
};

enum
{
    COLUMN_RGBA_PIXBUF,
    COLUMN_RGBA_NAME,
    N_RGBA_COLUMNS
74 75
};

76 77 78 79 80 81 82
enum {
	COLOR_FG,
	COLOR_BG,
	COLOR_SELECTED_BG,
	NUM_SYMBOLIC_COLORS
};

83
/* String arrays with the settings in combo boxes */
84 85 86 87
static const gchar* toolbar_styles_array[] =
{
    "icons", "text", "both", "both-horiz"
};
88

89 90 91 92
static const gchar* xft_hint_styles_array[] =
{
    "hintnone", "hintslight", "hintmedium", "hintfull"
};
93

94
static const gchar* xft_rgba_array[] =
95
{
96 97 98
    "none", "rgb", "bgr", "vrgb", "vbgr"
};

99 100 101 102 103
static const GtkTargetEntry theme_drop_targets[] =
{
  { "text/uri-list", 0, 0 }
};

104
/* Option entries */
105
static gint opt_socket_id = 0;
106 107 108
static gboolean opt_version = FALSE;
static GOptionEntry option_entries[] =
{
109
    { "socket-id", 's', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT, &opt_socket_id, N_("Settings manager socket"), N_("SOCKET ID") },
110
    { "version", 'v', 0, G_OPTION_ARG_NONE, &opt_version, N_("Version information"), NULL },
111 112 113
    { NULL }
};

114
/* Global xfconf channel */
115 116
static XfconfChannel *xsettings_channel;

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
typedef struct
{
    GtkListStore *list_store;
    GtkTreeView *tree_view;
} preview_data;


static preview_data *
preview_data_new (GtkListStore *list_store,
                  GtkTreeView *tree_view)
{
    preview_data *pd;

    g_return_val_if_fail (list_store != NULL, NULL);
    g_return_val_if_fail (tree_view != NULL, NULL);
    g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), NULL);
    g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);

    pd = g_slice_new0 (preview_data);
    g_return_val_if_fail (pd != NULL, NULL);

    pd->list_store = list_store;
    pd->tree_view = tree_view;

    g_object_ref (G_OBJECT (pd->list_store));
    g_object_ref (G_OBJECT (pd->tree_view));

    return pd;
}

static void
preview_data_free (preview_data *pd)
{
    if (G_UNLIKELY (pd == NULL))
        return;
    g_object_unref (G_OBJECT (pd->list_store));
    g_object_unref (G_OBJECT (pd->tree_view));
    g_slice_free (preview_data, pd);
}

157 158 159
static int
compute_xsettings_dpi (GtkWidget *widget)
{
160
    GdkScreen *screen;
161 162 163
    int width_mm, height_mm;
    int width, height;
    int dpi;
164

165
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
166 167 168
    screen = gtk_widget_get_screen (widget);
    width_mm = gdk_screen_get_width_mm (screen);
    height_mm = gdk_screen_get_height_mm (screen);
169
    dpi = FALLBACK_DPI;
170

171 172
    if (width_mm > 0 && height_mm > 0)
    {
173 174
        width = gdk_screen_get_width (screen);
        height = gdk_screen_get_height (screen);
175 176 177
        dpi = MIN (INCH_MM * width  / width_mm,
                   INCH_MM * height / height_mm);
    }
178
G_GNUC_END_IGNORE_DEPRECATIONS
179 180 181 182

    return dpi;
}

183
static void
184
cb_theme_tree_selection_changed (GtkTreeSelection *selection,
Nick Schermer's avatar
Nick Schermer committed
185
                                 const gchar      *property)
186
{
187 188 189 190
    GtkTreeModel *model;
    gboolean      has_selection;
    gchar        *name;
    GtkTreeIter   iter;
191

192 193 194 195 196
    /* Get the selected list iter */
    has_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
    if (G_LIKELY (has_selection))
    {
        /* Get the theme name */
197
        gtk_tree_model_get (model, &iter, COLUMN_THEME_NAME, &name, -1);
198

199
        /* Store the new theme */
Nick Schermer's avatar
Nick Schermer committed
200
        xfconf_channel_set_string (xsettings_channel, property, name);
201

202 203 204
        /* Cleanup */
        g_free (name);
    }
205 206
}

207
static void
208
cb_icon_theme_tree_selection_changed (GtkTreeSelection *selection)
209
{
210 211 212
    /* Set the new icon theme */
    cb_theme_tree_selection_changed (selection, "/Net/IconThemeName");
}
213

214 215 216 217 218
static void
cb_ui_theme_tree_selection_changed (GtkTreeSelection *selection)
{
    /* Set the new UI theme */
    cb_theme_tree_selection_changed (selection, "/Net/ThemeName");
219 220
}

221 222
static void
cb_toolbar_style_combo_changed (GtkComboBox *combo)
223
{
224 225
    gint active;

226 227
    /* Get active item, prevent number outside the array (stay within zero-index) */
    active = CLAMP (gtk_combo_box_get_active (combo), 0, (gint) G_N_ELEMENTS (toolbar_styles_array)-1);
228

229
    /* Save setting */
230
    xfconf_channel_set_string (xsettings_channel, "/Gtk/ToolbarStyle", toolbar_styles_array[active]);
231 232
}

233 234 235 236 237 238 239 240 241 242 243 244
static void
cb_window_scaling_factor_combo_changed (GtkComboBox *combo)
{
    gint active;

    /* Get active item, prevent number outside the array (stay within zero-index) */
    active = CLAMP (gtk_combo_box_get_active (combo) + 1, 1, 2);

    /* Save setting */
    xfconf_channel_set_int (xsettings_channel, "/Gdk/WindowScalingFactor", active);
}

245 246
static void
cb_antialias_check_button_toggled (GtkToggleButton *toggle)
247
{
248 249
    gint active;

250 251 252
    /* Don't allow an inconsistent button anymore */
    gtk_toggle_button_set_inconsistent (toggle, FALSE);

253
    /* Get active */
254 255
    active = gtk_toggle_button_get_active (toggle) ? 1 : 0;

256
    /* Save setting */
257
    xfconf_channel_set_int (xsettings_channel, "/Xft/Antialias", active);
258 259
}

260 261
static void
cb_hinting_style_combo_changed (GtkComboBox *combo)
262
{
263 264
    gint active;

265 266
    /* Get active item, prevent number outside the array (stay within zero-index) */
    active = CLAMP (gtk_combo_box_get_active (combo), 0, (gint) G_N_ELEMENTS (xft_hint_styles_array)-1);
267

268
    /* Save setting */
269
    xfconf_channel_set_string (xsettings_channel, "/Xft/HintStyle", xft_hint_styles_array[active]);
270 271 272

    /* Also update /Xft/Hinting to match */
    xfconf_channel_set_int (xsettings_channel, "/Xft/Hinting", active > 0 ? 1 : 0);
273 274
}

275 276
static void
cb_rgba_style_combo_changed (GtkComboBox *combo)
277
{
278 279
    gint active;

280 281
    /* Get active item, prevent number outside the array (stay within zero-index) */
    active = CLAMP (gtk_combo_box_get_active (combo), 0, (gint) G_N_ELEMENTS (xft_rgba_array)-1);
282

283
    /* Save setting */
284
    xfconf_channel_set_string (xsettings_channel, "/Xft/RGBA", xft_rgba_array[active]);
285 286
}

287
static void
288 289
cb_custom_dpi_check_button_toggled (GtkToggleButton *custom_dpi_toggle,
                                    GtkSpinButton   *custom_dpi_spin)
290
{
291 292 293
    gint dpi;

    if (gtk_toggle_button_get_active (custom_dpi_toggle))
294
    {
295 296 297 298 299 300 301 302
        /* Custom DPI is activated, so restore the last custom DPI we know about */
        dpi = xfconf_channel_get_int (xsettings_channel, "/Xfce/LastCustomDPI", -1);

        /* Unfortunately, we don't have a valid custom DPI value to use, so compute it */
        if (dpi <= 0)
            dpi = compute_xsettings_dpi (GTK_WIDGET (custom_dpi_toggle));

        /* Apply the computed custom DPI value */
303
        xfconf_channel_set_int (xsettings_channel, "/Xft/DPI", dpi);
304

305 306 307 308
        gtk_widget_set_sensitive (GTK_WIDGET (custom_dpi_spin), TRUE);
    }
    else
    {
309 310 311 312 313
        /* Custom DPI is deactivated, so remember the current value as the last custom DPI */
        dpi = gtk_spin_button_get_value_as_int (custom_dpi_spin);
        xfconf_channel_set_int (xsettings_channel, "/Xfce/LastCustomDPI", dpi);

        /* Tell xfsettingsd to compute the value itself */
314
        xfconf_channel_set_int (xsettings_channel, "/Xft/DPI", -1);
315 316 317 318 319 320 321 322 323 324 325 326

        /* Make the spin button insensitive */
        gtk_widget_set_sensitive (GTK_WIDGET (custom_dpi_spin), FALSE);
    }
}

static void
cb_custom_dpi_spin_button_changed (GtkSpinButton   *custom_dpi_spin,
                                   GtkToggleButton *custom_dpi_toggle)
{
    gint dpi = gtk_spin_button_get_value_as_int (custom_dpi_spin);

327
    if (gtk_widget_is_sensitive (GTK_WIDGET(custom_dpi_spin)) && gtk_toggle_button_get_active (custom_dpi_toggle))
328 329 330
    {
        /* Custom DPI is turned on and the spin button has changed, so remember the value */
        xfconf_channel_set_int (xsettings_channel, "/Xfce/LastCustomDPI", dpi);
331
    }
332 333 334

    /* Tell xfsettingsd to apply the custom DPI value */
    xfconf_channel_set_int (xsettings_channel, "/Xft/DPI", dpi);
335 336
}

337
#ifdef ENABLE_SOUND_SETTINGS
338 339 340 341 342 343 344 345 346
static void
cb_enable_event_sounds_check_button_toggled (GtkToggleButton *toggle, GtkWidget *button)
{
    gboolean active;

    active = gtk_toggle_button_get_active (toggle);
    gtk_widget_set_sensitive (button, active);
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), active);
}
347
#endif
348

349 350
static gboolean
appearance_settings_load_icon_themes (preview_data *pd)
351
{
352 353
    GtkListStore *list_store;
    GtkTreeView  *tree_view;
354 355 356 357 358 359 360 361 362
    GDir         *dir;
    GtkTreePath  *tree_path;
    GtkTreeIter   iter;
    XfceRc       *index_file;
    const gchar  *file;
    gchar       **icon_theme_dirs;
    gchar        *index_filename;
    const gchar  *theme_name;
    const gchar  *theme_comment;
363
    gchar        *name_escaped;
364
    gchar        *comment_escaped;
365
    gchar        *visible_name;
366
    gchar        *active_theme_name;
367 368
    gsize         i;
    gsize         p;
369
    GSList       *check_list = NULL;
370 371 372
    gchar        *cache_filename;
    gboolean      has_cache;
    gchar        *cache_tooltip;
373 374 375 376 377
    GtkIconTheme *icon_theme;
    GdkPixbuf    *preview;
    GdkPixbuf    *icon;
    gchar*        preview_icons[4] = { "folder", "go-down", "audio-volume-high", "web-browser" };
    int           coords[4][2] = { { 4, 4 }, { 24, 4 }, { 4, 24 }, { 24, 24 } };
378

379 380 381 382 383
    g_return_val_if_fail (pd != NULL, FALSE);

    list_store = pd->list_store;
    tree_view = pd->tree_view;

384
    /* Determine current theme */
385
    active_theme_name = xfconf_channel_get_string (xsettings_channel, "/Net/IconThemeName", "Rodent");
386 387

    /* Determine directories to look in for icon themes */
388
    xfce_resource_push_path (XFCE_RESOURCE_ICONS, DATADIR G_DIR_SEPARATOR_S "icons");
389 390 391 392 393
    icon_theme_dirs = xfce_resource_dirs (XFCE_RESOURCE_ICONS);
    xfce_resource_pop_path (XFCE_RESOURCE_ICONS);

    /* Iterate over all base directories */
    for (i = 0; icon_theme_dirs[i] != NULL; ++i)
394
    {
395 396
        /* Open directory handle */
        dir = g_dir_open (icon_theme_dirs[i], 0, NULL);
397

398 399 400
        /* Try next base directory if this one cannot be read */
        if (G_UNLIKELY (dir == NULL))
            continue;
401

402 403
        /* Iterate over filenames in the directory */
        while ((file = g_dir_read_name (dir)) != NULL)
404
        {
405 406
            /* Build filename for the index.theme of the current icon theme directory */
            index_filename = g_build_filename (icon_theme_dirs[i], file, "index.theme", NULL);
407

408 409
            /* Try to open the theme index file */
            index_file = xfce_rc_simple_open (index_filename, TRUE);
410

411
            if (index_file != NULL
412
                && g_slist_find_custom (check_list, file, (GCompareFunc) g_utf8_collate) == NULL)
413
            {
414
                /* Set the icon theme group */
415
                xfce_rc_set_group (index_file, "Icon Theme");
416

417 418 419
                /* Check if the icon theme is valid and visible to the user */
                if (G_LIKELY (xfce_rc_has_entry (index_file, "Directories")
                              && !xfce_rc_read_bool_entry (index_file, "Hidden", FALSE)))
420
                {
421 422 423
                    /* Insert the theme in the check list */
                    check_list = g_slist_prepend (check_list, g_strdup (file));

424 425 426 427 428 429 430 431
                    /* Create the icon-theme preview */
                    preview = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 44, 44);
                    gdk_pixbuf_fill (preview, 0x00);
                    icon_theme = gtk_icon_theme_new ();
                    gtk_icon_theme_set_custom_theme (icon_theme, file);

                    for (p = 0; p < 4; p++)
                    {
432
                        icon = NULL;
433
                        if (gtk_icon_theme_has_icon (icon_theme, preview_icons[p]))
Sean Davis's avatar
Sean Davis committed
434
                            icon = gtk_icon_theme_load_icon (icon_theme, preview_icons[p], 16, 0, NULL);
435
                        else if (gtk_icon_theme_has_icon (icon_theme, "image-missing"))
Sean Davis's avatar
Sean Davis committed
436
                            icon = gtk_icon_theme_load_icon (icon_theme, "image-missing", 16, 0, NULL);
437

Sean Davis's avatar
Sean Davis committed
438
                        if (icon)
439 440 441 442 443 444
                        {
                            gdk_pixbuf_copy_area (icon, 0, 0, 16, 16, preview, coords[p][0], coords[p][1]);
                            g_object_unref (icon);
                        }
                    }

445 446 447
                    /* Get translated icon theme name and comment */
                    theme_name = xfce_rc_read_entry (index_file, "Name", file);
                    theme_comment = xfce_rc_read_entry (index_file, "Comment", NULL);
448

449 450
                    /* Escape the theme's name and comment, since they are markup, not text */
                    name_escaped = g_markup_escape_text (theme_name, -1);
451
                    comment_escaped = theme_comment ? g_markup_escape_text (theme_comment, -1) : NULL;
452 453 454
                    visible_name = g_strdup_printf ("<b>%s</b>\n%s", name_escaped, comment_escaped);
                    g_free (name_escaped);
                    g_free (comment_escaped);
455

456 457 458 459 460 461 462 463 464 465
                    /* Cache filename */
                    cache_filename = g_build_filename (icon_theme_dirs[i], file, "icon-theme.cache", NULL);
                    has_cache = g_file_test (cache_filename, G_FILE_TEST_IS_REGULAR);
                    g_free (cache_filename);

                    /* If the theme has no cache, mention this in the tooltip */
                    if (!has_cache)
                        cache_tooltip = g_strdup_printf (_("Warning: this icon theme has no cache file. You can create this by "
                                                           "running <i>gtk-update-icon-cache %s/%s/</i> in a terminal emulator."),
                                                         icon_theme_dirs[i], file);
466
                    else
467
                        cache_tooltip = NULL;
468

469 470
                    /* Append icon theme to the list store */
                    gtk_list_store_append (list_store, &iter);
471
                    gtk_list_store_set (list_store, &iter,
472
                                        COLUMN_THEME_PREVIEW, preview,
473
                                        COLUMN_THEME_NAME, file,
474
                                        COLUMN_THEME_DISPLAY_NAME, visible_name,
475
                                        COLUMN_THEME_NO_CACHE, !has_cache,
476
                                        COLUMN_THEME_COMMENT, cache_tooltip,
477
                                        -1);
478

479
                    /* Check if this is the active theme, if so, select it */
480
                    if (G_UNLIKELY (g_utf8_collate (file, active_theme_name) == 0))
481
                    {
482 483
                        tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), &iter);
                        gtk_tree_selection_select_path (gtk_tree_view_get_selection (tree_view), tree_path);
484
                        gtk_tree_view_scroll_to_cell (tree_view, tree_path, NULL, TRUE, 0.5, 0);
485
                        gtk_tree_path_free (tree_path);
486
                    }
487

488
                    g_object_unref (icon_theme);
489
                    g_object_unref (preview);
490 491
                }
            }
492

493 494 495
            /* Close theme index file */
            if (G_LIKELY (index_file))
                xfce_rc_close (index_file);
496

497 498
            /* Free theme index filename */
            g_free (index_filename);
499 500
        }

501 502
        /* Close directory handle */
        g_dir_close (dir);
503 504
    }

505 506
    /* Free active theme name */
    g_free (active_theme_name);
507

508 509
    /* Free list of base directories */
    g_strfreev (icon_theme_dirs);
510

511 512 513
    /* Free the check list */
    if (G_LIKELY (check_list))
    {
Sean Davis's avatar
Sean Davis committed
514
        g_slist_foreach (check_list, (GFunc) (void (*)(void)) g_free, NULL);
515 516
        g_slist_free (check_list);
    }
517 518

    return FALSE;
519 520
}

521 522
static gboolean
appearance_settings_load_ui_themes (preview_data *pd)
523
{
524 525
    GtkListStore *list_store;
    GtkTreeView  *tree_view;
526 527 528 529 530 531 532 533 534 535 536
    GDir         *dir;
    GtkTreePath  *tree_path;
    GtkTreeIter   iter;
    XfceRc       *index_file;
    const gchar  *file;
    gchar       **ui_theme_dirs;
    gchar        *index_filename;
    const gchar  *theme_name;
    const gchar  *theme_comment;
    gchar        *active_theme_name;
    gchar        *gtkrc_filename;
537
    gchar        *gtkcss_filename;
538
    gchar        *comment_escaped;
539 540
    gint          i;
    GSList       *check_list = NULL;
541

542 543 544 545 546
    g_return_val_if_fail (pd != NULL, FALSE);

    list_store = pd->list_store;
    tree_view = pd->tree_view;

547 548
    /* Determine current theme */
    active_theme_name = xfconf_channel_get_string (xsettings_channel, "/Net/ThemeName", "Default");
549

550 551 552 553
    /* Determine directories to look in for ui themes */
    xfce_resource_push_path (XFCE_RESOURCE_THEMES, DATADIR G_DIR_SEPARATOR_S "themes");
    ui_theme_dirs = xfce_resource_dirs (XFCE_RESOURCE_THEMES);
    xfce_resource_pop_path (XFCE_RESOURCE_THEMES);
554

555 556
    /* Iterate over all base directories */
    for (i = 0; ui_theme_dirs[i] != NULL; ++i)
557
    {
558 559
        /* Open directory handle */
        dir = g_dir_open (ui_theme_dirs[i], 0, NULL);
560

561 562 563 564 565 566
        /* Try next base directory if this one cannot be read */
        if (G_UNLIKELY (dir == NULL))
            continue;

        /* Iterate over filenames in the directory */
        while ((file = g_dir_read_name (dir)) != NULL)
567
        {
568 569
            /* Build the theme style filename */
            gtkrc_filename = g_build_filename (ui_theme_dirs[i], file, "gtk-2.0", "gtkrc", NULL);
570
            gtkcss_filename = g_build_filename (ui_theme_dirs[i], file, "gtk-3.0", "gtk.css", NULL);
571

572
            /* Check if the gtkrc file exists and the theme is not already in the list */
573
            if (g_file_test (gtkcss_filename, G_FILE_TEST_EXISTS)
574
                && g_slist_find_custom (check_list, file, (GCompareFunc) g_utf8_collate) == NULL)
575 576 577
            {
                /* Insert the theme in the check list */
                check_list = g_slist_prepend (check_list, g_strdup (file));
578

579 580
                /* Build filename for the index.theme of the current ui theme directory */
                index_filename = g_build_filename (ui_theme_dirs[i], file, "index.theme", NULL);
581

582 583
                /* Try to open the theme index file */
                index_file = xfce_rc_simple_open (index_filename, TRUE);
584

585 586 587 588 589
                if (G_LIKELY (index_file != NULL))
                {
                    /* Get translated ui theme name and comment */
                    theme_name = xfce_rc_read_entry (index_file, "Name", file);
                    theme_comment = xfce_rc_read_entry (index_file, "Comment", NULL);
590

591 592
                    /* Escape the comment because tooltips are markup, not text */
                    comment_escaped = theme_comment ? g_markup_escape_text (theme_comment, -1) : NULL;
593 594 595 596 597
                }
                else
                {
                    /* Set defaults */
                    theme_name = file;
598
                    comment_escaped = NULL;
599
                }
600

601 602
                /* Append ui theme to the list store */
                gtk_list_store_append (list_store, &iter);
603
                gtk_list_store_set (list_store, &iter,
604 605
                                    COLUMN_THEME_NAME, file,
                                    COLUMN_THEME_DISPLAY_NAME, theme_name,
606
                                    COLUMN_THEME_COMMENT, comment_escaped, -1);
607

608
                /* Cleanup */
609 610
                if (G_LIKELY (index_file != NULL))
                    xfce_rc_close (index_file);
611
                g_free (comment_escaped);
612 613

                /* Check if this is the active theme, if so, select it */
614
                if (G_UNLIKELY (g_utf8_collate (file, active_theme_name) == 0))
615 616 617
                {
                    tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), &iter);
                    gtk_tree_selection_select_path (gtk_tree_view_get_selection (tree_view), tree_path);
618
                    gtk_tree_view_scroll_to_cell (tree_view, tree_path, NULL, TRUE, 0.5, 0);
619 620 621 622 623 624
                    gtk_tree_path_free (tree_path);
                }

                /* Free theme index filename */
                g_free (index_filename);
            }
625

626 627
            /* Free gtkrc filename */
            g_free (gtkrc_filename);
628
            g_free (gtkcss_filename);
629 630
        }

631 632
        /* Close directory handle */
        g_dir_close (dir);
633 634
    }

635 636
    /* Free active theme name */
    g_free (active_theme_name);
637

638 639
    /* Free list of base directories */
    g_strfreev (ui_theme_dirs);
640

641 642 643
    /* Free the check list */
    if (G_LIKELY (check_list))
    {
Sean Davis's avatar
Sean Davis committed
644
        g_slist_foreach (check_list, (GFunc) (void (*)(void)) g_free, NULL);
645 646
        g_slist_free (check_list);
    }
647 648

    return FALSE;
649 650
}

651 652 653 654
static void
appearance_settings_dialog_channel_property_changed (XfconfChannel *channel,
                                                     const gchar   *property_name,
                                                     const GValue  *value,
655
                                                     GtkBuilder    *builder)
656
{
657
    GObject      *object;
658 659
    gchar        *str;
    guint         i;
660
    gint          antialias, dpi, custom_dpi;
661 662 663
    GtkTreeModel *model;

    g_return_if_fail (property_name != NULL);
664
    g_return_if_fail (GTK_IS_BUILDER (builder));
665 666 667 668 669 670 671 672

    if (strcmp (property_name, "/Xft/RGBA") == 0)
    {
        str = xfconf_channel_get_string (xsettings_channel, property_name, xft_rgba_array[0]);
        for (i = 0; i < G_N_ELEMENTS (xft_rgba_array); i++)
        {
            if (strcmp (str, xft_rgba_array[i]) == 0)
            {
673 674
                object = gtk_builder_get_object (builder, "xft_rgba_combo_box");
                gtk_combo_box_set_active (GTK_COMBO_BOX (object), i);
675 676 677 678 679 680 681 682 683 684 685 686
                break;
            }
        }
        g_free (str);
    }
    else if (strcmp (property_name, "/Gtk/ToolbarStyle") == 0)
    {
        str = xfconf_channel_get_string (xsettings_channel, property_name, toolbar_styles_array[2]);
        for (i = 0; i < G_N_ELEMENTS (toolbar_styles_array); i++)
        {
            if (strcmp (str, toolbar_styles_array[i]) == 0)
            {
687 688
                object = gtk_builder_get_object (builder, "gtk_toolbar_style_combo_box");
                gtk_combo_box_set_active (GTK_COMBO_BOX (object), i);
689 690 691 692 693
                break;
            }
        }
        g_free (str);
    }
694 695 696 697 698 699
    else if (strcmp (property_name, "/Gdk/WindowScalingFactor") == 0)
    {
        i = xfconf_channel_get_int (xsettings_channel, property_name, 1);
        object = gtk_builder_get_object (builder, "gdk_window_scaling_factor_combo_box");
        gtk_combo_box_set_active (GTK_COMBO_BOX (object), i - 1);
    }
700 701 702 703 704 705 706
    else if (strcmp (property_name, "/Xft/HintStyle") == 0)
    {
        str = xfconf_channel_get_string (xsettings_channel, property_name, xft_hint_styles_array[0]);
        for (i = 0; i < G_N_ELEMENTS (xft_hint_styles_array); i++)
        {
            if (strcmp (str, xft_hint_styles_array[i]) == 0)
            {
707 708
                object = gtk_builder_get_object (builder, "xft_hinting_style_combo_box");
                gtk_combo_box_set_active (GTK_COMBO_BOX (object), i);
709 710 711 712 713 714 715
                break;
            }
        }
        g_free (str);
    }
    else if (strcmp (property_name, "/Xft/Antialias") == 0)
    {
716
        object = gtk_builder_get_object (builder, "xft_antialias_check_button");
717 718 719 720
        antialias = xfconf_channel_get_int (xsettings_channel, property_name, -1);
        switch (antialias)
        {
            case 1:
721
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (object), TRUE);
722 723 724
                break;

            case 0:
725
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (object), FALSE);
726 727 728
                break;

            default: /* -1 */
729
                gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (object), TRUE);
730 731 732 733 734
                break;
        }
    }
    else if (strcmp (property_name, "/Xft/DPI") == 0)
    {
735
        /* The DPI has changed, so get its value and the last known custom value */
736 737 738
        dpi = xfconf_channel_get_int (xsettings_channel, property_name, FALLBACK_DPI);
        custom_dpi = xfconf_channel_get_int (xsettings_channel, "/Xfce/LastCustomDPI", -1);

739
        /* Activate the check button if we're using a custom DPI */
740 741
        object = gtk_builder_get_object (builder, "xft_custom_dpi_check_button");
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (object), dpi >= 0);
742 743 744

        /* If we're not using a custom DPI, compute the future custom DPI automatically */
        if (custom_dpi == -1)
745
            custom_dpi = compute_xsettings_dpi (GTK_WIDGET (object));
746

747
        object = gtk_builder_get_object (builder, "xft_custom_dpi_spin_button");
748 749

        if (dpi > 0)
750
        {
751
            /* We're using a custom DPI, so use the current DPI setting for the spin value */
752
            gtk_spin_button_set_value (GTK_SPIN_BUTTON (object), dpi);
753 754 755
        }
        else
        {
756
            /* Set the spin button value to the last custom DPI */
757
            gtk_spin_button_set_value (GTK_SPIN_BUTTON (object), custom_dpi);
758 759 760 761
        }
    }
    else if (strcmp (property_name, "/Net/ThemeName") == 0)
    {
762 763
        GtkTreeIter iter;

764 765
        object = gtk_builder_get_object (builder, "gtk_theme_treeview");
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (object));
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780

        if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (object)),
                                             &model,
                                             &iter))
        {
            gchar *selected_name;
            gchar *new_name;

            gtk_tree_model_get (model, &iter, COLUMN_THEME_NAME, &selected_name, -1);

            new_name = xfconf_channel_get_string (channel, property_name, NULL);

            g_free (selected_name);
            g_free (new_name);
        }
781 782 783
    }
    else if (strcmp (property_name, "/Net/IconThemeName") == 0)
    {
784 785 786 787 788
        GtkTreeIter iter;
        gboolean    reload;

        reload = TRUE;

789 790
        object = gtk_builder_get_object (builder, "icon_theme_treeview");
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (object));
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811

        if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (object)),
                                             &model,
                                             &iter))
        {
            gchar *selected_name;
            gchar *new_name;

            gtk_tree_model_get (model, &iter, COLUMN_THEME_NAME, &selected_name, -1);

            new_name = xfconf_channel_get_string (channel, property_name, NULL);

            reload = (strcmp (new_name, selected_name) != 0);

            g_free (selected_name);
            g_free (new_name);
        }


        if (reload)
        {
812 813
            preview_data *pd;

814
            gtk_list_store_clear (GTK_LIST_STORE (model));
815 816 817 818 819
            pd = preview_data_new (GTK_LIST_STORE (model), GTK_TREE_VIEW (object));
            g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
                             (GSourceFunc) appearance_settings_load_icon_themes,
                             pd,
                             (GDestroyNotify) preview_data_free);
820
        }
821 822 823
    }
}

824 825 826 827 828 829 830
static void
cb_theme_uri_dropped (GtkWidget        *widget,
                      GdkDragContext   *drag_context,
                      gint              x,
                      gint              y,
                      GtkSelectionData *data,
                      guint             info,
831 832
                      guint             timestamp,
                      GtkBuilder       *builder)
833
{
834 835 836 837 838 839 840 841 842 843 844 845
    gchar        **uris;
    gchar         *argv[3];
    guint          i;
    GError        *error = NULL;
    gint           status;
    GtkWidget     *toplevel = gtk_widget_get_toplevel (widget);
    gchar         *filename;
    GdkCursor     *cursor;
    GdkWindow     *gdkwindow;
    gboolean       something_installed = FALSE;
    GObject       *object;
    GtkTreeModel  *model;
846
    preview_data  *pd;
847 848

    uris = gtk_selection_data_get_uris (data);
849 850
    if (uris == NULL)
        return;
851

852 853
    argv[0] = HELPERDIR G_DIR_SEPARATOR_S "appearance-install-theme";
    argv[2] = NULL;
854

855 856 857 858
    /* inform the user we are installing the theme */
    gdkwindow = gtk_widget_get_window (widget);
    cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_WATCH);
    gdk_window_set_cursor (gdkwindow, cursor);
859

860 861 862
    /* iterate main loop to show cursor */
    while (gtk_events_pending ())
        gtk_main_iteration ();
863

864 865 866 867 868
    for (i = 0; uris[i] != NULL; i++)
    {
        filename = g_filename_from_uri (uris[i], NULL, NULL);
        if (filename == NULL)
            continue;
869

870
        argv[1] = filename;
871

872 873 874 875
        if (g_spawn_sync (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL, &status, &error)
            && status > 0)
        {
            switch (WEXITSTATUS (status))
876
            {
877 878
                case 2:
                    g_set_error (&error, G_SPAWN_ERROR, 0,
Nick Schermer's avatar
Nick Schermer committed
879
                        _("File is larger than %d MB, installation aborted"), 50);
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
                    break;

                case 3:
                    g_set_error_literal (&error, G_SPAWN_ERROR, 0,
                        _("Failed to create temporary directory"));
                    break;

                case 4:
                    g_set_error_literal (&error, G_SPAWN_ERROR, 0,
                        _("Failed to extract archive"));
                    break;

                case 5:
                    g_set_error_literal (&error, G_SPAWN_ERROR, 0,
                        _("Unknown format, only archives and directories are supported"));
                    break;

                default:
                    g_set_error (&error, G_SPAWN_ERROR,
                        0, _("An unknown error, exit code is %d"), WEXITSTATUS (status));
                    break;
901
            }
902
        }
903

904 905 906 907
        if (error != NULL)
        {
            xfce_dialog_show_error (GTK_WINDOW (toplevel), error, _("Failed to install theme"));
            g_clear_error (&error);
908
        }
909 910 911 912
        else
        {
            something_installed = TRUE;
        }
913

914
        g_free (filename);
915
    }
916 917 918

    g_strfreev (uris);
    gdk_window_set_cursor (gdkwindow, NULL);
919
    g_object_unref (cursor);
920 921 922

    if (something_installed)
    {
923
        /* reload icon theme treeview in an idle loop */
924 925 926
        object = gtk_builder_get_object (builder, "icon_theme_treeview");
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (object));
        gtk_list_store_clear (GTK_LIST_STORE (model));
927 928 929 930 931
        pd = preview_data_new (GTK_LIST_STORE (model), GTK_TREE_VIEW (object));
        g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
                         (GSourceFunc) appearance_settings_load_icon_themes,
                         pd,
                         (GDestroyNotify) preview_data_free);
932 933 934 935 936

        /* reload gtk theme treeview */
        object = gtk_builder_get_object (builder, "gtk_theme_treeview");
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (object));
        gtk_list_store_clear (GTK_LIST_STORE (model));
937 938 939 940 941
        pd = preview_data_new (GTK_LIST_STORE (model), GTK_TREE_VIEW (object));
        g_idle_add_full (G_PRIORITY_HIGH_IDLE,
                         (GSourceFunc) appearance_settings_load_ui_themes,
                         pd,
                         (GDestroyNotify) preview_data_free);
942
    }
943 944
}

945
static void
946
appearance_settings_dialog_configure_widgets (GtkBuilder *builder)
947
{
948 949 950 951 952 953
    GObject           *object, *object2;
    GtkListStore      *list_store;
    GtkCellRenderer   *renderer;
    GdkPixbuf         *pixbuf;
    GtkTreeSelection  *selection;
    GtkTreeViewColumn *column;
954
    preview_data      *pd;
955

956
    /* Icon themes list */
957
    object = gtk_builder_get_object (builder, "icon_theme_treeview");