2
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
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.
9
See the file COPYING for the full license text.
17
#include "midori-app.h"
18
#include "midori-websettings.h"
19
#include "midori-trash.h"
20
#include "midori-browser.h"
23
#include <katze/katze.h>
35
static void stock_items_init(void)
37
static GtkStockItem items[] =
40
{ STOCK_LOCK_SECURE },
41
{ STOCK_LOCK_BROKEN },
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 },
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 },
60
GtkIconFactory* factory = gtk_icon_factory_new();
62
for(i = 0; i < (guint)G_N_ELEMENTS(items); i++)
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);
72
gtk_stock_add_static(items, G_N_ELEMENTS(items));
73
gtk_icon_factory_add_default(factory);
74
g_object_unref(factory);
81
bindtextdomain (GETTEXT_PACKAGE, MIDORI_LOCALEDIR);
82
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
83
textdomain (GETTEXT_PACKAGE);
87
static MidoriWebSettings*
88
settings_new_from_file (const gchar* filename)
90
MidoriWebSettings* settings = midori_web_settings_new ();
91
GKeyFile* key_file = g_key_file_new ();
93
if (!g_key_file_load_from_file (key_file, filename,
94
G_KEY_FILE_KEEP_COMMENTS, &error))
96
if (error->code != G_FILE_ERROR_NOENT)
97
printf (_("The configuration couldn't be loaded. %s\n"),
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++)
106
GParamSpec* pspec = pspecs[i];
107
if (!(pspec->flags & G_PARAM_WRITABLE))
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)
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);
119
else if (type == G_TYPE_PARAM_INT)
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);
126
else if (type == G_TYPE_PARAM_FLOAT)
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);
133
else if (type == G_TYPE_PARAM_BOOLEAN)
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);
140
else if (type == G_TYPE_PARAM_ENUM)
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);
151
g_object_set (settings, property, enum_value->value, NULL);
153
g_warning (_("Value '%s' is invalid for %s"),
157
g_type_class_unref (enum_class);
160
g_warning (_("Unhandled settings value '%s'"), property);
166
settings_save_to_file (MidoriWebSettings* settings,
167
const gchar* filename,
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++)
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))
181
gchar* comment = g_strdup_printf ("# %s", property);
182
g_key_file_set_string (key_file, "settings", comment, "");
186
if (type == G_TYPE_PARAM_STRING)
189
g_object_get (settings, property, &string, NULL);
190
g_key_file_set_string (key_file, "settings", property,
191
string ? string : "");
193
else if (type == G_TYPE_PARAM_INT)
196
g_object_get (settings, property, &integer, NULL);
197
g_key_file_set_integer (key_file, "settings", property, integer);
199
else if (type == G_TYPE_PARAM_FLOAT)
202
g_object_get (settings, property, &number, NULL);
203
g_key_file_set_double (key_file, "settings", property, number);
205
else if (type == G_TYPE_PARAM_BOOLEAN)
208
g_object_get (settings, property, &boolean, NULL);
209
g_key_file_set_boolean (key_file, "settings", property, boolean);
211
else if (type == G_TYPE_PARAM_ENUM)
213
GEnumClass* enum_class = G_ENUM_CLASS (
214
g_type_class_ref (pspec->value_type));
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);
222
g_warning (_("Unhandled settings property '%s'"), property);
224
gboolean saved = sokoke_key_file_save_to_file (key_file, filename, error);
225
g_key_file_free (key_file);
230
main (int argc, char** argv)
232
MidoriStartup load_on_startup;
236
g_set_application_name (_("midori"));
239
gboolean version = FALSE;
240
GOptionEntry entries[] =
242
{ "version", 'v', 0, G_OPTION_ARG_NONE, &version,
243
N_("Display program version"), NULL },
247
GError* error = NULL;
248
if (!gtk_init_with_args (&argc, &argv, _("[URL]"), entries,
249
GETTEXT_PACKAGE, &error))
251
g_error_free (error);
258
"%s %s - Copyright (c) 2007-2008 Christian Dywan\n\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:"),
275
_("Check for new versions at:")
280
// Standalone gjs support
281
if (argc > 1 && argv[1] && g_str_has_suffix (argv[1], ".js"))
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);
289
printf ("%s - Exception: %s\n", argv[1], exception);
293
// Load configuration files
294
GString* error_messages = g_string_new (NULL);
295
gchar* config_path = g_build_filename (g_get_user_config_dir (),
297
g_mkdir_with_parents (config_path, 0755);
298
gchar* config_file = g_build_filename (config_path, "config", 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));
305
searchEngines = search_engines_new ();
306
if (!search_engines_from_file (&searchEngines, config_file, &error))
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"),
313
g_error_free (error);
315
katze_assign (config_file, g_build_filename (config_path, "bookmarks.xbel",
317
bookmarks = katze_xbel_folder_new();
319
if (!katze_xbel_folder_from_file (bookmarks, config_file, &error))
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);
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)
331
config_file = g_build_filename (config_path, "session.xbel", NULL);
333
if (!katze_xbel_folder_from_file (_session, config_file, &error))
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);
340
g_free (config_file);
342
config_file = g_build_filename (config_path, "tabtrash.xbel", NULL);
343
KatzeXbelItem* xbel_trash = katze_xbel_folder_new ();
345
if (!katze_xbel_folder_from_file (xbel_trash, config_file, &error))
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);
352
g_free (config_file);
355
if (error_messages->len)
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
370
if(gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT)
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);
379
gtk_widget_destroy(dialog);
380
/* FIXME: Since we will overwrite files that could not be loaded
381
, would we want to make backups? */
383
g_string_free (error_messages, TRUE);
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;
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);
394
katze_xbel_folder_append_item (_session, item);
395
uri = strtok (NULL, "|");
399
if (katze_xbel_folder_is_empty (_session))
401
KatzeXbelItem* item = katze_xbel_bookmark_new ();
402
if (load_on_startup == MIDORI_STARTUP_BLANK_PAGE)
403
katze_xbel_bookmark_set_href (item, "");
406
g_object_get (settings, "homepage", &homepage, NULL);
407
katze_xbel_bookmark_set_href (item, homepage);
410
katze_xbel_folder_prepend_item (_session, item);
412
g_free (config_path);
416
MidoriApp* app = midori_app_new ();
417
g_object_set (app, "settings", settings, NULL);
419
MidoriTrash* trash = midori_app_get_trash (app);
420
guint n = katze_xbel_folder_get_n_items (xbel_trash);
422
for (i = 0; i < n; i++)
424
KatzeXbelItem* item = katze_xbel_folder_get_nth_item (xbel_trash, i);
425
midori_trash_prepend_xbel_item (trash, item);
428
MidoriBrowser* browser = g_object_new (MIDORI_TYPE_BROWSER,
429
"settings", settings,
432
g_signal_emit_by_name (app, "add-browser", browser);
434
gtk_widget_show (GTK_WIDGET (browser));
436
KatzeXbelItem* session = katze_xbel_folder_new ();
437
n = katze_xbel_folder_get_n_items (_session);
438
for (i = 0; i < n; i++)
440
KatzeXbelItem* item = katze_xbel_folder_get_nth_item (_session, i);
441
midori_browser_add_xbel_item (browser, item);
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);
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,
454
GDir* addon_dir = g_dir_open (addon_path, 0, NULL);
457
const gchar* filename;
458
while ((filename = g_dir_read_name (addon_dir)))
460
gchar* fullname = g_build_filename (addon_path, filename, NULL);
461
gchar* exception = NULL;
462
gjs_script_from_file (js_context, fullname, &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);
469
g_dir_close (addon_dir);
474
JSGlobalContextRelease (js_context);
476
// Save configuration files
477
config_path = g_build_filename (g_get_user_config_dir(), PACKAGE_NAME,
479
g_mkdir_with_parents (config_path, 0755);
480
config_file = g_build_filename (config_path, "search", NULL);
482
if (!search_engines_to_file (searchEngines, config_file, &error))
484
g_warning (_("The search engines couldn't be saved. %s"), error->message);
485
g_error_free (error);
487
search_engines_free(searchEngines);
488
g_free (config_file);
489
config_file = g_build_filename (config_path, "bookmarks.xbel", NULL);
491
if (!katze_xbel_folder_to_file (bookmarks, config_file, &error))
493
g_warning (_("The bookmarks couldn't be saved. %s"), error->message);
494
g_error_free (error);
496
katze_xbel_item_unref(bookmarks);
497
g_free (config_file);
498
config_file = g_build_filename (config_path, "tabtrash.xbel", NULL);
500
if (!katze_xbel_folder_to_file (xbel_trash, config_file, &error))
502
g_warning (_("The trash couldn't be saved. %s"), error->message);
503
g_error_free (error);
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)
509
katze_assign (config_file, g_build_filename (config_path,
510
"session.xbel", NULL));
512
if (!katze_xbel_folder_to_file (session, config_file, &error))
514
g_warning (_("The session couldn't be saved. %s"), error->message);
515
g_error_free (error);
518
katze_xbel_item_unref (session);
519
katze_assign (config_file, g_build_filename (config_path, "config", NULL));
521
if (!settings_save_to_file (settings, config_file, &error))
523
g_warning (_("The configuration couldn't be saved. %s"), error->message);
524
g_error_free (error);
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);