~midori/midori/cmake-make-dist

« back to all changes in this revision

Viewing changes to src/main.c

  • Committer: Christian Dywan
  • Date: 2008-06-01 21:47:27 UTC
  • Revision ID: git-v1:b511f12b9b4b063610161f2229b94a24a86be0fc
Rename folder 'src' to 'midori'

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
3
 
 
4
 
 This library is free software; you can redistribute it and/or
5
 
 modify it under the terms of the GNU Lesser General Public
6
 
 License as published by the Free Software Foundation; either
7
 
 version 2.1 of the License, or (at your option) any later version.
8
 
 
9
 
 See the file COPYING for the full license text.
10
 
*/
11
 
 
12
 
#include "main.h"
13
 
 
14
 
#include "sokoke.h"
15
 
#include "search.h"
16
 
 
17
 
#include "midori-app.h"
18
 
#include "midori-websettings.h"
19
 
#include "midori-trash.h"
20
 
#include "midori-browser.h"
21
 
#include "gjs.h"
22
 
 
23
 
#include <katze/katze.h>
24
 
#include <string.h>
25
 
#include <gtk/gtk.h>
26
 
 
27
 
#include "config.h"
28
 
 
29
 
#ifdef ENABLE_NLS
30
 
    #include <libintl.h>
31
 
#endif
32
 
 
33
 
// -- stock icons
34
 
 
35
 
static void stock_items_init(void)
36
 
{
37
 
    static GtkStockItem items[] =
38
 
    {
39
 
        { STOCK_LOCK_OPEN },
40
 
        { STOCK_LOCK_SECURE },
41
 
        { STOCK_LOCK_BROKEN },
42
 
        { STOCK_SCRIPT },
43
 
        { STOCK_THEME },
44
 
        { STOCK_USER_TRASH },
45
 
 
46
 
        { STOCK_BOOKMARK,       N_("Bookmark"), 0, 0, NULL },
47
 
        { STOCK_BOOKMARK_ADD,   N_("_Add Bookmark"), 0, 0, NULL },
48
 
        { STOCK_FORM_FILL,      N_("_Form Fill"), 0, 0, NULL },
49
 
        { STOCK_HOMEPAGE,       N_("_Homepage"), 0, 0, NULL },
50
 
        { STOCK_TAB_NEW,        N_("New _Tab"), 0, 0, NULL },
51
 
        { STOCK_WINDOW_NEW,     N_("New _Window"), 0, 0, NULL },
52
 
        #if !GTK_CHECK_VERSION(2, 10, 0)
53
 
        { GTK_STOCK_SELECT_ALL, N_("Select _All"), 0, 0, NULL },
54
 
        #endif
55
 
        #if !GTK_CHECK_VERSION(2, 8, 0)
56
 
        { GTK_STOCK_FULLSCREEN, N_("_Fullscreen"), 0, 0, NULL },
57
 
        { GTK_STOCK_LEAVE_FULLSCREEN, N_("_Leave Fullscreen"), 0, 0, NULL },
58
 
        #endif
59
 
    };
60
 
    GtkIconFactory* factory = gtk_icon_factory_new();
61
 
    guint i;
62
 
    for(i = 0; i < (guint)G_N_ELEMENTS(items); i++)
63
 
    {
64
 
        GtkIconSource* iconSource = gtk_icon_source_new();
65
 
        gtk_icon_source_set_icon_name(iconSource, items[i].stock_id);
66
 
        GtkIconSet* iconSet = gtk_icon_set_new();
67
 
        gtk_icon_set_add_source(iconSet, iconSource);
68
 
        gtk_icon_source_free(iconSource);
69
 
        gtk_icon_factory_add(factory, items[i].stock_id, iconSet);
70
 
        gtk_icon_set_unref(iconSet);
71
 
    }
72
 
    gtk_stock_add_static(items, G_N_ELEMENTS(items));
73
 
    gtk_icon_factory_add_default(factory);
74
 
    g_object_unref(factory);
75
 
}
76
 
 
77
 
static void
78
 
locale_init (void)
79
 
{
80
 
#ifdef ENABLE_NLS
81
 
    bindtextdomain (GETTEXT_PACKAGE, MIDORI_LOCALEDIR);
82
 
    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
83
 
    textdomain (GETTEXT_PACKAGE);
84
 
#endif
85
 
}
86
 
 
87
 
static MidoriWebSettings*
88
 
settings_new_from_file (const gchar* filename)
89
 
{
90
 
    MidoriWebSettings* settings = midori_web_settings_new ();
91
 
    GKeyFile* key_file = g_key_file_new ();
92
 
    GError* error = NULL;
93
 
    if (!g_key_file_load_from_file (key_file, filename,
94
 
                                   G_KEY_FILE_KEEP_COMMENTS, &error))
95
 
    {
96
 
        if (error->code != G_FILE_ERROR_NOENT)
97
 
            printf (_("The configuration couldn't be loaded. %s\n"),
98
 
                    error->message);
99
 
        g_error_free (error);
100
 
    }
101
 
    GObjectClass* class = G_OBJECT_GET_CLASS (settings);
102
 
    guint i, n_properties;
103
 
    GParamSpec** pspecs = g_object_class_list_properties (class, &n_properties);
104
 
    for (i = 0; i < n_properties; i++)
105
 
    {
106
 
        GParamSpec* pspec = pspecs[i];
107
 
        if (!(pspec->flags & G_PARAM_WRITABLE))
108
 
            continue;
109
 
        GType type = G_PARAM_SPEC_TYPE (pspec);
110
 
        const gchar* property = g_param_spec_get_name (pspec);
111
 
        if (type == G_TYPE_PARAM_STRING)
112
 
        {
113
 
            gchar* string = sokoke_key_file_get_string_default (key_file,
114
 
                "settings", property,
115
 
                G_PARAM_SPEC_STRING (pspec)->default_value, NULL);
116
 
            g_object_set (settings, property, string, NULL);
117
 
            g_free (string);
118
 
        }
119
 
        else if (type == G_TYPE_PARAM_INT)
120
 
        {
121
 
            gint integer = sokoke_key_file_get_integer_default (key_file,
122
 
                "settings", property,
123
 
                G_PARAM_SPEC_INT (pspec)->default_value, NULL);
124
 
            g_object_set (settings, property, integer, NULL);
125
 
        }
126
 
        else if (type == G_TYPE_PARAM_FLOAT)
127
 
        {
128
 
            gdouble number = sokoke_key_file_get_double_default (key_file,
129
 
                "settings", property,
130
 
                G_PARAM_SPEC_FLOAT (pspec)->default_value, NULL);
131
 
            g_object_set (settings, property, number, NULL);
132
 
        }
133
 
        else if (type == G_TYPE_PARAM_BOOLEAN)
134
 
        {
135
 
            gboolean boolean = sokoke_key_file_get_boolean_default (key_file,
136
 
                "settings", property,
137
 
                G_PARAM_SPEC_BOOLEAN (pspec)->default_value, NULL);
138
 
            g_object_set (settings, property, boolean, NULL);
139
 
        }
140
 
        else if (type == G_TYPE_PARAM_ENUM)
141
 
        {
142
 
            GEnumClass* enum_class = G_ENUM_CLASS (
143
 
                g_type_class_ref (pspec->value_type));
144
 
            GEnumValue* enum_value = g_enum_get_value (enum_class,
145
 
                G_PARAM_SPEC_ENUM (pspec)->default_value);
146
 
            gchar* string = sokoke_key_file_get_string_default (key_file,
147
 
                "settings", property,
148
 
                enum_value->value_name, NULL);
149
 
            enum_value = g_enum_get_value_by_name (enum_class, string);
150
 
            if (enum_value)
151
 
                 g_object_set (settings, property, enum_value->value, NULL);
152
 
             else
153
 
                 g_warning (_("Value '%s' is invalid for %s"),
154
 
                            string, property);
155
 
 
156
 
            g_free (string);
157
 
            g_type_class_unref (enum_class);
158
 
        }
159
 
        else
160
 
            g_warning (_("Unhandled settings value '%s'"), property);
161
 
    }
162
 
    return settings;
163
 
}
164
 
 
165
 
static gboolean
166
 
settings_save_to_file (MidoriWebSettings* settings,
167
 
                       const gchar*       filename,
168
 
                       GError**           error)
169
 
{
170
 
    GKeyFile* key_file = g_key_file_new ();
171
 
    GObjectClass* class = G_OBJECT_GET_CLASS (settings);
172
 
    guint i, n_properties;
173
 
    GParamSpec** pspecs = g_object_class_list_properties (class, &n_properties);
174
 
    for (i = 0; i < n_properties; i++)
175
 
    {
176
 
        GParamSpec* pspec = pspecs[i];
177
 
        GType type = G_PARAM_SPEC_TYPE (pspec);
178
 
        const gchar* property = g_param_spec_get_name (pspec);
179
 
        if (!(pspec->flags & G_PARAM_WRITABLE))
180
 
        {
181
 
            gchar* comment = g_strdup_printf ("# %s", property);
182
 
            g_key_file_set_string (key_file, "settings", comment, "");
183
 
            g_free (comment);
184
 
            continue;
185
 
        }
186
 
        if (type == G_TYPE_PARAM_STRING)
187
 
        {
188
 
            const gchar* string;
189
 
            g_object_get (settings, property, &string, NULL);
190
 
            g_key_file_set_string (key_file, "settings", property,
191
 
                                   string ? string : "");
192
 
        }
193
 
        else if (type == G_TYPE_PARAM_INT)
194
 
        {
195
 
            gint integer;
196
 
            g_object_get (settings, property, &integer, NULL);
197
 
            g_key_file_set_integer (key_file, "settings", property, integer);
198
 
        }
199
 
        else if (type == G_TYPE_PARAM_FLOAT)
200
 
        {
201
 
            gdouble number;
202
 
            g_object_get (settings, property, &number, NULL);
203
 
            g_key_file_set_double (key_file, "settings", property, number);
204
 
        }
205
 
        else if (type == G_TYPE_PARAM_BOOLEAN)
206
 
        {
207
 
            gboolean boolean;
208
 
            g_object_get (settings, property, &boolean, NULL);
209
 
            g_key_file_set_boolean (key_file, "settings", property, boolean);
210
 
        }
211
 
        else if (type == G_TYPE_PARAM_ENUM)
212
 
        {
213
 
            GEnumClass* enum_class = G_ENUM_CLASS (
214
 
                g_type_class_ref (pspec->value_type));
215
 
            gint integer;
216
 
            g_object_get (settings, property, &integer, NULL);
217
 
            GEnumValue* enum_value = g_enum_get_value (enum_class, integer);
218
 
            g_key_file_set_string (key_file, "settings", property,
219
 
                                   enum_value->value_name);
220
 
        }
221
 
        else
222
 
            g_warning (_("Unhandled settings property '%s'"), property);
223
 
    }
224
 
    gboolean saved = sokoke_key_file_save_to_file (key_file, filename, error);
225
 
    g_key_file_free (key_file);
226
 
    return saved;
227
 
}
228
 
 
229
 
int
230
 
main (int argc, char** argv)
231
 
{
232
 
    MidoriStartup load_on_startup;
233
 
    gchar* homepage;
234
 
 
235
 
    locale_init ();
236
 
    g_set_application_name (_("midori"));
237
 
 
238
 
    // Parse cli options
239
 
    gboolean version = FALSE;
240
 
    GOptionEntry entries[] =
241
 
    {
242
 
     { "version", 'v', 0, G_OPTION_ARG_NONE, &version,
243
 
       N_("Display program version"), NULL },
244
 
     { NULL }
245
 
    };
246
 
 
247
 
    GError* error = NULL;
248
 
    if (!gtk_init_with_args (&argc, &argv, _("[URL]"), entries,
249
 
                             GETTEXT_PACKAGE, &error))
250
 
    {
251
 
        g_error_free (error);
252
 
        return 1;
253
 
    }
254
 
 
255
 
    if (version)
256
 
    {
257
 
        g_print (
258
 
          "%s %s - Copyright (c) 2007-2008 Christian Dywan\n\n"
259
 
          "GTK+2:  \t\t%s\n"
260
 
          "WebKit: \t\t%s\n"
261
 
          "Libsexy:\t\t%s\n"
262
 
          "libXML2:\t\t%s\n"
263
 
          "\n"
264
 
          "%s:\t\t%s\n"
265
 
          "\n"
266
 
          "%s\n"
267
 
          "\t%s\n"
268
 
          "%s\n"
269
 
          "\thttp://software.twotoasts.de\n",
270
 
          _("midori"), PACKAGE_VERSION,
271
 
          GTK_VER, WEBKIT_VER, LIBSEXY_VER, LIBXML_VER,
272
 
          _("Debugging"), SOKOKE_DEBUG_,
273
 
          _("Please report comments, suggestions and bugs to:"),
274
 
          PACKAGE_BUGREPORT,
275
 
          _("Check for new versions at:")
276
 
        );
277
 
        return 0;
278
 
    }
279
 
 
280
 
    // Standalone gjs support
281
 
    if (argc > 1 && argv[1] && g_str_has_suffix (argv[1], ".js"))
282
 
    {
283
 
        JSGlobalContextRef js_context = gjs_global_context_new ();
284
 
        gchar* exception = NULL;
285
 
        gjs_script_from_file (js_context, argv[1], &exception);
286
 
        JSGlobalContextRelease (js_context);
287
 
        if (!exception)
288
 
            return 0;
289
 
        printf ("%s - Exception: %s\n", argv[1], exception);
290
 
        return 1;
291
 
    }
292
 
 
293
 
    // Load configuration files
294
 
    GString* error_messages = g_string_new (NULL);
295
 
    gchar* config_path = g_build_filename (g_get_user_config_dir (),
296
 
                                           PACKAGE_NAME, NULL);
297
 
    g_mkdir_with_parents (config_path, 0755);
298
 
    gchar* config_file = g_build_filename (config_path, "config", NULL);
299
 
    error = NULL;
300
 
    MidoriWebSettings* settings = settings_new_from_file (config_file);
301
 
    katze_assign (config_file, g_build_filename (config_path, "accels", NULL));
302
 
    gtk_accel_map_load (config_file);
303
 
    katze_assign (config_file, g_build_filename (config_path, "search", NULL));
304
 
    error = NULL;
305
 
    searchEngines = search_engines_new ();
306
 
    if (!search_engines_from_file (&searchEngines, config_file, &error))
307
 
    {
308
 
        // FIXME: We may have a "file empty" error, how do we recognize that?
309
 
        /*if (error->code != G_FILE_ERROR_NOENT)
310
 
            g_string_append_printf (error_messages,
311
 
                _("The search engines couldn't be loaded. %s\n"),
312
 
                error->message);*/
313
 
        g_error_free (error);
314
 
    }
315
 
    katze_assign (config_file, g_build_filename (config_path, "bookmarks.xbel",
316
 
                                                 NULL));
317
 
    bookmarks = katze_xbel_folder_new();
318
 
    error = NULL;
319
 
    if (!katze_xbel_folder_from_file (bookmarks, config_file, &error))
320
 
    {
321
 
        if (error->code != G_FILE_ERROR_NOENT)
322
 
            g_string_append_printf (error_messages,
323
 
                _("The bookmarks couldn't be loaded. %s\n"), error->message);
324
 
        g_error_free (error);
325
 
    }
326
 
    g_free (config_file);
327
 
    KatzeXbelItem* _session = katze_xbel_folder_new ();
328
 
    g_object_get (settings, "load-on-startup", &load_on_startup, NULL);
329
 
    if (load_on_startup == MIDORI_STARTUP_LAST_OPEN_PAGES)
330
 
    {
331
 
        config_file = g_build_filename (config_path, "session.xbel", NULL);
332
 
        error = NULL;
333
 
        if (!katze_xbel_folder_from_file (_session, config_file, &error))
334
 
        {
335
 
            if (error->code != G_FILE_ERROR_NOENT)
336
 
                g_string_append_printf (error_messages,
337
 
                    _("The session couldn't be loaded. %s\n"), error->message);
338
 
            g_error_free (error);
339
 
        }
340
 
        g_free (config_file);
341
 
    }
342
 
    config_file = g_build_filename (config_path, "tabtrash.xbel", NULL);
343
 
    KatzeXbelItem* xbel_trash = katze_xbel_folder_new ();
344
 
    error = NULL;
345
 
    if (!katze_xbel_folder_from_file (xbel_trash, config_file, &error))
346
 
    {
347
 
        if (error->code != G_FILE_ERROR_NOENT)
348
 
            g_string_append_printf(error_messages,
349
 
                _("The trash couldn't be loaded. %s\n"), error->message);
350
 
        g_error_free (error);
351
 
    }
352
 
    g_free (config_file);
353
 
 
354
 
    // In case of errors
355
 
    if (error_messages->len)
356
 
    {
357
 
        GtkWidget* dialog = gtk_message_dialog_new(NULL
358
 
         , 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE
359
 
         , _("The following errors occured:"));
360
 
        gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dialog), FALSE);
361
 
        gtk_window_set_title(GTK_WINDOW(dialog), g_get_application_name());
362
 
        // FIXME: Use custom program icon
363
 
        gtk_window_set_icon_name(GTK_WINDOW(dialog), "web-browser");
364
 
        gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog)
365
 
         , "%s", error_messages->str);
366
 
        gtk_dialog_add_buttons(GTK_DIALOG(dialog)
367
 
         , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL
368
 
         , "_Ignore", GTK_RESPONSE_ACCEPT
369
 
         , NULL);
370
 
        if(gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT)
371
 
        {
372
 
            search_engines_free(searchEngines);
373
 
            katze_xbel_item_unref(bookmarks);
374
 
            katze_xbel_item_unref(_session);
375
 
            katze_xbel_item_unref(xbel_trash);
376
 
            g_string_free(error_messages, TRUE);
377
 
            return 0;
378
 
        }
379
 
        gtk_widget_destroy(dialog);
380
 
        /* FIXME: Since we will overwrite files that could not be loaded
381
 
                  , would we want to make backups? */
382
 
    }
383
 
    g_string_free (error_messages, TRUE);
384
 
 
385
 
    // TODO: Handle any number of separate uris from argv
386
 
    // Open as many tabs as we have uris, seperated by pipes
387
 
    gchar* uri = argc > 1 ? strtok (g_strdup(argv[1]), "|") : NULL;
388
 
    while (uri != NULL)
389
 
    {
390
 
        KatzeXbelItem* item = katze_xbel_bookmark_new ();
391
 
        gchar* uri_ready = sokoke_magic_uri (uri, NULL);
392
 
        katze_xbel_bookmark_set_href (item, uri_ready);
393
 
        g_free (uri_ready);
394
 
        katze_xbel_folder_append_item (_session, item);
395
 
        uri = strtok (NULL, "|");
396
 
    }
397
 
    g_free (uri);
398
 
 
399
 
    if (katze_xbel_folder_is_empty (_session))
400
 
    {
401
 
        KatzeXbelItem* item = katze_xbel_bookmark_new ();
402
 
        if (load_on_startup == MIDORI_STARTUP_BLANK_PAGE)
403
 
            katze_xbel_bookmark_set_href (item, "");
404
 
        else
405
 
        {
406
 
            g_object_get (settings, "homepage", &homepage, NULL);
407
 
            katze_xbel_bookmark_set_href (item, homepage);
408
 
            g_free (homepage);
409
 
        }
410
 
        katze_xbel_folder_prepend_item (_session, item);
411
 
    }
412
 
    g_free (config_path);
413
 
 
414
 
    stock_items_init ();
415
 
 
416
 
    MidoriApp* app = midori_app_new ();
417
 
    g_object_set (app, "settings", settings, NULL);
418
 
 
419
 
    MidoriTrash* trash = midori_app_get_trash (app);
420
 
    guint n = katze_xbel_folder_get_n_items (xbel_trash);
421
 
    guint i;
422
 
    for (i = 0; i < n; i++)
423
 
    {
424
 
        KatzeXbelItem* item = katze_xbel_folder_get_nth_item (xbel_trash, i);
425
 
        midori_trash_prepend_xbel_item (trash, item);
426
 
    }
427
 
 
428
 
    MidoriBrowser* browser = g_object_new (MIDORI_TYPE_BROWSER,
429
 
                                           "settings", settings,
430
 
                                           "trash", trash,
431
 
                                           NULL);
432
 
    g_signal_emit_by_name (app, "add-browser", browser);
433
 
 
434
 
    gtk_widget_show (GTK_WIDGET (browser));
435
 
 
436
 
    KatzeXbelItem* session = katze_xbel_folder_new ();
437
 
    n = katze_xbel_folder_get_n_items (_session);
438
 
    for (i = 0; i < n; i++)
439
 
    {
440
 
        KatzeXbelItem* item = katze_xbel_folder_get_nth_item (_session, i);
441
 
        midori_browser_add_xbel_item (browser, item);
442
 
    }
443
 
    // FIXME: Switch to the last active page
444
 
    KatzeXbelItem* item = katze_xbel_folder_get_nth_item (_session, 0);
445
 
    if (!strcmp (katze_xbel_bookmark_get_href (item), ""))
446
 
        midori_browser_activate_action (browser, "Location");
447
 
    katze_xbel_item_unref (_session);
448
 
 
449
 
    // Load extensions
450
 
    JSGlobalContextRef js_context = gjs_global_context_new ();
451
 
    // FIXME: We want to honor system installed addons as well
452
 
    gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME,
453
 
                                          "extensions", NULL);
454
 
    GDir* addon_dir = g_dir_open (addon_path, 0, NULL);
455
 
    if (addon_dir)
456
 
    {
457
 
        const gchar* filename;
458
 
        while ((filename = g_dir_read_name (addon_dir)))
459
 
        {
460
 
            gchar* fullname = g_build_filename (addon_path, filename, NULL);
461
 
            gchar* exception = NULL;
462
 
            gjs_script_from_file (js_context, fullname, &exception);
463
 
            if (exception)
464
 
            // FIXME: Do we want to print this somewhere else?
465
 
            // FIXME Convert the filename to UTF8
466
 
                printf ("%s - Exception: %s\n", filename, exception);
467
 
            g_free (fullname);
468
 
        }
469
 
        g_dir_close (addon_dir);
470
 
    }
471
 
 
472
 
    gtk_main ();
473
 
 
474
 
    JSGlobalContextRelease (js_context);
475
 
 
476
 
    // Save configuration files
477
 
    config_path = g_build_filename (g_get_user_config_dir(), PACKAGE_NAME,
478
 
                                    NULL);
479
 
    g_mkdir_with_parents (config_path, 0755);
480
 
    config_file = g_build_filename (config_path, "search", NULL);
481
 
    error = NULL;
482
 
    if (!search_engines_to_file (searchEngines, config_file, &error))
483
 
    {
484
 
        g_warning (_("The search engines couldn't be saved. %s"), error->message);
485
 
        g_error_free (error);
486
 
    }
487
 
    search_engines_free(searchEngines);
488
 
    g_free (config_file);
489
 
    config_file = g_build_filename (config_path, "bookmarks.xbel", NULL);
490
 
    error = NULL;
491
 
    if (!katze_xbel_folder_to_file (bookmarks, config_file, &error))
492
 
    {
493
 
        g_warning (_("The bookmarks couldn't be saved. %s"), error->message);
494
 
        g_error_free (error);
495
 
    }
496
 
    katze_xbel_item_unref(bookmarks);
497
 
    g_free (config_file);
498
 
    config_file = g_build_filename (config_path, "tabtrash.xbel", NULL);
499
 
    error = NULL;
500
 
    if (!katze_xbel_folder_to_file (xbel_trash, config_file, &error))
501
 
    {
502
 
        g_warning (_("The trash couldn't be saved. %s"), error->message);
503
 
        g_error_free (error);
504
 
    }
505
 
    katze_xbel_item_unref (xbel_trash);
506
 
    g_object_get (settings, "load-on-startup", &load_on_startup, NULL);
507
 
    if(load_on_startup == MIDORI_STARTUP_LAST_OPEN_PAGES)
508
 
    {
509
 
        katze_assign (config_file, g_build_filename (config_path,
510
 
                                                     "session.xbel", NULL));
511
 
        error = NULL;
512
 
        if (!katze_xbel_folder_to_file (session, config_file, &error))
513
 
        {
514
 
            g_warning (_("The session couldn't be saved. %s"), error->message);
515
 
            g_error_free (error);
516
 
        }
517
 
    }
518
 
    katze_xbel_item_unref (session);
519
 
    katze_assign (config_file, g_build_filename (config_path, "config", NULL));
520
 
    error = NULL;
521
 
    if (!settings_save_to_file (settings, config_file, &error))
522
 
    {
523
 
        g_warning (_("The configuration couldn't be saved. %s"), error->message);
524
 
        g_error_free (error);
525
 
    }
526
 
    katze_assign (config_file, g_build_filename (config_path, "accels", NULL));
527
 
    gtk_accel_map_save (config_file);
528
 
    g_free (config_file);
529
 
    g_free (config_path);
530
 
    return 0;
531
 
}