From e1f62329f1d3ec037b398cf6148695063936f2ea Mon Sep 17 00:00:00 2001 From: Christian Dywan Date: Mon, 10 Mar 2008 22:26:09 +0100 Subject: [PATCH] Initial refactoring work, regressions expected The 'browser' struct is superseded by MidoriBrowser, which actually represents a window that holds pages, i.e. tabs. The tabs are currently of the type MidoriWebView, which is a slightly enhanced WebView. Also MidoriWebSettings is introduced to hold additional settings that Midori needs. The other two new classes are MidoriTrash, representing closed tabs and windows and MidoriPanel, representing the side panel. The refactoring allows for several features to be much more easily implemented, such as full support for multiple windows and instant saving of modified files, such as bookmarks or the session. Regressions are expected and not everything is done yet. --- HACKING | 20 +- katze/katze-throbber.c | 6 +- katze/katze-throbber.h | 3 +- src/Makefile.am | 7 +- src/browser.c | 1775 ---------------------- src/browser.h | 600 -------- src/global.h | 18 +- src/helpers.c | 287 +--- src/helpers.h | 61 +- src/main.c | 153 +- src/midori-browser.c | 2986 ++++++++++++++++++++++++++++++++++++++ src/midori-browser.h | 90 ++ src/midori-panel.c | 515 +++++++ src/midori-panel.h | 90 ++ src/midori-trash.c | 327 +++++ src/midori-trash.h | 85 ++ src/midori-websettings.c | 200 +++ src/midori-websettings.h | 89 ++ src/midori-webview.c | 1039 +++++++++++++ src/midori-webview.h | 118 ++ src/prefs.c | 53 +- src/prefs.h | 7 +- src/search.c | 2 +- src/sokoke.c | 95 -- src/sokoke.h | 21 - src/ui.h | 242 --- src/webSearch.c | 43 +- src/webSearch.h | 18 +- src/webView.c | 376 ----- src/webView.h | 87 -- 30 files changed, 5740 insertions(+), 3673 deletions(-) delete mode 100644 src/browser.c delete mode 100644 src/browser.h mode change 100755 => 100644 src/main.c create mode 100644 src/midori-browser.c create mode 100644 src/midori-browser.h create mode 100644 src/midori-panel.c create mode 100644 src/midori-panel.h create mode 100644 src/midori-trash.c create mode 100644 src/midori-trash.h create mode 100644 src/midori-websettings.c create mode 100644 src/midori-websettings.h create mode 100644 src/midori-webview.c create mode 100644 src/midori-webview.h delete mode 100644 src/webView.c delete mode 100644 src/webView.h diff --git a/HACKING b/HACKING index 22c846aa..ae54476f 100644 --- a/HACKING +++ b/HACKING @@ -21,16 +21,16 @@ Source file example: return; #ifdef BAR_STRICT - if(bar == FOO_N) + if (bar == FOO_N) { - g_print("illegal value for 'bar'.\n"); + g_print ("illegal value for 'bar'.\n"); return; } #endif // this is an example gint n; - switch(bar) + switch (bar) { case FOO_FOO: n = bar + 1; @@ -43,9 +43,9 @@ Source file example: } guint i; - for(i = 0; i < n; i++) + for (i = 0; i < n; i++) { - g_print("%s\n", foo); + g_print ("%s\n", foo); } } @@ -74,12 +74,18 @@ Header file example: typedef struct { - FooEnum fooBar; + FooEnum foo_bar; } FooStruct; // -- Declarations void - foobar(FooEnum, const gchar*); + foo_bar (FooEnum bar, + const gchar* foo); + + const gchar* + foo_foo (FooStruct foo_struct, + guint number, + gboolean flag); #endif /* !__FOO_H__ */ diff --git a/katze/katze-throbber.c b/katze/katze-throbber.c index fcaae5e6..0565f345 100644 --- a/katze/katze-throbber.c +++ b/katze/katze-throbber.c @@ -222,11 +222,9 @@ katze_throbber_destroy (GtkObject *object) KatzeThrobberPrivate* priv = throbber->priv; katze_assign (priv->icon_name, NULL); - if (priv->pixbuf) - katze_object_assign (priv->pixbuf, NULL); + katze_object_assign (priv->pixbuf, NULL); katze_assign (priv->static_icon_name, NULL); - if (priv->static_pixbuf) - katze_object_assign (priv->static_pixbuf, NULL); + katze_object_assign (priv->static_pixbuf, NULL); katze_assign (priv->static_stock_id, NULL); GTK_OBJECT_CLASS (katze_throbber_parent_class)->destroy (object); diff --git a/katze/katze-throbber.h b/katze/katze-throbber.h index 17f570b8..6f1be411 100644 --- a/katze/katze-throbber.h +++ b/katze/katze-throbber.h @@ -38,7 +38,8 @@ typedef struct _KatzeThrobberClass KatzeThrobberClass; struct _KatzeThrobber { - GtkMisc parent_object; + GtkMisc parent_instance; + KatzeThrobberPrivate* priv; }; diff --git a/src/Makefile.am b/src/Makefile.am index 2b98976a..82951045 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,11 +15,14 @@ bin_PROGRAMS = \ midori_SOURCES = \ main.c main.h \ - browser.c browser.h \ + midori-browser.c midori-browser.h \ + midori-panel.c midori-panel.h \ + midori-trash.c midori-trash.h \ + midori-webview.c midori-webview.h \ + midori-websettings.c midori-websettings.h \ prefs.c prefs.h \ webSearch.c webSearch.h \ helpers.c helpers.h \ - webView.c webView.h \ sokoke.c sokoke.h \ conf.c conf.h \ search.c search.h \ diff --git a/src/browser.c b/src/browser.c deleted file mode 100644 index 88044e39..00000000 --- a/src/browser.c +++ /dev/null @@ -1,1775 +0,0 @@ -/* - Copyright (C) 2007-2008 Christian Dywan - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - See the file COPYING for the full license text. -*/ - -#include "browser.h" - -#include "helpers.h" -#include "prefs.h" -#include "sokoke.h" -#include "ui.h" -#include "webView.h" -#include "webSearch.h" -#include "../katze/katze.h" - -#include -#include - -// -- GTK+ signal handlers begin here - -void on_action_window_new_activate(GtkAction* action, CBrowser* browser) -{ - browser_new(NULL); -} - -void on_action_tab_new_activate(GtkAction* action, CBrowser* browser) -{ - browser_new(browser); - update_browser_actions(browser); -} - -void on_action_open_activate(GtkAction* action, CBrowser* browser) -{ - GtkWidget* dialog = gtk_file_chooser_dialog_new("Open file" - , GTK_WINDOW(browser->window) - , GTK_FILE_CHOOSER_ACTION_OPEN - , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL - , GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT - , NULL); - gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_OPEN); - if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - gchar* sFilename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - webView_open(get_nth_webView(-1, browser), sFilename); - g_free(sFilename); - } - gtk_widget_destroy(dialog); -} - -void on_action_tab_close_activate(GtkAction* action, CBrowser* browser) -{ - webView_close(get_nth_webView(-1, browser), browser); -} - -void on_action_window_close_activate(GtkAction* action, CBrowser* browser) -{ - gtk_widget_destroy(browser->window); -} - -void on_action_quit_activate(GtkAction* action, CBrowser* browser) -{ - gtk_main_quit(); -} - -void on_action_edit_activate(GtkAction* action, CBrowser* browser) -{ - update_edit_items(browser); -} - -void on_action_cut_activate(GtkAction* action, CBrowser* browser) -{ - GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window)); - if(G_LIKELY(widget)) - g_signal_emit_by_name(widget, "cut-clipboard"); -} - -void on_action_copy_activate(GtkAction* action, CBrowser* browser) -{ - GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window)); - if(G_LIKELY(widget)) - g_signal_emit_by_name(widget, "copy-clipboard"); -} - -void on_action_paste_activate(GtkAction* action, CBrowser* browser) -{ - GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window)); - if(G_LIKELY(widget)) - g_signal_emit_by_name(widget, "paste-clipboard"); -} - -void on_action_delete_activate(GtkAction* action, CBrowser* browser) -{ - GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window)); - if(G_LIKELY(widget)) - { - if(WEBKIT_IS_WEB_VIEW(widget)) - webkit_web_view_delete_selection(WEBKIT_WEB_VIEW(widget)); - else if(GTK_IS_EDITABLE(widget)) - gtk_editable_delete_selection(GTK_EDITABLE(widget)); - } -} - -void on_action_selectAll_activate(GtkAction* action, CBrowser* browser) -{ - GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window)); - if(G_LIKELY(widget)) - { - if(GTK_IS_ENTRY(widget)) - gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1); - else - g_signal_emit_by_name(widget, "select-all"); - } -} - -void on_action_find_activate(GtkAction* action, CBrowser* browser) -{ - if(GTK_WIDGET_VISIBLE(browser->findbox)) - { - GtkWidget* webView = get_nth_webView(-1, browser); - webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(webView)); - gtk_toggle_tool_button_set_active( - GTK_TOGGLE_TOOL_BUTTON(browser->findbox_highlight), FALSE); - gtk_widget_hide(browser->findbox); - } - else - { - GtkWidget* icon = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->findbox_text) - , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(icon)); - gtk_entry_set_text(GTK_ENTRY(browser->findbox_text), ""); - gtk_widget_show(browser->findbox); - gtk_widget_grab_focus(GTK_WIDGET(browser->findbox_text)); - } -} - -static void findbox_find(gboolean forward, CBrowser* browser) -{ - const gchar* text = gtk_entry_get_text(GTK_ENTRY(browser->findbox_text)); - const gboolean caseSensitive = gtk_toggle_tool_button_get_active( - GTK_TOGGLE_TOOL_BUTTON(browser->findbox_case)); - GtkWidget* webView = get_nth_webView(-1, browser); - if(GTK_WIDGET_VISIBLE(browser->findbox)) - webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(webView)); - gboolean found = webkit_web_view_search_text(WEBKIT_WEB_VIEW(webView) - , text, caseSensitive, forward, TRUE); - if(GTK_WIDGET_VISIBLE(browser->findbox)) - { - GtkWidget* icon; - if(found) - icon = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); - else - icon = gtk_image_new_from_stock(GTK_STOCK_STOP, GTK_ICON_SIZE_MENU); - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->findbox_text) - , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(icon)); - webkit_web_view_mark_text_matches(WEBKIT_WEB_VIEW(webView), text, caseSensitive, 0); - const gboolean highlight = gtk_toggle_tool_button_get_active( - GTK_TOGGLE_TOOL_BUTTON(browser->findbox_highlight)); - webkit_web_view_set_highlight_text_matches(WEBKIT_WEB_VIEW(webView), highlight); - } -} - -void on_action_find_next_activate(GtkAction* action, CBrowser* browser) -{ - findbox_find(TRUE, browser); -} - -void on_action_find_previous_activate(GtkAction* action, CBrowser* browser) -{ - findbox_find(FALSE, browser); -} - -void on_findbox_highlight_toggled(GtkToggleToolButton* toolitem, CBrowser* browser) -{ - GtkWidget* webView = get_nth_webView(-1, browser); - const gboolean highlight = gtk_toggle_tool_button_get_active(toolitem); - webkit_web_view_set_highlight_text_matches(WEBKIT_WEB_VIEW(webView), highlight); -} - -void on_findbox_button_close_clicked(GtkWidget* widget, CBrowser* browser) -{ - gtk_widget_hide(browser->findbox); -} - -void on_action_preferences_activate(GtkAction* action, CBrowser* browser) -{ - // Show the preferences dialog. Create it if necessary. - static GtkWidget* dialog; - if(GTK_IS_DIALOG(dialog)) - gtk_window_present(GTK_WINDOW(dialog)); - else - { - dialog = prefs_preferences_dialog_new(browser); - gtk_widget_show(dialog); - } -} - -static void on_toolbar_navigation_notify_style(GObject* object, GParamSpec* arg1 - , CBrowser* browser) -{ - if(config->toolbarStyle == CONFIG_TOOLBAR_DEFAULT) - { - gtk_toolbar_set_style(GTK_TOOLBAR(browser->navibar) - , config_to_toolbarstyle(config->toolbarStyle)); - } -} - -void on_action_toolbar_navigation_activate(GtkToggleAction* action, CBrowser* browser) -{ - config->toolbarNavigation = gtk_toggle_action_get_active(action); - sokoke_widget_set_visible(browser->navibar, config->toolbarNavigation); -} - -void on_action_toolbar_bookmarks_activate(GtkToggleAction* action, CBrowser* browser) -{ - config->toolbarBookmarks = gtk_toggle_action_get_active(action); - sokoke_widget_set_visible(browser->bookmarkbar, config->toolbarBookmarks); -} - -void on_action_toolbar_downloads_activate(GtkToggleAction* action, CBrowser* browser) -{ - /*config->toolbarDownloads = gtk_toggle_action_get_active(action); - sokoke_widget_set_visible(browser->downloadbar, config->toolbarDownloads);*/ -} - -void on_action_toolbar_status_activate(GtkToggleAction* action, CBrowser* browser) -{ - config->toolbarStatus = gtk_toggle_action_get_active(action); - sokoke_widget_set_visible(browser->statusbar, config->toolbarStatus); -} - -void on_action_refresh_activate(GtkAction* action, CBrowser* browser) -{ - /*GdkModifierType state = (GdkModifierType)0; - gint x, y; gdk_window_get_pointer(NULL, &x, &y, &state); - gboolean fromCache = state & GDK_SHIFT_MASK;*/ - webkit_web_view_reload(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser))); -} - -void on_action_refresh_stop_activate(GtkAction* action, CBrowser* browser) -{ - gchar* stockId; g_object_get(action, "stock-id", &stockId, NULL); - // Refresh or stop, depending on the stock id - if(!strcmp(stockId, GTK_STOCK_REFRESH)) - { - /*GdkModifierType state = (GdkModifierType)0; - gint x, y; gdk_window_get_pointer(NULL, &x, &y, &state); - gboolean fromCache = state & GDK_SHIFT_MASK;*/ - webkit_web_view_reload(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser))); - } - else - webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser))); - g_free(stockId); -} - -void on_action_stop_activate(GtkAction* action, CBrowser* browser) -{ - webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser))); -} - -void on_action_zoom_in_activate(GtkAction* action, CBrowser* browser) -{ - /*GtkWidget* webView = get_nth_webView(-1, browser); - const gfloat zoom = webkit_web_view_get_text_multiplier(WEBKIT_WEB_VIEW(webView)); - webkit_web_view_set_text_multiplier(WEBKIT_WEB_VIEW(webView), zoom + 0.1);*/ -} - -void on_action_zoom_out_activate(GtkAction* action, CBrowser* browser) -{ - /*GtkWidget* webView = get_nth_webView(-1, browser); - const gfloat zoom = webView_get_text_size(WEBKIT_WEB_VIEW(webView)); - webkit_web_view_set_text_multiplier(WEBKIT_WEB_VIEW(webView), zoom - 0.1);*/ -} - -void on_action_zoom_normal_activate(GtkAction* action, CBrowser* browser) -{ - //webkit_web_view_set_text_multiplier(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser)), 1); -} - -void on_action_source_view_activate(GtkAction* action, CBrowser* browser) -{ - /*GtkWidget* webView = get_nth_webView(-1, browser); - gchar* source = webkit_web_view_copy_source(WEBKIT_WEB_VIEW(webView)); - webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(webView), source, ""); - g_free(source);*/ -} - -void on_action_fullscreen_activate(GtkAction* action, CBrowser* browser) -{ - GdkWindowState state = gdk_window_get_state(browser->window->window); - if(state & GDK_WINDOW_STATE_FULLSCREEN) - gtk_window_unfullscreen(GTK_WINDOW(browser->window)); - else - gtk_window_fullscreen(GTK_WINDOW(browser->window)); -} - -void on_action_back_activate(GtkAction* action, CBrowser* browser) -{ - webkit_web_view_go_back(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser))); -} - -void on_action_forward_activate(GtkAction* action, CBrowser* browser) -{ - webkit_web_view_go_forward(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser))); -} - -void on_action_home_activate(GtkAction* action, CBrowser* browser) -{ - webView_open(get_nth_webView(-1, browser), config->homepage); -} - -void on_action_location_activate(GtkAction* action, CBrowser* browser) -{ - if(GTK_WIDGET_VISIBLE(browser->navibar)) - gtk_widget_grab_focus(browser->location); - else - { - // TODO: We should offer all of the toolbar location's features here - GtkWidget* dialog; - dialog = gtk_dialog_new_with_buttons("Open location" - , GTK_WINDOW(browser->window) - , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR - , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL - , GTK_STOCK_JUMP_TO, GTK_RESPONSE_ACCEPT - , NULL); - gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_JUMP_TO); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); - gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 5); - GtkWidget* hbox = gtk_hbox_new(FALSE, 8); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); - GtkWidget* label = gtk_label_new_with_mnemonic("_Location:"); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - GtkWidget* entry = gtk_entry_new(); - gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); - gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); - gtk_widget_show_all(hbox); - gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); - if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - gtk_entry_set_text(GTK_ENTRY(browser->location) - , gtk_entry_get_text(GTK_ENTRY(entry))); - GdkEventKey event; - event.keyval = GDK_Return; - on_location_key_down(browser->location, &event, browser); - } - gtk_widget_destroy(dialog); - } -} - -void on_action_webSearch_activate(GtkAction* action, CBrowser* browser) -{ - if(GTK_WIDGET_VISIBLE(browser->webSearch) - && GTK_WIDGET_VISIBLE(browser->navibar)) - gtk_widget_grab_focus(browser->webSearch); - else - { - // TODO: We should offer all of the toolbar search's features here - GtkWidget* dialog = gtk_dialog_new_with_buttons("Web search" - , GTK_WINDOW(browser->window) - , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR - , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL - , GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT - , NULL); - gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_FIND); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); - gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 5); - GtkWidget* hbox = gtk_hbox_new(FALSE, 8); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); - GtkWidget* label = gtk_label_new_with_mnemonic("_Location:"); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - GtkWidget* entry = gtk_entry_new(); - gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); - gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); - gtk_widget_show_all(hbox); - gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); - if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - gtk_entry_set_text(GTK_ENTRY(browser->webSearch) - , gtk_entry_get_text(GTK_ENTRY(entry))); - on_webSearch_activate(browser->webSearch, browser); - } - gtk_widget_destroy(dialog); - } -} - -void on_menu_tabsClosed_activate(GtkWidget* widget, CBrowser* browser) -{ - GtkWidget* menu = gtk_menu_new(); - guint n = katze_xbel_folder_get_n_items(tabtrash); - GtkWidget* menuitem; - guint i; - for(i = 0; i < n; i++) - { - KatzeXbelItem* item = katze_xbel_folder_get_nth_item(tabtrash, i); - const gchar* title = katze_xbel_item_get_title(item); - const gchar* uri = katze_xbel_bookmark_get_href(item); - menuitem = gtk_image_menu_item_new_with_label(title ? title : uri); - // FIXME: Get the real icon - GtkWidget* icon = gtk_image_new_from_stock(GTK_STOCK_FILE, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), icon); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - g_object_set_data(G_OBJECT(menuitem), "KatzeXbelItem", item); - g_signal_connect(menuitem, "activate", G_CALLBACK(on_menu_tabsClosed_item_activate), browser); - gtk_widget_show(menuitem); - } - - menuitem = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - gtk_widget_show(menuitem); - GtkAction* action = gtk_action_group_get_action( - browser->actiongroup, "TabsClosedClear"); - menuitem = gtk_action_create_menu_item(action); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - gtk_widget_show(menuitem); - sokoke_widget_popup(widget, GTK_MENU(menu), NULL); -} - -void on_menu_tabsClosed_item_activate(GtkWidget* menuitem, CBrowser* browser) -{ - // Create a new webView with an uri which has been closed before - KatzeXbelItem* item = g_object_get_data(G_OBJECT(menuitem), "KatzeXbelItem"); - const gchar* uri = katze_xbel_bookmark_get_href(item); - CBrowser* curBrowser = browser_new(browser); - webView_open(curBrowser->webView, uri); - katze_xbel_item_unref(item); - update_browser_actions(curBrowser); -} - -void on_action_tabsClosed_undo_activate(GtkAction* action, CBrowser* browser) -{ - // Open the most recent tabtrash item - KatzeXbelItem* item = katze_xbel_folder_get_nth_item(tabtrash, 0); - const gchar* uri = katze_xbel_bookmark_get_href(item); - CBrowser* curBrowser = browser_new(browser); - webView_open(curBrowser->webView, uri); - katze_xbel_item_unref(item); - update_browser_actions(curBrowser); -} - -void on_action_tabsClosed_clear_activate(GtkAction* action, CBrowser* browser) -{ - // Clear the closed tabs list - katze_xbel_item_unref(tabtrash); - tabtrash = katze_xbel_folder_new(); - update_browser_actions(browser); -} - -void on_action_link_tab_new_activate(GtkAction* action, CBrowser* browser) -{ - CBrowser* curBrowser = browser_new(browser); - webView_open(curBrowser->webView, browser->elementUri); -} - -void on_action_link_tab_current_activate(GtkAction* action, CBrowser* browser) -{ - webView_open(get_nth_webView(-1, browser), browser->elementUri); -} - -void on_action_link_window_new_activate(GtkAction* action, CBrowser* browser) -{ - CBrowser* curBrowser = browser_new(NULL); - webView_open(curBrowser->webView, browser->elementUri); -} - -void on_action_link_saveWith_activate(GtkAction* action, CBrowser* browser) -{ - spawn_protocol_command("download", browser->elementUri); -} - -void on_action_link_copy_activate(GtkAction* action, CBrowser* browser) -{ - GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - gtk_clipboard_set_text(clipboard, browser->elementUri, -1); -} - -static void browser_editBookmark_dialog_new(KatzeXbelItem* bookmark, CBrowser* browser) -{ - gboolean newBookmark = !bookmark; - GtkWidget* dialog = gtk_dialog_new_with_buttons( - newBookmark ? "New bookmark" : "Edit bookmark" - , GTK_WINDOW(browser->window) - , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR - , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL - , newBookmark ? GTK_STOCK_ADD : GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT - , NULL); - gtk_window_set_icon_name(GTK_WINDOW(dialog) - , newBookmark ? GTK_STOCK_ADD : GTK_STOCK_REMOVE); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); - gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 5); - GtkSizeGroup* sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - - if(newBookmark) - bookmark = katze_xbel_bookmark_new(); - - GtkWidget* hbox = gtk_hbox_new(FALSE, 8); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); - GtkWidget* label = gtk_label_new_with_mnemonic("_Title:"); - gtk_size_group_add_widget(sizegroup, label); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - GtkWidget* entry_title = gtk_entry_new(); - gtk_entry_set_activates_default(GTK_ENTRY(entry_title), TRUE); - if(!newBookmark) - { - const gchar* title = katze_xbel_item_get_title(bookmark); - gtk_entry_set_text(GTK_ENTRY(entry_title), title ? title : ""); - } - gtk_box_pack_start(GTK_BOX(hbox), entry_title, TRUE, TRUE, 0); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); - gtk_widget_show_all(hbox); - - hbox = gtk_hbox_new(FALSE, 8); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); - label = gtk_label_new_with_mnemonic("_Description:"); - gtk_size_group_add_widget(sizegroup, label); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - GtkWidget* entry_desc = gtk_entry_new(); - gtk_entry_set_activates_default(GTK_ENTRY(entry_desc), TRUE); - if(!newBookmark) - { - const gchar* desc = katze_xbel_item_get_desc(bookmark); - gtk_entry_set_text(GTK_ENTRY(entry_desc), desc ? desc : ""); - } - gtk_box_pack_start(GTK_BOX(hbox), entry_desc, TRUE, TRUE, 0); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); - gtk_widget_show_all(hbox); - - GtkWidget* entry_uri = NULL; - if(katze_xbel_item_is_bookmark(bookmark)) - { - hbox = gtk_hbox_new(FALSE, 8); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); - label = gtk_label_new_with_mnemonic("_Uri:"); - gtk_size_group_add_widget(sizegroup, label); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - entry_uri = gtk_entry_new(); - gtk_entry_set_activates_default(GTK_ENTRY(entry_uri), TRUE); - if(!newBookmark) - gtk_entry_set_text(GTK_ENTRY(entry_uri), katze_xbel_bookmark_get_href(bookmark)); - gtk_box_pack_start(GTK_BOX(hbox), entry_uri, TRUE, TRUE, 0); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); - gtk_widget_show_all(hbox); - } - - GtkWidget* combo_folder = NULL; - if(newBookmark) - { - hbox = gtk_hbox_new(FALSE, 8); - gtk_container_set_border_width(GTK_CONTAINER(hbox), 5); - label = gtk_label_new_with_mnemonic("_Folder:"); - gtk_size_group_add_widget(sizegroup, label); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - combo_folder = gtk_combo_box_new_text(); - gtk_combo_box_append_text(GTK_COMBO_BOX(combo_folder), "Root"); - gtk_widget_set_sensitive(combo_folder, FALSE); - gtk_box_pack_start(GTK_BOX(hbox), combo_folder, TRUE, TRUE, 0); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); - gtk_widget_show_all(hbox); - } - - gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); - if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) - { - katze_xbel_item_set_title(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_title))); - katze_xbel_item_set_desc(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_desc))); - if(katze_xbel_item_is_bookmark(bookmark)) - katze_xbel_bookmark_set_href(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_uri))); - - // FIXME: We want to choose a folder - if(newBookmark) - { - katze_xbel_folder_append_item(bookmarks, bookmark); - GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks); - GtkTreeModel* treemodel = gtk_tree_view_get_model(treeview); - GtkTreeIter iter; - gtk_tree_store_insert_with_values(GTK_TREE_STORE(treemodel) - , &iter, NULL, G_MAXINT, 0, bookmark, -1); - katze_xbel_item_ref(bookmark); - } - - // FIXME: update toolbar - // FIXME: Update panels in other windows - } - gtk_widget_destroy(dialog); -} - -static void on_panel_bookmarks_row_activated(GtkTreeView* treeview - , GtkTreePath* path, GtkTreeViewColumn* column, CBrowser* browser) -{ - GtkTreeModel* model = gtk_tree_view_get_model(treeview); - GtkTreeIter iter; - if(gtk_tree_model_get_iter(model, &iter, path)) - { - KatzeXbelItem* item; - gtk_tree_model_get(model, &iter, 0, &item, -1); - if(katze_xbel_item_is_bookmark(item)) - webView_open(get_nth_webView(-1, browser), katze_xbel_bookmark_get_href(item)); - } -} - -static void on_panel_bookmarks_cursor_or_row_changed(GtkTreeView* treeview - , CBrowser* browser) -{ - GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview); - if(selection) - { - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - KatzeXbelItem* item; - gtk_tree_model_get(model, &iter, 0, &item, -1); - - gboolean isSeparator = katze_xbel_item_is_separator(item); - action_set_sensitive("BookmarkEdit", !isSeparator, browser); - action_set_sensitive("BookmarkDelete", TRUE, browser); - } - else - { - action_set_sensitive("BookmarkEdit", FALSE, browser); - action_set_sensitive("BookmarkDelete", FALSE, browser); - } - } -} - -static void panel_bookmarks_popup(GtkWidget* widget, GdkEventButton* event - , KatzeXbelItem* item, CBrowser* browser) -{ - gboolean isBookmark = katze_xbel_item_is_bookmark(item); - - action_set_sensitive("BookmarkOpen", isBookmark, browser); - action_set_sensitive("BookmarkOpenTab", isBookmark, browser); - action_set_sensitive("BookmarkOpenWindow", isBookmark, browser); - - sokoke_widget_popup(widget, GTK_MENU(browser->popup_bookmark), event); -} - -static gboolean on_panel_bookmarks_button_release(GtkWidget* widget - , GdkEventButton* event, CBrowser* browser) -{ - if(event->button != 2 && event->button != 3) - return FALSE; - - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); - if(selection) - { - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - KatzeXbelItem* item; - gtk_tree_model_get(model, &iter, 0, &item, -1); - if(event->button == 2 && katze_xbel_item_is_bookmark(item)) - { - CBrowser* newBrowser = browser_new(browser); - const gchar* uri = katze_xbel_bookmark_get_href(item); - webView_open(newBrowser->webView, uri); - } - else - panel_bookmarks_popup(widget, event, item, browser); - return TRUE; - } - } - return FALSE; -} - -void on_panel_bookmarks_popup(GtkWidget* widget, CBrowser* browser) -{ - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); - if(selection) - { - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - KatzeXbelItem* item; - gtk_tree_model_get(model, &iter, 0, &item, -1); - panel_bookmarks_popup(widget, NULL, item, browser); - } - } -} - -void on_action_bookmarkOpen_activate(GtkAction* action, CBrowser* browser) -{ - GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks); - GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview); - if(selection) - { - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - KatzeXbelItem* item; - gtk_tree_model_get(model, &iter, 0, &item, -1); - if(katze_xbel_item_is_bookmark(item)) - webView_open(get_nth_webView(-1, browser) - , katze_xbel_bookmark_get_href(item)); - } - } -} - -void on_action_bookmarkOpenTab_activate(GtkAction* action, CBrowser* browser) -{ - GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks); - GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview); - if(selection) - { - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - KatzeXbelItem* item; - gtk_tree_model_get(model, &iter, 0, &item, -1); - if(katze_xbel_item_is_bookmark(item)) - { - CBrowser* newBrowser = browser_new(browser); - const gchar* uri = katze_xbel_bookmark_get_href(item); - webView_open(newBrowser->webView, uri); - } - } - } -} - -void on_action_bookmarkOpenWindow_activate(GtkAction* action, CBrowser* browser) -{ - GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks); - GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview); - if(selection) - { - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - KatzeXbelItem* item; - gtk_tree_model_get(model, &iter, 0, &item, -1); - if(katze_xbel_item_is_bookmark(item)) - { - CBrowser* newBrowser = browser_new(NULL); - const gchar* uri = katze_xbel_bookmark_get_href(item); - webView_open(newBrowser->webView, uri); - } - } - } -} - -void on_action_bookmarkEdit_activate(GtkAction* action, CBrowser* browser) -{ - GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks); - GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview); - if(selection) - { - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - KatzeXbelItem* item; - gtk_tree_model_get(model, &iter, 0, &item, -1); - if(!katze_xbel_item_is_separator(item)) - browser_editBookmark_dialog_new(item, browser); - } - } -} - -void on_action_bookmarkDelete_activate(GtkAction* action, CBrowser* browser) -{ - GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks); - GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview); - if(selection) - { - GtkTreeModel* model; - GtkTreeIter iter; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - KatzeXbelItem* item; - gtk_tree_model_get(model, &iter, 0, &item, -1); - KatzeXbelItem* parent = katze_xbel_item_get_parent(item); - katze_xbel_folder_remove_item(parent, item); - katze_xbel_item_unref(item); - } - } -} - -static void tree_store_insert_folder(GtkTreeStore* treestore, GtkTreeIter* parent - , KatzeXbelItem* folder) -{ - guint n = katze_xbel_folder_get_n_items(folder); - guint i; - for(i = 0; i < n; i++) - { - KatzeXbelItem* item = katze_xbel_folder_get_nth_item(folder, i); - GtkTreeIter iter; - gtk_tree_store_insert_with_values(treestore, &iter, parent, n, 0, item, -1); - katze_xbel_item_ref(item); - if(katze_xbel_item_is_folder(item)) - tree_store_insert_folder(treestore, &iter, item); - } -} - -static void on_bookmarks_item_render_icon(GtkTreeViewColumn* column - , GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter - , GtkWidget* treeview) -{ - KatzeXbelItem* item; - gtk_tree_model_get(model, iter, 0, &item, -1); - - if(G_UNLIKELY(!item)) - return; - if(G_UNLIKELY(!katze_xbel_item_get_parent(item))) - { - gtk_tree_store_remove(GTK_TREE_STORE(model), iter); - katze_xbel_item_unref(item); - return; - } - - // TODO: Would it be better to not do this on every redraw? - GdkPixbuf* pixbuf = NULL; - if(katze_xbel_item_is_bookmark(item)) - pixbuf = gtk_widget_render_icon(treeview, STOCK_BOOKMARK - , GTK_ICON_SIZE_MENU, NULL); - else if(katze_xbel_item_is_folder(item)) - pixbuf = gtk_widget_render_icon(treeview, GTK_STOCK_DIRECTORY - , GTK_ICON_SIZE_MENU, NULL); - g_object_set(renderer, "pixbuf", pixbuf, NULL); - if(pixbuf) - g_object_unref(pixbuf); -} - -static void on_bookmarks_item_render_text(GtkTreeViewColumn* column - , GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter - , GtkWidget* treeview) -{ - KatzeXbelItem* item; - gtk_tree_model_get(model, iter, 0, &item, -1); - - if(G_UNLIKELY(!item)) - return; - if(G_UNLIKELY(!katze_xbel_item_get_parent(item))) - { - gtk_tree_store_remove(GTK_TREE_STORE(model), iter); - katze_xbel_item_unref(item); - return; - } - - if(katze_xbel_item_is_separator(item)) - g_object_set(renderer - , "markup", "Separator", NULL); - else - g_object_set(renderer - , "markup", NULL, "text", katze_xbel_item_get_title(item), NULL); -} - -static void create_bookmark_menu(KatzeXbelItem*, GtkWidget*, CBrowser*); - -static void on_bookmark_menu_folder_activate(GtkWidget* menuitem, CBrowser* browser) -{ - GtkWidget* menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem)); - gtk_container_foreach(GTK_CONTAINER(menu), (GtkCallback)gtk_widget_destroy, NULL);//... - KatzeXbelItem* folder = (KatzeXbelItem*)g_object_get_data(G_OBJECT(menuitem), "KatzeXbelItem"); - create_bookmark_menu(folder, menu, browser); - // Remove all menuitems when the menu is hidden. - // FIXME: We really *want* the line below, but it won't work like that - //g_signal_connect_after(menu, "hide", G_CALLBACK(gtk_container_foreach), gtk_widget_destroy); - gtk_widget_show(menuitem); -} - -static void on_bookmark_toolbar_folder_activate(GtkToolItem* toolitem, CBrowser* browser) -{ - GtkWidget* menu = gtk_menu_new(); - KatzeXbelItem* folder = (KatzeXbelItem*)g_object_get_data(G_OBJECT(toolitem), "KatzeXbelItem"); - create_bookmark_menu(folder, menu, browser); - // Remove all menuitems when the menu is hidden. - // FIXME: We really *should* run the line below, but it won't work like that - //g_signal_connect(menu, "hide", G_CALLBACK(gtk_container_foreach), gtk_widget_destroy); - sokoke_widget_popup(GTK_WIDGET(toolitem), GTK_MENU(menu), NULL); -} - -void on_menu_bookmarks_item_activate(GtkWidget* widget, CBrowser* browser) -{ - KatzeXbelItem* item = (KatzeXbelItem*)g_object_get_data(G_OBJECT(widget), "KatzeXbelItem"); - webView_open(get_nth_webView(-1, browser), katze_xbel_bookmark_get_href(item)); -} - -static void create_bookmark_menu(KatzeXbelItem* folder, GtkWidget* menu, CBrowser* browser) -{ - guint n = katze_xbel_folder_get_n_items(folder); - guint i; - for(i = 0; i < n; i++) - { - KatzeXbelItem* item = katze_xbel_folder_get_nth_item(folder, i); - const gchar* title = katze_xbel_item_is_separator(item) ? "" : katze_xbel_item_get_title(item); - //const gchar* desc = katze_xbel_item_is_separator(item) ? "" : katze_xbel_item_get_desc(item); - GtkWidget* menuitem = NULL; - switch(katze_xbel_item_get_kind(item)) - { - case KATZE_XBEL_ITEM_KIND_FOLDER: - // FIXME: what about katze_xbel_folder_is_folded? - menuitem = gtk_image_menu_item_new_with_label(title); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem) - , gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU)); - GtkWidget* _menu = gtk_menu_new(); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), _menu); - g_signal_connect(menuitem, "activate" - , G_CALLBACK(on_bookmark_menu_folder_activate), browser); - g_object_set_data(G_OBJECT(menuitem), "KatzeXbelItem", item); - break; - case KATZE_XBEL_ITEM_KIND_BOOKMARK: - menuitem = menu_item_new(title, STOCK_BOOKMARK - , G_CALLBACK(on_menu_bookmarks_item_activate), TRUE, browser); - g_object_set_data(G_OBJECT(menuitem), "KatzeXbelItem", item); - break; - case KATZE_XBEL_ITEM_KIND_SEPARATOR: - menuitem = gtk_separator_menu_item_new(); - break; - default: - g_warning("Unknown xbel item kind"); - } - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - gtk_widget_show(menuitem); - } -} - -void on_action_bookmark_new_activate(GtkAction* action, CBrowser* browser) -{ - browser_editBookmark_dialog_new(NULL, browser); -} - -void on_action_manageSearchEngines_activate(GtkAction* action, CBrowser* browser) -{ - // Show the Manage search engines dialog. Create it if necessary. - static GtkWidget* dialog; - if(GTK_IS_DIALOG(dialog)) - gtk_window_present(GTK_WINDOW(dialog)); - else - { - dialog = webSearch_manageSearchEngines_dialog_new(browser); - gtk_widget_show(dialog); - } -} - -void on_action_tab_previous_activate(GtkAction* action, CBrowser* browser) -{ - gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(browser->webViews)); - gtk_notebook_set_current_page(GTK_NOTEBOOK(browser->webViews), page - 1); -} - -void on_action_tab_next_activate(GtkAction* action, CBrowser* browser) -{ - // Advance one tab or jump to the first one if we are at the last one - gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(browser->webViews)); - if(page == gtk_notebook_get_n_pages(GTK_NOTEBOOK(browser->webViews)) - 1) - page = -1; - gtk_notebook_set_current_page(GTK_NOTEBOOK(browser->webViews), page + 1); -} - -void on_window_menu_item_activate(GtkImageMenuItem* widget, CBrowser* browser) -{ - gint page = get_webView_index(browser->webView, browser); - gtk_notebook_set_current_page(GTK_NOTEBOOK(browser->webViews), page); -} - -void on_action_about_activate(GtkAction* action, CBrowser* browser) -{ - gtk_show_about_dialog(GTK_WINDOW(browser->window) - , "logo-icon-name", gtk_window_get_icon_name(GTK_WINDOW(browser->window)) - , "name", PACKAGE_NAME - , "version", PACKAGE_VERSION - , "comments", "A lightweight web browser." - , "copyright", "Copyright © 2007 Christian Dywan" - , "website", "http://software.twotoasts.de" - , "authors", credits_authors - , "documenters", credits_documenters - , "artists", credits_artists - , "license", license - , "wrap-license", TRUE - //, "translator-credits", _("translator-credits") - , NULL); -} - -gboolean on_location_key_down(GtkWidget* widget, GdkEventKey* event, CBrowser* browser) -{ - switch(event->keyval) - { - case GDK_Return: - { - const gchar* uri = gtk_entry_get_text(GTK_ENTRY(widget)); - if(uri) - { - gchar* newUri = magic_uri(uri, TRUE); - // TODO: Use newUrl intermediately when completion is better - /* TODO Completion should be generated from history, that is - the uri as well as the title. */ - entry_completion_append(GTK_ENTRY(widget), uri); - webView_open(get_nth_webView(-1, browser), newUri); - g_free(newUri); - } - return TRUE; - } - case GDK_Escape: - { - GtkWidget* webView = get_nth_webView(-1, browser); - WebKitWebFrame* frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(webView)); - const gchar* uri = webkit_web_frame_get_uri(frame); - if(uri && *uri) - gtk_entry_set_text(GTK_ENTRY(widget), uri); - return TRUE; - } - } - return FALSE; -} - -void on_location_changed(GtkWidget* widget, CBrowser* browser) -{ - // Preserve changes to the uri - /*const gchar* newUri = gtk_entry_get_text(GTK_ENTRY(widget)); - katze_xbel_bookmark_set_href(browser->sessionItem, newUri);*/ - // FIXME: If we want this feature, this is the wrong approach -} - -void on_action_panels_activate(GtkToggleAction* action, CBrowser* browser) -{ - config->panelShow = gtk_toggle_action_get_active(action); - sokoke_widget_set_visible(browser->panels, config->panelShow); -} - -void on_action_panel_item_activate(GtkRadioAction* action - , GtkRadioAction* currentAction, CBrowser* browser) -{ - g_return_if_fail(GTK_IS_ACTION(action)); - // TODO: Activating again should hide the contents; how? - //gint iValue; gint iCurrentValue; - //g_object_get(G_OBJECT(action), "value", &iValue, NULL); - //g_object_get(G_OBJECT(currentAction), "value", &iCurrentValue, NULL); - //GtkWidget* parent = gtk_widget_get_parent(browser->panels_notebook); - //sokoke_widget_set_visible(parent, iCurrentValue == iValue); - /*gtk_paned_set_position(GTK_PANED(gtk_widget_get_parent(browser->panels)) - , iCurrentValue == iValue ? config->iPanelPos : 0);*/ - config->panelActive = gtk_radio_action_get_current_value(action); - gint page = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(currentAction), "iPage")); - gtk_notebook_set_current_page(GTK_NOTEBOOK(browser->panels_notebook), page); - // This is a special case where activation was not user requested. - if(!GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "once-silent"))) - { - config->panelShow = TRUE; - gtk_widget_show(browser->panels); - } - else - g_object_set_data(G_OBJECT(action), "once-silent", NULL); -} - -void on_action_openInPanel_activate(GtkAction* action, CBrowser* browser) -{ - GtkWidget* webView = get_nth_webView(-1, browser); - WebKitWebFrame* frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(webView)); - const gchar* uri = webkit_web_frame_get_uri(frame); - katze_assign(config->panelPageholder, g_strdup(uri)); - GtkAction* action_pageholder = - gtk_action_group_get_action(browser->actiongroup, "PanelPageholder"); - gint value; - g_object_get(G_OBJECT(action_pageholder), "value", &value, NULL); - sokoke_radio_action_set_current_value(GTK_RADIO_ACTION(action_pageholder), value); - gtk_widget_show(browser->panels); - webView_open(browser->panel_pageholder, config->panelPageholder); -} - - -static void on_panels_notify_position(GObject* object, GParamSpec* arg1 - , CBrowser* browser) -{ - config->winPanelPos = gtk_paned_get_position(GTK_PANED(object)); -} - -void on_panels_button_close_clicked(GtkWidget* widget, CBrowser* browser) -{ - config->panelShow = FALSE; - gtk_widget_hide(browser->panels); -} - -gboolean on_notebook_tab_mouse_up(GtkWidget* widget, GdkEventButton* event - , CBrowser* browser) -{ - if(event->button == 1 && event->type == GDK_2BUTTON_PRESS) - { - // Toggle the label visibility on double click - GtkWidget* child = gtk_bin_get_child(GTK_BIN(widget)); - GList* children = gtk_container_get_children(GTK_CONTAINER(child)); - child = (GtkWidget*)g_list_nth_data(children, 1); - gboolean visible = gtk_widget_get_child_visible(GTK_WIDGET(child)); - gtk_widget_set_child_visible(GTK_WIDGET(child), !visible); - gint a, b; sokoke_widget_get_text_size(browser->webView_name, "M", &a, &b); - gtk_widget_set_size_request(child, !visible - ? a * config->tabSize : 0, !visible ? -1 : 0); - g_list_free(children); - return TRUE; - } - else if(event->button == 2) - { - // Close the webView on middle click - webView_close(browser->webView, browser); - return TRUE; - } - - return FALSE; -} - -gboolean on_notebook_tab_close_clicked(GtkWidget* widget, CBrowser* browser) -{ - webView_close(browser->webView, browser); - return TRUE; -} - -void on_notebook_switch_page(GtkWidget* widget, GtkNotebookPage* page - , guint page_num, CBrowser* browser) -{ - GtkWidget* webView = get_nth_webView(page_num, browser); - browser = get_browser_from_webView(webView); - const gchar* uri = katze_xbel_bookmark_get_href(browser->sessionItem); - gtk_entry_set_text(GTK_ENTRY(browser->location), uri); - const gchar* title = katze_xbel_item_get_title(browser->sessionItem); - const gchar* effectiveTitle = title ? title : uri; - gchar* windowTitle = g_strconcat(effectiveTitle, " - ", PACKAGE_NAME, NULL); - gtk_window_set_title(GTK_WINDOW(browser->window), windowTitle); - g_free(windowTitle); - update_favicon(browser); - update_security(browser); - update_gui_state(browser); - update_statusbar(browser); - update_feeds(browser); - update_search_engines(browser); -} - -static void on_window_state_changed(GtkWidget* widget - , GdkEventWindowState* event, CBrowser* browser) -{ - if(event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) - { - if(event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) - { - gtk_widget_hide(browser->menubar); - g_object_set(browser->fullscreen, "stock-id" - , GTK_STOCK_LEAVE_FULLSCREEN, NULL); - gtk_widget_show(browser->fullscreen); - } - else - { - gtk_widget_show(browser->menubar); - gtk_widget_hide(browser->fullscreen); - g_object_set(browser->fullscreen, "stock-id" - , GTK_STOCK_FULLSCREEN, NULL); - } - } -} - -static void on_window_size_allocate(GtkWidget* widget, GtkAllocation* allocation - , CBrowser* browser) -{ - if(GTK_WIDGET_REALIZED(widget)) - { - GdkWindowState state = gdk_window_get_state(widget->window); - if(!(state & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN))) - { - config->winWidth = allocation->width; - config->winHeight = allocation->height; - } - } -} - -gboolean on_window_destroy(GtkWidget* widget, GdkEvent* event, CBrowser* browser) -{ - gboolean proceed = TRUE; - // TODO: What if there are multiple windows? - // TODO: Smart dialog, à la 'Session?: Save, Discard, Cancel' - // TODO: Pref startup: session, ask, homepage, blank <-- ask - // TODO: Pref quit: session, ask, none <-- ask - - if(0 /*g_list_length(browser_list) > 1*/) - { - GtkDialog* dialog; - dialog = GTK_DIALOG(gtk_message_dialog_new(GTK_WINDOW(browser->window) - , GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO - , "There is more than one tab open. Do you want to close anyway?")); - gtk_window_set_title(GTK_WINDOW(dialog), PACKAGE_NAME); - gtk_dialog_set_default_response(dialog, GTK_RESPONSE_YES); - proceed = gtk_dialog_run(dialog) == GTK_RESPONSE_YES; - gtk_widget_destroy(GTK_WIDGET(dialog)); - } - return !proceed; -} - -// -- Browser creation begins here - -CBrowser* browser_new(CBrowser* oldBrowser) -{ - CBrowser* browser = g_new0(CBrowser, 1); - browsers = g_list_prepend(browsers, browser); - browser->sessionItem = katze_xbel_bookmark_new(); - katze_xbel_item_set_title(browser->sessionItem, "about:blank"); - katze_xbel_folder_append_item(session, browser->sessionItem); - - GtkWidget* scrolled; - - if(!oldBrowser) - { - - GtkWidget* label; GtkWidget* hbox; - - // Setup the window metrics - browser->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - g_signal_connect(browser->window, "window-state-event" - , G_CALLBACK(on_window_state_changed), browser); - GdkScreen* screen = gtk_window_get_screen(GTK_WINDOW(browser->window)); - const gint defaultWidth = (gint)gdk_screen_get_width(screen) / 1.7; - const gint defaultHeight = (gint)gdk_screen_get_height(screen) / 1.7; - if(config->rememberWinSize) - { - if(!config->winWidth && !config->winHeight) - { - config->winWidth = defaultWidth; - config->winHeight = defaultWidth; - } - gtk_window_set_default_size(GTK_WINDOW(browser->window) - , config->winWidth, config->winHeight); - } - else - gtk_window_set_default_size(GTK_WINDOW(browser->window) - , defaultWidth, defaultHeight); - g_signal_connect(browser->window, "size-allocate" - , G_CALLBACK(on_window_size_allocate), browser); - // FIXME: Use custom program icon - gtk_window_set_icon_name(GTK_WINDOW(browser->window), "web-browser"); - gtk_window_set_title(GTK_WINDOW(browser->window), g_get_application_name()); - gtk_window_add_accel_group(GTK_WINDOW(browser->window), accel_group); - g_signal_connect(browser->window, "delete-event" - , G_CALLBACK(on_window_destroy), browser); - GtkWidget* vbox = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(browser->window), vbox); - gtk_widget_show(vbox); - - // Let us see some ui manager magic - browser->actiongroup = gtk_action_group_new("Browser"); - gtk_action_group_add_actions(browser->actiongroup, entries, entries_n, browser); - gtk_action_group_add_toggle_actions(browser->actiongroup - , toggle_entries, toggle_entries_n, browser); - gtk_action_group_add_radio_actions(browser->actiongroup - , refreshevery_entries, refreshevery_entries_n - , 300, NULL/*G_CALLBACK(activate_refreshevery_period_action)*/, browser); - gtk_action_group_add_radio_actions(browser->actiongroup - , panel_entries, panel_entries_n, -1 - , G_CALLBACK(on_action_panel_item_activate), browser); - GtkUIManager* ui_manager = gtk_ui_manager_new(); - gtk_ui_manager_insert_action_group(ui_manager, browser->actiongroup, 0); - gtk_window_add_accel_group(GTK_WINDOW(browser->window) - , gtk_ui_manager_get_accel_group(ui_manager)); - - GError* error = NULL; - if(!gtk_ui_manager_add_ui_from_string(ui_manager, ui_markup, -1, &error)) - { - // TODO: Should this be a message dialog? When does this happen? - g_message("User interface couldn't be created: %s", error->message); - g_error_free(error); - } - - GtkAction* action; - // Make all actions except toplevel menus which lack a callback insensitive - // This will vanish once all actions are implemented - guint i; - for(i = 0; i < entries_n; i++) - { - action = gtk_action_group_get_action(browser->actiongroup, entries[i].name); - gtk_action_set_sensitive(action, entries[i].callback || !entries[i].tooltip); - } - for(i = 0; i < toggle_entries_n; i++) - { - action = gtk_action_group_get_action(browser->actiongroup - , toggle_entries[i].name); - gtk_action_set_sensitive(action, toggle_entries[i].callback != NULL); - } - for(i = 0; i < refreshevery_entries_n; i++) - { - action = gtk_action_group_get_action(browser->actiongroup - , refreshevery_entries[i].name); - gtk_action_set_sensitive(action, FALSE); - } - - //action_set_active("ToolbarDownloads", config->bToolbarDownloads, browser); - - // Create the menubar - browser->menubar = gtk_ui_manager_get_widget(ui_manager, "/menubar"); - GtkWidget* menuitem = gtk_menu_item_new(); - gtk_widget_show(menuitem); - browser->throbber = katze_throbber_new(); - gtk_widget_show(browser->throbber); - gtk_container_add(GTK_CONTAINER(menuitem), browser->throbber); - gtk_widget_set_sensitive(menuitem, FALSE); - gtk_menu_item_set_right_justified(GTK_MENU_ITEM(menuitem), TRUE); - gtk_menu_shell_append(GTK_MENU_SHELL(browser->menubar), menuitem); - gtk_box_pack_start(GTK_BOX(vbox), browser->menubar, FALSE, FALSE, 0); - menuitem = gtk_ui_manager_get_widget(ui_manager, "/menubar/Go/TabsClosed"); - g_signal_connect(menuitem, "activate" - , G_CALLBACK(on_menu_tabsClosed_activate), browser); - browser->menu_bookmarks = gtk_menu_item_get_submenu( - GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui_manager, "/menubar/Bookmarks"))); - menuitem = gtk_separator_menu_item_new(); - gtk_widget_show(menuitem); - gtk_menu_shell_append(GTK_MENU_SHELL(browser->menu_bookmarks), menuitem); - browser->popup_bookmark = gtk_ui_manager_get_widget(ui_manager, "/popup_bookmark"); - g_object_ref(browser->popup_bookmark); - browser->menu_window = gtk_menu_item_get_submenu( - GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui_manager, "/menubar/Window"))); - menuitem = gtk_separator_menu_item_new(); - gtk_widget_show(menuitem); - gtk_menu_shell_append(GTK_MENU_SHELL(browser->menu_window), menuitem); - gtk_widget_show(browser->menubar); - action_set_sensitive("PrivateBrowsing", FALSE, browser); //... - action_set_sensitive("WorkOffline", FALSE, browser); //... - browser->popup_webView = gtk_ui_manager_get_widget(ui_manager, "/popup_webView"); - g_object_ref(browser->popup_webView); - browser->popup_element = gtk_ui_manager_get_widget(ui_manager, "/popup_element"); - g_object_ref(browser->popup_element); - browser->popup_editable = gtk_ui_manager_get_widget(ui_manager, "/popup_editable"); - g_object_ref(browser->popup_editable); - - // Create the navigation toolbar - browser->navibar = gtk_ui_manager_get_widget(ui_manager, "/toolbar_navigation"); - gtk_toolbar_set_style(GTK_TOOLBAR(browser->navibar) - , config_to_toolbarstyle(config->toolbarStyle)); - g_signal_connect(gtk_settings_get_default(), "notify::gtk-toolbar-style" - , G_CALLBACK(on_toolbar_navigation_notify_style), browser); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(browser->navibar) - , config_to_toolbariconsize(config->toolbarSmall)); - gtk_toolbar_set_show_arrow(GTK_TOOLBAR(browser->navibar), TRUE); - gtk_box_pack_start(GTK_BOX(vbox), browser->navibar, FALSE, FALSE, 0); - browser->newTab = gtk_ui_manager_get_widget(ui_manager, "/toolbar_navigation/TabNew"); - action = gtk_action_group_get_action(browser->actiongroup, "Back"); - g_object_set(action, "is-important", TRUE, NULL); - - // Location entry - browser->location = sexy_icon_entry_new(); - entry_setup_completion(GTK_ENTRY(browser->location)); - sokoke_entry_set_can_undo(GTK_ENTRY(browser->location), TRUE); - browser->location_icon = gtk_image_new(); - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->location) - , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(browser->location_icon)); - sexy_icon_entry_add_clear_button(SEXY_ICON_ENTRY(browser->location)); - g_signal_connect(browser->location, "key-press-event" - , G_CALLBACK(on_location_key_down), browser); - g_signal_connect(browser->location, "changed" - , G_CALLBACK(on_location_changed), browser); - GtkToolItem* toolitem = gtk_tool_item_new(); - gtk_tool_item_set_expand(GTK_TOOL_ITEM(toolitem), TRUE); - gtk_container_add(GTK_CONTAINER(toolitem), browser->location); - gtk_toolbar_insert(GTK_TOOLBAR(browser->navibar), toolitem, -1); - - // Search entry - browser->webSearch = sexy_icon_entry_new(); - sexy_icon_entry_set_icon_highlight(SEXY_ICON_ENTRY(browser->webSearch) - , SEXY_ICON_ENTRY_PRIMARY, TRUE); - // TODO: Make this actively resizable or enlarge to fit contents? - // FIXME: The interface is somewhat awkward and ought to be rethought - // TODO: Display "show in context menu" search engines as "completion actions" - entry_setup_completion(GTK_ENTRY(browser->webSearch)); - sokoke_entry_set_can_undo(GTK_ENTRY(browser->webSearch), TRUE); - update_searchEngine(config->searchEngine, browser); - g_signal_connect(browser->webSearch, "icon-released" - , G_CALLBACK(on_webSearch_icon_released), browser); - g_signal_connect(browser->webSearch, "key-press-event" - , G_CALLBACK(on_webSearch_key_down), browser); - g_signal_connect(browser->webSearch, "scroll-event" - , G_CALLBACK(on_webSearch_scroll), browser); - g_signal_connect(browser->webSearch, "activate" - , G_CALLBACK(on_webSearch_activate), browser); - toolitem = gtk_tool_item_new(); - gtk_container_add(GTK_CONTAINER(toolitem), browser->webSearch); - gtk_toolbar_insert(GTK_TOOLBAR(browser->navibar), toolitem, -1); - action = gtk_action_group_get_action(browser->actiongroup, "TabsClosed"); - browser->closedTabs = gtk_action_create_tool_item(action); - g_signal_connect(browser->closedTabs, "clicked" - , G_CALLBACK(on_menu_tabsClosed_activate), browser); - gtk_toolbar_insert(GTK_TOOLBAR(browser->navibar) - , GTK_TOOL_ITEM(browser->closedTabs), -1); - sokoke_container_show_children(GTK_CONTAINER(browser->navibar)); - action = gtk_action_group_get_action(browser->actiongroup, "Fullscreen"); - browser->fullscreen = gtk_action_create_tool_item(action); - gtk_widget_hide(browser->fullscreen); - g_signal_connect(browser->fullscreen, "clicked" - , G_CALLBACK(on_action_fullscreen_activate), browser); - gtk_toolbar_insert(GTK_TOOLBAR(browser->navibar) - , GTK_TOOL_ITEM(browser->fullscreen), -1); - action_set_active("ToolbarNavigation", config->toolbarNavigation, browser); - - // Bookmarkbar - browser->bookmarkbar = gtk_toolbar_new(); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(browser->bookmarkbar), GTK_ICON_SIZE_MENU); - gtk_toolbar_set_style(GTK_TOOLBAR(browser->bookmarkbar), GTK_TOOLBAR_BOTH_HORIZ); - create_bookmark_menu(bookmarks, browser->menu_bookmarks, browser); - for(i = 0; i < katze_xbel_folder_get_n_items(bookmarks); i++) - { - KatzeXbelItem* item = katze_xbel_folder_get_nth_item(bookmarks, i); - const gchar* title = katze_xbel_item_is_separator(item) - ? "" : katze_xbel_item_get_title(item); - const gchar* desc = katze_xbel_item_is_separator(item) - ? "" : katze_xbel_item_get_desc(item); - switch(katze_xbel_item_get_kind(item)) - { - case KATZE_XBEL_ITEM_KIND_FOLDER: - toolitem = tool_button_new(title, GTK_STOCK_DIRECTORY, TRUE, TRUE - , G_CALLBACK(on_bookmark_toolbar_folder_activate), desc, browser); - g_object_set_data(G_OBJECT(toolitem), "KatzeXbelItem", item); - break; - case KATZE_XBEL_ITEM_KIND_BOOKMARK: - toolitem = tool_button_new(title, STOCK_BOOKMARK, TRUE, TRUE - , G_CALLBACK(on_menu_bookmarks_item_activate), desc, browser); - g_object_set_data(G_OBJECT(toolitem), "KatzeXbelItem", item); - break; - case KATZE_XBEL_ITEM_KIND_SEPARATOR: - toolitem = gtk_separator_tool_item_new(); - break; - default: - g_warning("Unknown item kind"); - } - gtk_toolbar_insert(GTK_TOOLBAR(browser->bookmarkbar), toolitem, -1); - } - sokoke_container_show_children(GTK_CONTAINER(browser->bookmarkbar)); - gtk_box_pack_start(GTK_BOX(vbox), browser->bookmarkbar, FALSE, FALSE, 0); - action_set_active("ToolbarBookmarks", config->toolbarBookmarks, browser); - - // Superuser warning - if((hbox = sokoke_superuser_warning_new())) - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - // Create the panels - GtkWidget* hpaned = gtk_hpaned_new(); - gtk_paned_set_position(GTK_PANED(hpaned), config->winPanelPos); - g_signal_connect(hpaned, "notify::position" - , G_CALLBACK(on_panels_notify_position), browser); - gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0); - gtk_widget_show(hpaned); - - browser->panels = gtk_hbox_new(FALSE, 0); - gtk_paned_pack1(GTK_PANED(hpaned), browser->panels, FALSE, FALSE); - sokoke_widget_set_visible(browser->panels, config->panelShow); - - // Create the panel toolbar - GtkWidget* panelbar = gtk_ui_manager_get_widget(ui_manager, "/toolbar_panels"); - gtk_toolbar_set_style(GTK_TOOLBAR(panelbar), GTK_TOOLBAR_BOTH); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(panelbar), GTK_ICON_SIZE_BUTTON); - gtk_toolbar_set_orientation(GTK_TOOLBAR(panelbar), GTK_ORIENTATION_VERTICAL); - gtk_box_pack_start(GTK_BOX(browser->panels), panelbar, FALSE, FALSE, 0); - action_set_active("Panels", config->panelShow, browser); - - GtkWidget* cbox = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(browser->panels), cbox, TRUE, TRUE, 0); - gtk_widget_show(cbox); - - // Panels titlebar - GtkWidget* labelbar = gtk_toolbar_new(); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(labelbar), GTK_ICON_SIZE_MENU); - gtk_toolbar_set_style(GTK_TOOLBAR(labelbar), GTK_TOOLBAR_ICONS); - toolitem = gtk_tool_item_new(); - gtk_tool_item_set_expand(toolitem, TRUE); - label = gtk_label_new_with_mnemonic("_Panels"); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_container_add(GTK_CONTAINER(toolitem), label); - gtk_container_set_border_width(GTK_CONTAINER(toolitem), 6); - gtk_toolbar_insert(GTK_TOOLBAR(labelbar), toolitem, -1); - // TODO: Does 'goto top' actually indicate 'detach'? - toolitem = tool_button_new(NULL, GTK_STOCK_GOTO_TOP, FALSE, TRUE - , NULL/*G_CALLBACK(on_panels_button_float_clicked)*/, "Detach panel", browser); - gtk_toolbar_insert(GTK_TOOLBAR(labelbar), toolitem, -1); - toolitem = tool_button_new(NULL, GTK_STOCK_CLOSE, FALSE, TRUE - , G_CALLBACK(on_panels_button_close_clicked), "Close panel", browser); - gtk_toolbar_insert(GTK_TOOLBAR(labelbar), toolitem, -1); - gtk_box_pack_start(GTK_BOX(cbox), labelbar, FALSE, FALSE, 0); - gtk_widget_show_all(labelbar); - - // Notebook, containing all panels - browser->panels_notebook = gtk_notebook_new(); - gtk_notebook_set_show_border(GTK_NOTEBOOK(browser->panels_notebook), FALSE); - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(browser->panels_notebook), FALSE); - gint page; - // Dummy: This is the "fallback" panel for now - page = gtk_notebook_append_page(GTK_NOTEBOOK(browser->panels_notebook) - , gtk_label_new("empty"), NULL); - // Bookmarks - GtkWidget* box = gtk_vbox_new(FALSE, 0); - GtkWidget* toolbar = gtk_ui_manager_get_widget(ui_manager, "/toolbar_bookmarks"); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar), GTK_ICON_SIZE_MENU); - gtk_box_pack_start(GTK_BOX(box), toolbar, FALSE, FALSE, 0); - gtk_widget_show(toolbar); - GtkTreeViewColumn* column; - GtkCellRenderer* renderer_text; GtkCellRenderer* renderer_pixbuf; - GtkTreeStore* treestore = gtk_tree_store_new(1, KATZE_TYPE_XBEL_ITEM); - GtkWidget* treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(treestore)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE); - column = gtk_tree_view_column_new(); - renderer_pixbuf = gtk_cell_renderer_pixbuf_new(); - gtk_tree_view_column_pack_start(column, renderer_pixbuf, FALSE); - gtk_tree_view_column_set_cell_data_func(column, renderer_pixbuf - , (GtkTreeCellDataFunc)on_bookmarks_item_render_icon, treeview, NULL); - renderer_text = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer_text, FALSE); - gtk_tree_view_column_set_cell_data_func(column, renderer_text - , (GtkTreeCellDataFunc)on_bookmarks_item_render_text, treeview, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); - GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled) - , GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_container_add(GTK_CONTAINER(scrolled), treeview); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); - tree_store_insert_folder(GTK_TREE_STORE(treestore), NULL, bookmarks); - g_object_unref(treestore); - g_signal_connect(treeview, "row-activated" - , G_CALLBACK(on_panel_bookmarks_row_activated), browser); - g_signal_connect(treeview, "cursor-changed" - , G_CALLBACK(on_panel_bookmarks_cursor_or_row_changed), browser); - g_signal_connect(treeview, "columns-changed" - , G_CALLBACK(on_panel_bookmarks_cursor_or_row_changed), browser); - on_panel_bookmarks_cursor_or_row_changed(GTK_TREE_VIEW(treeview), browser); - g_signal_connect(treeview, "button-release-event" - , G_CALLBACK(on_panel_bookmarks_button_release), browser); - g_signal_connect(treeview, "popup-menu" - , G_CALLBACK(on_panel_bookmarks_popup), browser); - browser->panel_bookmarks = treeview; - gtk_box_pack_start(GTK_BOX(box), scrolled, TRUE, TRUE, 0); - gtk_widget_show(box); - page = gtk_notebook_append_page(GTK_NOTEBOOK(browser->panels_notebook) - , box, NULL); - action = gtk_action_group_get_action(browser->actiongroup, "PanelBookmarks"); - g_object_set_data(G_OBJECT(action), "iPage", GINT_TO_POINTER(page)); - // Pageholder - browser->panel_pageholder = webView_new(&scrolled); - page = gtk_notebook_append_page(GTK_NOTEBOOK(browser->panels_notebook) - , scrolled, NULL); - //webView_load_from_uri(browser->panel_pageholder, config->panelPageholder); - action = gtk_action_group_get_action(browser->actiongroup, "PanelPageholder"); - g_object_set_data(G_OBJECT(action), "iPage", GINT_TO_POINTER(page)); - GtkWidget* frame = gtk_frame_new(NULL); - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); - gtk_container_add(GTK_CONTAINER(frame), browser->panels_notebook); - gtk_box_pack_start(GTK_BOX(cbox), frame, TRUE, TRUE, 0); - gtk_widget_show_all(gtk_widget_get_parent(browser->panels_notebook)); - action = gtk_action_group_get_action(browser->actiongroup, "PanelDownloads"); - g_object_set_data(G_OBJECT(action), "once-silent", GINT_TO_POINTER(1)); - sokoke_radio_action_set_current_value(GTK_RADIO_ACTION(action), config->panelActive); - sokoke_widget_set_visible(browser->panels, config->panelShow); - g_object_unref(ui_manager); - - // Notebook, containing all webViews - browser->webViews = gtk_notebook_new(); - gtk_notebook_set_scrollable(GTK_NOTEBOOK(browser->webViews), TRUE); - #if GTK_CHECK_VERSION(2, 10, 0) - //gtk_notebook_set_group_id(GTK_NOTEBOOK(browser->webViews), 0); - #endif - gtk_paned_pack2(GTK_PANED(hpaned), browser->webViews, FALSE, FALSE); - gtk_widget_show(browser->webViews); - - // Incremental findbar - browser->findbox = gtk_toolbar_new(); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(browser->findbox), GTK_ICON_SIZE_MENU); - gtk_toolbar_set_style(GTK_TOOLBAR(browser->findbox), GTK_TOOLBAR_BOTH_HORIZ); - toolitem = gtk_tool_item_new(); - gtk_container_set_border_width(GTK_CONTAINER(toolitem), 6); - gtk_container_add(GTK_CONTAINER(toolitem) - , gtk_label_new_with_mnemonic("_Inline find:")); - gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1); - browser->findbox_text = sexy_icon_entry_new(); - GtkWidget* icon = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->findbox_text) - , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(icon)); - sexy_icon_entry_add_clear_button(SEXY_ICON_ENTRY(browser->findbox_text)); - sokoke_entry_set_can_undo(GTK_ENTRY(browser->findbox_text), TRUE); - g_signal_connect(browser->findbox_text, "activate" - , G_CALLBACK(on_action_find_next_activate), browser); - toolitem = gtk_tool_item_new(); - gtk_container_add(GTK_CONTAINER(toolitem), browser->findbox_text); - gtk_tool_item_set_expand(GTK_TOOL_ITEM(toolitem), TRUE); - gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1); - toolitem = tool_button_new(NULL, GTK_STOCK_GO_BACK, TRUE, TRUE - , G_CALLBACK(on_action_find_previous_activate), NULL, browser); - gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1); - toolitem = tool_button_new(NULL, GTK_STOCK_GO_FORWARD, TRUE, TRUE - , G_CALLBACK(on_action_find_next_activate), NULL, browser); - gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1); - browser->findbox_case = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_SPELL_CHECK); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(browser->findbox_case), "Match Case"); - gtk_tool_item_set_is_important(GTK_TOOL_ITEM(browser->findbox_case), TRUE); - gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), browser->findbox_case, -1); - browser->findbox_highlight = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_SELECT_ALL); - g_signal_connect(browser->findbox_highlight, "toggled" - , G_CALLBACK(on_findbox_highlight_toggled), browser); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(browser->findbox_highlight), "Highlight Matches"); - gtk_tool_item_set_is_important(GTK_TOOL_ITEM(browser->findbox_highlight), TRUE); - gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), browser->findbox_highlight, -1); - toolitem = gtk_separator_tool_item_new(); - gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); - gtk_tool_item_set_expand(GTK_TOOL_ITEM(toolitem), TRUE); - gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1); - toolitem = tool_button_new(NULL, GTK_STOCK_CLOSE, FALSE, TRUE - , G_CALLBACK(on_findbox_button_close_clicked), "Close Findbar", browser); - gtk_toolbar_insert(GTK_TOOLBAR(browser->findbox), toolitem, -1); - sokoke_container_show_children(GTK_CONTAINER(browser->findbox)); - gtk_box_pack_start(GTK_BOX(vbox), browser->findbox, FALSE, FALSE, 0); - - // Statusbar - // TODO: fix children overlapping statusbar border - browser->statusbar = gtk_statusbar_new(); - gtk_box_pack_start(GTK_BOX(vbox), browser->statusbar, FALSE, FALSE, 0); - browser->progress = gtk_progress_bar_new(); - // Setting the progressbar's height to 1 makes it fit in the statusbar - gtk_widget_set_size_request(browser->progress, -1, 1); - gtk_box_pack_start(GTK_BOX(browser->statusbar), browser->progress - , FALSE, FALSE, 3); - browser->icon_security = gtk_image_new(); - gtk_box_pack_start(GTK_BOX(browser->statusbar) - , browser->icon_security, FALSE, FALSE, 0); - gtk_widget_show(browser->icon_security); - browser->icon_newsfeed = gtk_image_new_from_icon_name(STOCK_NEWSFEED - , GTK_ICON_SIZE_MENU); - gtk_box_pack_start(GTK_BOX(browser->statusbar) - , browser->icon_newsfeed, FALSE, FALSE, 0); - action_set_active("ToolbarStatus", config->toolbarStatus, browser); - - } - else - { - - browser->window = oldBrowser->window; - browser->actiongroup = oldBrowser->actiongroup; - browser->menubar = oldBrowser->menubar; - browser->menu_bookmarks = oldBrowser->menu_bookmarks; - browser->popup_bookmark = oldBrowser->popup_bookmark; - browser->menu_window = oldBrowser->menu_window; - browser->popup_webView = oldBrowser->popup_webView; - browser->popup_element = oldBrowser->popup_element; - browser->popup_editable = oldBrowser->popup_editable; - browser->throbber = oldBrowser->throbber; - browser->navibar = oldBrowser->navibar; - browser->newTab = oldBrowser->newTab; - browser->location_icon = oldBrowser->location_icon; - browser->location = oldBrowser->location; - browser->webSearch = oldBrowser->webSearch; - browser->closedTabs = oldBrowser->closedTabs; - browser->fullscreen = oldBrowser->fullscreen; - browser->bookmarkbar = oldBrowser->bookmarkbar; - browser->panels = oldBrowser->panels; - browser->panels_notebook = oldBrowser->panels_notebook; - browser->panel_pageholder = oldBrowser->panel_pageholder; - browser->webViews = oldBrowser->webViews; - browser->findbox = oldBrowser->findbox; - browser->findbox_case = oldBrowser->findbox_case; - browser->findbox_highlight = oldBrowser->findbox_highlight; - browser->statusbar = oldBrowser->statusbar; - browser->progress = oldBrowser->progress; - browser->icon_security = oldBrowser->icon_security; - browser->icon_newsfeed = oldBrowser->icon_newsfeed; - - } - - // Define some default values - browser->hasMenubar = TRUE; - browser->hasToolbar = TRUE; - browser->hasLocation = TRUE; - browser->hasStatusbar = TRUE; - browser->elementUri = NULL; - browser->loadedPercent = -1; // initially "not loading" - - // Add a window menu item - // TODO: Menu items should be ordered like the notebook tabs - // TODO: Watch tab reordering in >= gtk 2.10 - browser->webView_menu = menu_item_new("about:blank", GTK_STOCK_FILE - , G_CALLBACK(on_window_menu_item_activate), TRUE, browser); - gtk_widget_show(browser->webView_menu); - gtk_menu_shell_append(GTK_MENU_SHELL(browser->menu_window), browser->webView_menu); - - // Create a new tab label - GtkWidget* eventbox = gtk_event_box_new(); - gtk_event_box_set_visible_window(GTK_EVENT_BOX(eventbox), FALSE); - g_signal_connect(eventbox, "button-release-event" - , G_CALLBACK(on_notebook_tab_mouse_up), browser); - GtkWidget* hbox = gtk_hbox_new(FALSE, 1); - gtk_container_add(GTK_CONTAINER(eventbox), GTK_WIDGET(hbox)); - browser->webView_icon = katze_throbber_new(); - katze_throbber_set_static_stock_id(KATZE_THROBBER(browser->webView_icon) - , GTK_STOCK_FILE); - gtk_box_pack_start(GTK_BOX(hbox), browser->webView_icon, FALSE, FALSE, 0); - browser->webView_name = gtk_label_new(katze_xbel_item_get_title(browser->sessionItem)); - gtk_misc_set_alignment(GTK_MISC(browser->webView_name), 0.0, 0.5); - // TODO: make the tab initially look "unvisited" until it's focused - // TODO: gtk's tab scrolling is weird? - gint w, h; - sokoke_widget_get_text_size(browser->webView_name, "M", &w, &h); - gtk_widget_set_size_request(GTK_WIDGET(browser->webView_name) - , w * config->tabSize, -1); - gtk_label_set_ellipsize(GTK_LABEL(browser->webView_name), PANGO_ELLIPSIZE_END); - gtk_box_pack_start(GTK_BOX(hbox), browser->webView_name, FALSE, FALSE, 0); - browser->webView_close = gtk_button_new(); - gtk_button_set_relief(GTK_BUTTON(browser->webView_close), GTK_RELIEF_NONE); - gtk_button_set_focus_on_click(GTK_BUTTON(browser->webView_close), FALSE); - GtkRcStyle* rcstyle = gtk_rc_style_new(); - rcstyle->xthickness = rcstyle->ythickness = 0; - gtk_widget_modify_style(browser->webView_close, rcstyle); - GtkWidget* image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU); - gtk_button_set_image(GTK_BUTTON(browser->webView_close), image); - gtk_box_pack_start(GTK_BOX(hbox), browser->webView_close, FALSE, FALSE, 0); - GtkSettings* gtksettings = gtk_settings_get_default(); - gint height; - gtk_icon_size_lookup_for_settings(gtksettings, GTK_ICON_SIZE_BUTTON, 0, &height); - gtk_widget_set_size_request(browser->webView_close, -1, height); - gtk_widget_show_all(GTK_WIDGET(eventbox)); - sokoke_widget_set_visible(browser->webView_close, config->tabClose); - g_signal_connect(browser->webView_close, "clicked" - , G_CALLBACK(on_notebook_tab_close_clicked), browser); - - // Create a webView inside a scrolled window - browser->webView = webView_new(&scrolled); - gtk_widget_show(GTK_WIDGET(scrolled)); - gtk_widget_show(GTK_WIDGET(browser->webView)); - gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(browser->webViews)); - page = gtk_notebook_insert_page(GTK_NOTEBOOK(browser->webViews) - , scrolled, GTK_WIDGET(eventbox), page + 1); - g_signal_connect_after(browser->webViews, "switch-page" - , G_CALLBACK(on_notebook_switch_page), browser); - #if GTK_CHECK_VERSION(2, 10, 0) - gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(browser->webViews), scrolled, TRUE); - gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(browser->webViews), scrolled, TRUE); - #endif - - // Connect signals - #define DOC_CONNECT(__sig, __func) g_signal_connect \ - (browser->webView, __sig, G_CALLBACK(__func), browser); - #define DOC_CONNECTA(__sig, __func) g_signal_connect_after \ - (browser->webView, __sig, G_CALLBACK(__func), browser); - DOC_CONNECT ("navigation-requested" , on_webView_navigation_requested) - DOC_CONNECT ("title-changed" , on_webView_title_changed) - DOC_CONNECT ("icon-loaded" , on_webView_icon_changed) - DOC_CONNECT ("load-started" , on_webView_load_started) - DOC_CONNECT ("load-committed" , on_webView_load_committed) - DOC_CONNECT ("load-progress-changed" , on_webView_load_changed) - DOC_CONNECT ("load-finished" , on_webView_load_finished) - DOC_CONNECT ("status-bar-text-changed" , on_webView_status_message) - DOC_CONNECT ("hovering-over-link" , on_webView_link_hover) - DOC_CONNECT ("console-message" , on_webView_console_message) - - DOC_CONNECT ("button-press-event" , on_webView_button_press) - DOC_CONNECTA ("button-press-event" , on_webView_button_press_after) - DOC_CONNECT ("popup-menu" , on_webView_popup); - DOC_CONNECT ("scroll-event" , on_webView_scroll); - DOC_CONNECT ("leave-notify-event" , on_webView_leave) - DOC_CONNECT ("destroy" , on_webView_destroy) - #undef DOC_CONNECT - #undef DOC_CONNECTA - - webkit_web_view_set_settings(WEBKIT_WEB_VIEW(browser->webView), webSettings); - - // Eventually pack and display everything - sokoke_widget_set_visible(browser->navibar, config->toolbarNavigation); - sokoke_widget_set_visible(browser->newTab, config->toolbarNewTab); - sokoke_widget_set_visible(browser->webSearch, config->toolbarWebSearch); - sokoke_widget_set_visible(browser->closedTabs, config->toolbarClosedTabs); - sokoke_widget_set_visible(browser->bookmarkbar, config->toolbarBookmarks); - sokoke_widget_set_visible(browser->statusbar, config->toolbarStatus); - if(!config->openTabsInTheBackground) - gtk_notebook_set_current_page(GTK_NOTEBOOK(browser->webViews), page); - - update_browser_actions(browser); - gtk_widget_show(browser->window); - gtk_widget_grab_focus(GTK_WIDGET(browser->location)); - - return browser; -} diff --git a/src/browser.h b/src/browser.h deleted file mode 100644 index a3c4f3df..00000000 --- a/src/browser.h +++ /dev/null @@ -1,600 +0,0 @@ -/* - Copyright (C) 2007 Christian Dywan - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - See the file COPYING for the full license text. -*/ - -#ifndef __BROWSER_H__ -#define __BROWSER_H__ 1 - -#include "global.h" - -#include - -// -- Types - -typedef struct _CBrowser -{ - // shared widgets - GtkWidget* window; - GtkActionGroup* actiongroup; - // menus - GtkWidget* menubar; - GtkWidget* menu_bookmarks; - GtkWidget* popup_bookmark; - GtkWidget* menu_window; - GtkWidget* popup_webView; - GtkWidget* popup_element; - GtkWidget* popup_editable; - GtkWidget* throbber; - // navibar - GtkWidget* navibar; - GtkWidget* newTab; - GtkWidget* location_icon; - GtkWidget* location; - GtkWidget* webSearch; - GtkWidget* closedTabs; - GtkWidget* fullscreen; - GtkWidget* bookmarkbar; - // panels - GtkWidget* panels; - GtkWidget* panels_notebook; - GtkWidget* panel_bookmarks; - GtkWidget* panel_pageholder; - GtkWidget* webViews; - // findbox - GtkWidget* findbox; - GtkWidget* findbox_text; - GtkToolItem* findbox_case; - GtkToolItem* findbox_highlight; - GtkWidget* statusbar; - GtkWidget* progress; - GtkWidget* icon_security; - GtkWidget* icon_newsfeed; - - // view specific widgets - GtkWidget* webView_menu; - GtkWidget* webView_icon; - GtkWidget* webView_name; - GtkWidget* webView_close; - GtkWidget* webView; - - // view specific values - gboolean hasMenubar; - gboolean hasToolbar; - gboolean hasLocation; - gboolean hasStatusbar; - gchar* elementUri; // the element the mouse is hovering on - gint loadedPercent; // -1 means "not loading" - //UNDEFINED favicon; - guint security; - gchar* statusMessage; // message from a webView - KatzeXbelItem* sessionItem; -} CBrowser; - -enum -{ - SEARCH_COL_ICON, - SEARCH_COL_TEXT, - SEARCH_COL_N -}; - -// -- Declarations - -void -on_action_window_new_activate(GtkAction*, CBrowser*); - -void -on_action_tab_new_activate(GtkAction*, CBrowser*); - -void -on_action_open_activate(GtkAction*, CBrowser*); - -void -on_action_tab_close_activate(GtkAction*, CBrowser*); - -void -on_action_window_close_activate(GtkAction*, CBrowser*); - -void -on_action_quit_activate(GtkAction*, CBrowser*); - -void -on_action_edit_activate(GtkAction*, CBrowser*); - -void -on_action_cut_activate(GtkAction*, CBrowser*); - -void -on_action_copy_activate(GtkAction*, CBrowser*); - -void -on_action_paste_activate(GtkAction*, CBrowser*); - -void -on_action_delete_activate(GtkAction*, CBrowser*); - -void -on_action_selectAll_activate(GtkAction*, CBrowser*); - -void -on_action_find_activate(GtkAction*, CBrowser*); - -void -on_action_find_next_activate(GtkAction*, CBrowser*); - -void -on_action_find_previous_activate(GtkAction*, CBrowser*); - -void -on_action_preferences_activate(GtkAction*, CBrowser*); - -void -on_action_toolbar_navigation_activate(GtkToggleAction*, CBrowser*); - -void -on_action_toolbar_bookmarks_activate(GtkToggleAction*, CBrowser*); - -void -on_action_panels_activate(GtkToggleAction*, CBrowser*); - -void -on_action_toolbar_status_activate(GtkToggleAction*, CBrowser*); - -void -on_action_refresh_stop_activate(GtkAction*, CBrowser*); - -void -on_action_zoom_in_activate(GtkAction*, CBrowser*); - -void -on_action_zoom_out_activate(GtkAction*, CBrowser*); - -void -on_action_zoom_normal_activate(GtkAction*, CBrowser*); - -void -on_action_source_view_activate(GtkAction*, CBrowser*); - -void -on_action_fullscreen_activate(GtkAction*, CBrowser*); - -void -on_action_back_activate(GtkAction*, CBrowser*); - -void -on_action_forward_activate(GtkAction*, CBrowser*); - -void -on_action_home_activate(GtkAction*, CBrowser*); - -void -on_action_location_activate(GtkAction*, CBrowser*); - -void -on_action_webSearch_activate(GtkAction*, CBrowser*); - -void -on_action_openInPanel_activate(GtkAction*, CBrowser*); - -void -on_menu_tabsClosed_activate(GtkWidget*, CBrowser*); - -void -on_menu_tabsClosed_item_activate(GtkWidget*, CBrowser*); - -void -on_action_tabsClosed_clear_activate(GtkAction*, CBrowser*); - -void -on_action_tabsClosed_undo_activate(GtkAction*, CBrowser*); - -void -on_action_link_tab_new_activate(GtkAction*, CBrowser*); - -void -on_action_link_tab_current_activate(GtkAction*, CBrowser*); - -void -on_action_link_window_new_activate(GtkAction*, CBrowser*); - -void -on_action_link_saveWith_activate(GtkAction*, CBrowser*); - -void -on_action_link_copy_activate(GtkAction*, CBrowser*); - -void -on_action_bookmarkOpen_activate(GtkAction*, CBrowser*); - -void -on_action_bookmarkOpenTab_activate(GtkAction*, CBrowser*); - -void -on_action_bookmarkOpenWindow_activate(GtkAction*, CBrowser*); - -void -on_action_bookmarkEdit_activate(GtkAction*, CBrowser*); - -void -on_action_bookmarkDelete_activate(GtkAction*, CBrowser*); - -void -on_menu_bookmarks_item_activate(GtkWidget*, CBrowser*); - -void -on_action_bookmark_new_activate(GtkAction*, CBrowser*); - -void -on_action_manageSearchEngines_activate(GtkAction*, CBrowser*); - -void -on_action_tab_previous_activate(GtkAction*, CBrowser*); - -void -on_action_tab_next_activate(GtkAction*, CBrowser*); - -void -on_action_about_activate(GtkAction*, CBrowser*); - -gboolean -on_location_key_down(GtkWidget*, GdkEventKey*, CBrowser*); - -CBrowser* -browser_new(CBrowser*); - -// -- Action definitions - -// TODO: Fill in a good description for each 'hm?' -static const GtkActionEntry entries[] = { - { "File", NULL, "_File" }, - { "WindowNew", STOCK_WINDOW_NEW - , NULL, "n" - , "Open a new window", G_CALLBACK(on_action_window_new_activate) }, - { "TabNew", STOCK_TAB_NEW - , NULL, "t" - , "Open a new tab", G_CALLBACK(on_action_tab_new_activate) }, - { "Open", GTK_STOCK_OPEN - , NULL, "o" - , "Open a file", G_CALLBACK(on_action_open_activate) }, - { "SaveAs", GTK_STOCK_SAVE_AS - , NULL, "s" - , "Save to a file", NULL/*G_CALLBACK(on_action_saveas_activate)*/ }, - { "TabClose", STOCK_TAB_CLOSE - , NULL, "w" - , "Close the current tab", G_CALLBACK(on_action_tab_close_activate) }, - { "WindowClose", STOCK_WINDOW_CLOSE - , NULL, "w" - , "Close this window", G_CALLBACK(on_action_window_close_activate) }, - { "PageSetup", GTK_STOCK_PROPERTIES - , "Pa_ge Setup", "" - , "hm?", NULL/*G_CALLBACK(on_action_page_setup_activate)*/ }, - { "PrintPreview", GTK_STOCK_PRINT_PREVIEW - , NULL, "" - , "hm?", NULL/*G_CALLBACK(on_action_print_preview_activate)*/ }, - { "Print", GTK_STOCK_PRINT - , NULL, "p" - , "hm?", NULL/*G_CALLBACK(on_action_print_activate)*/ }, - { "Quit", GTK_STOCK_QUIT - , NULL, "q" - , "Quit the application", G_CALLBACK(on_action_quit_activate) }, - - { "Edit", NULL, "_Edit", NULL, NULL, G_CALLBACK(on_action_edit_activate) }, - { "Undo", GTK_STOCK_UNDO - , NULL, "z" - , "Undo the last modification", NULL/*G_CALLBACK(on_action_undo_activate)*/ }, - { "Redo", GTK_STOCK_REDO - , NULL, "z" - , "Redo the last modification", NULL/*G_CALLBACK(on_action_redo_activate)*/ }, - { "Cut", GTK_STOCK_CUT - , NULL, "x" - , "Cut the selected text", G_CALLBACK(on_action_cut_activate) }, - { "Copy", GTK_STOCK_COPY - , NULL, "c" - , "Copy the selected text", G_CALLBACK(on_action_copy_activate) }, - { "Copy_", GTK_STOCK_COPY - , NULL, "c" - , "Copy the selected text", G_CALLBACK(on_action_copy_activate) }, - { "Paste", GTK_STOCK_PASTE - , NULL, "v" - , "Paste text from the clipboard", G_CALLBACK(on_action_paste_activate) }, - { "Delete", GTK_STOCK_DELETE - , NULL, NULL - , "Delete the selected text", G_CALLBACK(on_action_delete_activate) }, - { "SelectAll", GTK_STOCK_SELECT_ALL - , NULL, "a" - , "Selected all text", G_CALLBACK(on_action_selectAll_activate) }, - { "FormFill", STOCK_FORM_FILL - , NULL, "" - , "hm?", NULL/*G_CALLBACK(on_action_formfill_activate)*/ }, - { "Find", GTK_STOCK_FIND - , NULL, "f" - , "hm?", G_CALLBACK(on_action_find_activate) }, - { "FindNext", GTK_STOCK_GO_FORWARD - , "Find _Next", "g" - , "hm?", G_CALLBACK(on_action_find_next_activate) }, - { "FindPrevious", GTK_STOCK_GO_BACK - , "Find _Previous", "g" - , "hm?", G_CALLBACK(on_action_find_previous_activate) }, - { "FindQuick", GTK_STOCK_FIND - , "_Quick Find", "period" - , "hm?", NULL/*G_CALLBACK(on_action_find_quick_activate)*/ }, - { "ManageSearchEngines", GTK_STOCK_PROPERTIES - , "_Manage Search Engines", "s" - , "hm?", G_CALLBACK(on_action_manageSearchEngines_activate) }, - { "Preferences", GTK_STOCK_PREFERENCES - , NULL, "p" - , "hm?", G_CALLBACK(on_action_preferences_activate) }, - - { "View", NULL, "_View" }, - { "Toolbars", NULL, "_Toolbars" }, - { "Refresh", GTK_STOCK_REFRESH - , NULL, "r" - , "Refresh the current page", G_CALLBACK(on_action_refresh_stop_activate) }, - // TODO: Is appointment-new a good choice? - // TODO: What if it isn't available? - { "RefreshEvery", "appointment-new" - , "Refresh _Every...", "" - , "Refresh the current page", G_CALLBACK(on_action_refresh_stop_activate) }, - { "Stop", GTK_STOCK_STOP - , NULL, "Escape" - , "Stop loading of the current page", G_CALLBACK(on_action_refresh_stop_activate) }, - { "RefreshStop", GTK_STOCK_REFRESH - , NULL, "" - , NULL, G_CALLBACK(on_action_refresh_stop_activate) }, - { "ZoomIn", GTK_STOCK_ZOOM_IN - , NULL, "plus" - , "hm?", G_CALLBACK(on_action_zoom_in_activate) }, - { "ZoomOut", GTK_STOCK_ZOOM_OUT - , NULL, "minus" - , "hm?", G_CALLBACK(on_action_zoom_out_activate) }, - { "ZoomNormal", GTK_STOCK_ZOOM_100 - , NULL, "0" - , "hm?", G_CALLBACK(on_action_zoom_normal_activate) }, - { "BackgroundImage", STOCK_IMAGE - , "_Background Image", "" - , "hm?", NULL/*G_CALLBACK(on_action_background_image_activate)*/ }, - { "SourceView", STOCK_SOURCE_VIEW - , NULL, "" - , "hm?", /*G_CALLBACK(on_action_source_view_activate)*/ }, - { "SelectionSourceView", STOCK_SOURCE_VIEW - , "View Selection Source", "" - , "hm?", NULL/*G_CALLBACK(on_action_selection_source_view_activate)*/ }, - { "Properties", GTK_STOCK_PROPERTIES - , NULL, "" - , "hm?", NULL/*G_CALLBACK(on_action_properties_activate)*/ }, - { "Fullscreen", GTK_STOCK_FULLSCREEN - , NULL, "F11" - , "Toggle fullscreen view", G_CALLBACK(on_action_fullscreen_activate) }, - - { "Go", NULL, "_Go" }, - { "Back", GTK_STOCK_GO_BACK - , NULL, "Left" - , "hm?", G_CALLBACK(on_action_back_activate) }, - { "Forward", GTK_STOCK_GO_FORWARD - , NULL, "Right" - , "hm?", G_CALLBACK(on_action_forward_activate) }, - { "Home", STOCK_HOMEPAGE - , NULL, "Home" - , "hm?", G_CALLBACK(on_action_home_activate) }, - { "Location", GTK_STOCK_JUMP_TO - , "Location...", "l" - , "hm?", G_CALLBACK(on_action_location_activate) }, - { "Websearch", GTK_STOCK_FIND - , "Websearch...", "f" - , "hm?", G_CALLBACK(on_action_webSearch_activate) }, - { "OpenInPageholder", GTK_STOCK_JUMP_TO - , "Open in Page_holder...", "" - , "hm?", G_CALLBACK(on_action_openInPanel_activate) }, - { "TabsClosed", STOCK_USER_TRASH - , "Closed Tabs", "" - , "hm?", NULL }, - { "TabsClosedClear", GTK_STOCK_CLEAR - , "Clear List of Closed Tabs", "" - , "hm?", G_CALLBACK(on_action_tabsClosed_clear_activate) }, - { "UndoTabClose", GTK_STOCK_UNDELETE - , "Undo Close Tab", "" - , "hm?", G_CALLBACK(on_action_tabsClosed_undo_activate) }, - { "LinkTabNew", STOCK_TAB_NEW - , "Open Link in New Tab", "" - , "hm?", G_CALLBACK(on_action_link_tab_new_activate) }, - { "LinkTabCurrent", NULL - , "Open Link in Current Tab", "" - , "hm?", G_CALLBACK(on_action_link_tab_current_activate) }, - { "LinkWindowNew", STOCK_WINDOW_NEW - , "Open Link in New Window", "" - , "hm?", G_CALLBACK(on_action_link_window_new_activate) }, - { "LinkBookmarkNew", STOCK_BOOKMARK_NEW - , NULL, "" - , "Bookmark this link", NULL/*G_CALLBACK(on_action_link_bookmark_activate)*/ }, - { "LinkSaveAs", GTK_STOCK_SAVE - , "Save Destination as...", "" - , "Save destination to a file", NULL/*G_CALLBACK(on_action_link_saveas_activate)*/ }, - { "LinkSaveWith", STOCK_DOWNLOADS - , "Download Destination", "" - , "Save destination with the chosen download manager", G_CALLBACK(on_action_link_saveWith_activate) }, - { "LinkCopy", GTK_STOCK_COPY - , "Copy Link Address", "" - , "Copy the link address to the clipboard", G_CALLBACK(on_action_link_copy_activate) }, - { "SelectionLinksNewTabs", NULL - , "Open Selected Links in Tabs", "" - , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - { "SelectionTextTabNew", STOCK_TAB_NEW - , "Open in New Tab", "" - , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - { "SelectionTextTabCurrent", NULL - , "Open in Current Tab", "" - , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - { "SelectionTextWindowNew", STOCK_WINDOW_NEW - , "Open in New Qindow", "" - , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - { "SelectionSearch", GTK_STOCK_FIND - , "Search for ", "" - , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - { "SelectionSearchWith", GTK_STOCK_FIND - , "Search for with...", "" - , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - { "ImageViewTabNew", STOCK_TAB_NEW - , "View Image in New Tab", "" - , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - { "ImageViewTabCurrent", NULL - , "View image in current tab", "" - , "hm?", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - { "ImageSaveAs", GTK_STOCK_SAVE - , "Save Image as...", "" - , "Save image to a file", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - { "ImageSaveWith", STOCK_DOWNLOADS - , "Download Image", "" - , "Save image with the chosen download manager", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - { "ImageCopy", GTK_STOCK_COPY - , "Copy Image Address", "" - , "Copy the image address to the clipboard", NULL/*G_CALLBACK(on_action_properties_selection_activate)*/ }, - - { "Bookmarks", NULL, "_Bookmarks" }, - { "BookmarkNew", STOCK_BOOKMARK_NEW - , NULL, "d" - , "hm?", G_CALLBACK(on_action_bookmark_new_activate) }, - { "BookmarksManage", STOCK_BOOKMARKS - , "_Manage Bookmarks", "b" - , "hm?", NULL/*G_CALLBACK(on_action_bookmarks_manage_activate)*/ }, - { "BookmarkOpen", GTK_STOCK_OPEN - , NULL, "" - , "hm?", G_CALLBACK(on_action_bookmarkOpen_activate) }, - { "BookmarkOpenTab", STOCK_TAB_NEW - , "Open in New _Tab", "" - , "hm?", G_CALLBACK(on_action_bookmarkOpenTab_activate) }, - { "BookmarkOpenWindow", STOCK_WINDOW_NEW - , "Open in New _Window", "" - , "hm?", G_CALLBACK(on_action_bookmarkOpenWindow_activate) }, - { "BookmarkEdit", GTK_STOCK_EDIT - , NULL, "" - , "hm?", G_CALLBACK(on_action_bookmarkEdit_activate) }, - { "BookmarkDelete", GTK_STOCK_DELETE - , NULL, "" - , "hm?", G_CALLBACK(on_action_bookmarkDelete_activate) }, - - { "Tools", NULL, "_Tools" }, - - { "Window", NULL, "_Window" }, - { "SessionLoad", GTK_STOCK_REVERT_TO_SAVED - , "_Load Session", "" - , "hm?", NULL/*G_CALLBACK(on_action_session_load_activate)*/ }, - { "SessionSave", GTK_STOCK_SAVE_AS - , "_Save Session", "" - , "hm?", NULL/*G_CALLBACK(on_action_session_save_activate)*/ }, - { "TabPrevious", GTK_STOCK_GO_BACK - , "_Previous Tab", "Page_Up" - , "hm?", G_CALLBACK(on_action_tab_previous_activate) }, - { "TabNext", GTK_STOCK_GO_FORWARD - , "_Next Tab", "Page_Down" - , "hm?", G_CALLBACK(on_action_tab_next_activate) }, - { "TabOverview", NULL - , "Tab _Overview", "" - , "hm?", NULL/*G_CALLBACK(on_action_tab_overview_activate)*/ }, - - { "Help", NULL, "_Help" }, - { "HelpContents", GTK_STOCK_HELP - , "_Contents", "F1" - , "hm?", NULL/*G_CALLBACK(on_action_help_contents_activate)*/ }, - { "About", GTK_STOCK_ABOUT - , NULL, "" - , "hm?", G_CALLBACK(on_action_about_activate) }, - }; - static const guint entries_n = G_N_ELEMENTS(entries); - -static const GtkToggleActionEntry toggle_entries[] = { - { "PrivateBrowsing", NULL - , "P_rivate Browsing", "" - , "hm?", NULL/*G_CALLBACK(on_action_private_browsing_activate)*/ - , FALSE }, - { "WorkOffline", GTK_STOCK_DISCONNECT - , "_Work Offline", "" - , "hm?", NULL/*G_CALLBACK(on_action_work_offline_activate)*/ - , FALSE }, - - { "ToolbarNavigation", NULL - , "_Navigationbar", "" - , "hm?", G_CALLBACK(on_action_toolbar_navigation_activate) - , FALSE }, - { "Panels", NULL - , "_Panels", "F9" - , "hm?", G_CALLBACK(on_action_panels_activate) - , FALSE }, - { "ToolbarBookmarks", NULL - , "_Bookmarkbar", "" - , "hm?", G_CALLBACK(on_action_toolbar_bookmarks_activate) - , FALSE }, - { "ToolbarDownloads", NULL - , "_Downloadbar", "" - , "hm?", NULL/*G_CALLBACK(on_action_toolbar_downloads_activate)*/ - , FALSE }, - { "ToolbarStatus", NULL - , "_Statusbar", "" - , "hm?", G_CALLBACK(on_action_toolbar_status_activate) - , FALSE }, - { "RefreshEveryEnable", NULL - , "_Enabled", "" - , "hm?", NULL/*G_CALLBACK(on_action_reloadevery_enable_activate)*/ - , FALSE }, - { "ReloadEveryActive", NULL - , "_Active", "" - , "hm?", NULL/*G_CALLBACK(on_action_reloadevery_active_activate)*/ - , FALSE }, - }; - static const guint toggle_entries_n = G_N_ELEMENTS(toggle_entries); - -static const GtkRadioActionEntry refreshevery_entries[] = { - { "RefreshEvery30", NULL - , "30 seconds", "" - , "Refresh Every _30 Seconds", 30 }, - { "RefreshEvery60", NULL - , "60 seconds", "" - , "Refresh Every _60 Seconds", 60 }, - { "RefreshEvery300", NULL - , "5 minutes", "" - , "Refresh Every _5 Minutes", 300 }, - { "RefreshEvery900", NULL - , "15 minutes", "" - , "Refresh Every _15 Minutes", 900 }, - { "RefreshEvery1800", NULL - , "30 minutes", "" - , "Refresh Every 3_0 Minutes", 1800 }, - { "RefreshEveryCustom", NULL - , "Custom...", "" - , "Refresh by a _Custom Period", 0 }, - }; - static const guint refreshevery_entries_n = G_N_ELEMENTS(refreshevery_entries); - -static const GtkRadioActionEntry panel_entries[] = { - { "PanelDownloads", STOCK_DOWNLOADS - , NULL, "" - , "hm?", 0 }, - { "PanelBookmarks", STOCK_BOOKMARKS - , "_Bookmarks", "" - , "hm?", 1 }, - { "PanelConsole", STOCK_CONSOLE - , NULL, "" - , "hm?", 2 }, - { "PanelExtensions", STOCK_EXTENSIONS - , NULL, "" - , "hm?", 3 }, - { "PanelHistory", STOCK_HISTORY - , "_History", "" - , "hm?", 4 }, - // TODO: We want a better icon here, but which one? - { "PanelTabs", STOCK_TAB_NEW - , "_Tabs", "" - , "hm?", 5 }, - // TODO: We probably want another icon here - { "PanelPageholder", GTK_STOCK_CONVERT - , "_Pageholder", "" - , "hm?", 6 }, - }; - static const guint panel_entries_n = G_N_ELEMENTS(panel_entries); - -#endif /* !__BROWSER_H__ */ diff --git a/src/global.h b/src/global.h index 868ebd68..e27125c9 100644 --- a/src/global.h +++ b/src/global.h @@ -13,21 +13,19 @@ #define __GLOBAL_H__ 1 #include "conf.h" + +#include "midori-websettings.h" #include "../katze/katze.h" #include #include -// -- globals +// FIXME: Remove these globals -CConfig* config; GList* searchEngines; // Items of type 'SearchEngine' -GList* browsers; // Items of type 'CBrowser' -WebKitWebSettings* webSettings; -GtkAccelGroup* accel_group; KatzeXbelItem* bookmarks; -KatzeXbelItem* session; -KatzeXbelItem* tabtrash; +CConfig* config; +MidoriWebSettings* webSettings; // Custom stock items @@ -37,13 +35,7 @@ KatzeXbelItem* tabtrash; in order to reduce the amount of warnings :D */ #define STOCK_BOOKMARK GTK_STOCK_FILE // "stock_bookmark" // "bookmark-web" -#define STOCK_BOOKMARKS "bookmark-view" -#define STOCK_DOWNLOADS "package" // "download" -#define STOCK_CONSOLE "terminal" // "console" // MISSING -#define STOCK_EXTENSIONS "extension" // MISSING #define STOCK_FORM_FILL "insert-text" // "form-fill" // MISSING -#define STOCK_HISTORY "document-open-recent" -#define STOCK_HISTORY_ "history-view" #define STOCK_LOCATION "location-entry" #define STOCK_NEWSFEED "gtk-index" // "newsfeed" // MISSING #define STOCK_PLUGINS "plugin" // MISSING diff --git a/src/helpers.c b/src/helpers.c index 04b66837..489b8d7e 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -11,78 +11,24 @@ #include "helpers.h" +#include "global.h" #include "search.h" #include "sokoke.h" -#include "../katze/katze.h" + +#include "midori-webview.h" +#include #include #include -GtkIconTheme* get_icon_theme(GtkWidget* widget) -{ - return gtk_icon_theme_get_for_screen(gtk_widget_get_screen(widget)); -} - -GtkWidget* menu_item_new(const gchar* text, const gchar* icon - , GCallback signal, gboolean sensitive, gpointer userdata) -{ - GtkWidget* menuitem; - if(text) - menuitem = gtk_image_menu_item_new_with_mnemonic(text); - else - menuitem = gtk_image_menu_item_new_from_stock(icon, NULL); - if(icon) - { - GtkWidget* image = gtk_image_new_from_stock(icon, GTK_ICON_SIZE_MENU); - if(gtk_image_get_storage_type(GTK_IMAGE(image)) == GTK_IMAGE_EMPTY) - image = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_MENU); - if(gtk_image_get_storage_type(GTK_IMAGE(image)) != GTK_IMAGE_EMPTY) - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image); - else - g_print("Note: The icon %s is not available.", icon); - } - if(signal) - g_signal_connect(menuitem, "activate", signal, userdata); - gtk_widget_set_sensitive(GTK_WIDGET(menuitem), sensitive && signal); - return menuitem; -} - -GtkToolItem* tool_button_new(const gchar* text, const gchar* icon - , gboolean important, gboolean sensitive, GCallback signal - , const gchar* tooltip, gpointer userdata) -{ - GtkToolItem* toolbutton = gtk_tool_button_new(NULL, NULL); - GtkStockItem stockItem; - if(gtk_stock_lookup(icon, &stockItem)) - toolbutton = gtk_tool_button_new_from_stock(icon); - else - { - GtkIconTheme* iconTheme = get_icon_theme(GTK_WIDGET(toolbutton)); - if(gtk_icon_theme_has_icon(iconTheme, icon)) - gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolbutton), icon); - else - gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(toolbutton), GTK_STOCK_MISSING_IMAGE); - } - if(text) - gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolbutton), text); - if(important) - gtk_tool_item_set_is_important(toolbutton, TRUE); - if(signal) - g_signal_connect(toolbutton, "clicked", signal, userdata); - gtk_widget_set_sensitive(GTK_WIDGET(toolbutton), sensitive && signal); - if(tooltip) - sokoke_tool_item_set_tooltip_text(toolbutton, tooltip); - return toolbutton; -} - GtkWidget* check_menu_item_new(const gchar* text - , GCallback signal, gboolean sensitive, gboolean active, CBrowser* browser) + , GCallback signal, gboolean sensitive, gboolean active, gpointer userdata) { GtkWidget* menuitem = gtk_check_menu_item_new_with_mnemonic(text); gtk_widget_set_sensitive(menuitem, sensitive && signal); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), active); if(signal) - g_signal_connect(menuitem, "activate", signal, browser); + g_signal_connect(menuitem, "activate", signal, userdata); return menuitem; } @@ -91,10 +37,10 @@ GtkWidget* radio_button_new(GtkRadioButton* radio_button, const gchar* label) return gtk_radio_button_new_with_mnemonic_from_widget(radio_button, label); } -void show_error(const gchar* text, const gchar* text2, CBrowser* browser) +void show_error(const gchar* text, const gchar* text2, MidoriBrowser* browser) { GtkWidget* dialog = gtk_message_dialog_new( - browser ? GTK_WINDOW(browser->window) : NULL + browser ? GTK_WINDOW(browser) : NULL , 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, text); if(text2) gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), text2); @@ -191,223 +137,6 @@ void entry_completion_append(GtkEntry* entry, const gchar* text) gtk_list_store_set(GTK_LIST_STORE(completion_store), &iter, 0, text, -1); } -GtkWidget* get_nth_webView(gint n, CBrowser* browser) -{ - if(n < 0) - n = gtk_notebook_get_current_page(GTK_NOTEBOOK(browser->webViews)); - GtkWidget* scrolled = gtk_notebook_get_nth_page(GTK_NOTEBOOK(browser->webViews), n); - return gtk_bin_get_child(GTK_BIN(scrolled)); -} - -gint get_webView_index(GtkWidget* webView, CBrowser* browser) -{ - GtkWidget* scrolled = gtk_widget_get_parent(webView); - return gtk_notebook_page_num(GTK_NOTEBOOK(browser->webViews), scrolled); -} - -CBrowser* get_browser_from_webView(GtkWidget* webView) -{ - // FIXME: g_list_first - CBrowser* browser = NULL; GList* item = g_list_first(browsers); - do - { - browser = (CBrowser*)item->data; - if(browser->webView == webView) - return browser; - } - while((item = g_list_next(item))); - return NULL; -} - -void update_favicon(CBrowser* browser) -{ - if(browser->loadedPercent == -1) - { - if(0) //browser->favicon // Has favicon? - { - // TODO: use custom icon - // gtk_image_set_from_file(GTK_IMAGE(browser->icon_page), "image"); - } - else if(0) // Known mime-type? - { - // TODO: Retrieve mime type and load icon; don't forget ftp listings - } - else - katze_throbber_set_static_stock_id(KATZE_THROBBER(browser->webView_icon) - , GTK_STOCK_FILE); - } - katze_throbber_set_animated(KATZE_THROBBER(browser->webView_icon) - , browser->loadedPercent != -1); -} - -void update_security(CBrowser* browser) -{ - const gchar* uri = katze_xbel_bookmark_get_href(browser->sessionItem); - // TODO: This check is bogus, until webkit tells us how secure a page is - if(g_str_has_prefix(uri, "https://")) - { - // TODO: highlighted entry indicates security, find an alternative - gtk_widget_modify_base(browser->location, GTK_STATE_NORMAL - , &browser->location->style->base[GTK_STATE_SELECTED]); - gtk_widget_modify_text(browser->location, GTK_STATE_NORMAL - , &browser->location->style->text[GTK_STATE_SELECTED]); - gtk_image_set_from_stock(GTK_IMAGE(browser->icon_security) - , GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_MENU); - } - else - { - gtk_widget_modify_base(browser->location, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_text(browser->location, GTK_STATE_NORMAL, NULL); - gtk_image_set_from_stock(GTK_IMAGE(browser->icon_security) - , GTK_STOCK_INFO, GTK_ICON_SIZE_MENU); - } -} - -void update_visibility(CBrowser* browser, gboolean visibility) -{ - // A tabbed window shouldn't be manipulatable - if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(browser->webViews)) > 1) - return; - - // SHOULD SCRIPTS BE ABLE TO HIDE WINDOWS AT ALL? - if(0 && !visibility) - { - gtk_widget_hide(browser->window); - return; - } - else if(!visibility) - g_print("Window was not hidden.\n"); - - sokoke_widget_set_visible(browser->menubar, browser->hasMenubar); - sokoke_widget_set_visible(browser->navibar, browser->hasToolbar); - sokoke_widget_set_visible(browser->location, browser->hasLocation); - sokoke_widget_set_visible(browser->webSearch, browser->hasLocation); - sokoke_widget_set_visible(browser->statusbar, browser->hasStatusbar); -} - -void action_set_active(const gchar* name, gboolean active, CBrowser* browser) -{ - // This shortcut toggles activity state by an action name - GtkAction* action = gtk_action_group_get_action(browser->actiongroup, name); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), active); -} - -void action_set_sensitive(const gchar* name, gboolean sensitive, CBrowser* browser) -{ - // This shortcut toggles sensitivity by an action name - GtkAction* action = gtk_action_group_get_action(browser->actiongroup, name); - gtk_action_set_sensitive(action, sensitive); -} - -void action_set_visible(const gchar* name, gboolean visible, CBrowser* browser) -{ - // This shortcut toggles visibility by an action name - GtkAction* action = gtk_action_group_get_action(browser->actiongroup, name); - gtk_action_set_visible(action, visible); -} - -void update_statusbar(CBrowser* browser) -{ - gtk_statusbar_pop(GTK_STATUSBAR(browser->statusbar), 1); - gtk_statusbar_push(GTK_STATUSBAR(browser->statusbar), 1 - , browser->statusMessage ? browser->statusMessage : ""); - if(browser->loadedPercent > -1) - { - if(browser->loadedPercent > -1) - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(browser->progress) - , browser->loadedPercent ? browser->loadedPercent / 100.0 : 0); - else - gtk_progress_bar_pulse(GTK_PROGRESS_BAR(browser->progress)); - gchar* message = g_strdup_printf("%d%% loaded", browser->loadedPercent); - gtk_progress_bar_set_text(GTK_PROGRESS_BAR(browser->progress), message); - g_free(message); - } -} - -void update_edit_items(CBrowser* browser) -{ - GtkWidget* widget = gtk_window_get_focus(GTK_WINDOW(browser->window)); - gboolean canCut = FALSE; gboolean canCopy = FALSE; gboolean canPaste = FALSE; - if(widget && (WEBKIT_IS_WEB_VIEW(widget) || GTK_IS_EDITABLE(widget))) - { - gboolean hasSelection = WEBKIT_IS_WEB_VIEW(widget) - ? webkit_web_view_has_selection(WEBKIT_WEB_VIEW(widget)) - : gtk_editable_get_selection_bounds(GTK_EDITABLE(widget), NULL, NULL); - canCut = WEBKIT_IS_WEB_VIEW(widget) - ? webkit_web_view_can_cut_clipboard(WEBKIT_WEB_VIEW(widget)) - : hasSelection && gtk_editable_get_editable(GTK_EDITABLE(widget)); - canCopy = WEBKIT_IS_WEB_VIEW(widget) - ? webkit_web_view_can_copy_clipboard(WEBKIT_WEB_VIEW(widget)) - : hasSelection; - canPaste = WEBKIT_IS_WEB_VIEW(widget) - ? webkit_web_view_can_paste_clipboard(WEBKIT_WEB_VIEW(widget)) - : gtk_editable_get_editable(GTK_EDITABLE(widget)); - action_set_sensitive("SelectAll", TRUE, browser); - } - else - action_set_sensitive("SelectAll", FALSE, browser); - action_set_sensitive("Cut", canCut, browser); - action_set_sensitive("Copy", canCopy, browser); - action_set_sensitive("Paste", canPaste, browser); - action_set_sensitive("Delete", canCut, browser); -} - -void update_gui_state(CBrowser* browser) -{ - GtkWidget* webView = get_nth_webView(-1, browser); - action_set_sensitive("ZoomIn", FALSE, browser);//webkit_web_view_can_increase_text_size(WEBKIT_WEB_VIEW(webView), browser); - action_set_sensitive("ZoomOut", FALSE, browser);//webkit_web_view_can_decrease_text_size(WEBKIT_WEB_VIEW(webView)), browser); - action_set_sensitive("ZoomNormal", FALSE, browser);//webkit_web_view_get_text_size(WEBKIT_WEB_VIEW(webView)) != 1, browser); - action_set_sensitive("Back", webkit_web_view_can_go_back(WEBKIT_WEB_VIEW(webView)), browser); - action_set_sensitive("Forward", webkit_web_view_can_go_forward(WEBKIT_WEB_VIEW(webView)), browser); - action_set_sensitive("Refresh", browser->loadedPercent == -1, browser); - action_set_sensitive("Stop", browser->loadedPercent != -1, browser); - - GtkAction* action = gtk_action_group_get_action(browser->actiongroup, "RefreshStop"); - if(browser->loadedPercent == -1) - { - gtk_widget_set_sensitive(browser->throbber, FALSE); - g_object_set(action, "stock-id", GTK_STOCK_REFRESH, NULL); - g_object_set(action, "tooltip", "Refresh the current page", NULL); - gtk_widget_hide(browser->progress); - } - else - { - gtk_widget_set_sensitive(browser->throbber, TRUE); - g_object_set(action, "stock-id", GTK_STOCK_STOP, NULL); - g_object_set(action, "tooltip", "Stop loading the current page", NULL); - gtk_widget_show(browser->progress); - } - katze_throbber_set_animated(KATZE_THROBBER(browser->throbber) - , browser->loadedPercent != -1); - - gtk_image_set_from_stock(GTK_IMAGE(browser->location_icon), GTK_STOCK_FILE - , GTK_ICON_SIZE_MENU); -} - -void update_feeds(CBrowser* browser) -{ - // TODO: Look for available feeds, requires dom access -} - -void update_search_engines(CBrowser* browser) -{ - // TODO: Look for available search engines, requires dom access -} - -void update_browser_actions(CBrowser* browser) -{ - gboolean active = gtk_notebook_get_n_pages(GTK_NOTEBOOK(browser->webViews)) > 1; - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(browser->webViews), active); - action_set_sensitive("TabClose", active, browser); - action_set_sensitive("TabPrevious", active, browser); - action_set_sensitive("TabNext", active, browser); - - gboolean tabtrashEmpty = katze_xbel_folder_is_empty(tabtrash); - action_set_sensitive("UndoTabClose", !tabtrashEmpty, browser); - action_set_sensitive("TabsClosed", !tabtrashEmpty, browser); -} - gchar* magic_uri(const gchar* uri, gboolean search) { // Add file:// if we have a local path diff --git a/src/helpers.h b/src/helpers.h index c1812166..0db7400f 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -12,28 +12,18 @@ #ifndef __HELPERS_H__ #define __HELPERS_H__ 1 -#include "browser.h" - #include -GtkIconTheme* -get_icon_theme(GtkWidget*); +#include "midori-browser.h" GtkWidget* -menu_item_new(const gchar*, const gchar*, GCallback, gboolean, gpointer); - -GtkToolItem* -tool_button_new(const gchar*, const gchar* - , gboolean, gboolean, GCallback, const gchar*, gpointer); - -GtkWidget* -check_menu_item_new(const gchar*, GCallback, gboolean, gboolean, CBrowser*); +check_menu_item_new(const gchar*, GCallback, gboolean, gboolean, gpointer); GtkWidget* radio_button_new(GtkRadioButton*, const gchar*); void -show_error(const gchar*, const gchar*, CBrowser*); +show_error(const gchar*, const gchar*, MidoriBrowser*); gboolean spawn_protocol_command(const gchar*, const gchar*); @@ -47,51 +37,6 @@ entry_setup_completion(GtkEntry*); void entry_completion_append(GtkEntry*, const gchar*); -GtkWidget* -get_nth_webView(gint, CBrowser*); - -gint -get_webView_index(GtkWidget*, CBrowser*); - -CBrowser* -get_browser_from_webView(GtkWidget*); - -void -update_favicon(CBrowser*); - -void -update_security(CBrowser*); - -void -update_visibility(CBrowser*, gboolean); - -void -action_set_active(const gchar*, gboolean, CBrowser*); - -void -action_set_sensitive(const gchar*, gboolean, CBrowser*); - -void -action_set_visible(const gchar*, gboolean, CBrowser*); - -void -update_statusbar(CBrowser*); - -void -update_edit_items(CBrowser*); - -void -update_gui_state(CBrowser*); - -void -update_feeds(CBrowser*); - -void -update_search_engines(CBrowser*); - -void -update_browser_actions(CBrowser*); - gchar* magic_uri(const gchar*, gboolean bSearch); diff --git a/src/main.c b/src/main.c old mode 100755 new mode 100644 index 55e23485..2fdf1854 --- a/src/main.c +++ b/src/main.c @@ -11,17 +11,18 @@ #include "main.h" -#include "browser.h" #include "global.h" #include "helpers.h" #include "sokoke.h" #include "search.h" -#include "webView.h" -#include "../katze/katze.h" + +#include "midori-websettings.h" +#include "midori-trash.h" +#include "midori-browser.h" +#include #include #include -#include #include "config.h" @@ -40,12 +41,7 @@ static void stock_items_init(void) { STOCK_BOOKMARK, "Bookmark", 0, 0, NULL }, { STOCK_BOOKMARK_NEW, "New Bookmark", 0, 0, NULL }, - { STOCK_BOOKMARKS, "_Bookmarks", 0, 0, NULL }, - { STOCK_DOWNLOADS, "_Downloads", 0, 0, NULL }, - { STOCK_CONSOLE, "_Console", 0, 0, NULL }, - { STOCK_EXTENSIONS, "_Extensions", 0, 0, NULL }, { STOCK_FORM_FILL, "_Form Fill", 0, 0, NULL }, - { STOCK_HISTORY, "History", 0, 0, NULL }, { STOCK_HOMEPAGE, "Homepage", 0, 0, NULL }, { STOCK_LOCATION, "Location Entry", 0, 0, NULL }, { STOCK_NEWSFEED, "Newsfeed", 0, 0, NULL }, @@ -81,7 +77,46 @@ static void stock_items_init(void) g_object_unref(factory); } -// -- main function +static gboolean +midori_browser_delete_event_cb (MidoriBrowser* browser, + GdkEvent* event, + GList* browsers) +{ + browsers = g_list_remove (browsers, browser); + if (g_list_nth (browsers, 0)) + return FALSE; + gtk_main_quit (); + return TRUE; +} + +static void +midori_browser_quit_cb (MidoriBrowser* browser, + GdkEvent* event, + GList* browsers) +{ + gtk_main_quit (); +} + +static void +midori_browser_new_window_cb (MidoriBrowser* browser, + const gchar* uri, + GList* browsers) +{ + MidoriBrowser* new_browser = g_object_new (MIDORI_TYPE_BROWSER, + // "settings", settings, + // "trash", trash, + NULL); + // gtk_window_add_accel_group (GTK_WINDOW (browser), accel_group); + g_object_connect (new_browser, + "signal::new-window", midori_browser_new_window_cb, browsers, + "signal::delete-event", midori_browser_delete_event_cb, browsers, + "signal::quit", midori_browser_quit_cb, browsers, + NULL); + browsers = g_list_prepend(browsers, new_browser); + gtk_widget_show (GTK_WIDGET (new_browser)); + + midori_browser_append_uri (new_browser, uri); +} int main(int argc, char** argv) { @@ -105,7 +140,7 @@ int main(int argc, char** argv) if(version) { - g_print(PACKAGE_STRING " - Copyright (c) 2007 Christian Dywan\n\n" + g_print(PACKAGE_STRING " - Copyright (c) 2007-2008 Christian Dywan\n\n" "GTK+2: " GTK_VER "\n" "WebKit: " WEBKIT_VER "\n" "Libsexy: " LIBSEXY_VER "\n" @@ -128,7 +163,7 @@ int main(int argc, char** argv) g_mkdir_with_parents(configPath, 0755); gchar* configFile = g_build_filename(configPath, "config", NULL); error = NULL; - config = config_new(); + /*CConfig* */config = config_new(); if(!config_from_file(config, configFile, &error)) { if(error->code != G_FILE_ERROR_NOENT) @@ -178,9 +213,9 @@ int main(int argc, char** argv) g_free(configFile); } configFile = g_build_filename(configPath, "tabtrash.xbel", NULL); - tabtrash = katze_xbel_folder_new(); + KatzeXbelItem* xbel_trash = katze_xbel_folder_new(); error = NULL; - if(!katze_xbel_folder_from_file(tabtrash, configFile, &error)) + if(!katze_xbel_folder_from_file(xbel_trash, configFile, &error)) { if(error->code != G_FILE_ERROR_NOENT) g_string_append_printf(errorMessages @@ -211,6 +246,7 @@ int main(int argc, char** argv) search_engines_free(searchEngines); katze_xbel_item_unref(bookmarks); katze_xbel_item_unref(_session); + katze_xbel_item_unref(xbel_trash); g_string_free(errorMessages, TRUE); return 0; } @@ -245,37 +281,68 @@ int main(int argc, char** argv) } g_free(configPath); - accel_group = gtk_accel_group_new(); stock_items_init(); - browsers = NULL; - webSettings = g_object_new(WEBKIT_TYPE_WEB_SETTINGS - , "default-font-family" , config->defaultFontFamily - , "default-font-size" , config->defaultFontSize - , "minimum-font-size" , config->minimumFontSize - , "default-encoding" , config->defaultEncoding - , "auto-load-images" , config->autoLoadImages - , "auto-shrink-images" , config->autoShrinkImages - , "print-backgrounds" , config->printBackgrounds - , "resizable-text-areas", config->resizableTextAreas - , "user-stylesheet-uri" , config->userStylesheet ? config->userStylesheetUri : NULL - , "enable-scripts" , config->enableScripts - , "enable-plugins" , config->enablePlugins - , NULL); + MidoriWebSettings* settings; + settings = g_object_new (MIDORI_TYPE_WEB_SETTINGS, + "default-font-family", config->defaultFontFamily, + "default-font-size", config->defaultFontSize, + "minimum-font-size", config->minimumFontSize, + "default-encoding", config->defaultEncoding, + "auto-load-images", config->autoLoadImages, + "auto-shrink-images", config->autoShrinkImages, + "print-backgrounds", config->printBackgrounds, + "resizable-text-areas", config->resizableTextAreas, + "user-stylesheet-uri", + config->userStylesheet ? + config->userStylesheetUri : NULL, + "enable-scripts", config->enableScripts, + "enable-plugins", config->enablePlugins, + "tab-label-size", config->tabSize, + "close-button", config->tabClose, + "middle-click-goto", config->middleClickGoto, + NULL); + webSettings = settings; - session = katze_xbel_folder_new(); - CBrowser* browser = NULL; - guint n = katze_xbel_folder_get_n_items(_session); + MidoriTrash* trash = g_object_new (MIDORI_TYPE_TRASH, + "limit", 10, + NULL); guint i; - for(i = 0; i < n; i++) + guint n = katze_xbel_folder_get_n_items (xbel_trash); + for (i = 0; i < n; i++) { - KatzeXbelItem* item = katze_xbel_folder_get_nth_item(_session, i); - browser = browser_new(browser); - webView_open(browser->webView, katze_xbel_bookmark_get_href(item)); + KatzeXbelItem* item = katze_xbel_folder_get_nth_item (xbel_trash, i); + midori_trash_prepend_xbel_item (trash, item); } - katze_xbel_item_unref(_session); - gtk_main(); + GtkAccelGroup* accel_group = gtk_accel_group_new(); + GList* browsers = NULL; + + MidoriBrowser* browser = g_object_new (MIDORI_TYPE_BROWSER, + "settings", settings, + "trash", trash, + NULL); + gtk_window_add_accel_group (GTK_WINDOW (browser), accel_group); + g_object_connect (browser, + "signal::new-window", midori_browser_new_window_cb, browsers, + "signal::delete-event", midori_browser_delete_event_cb, browsers, + "signal::quit", midori_browser_quit_cb, browsers, + NULL); + browsers = g_list_prepend(browsers, browser); + gtk_widget_show (GTK_WIDGET (browser)); + + KatzeXbelItem* session = katze_xbel_folder_new (); + n = katze_xbel_folder_get_n_items (_session); + for (i = 0; i < n; i++) + { + KatzeXbelItem* item = katze_xbel_folder_get_nth_item (_session, i); + midori_browser_append_xbel_item (browser, item); + } + katze_xbel_item_unref (_session); + + gtk_main (); + + g_object_unref (accel_group); // Save configuration files configPath = g_build_filename(g_get_user_config_dir(), PACKAGE_NAME, NULL); @@ -300,13 +367,13 @@ int main(int argc, char** argv) g_free(configFile); configFile = g_build_filename(configPath, "tabtrash.xbel", NULL); error = NULL; - if(!katze_xbel_folder_to_file(tabtrash, configFile, &error)) + if (!katze_xbel_folder_to_file (xbel_trash, configFile, &error)) { - g_warning("Tabtrash couldn't be saved. %s", error->message); - g_error_free(error); + g_warning ("Tabtrash couldn't be saved. %s", error->message); + g_error_free (error); } - katze_xbel_item_unref(tabtrash); - g_free(configFile); + katze_xbel_item_unref (xbel_trash); + g_free (configFile); if(config->startup == CONFIG_STARTUP_SESSION) { configFile = g_build_filename(configPath, "session.xbel", NULL); diff --git a/src/midori-browser.c b/src/midori-browser.c new file mode 100644 index 00000000..21e54763 --- /dev/null +++ b/src/midori-browser.c @@ -0,0 +1,2986 @@ +/* + Copyright (C) 2007-2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#include "config.h" + +#include "midori-browser.h" + +#include "global.h" +#include "conf.h" +#include "helpers.h" +#include "webSearch.h" +#include "prefs.h" + +#include "sokoke.h" +#include "midori-webview.h" +#include "midori-panel.h" +#include "midori-trash.h" + +#include +#include +#include +#include + +G_DEFINE_TYPE (MidoriBrowser, midori_browser, GTK_TYPE_WINDOW) + +struct _MidoriBrowserPrivate +{ + GtkActionGroup* action_group; + GtkWidget* menubar; + GtkWidget* menu_bookmarks; + GtkWidget* menu_tools; + GtkWidget* menu_window; + GtkWidget* popup_bookmark; + GtkWidget* throbber; + GtkWidget* navigationbar; + GtkWidget* button_tab_new; + GtkWidget* location_icon; + GtkWidget* location; + GtkWidget* search; + GtkWidget* button_trash; + GtkWidget* button_fullscreen; + GtkWidget* bookmarkbar; + + GtkWidget* panel; + GtkWidget* panel_bookmarks; + GtkWidget* panel_pageholder; + GtkWidget* notebook; + + GtkWidget* find; + GtkWidget* find_text; + GtkToolItem* find_case; + GtkToolItem* find_highlight; + + GtkWidget* statusbar; + GtkWidget* progressbar; + + gchar* uri; + gchar* title; + gchar* statusbar_text; + MidoriWebSettings* settings; + + KatzeXbelItem* proxy_xbel_folder; + MidoriTrash* trash; +}; + +#define MIDORI_BROWSER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + MIDORI_TYPE_BROWSER, MidoriBrowserPrivate)) + +enum +{ + PROP_0, + + PROP_SETTINGS, + PROP_STATUSBAR_TEXT, + PROP_TRASH +}; + +enum { + NEW_WINDOW, + STATUSBAR_TEXT_CHANGED, + ELEMENT_MOTION, + QUIT, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void +midori_browser_finalize (GObject* object); + +static void +midori_browser_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec); + +static void +midori_browser_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec); + +static GtkAction* +_action_by_name (MidoriBrowser* browser, + const gchar* name) +{ + MidoriBrowserPrivate* priv = browser->priv; + + return gtk_action_group_get_action (priv->action_group, name); +} + +static void +_action_set_sensitive (MidoriBrowser* browser, + const gchar* name, + gboolean sensitive) +{ + gtk_action_set_sensitive (_action_by_name (browser, name), sensitive); +} + +static void +_action_set_active (MidoriBrowser* browser, + const gchar* name, + gboolean active) +{ + GtkAction* action = _action_by_name (browser, name); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active); +} + +static void +_midori_browser_update_actions (MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + guint n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), n > 1); + _action_set_sensitive (browser, "TabClose", n > 1); + _action_set_sensitive (browser, "TabPrevious", n > 1); + _action_set_sensitive (browser, "TabNext", n > 1); + + if (priv->trash) + { + gboolean trash_empty = midori_trash_is_empty (priv->trash); + _action_set_sensitive (browser, "UndoTabClose", !trash_empty); + _action_set_sensitive (browser, "Trash", !trash_empty); + } +} + +static void +_midori_browser_update_interface (MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + gboolean loading = midori_web_view_is_loading (MIDORI_WEB_VIEW (web_view)); + /*_action_set_sensitive (browser, "ZoomIn", + webkit_web_view_can_increase_text_size (WEBKIT_WEB_VIEW (web_view))); + _action_set_sensitive (browser, "ZoomOut", + webkit_web_view_can_decrease_text_size (WEBKIT_WEB_VIEW (web_view))); + _action_set_sensitive (browser, "ZoomNormal", + webkit_web_view_get_text_size (WEBKIT_WEB_VIEW (web_view)) != 1);*/ + _action_set_sensitive (browser, "Back", + webkit_web_view_can_go_back (WEBKIT_WEB_VIEW (web_view))); + _action_set_sensitive (browser, "Back", + webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW (web_view))); + _action_set_sensitive (browser, "Reload", loading); + _action_set_sensitive (browser, "Stop", !loading); + + GtkAction* action = gtk_action_group_get_action (priv->action_group, + "ReloadStop"); + if (!loading) + { + gtk_widget_set_sensitive (priv->throbber, FALSE); + g_object_set (action, + "stock-id", GTK_STOCK_REFRESH, + "tooltip", "Reload the current page", NULL); + gtk_widget_hide (priv->progressbar); + } + else + { + gtk_widget_set_sensitive (priv->throbber, TRUE); + g_object_set (action, + "stock-id", GTK_STOCK_STOP, + "tooltip", "Stop loading the current page", NULL); + gtk_widget_show (priv->progressbar); + } + katze_throbber_set_animated (KATZE_THROBBER (priv->throbber), loading); + gtk_image_set_from_stock (GTK_IMAGE (priv->location_icon), + GTK_STOCK_FILE, GTK_ICON_SIZE_MENU); +} + +static GtkWidget* +_midori_browser_scrolled_for_child (MidoriBrowser* panel, + GtkWidget* child) +{ + GtkWidget* scrolled = gtk_widget_get_parent (child); + if (GTK_IS_VIEWPORT (scrolled)) + scrolled = gtk_widget_get_parent (scrolled); + return scrolled; +} + +static GtkWidget* +_midori_browser_child_for_scrolled (MidoriBrowser* panel, + GtkWidget* scrolled) +{ + GtkWidget* child = gtk_bin_get_child (GTK_BIN (scrolled)); + if (GTK_IS_VIEWPORT (child)) + child = gtk_bin_get_child (GTK_BIN (child)); + return child; +} + +static WebKitNavigationResponse +midori_web_view_navigation_requested_cb (GtkWidget* web_view, + WebKitWebFrame* web_frame, + WebKitNetworkRequest* request) +{ + WebKitNavigationResponse response = WEBKIT_NAVIGATION_RESPONSE_ACCEPT; + // FIXME: This isn't the place for uri scheme handling + const gchar* uri = webkit_network_request_get_uri (request); + gchar* protocol = strtok (g_strdup (uri), ":"); + if (spawn_protocol_command (protocol, uri)) + response = WEBKIT_NAVIGATION_RESPONSE_IGNORE; + g_free (protocol); + return response; +} + +static void +_midori_browser_set_statusbar_text (MidoriBrowser* browser, + const gchar* text) +{ + MidoriBrowserPrivate* priv = browser->priv; + + katze_assign (priv->statusbar_text, g_strdup (text)); + gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar), 1); + gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar), 1, + priv->statusbar_text ? priv->statusbar_text : ""); +} + +static void +_midori_browser_update_progress (MidoriBrowser* browser, + gint progress) +{ + MidoriBrowserPrivate* priv = browser->priv; + + if (progress > -1) + { + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progressbar), + progress ? progress / 100.0 : 0); + gchar* message = g_strdup_printf ("%d%% loaded", progress); + gtk_progress_bar_set_text (GTK_PROGRESS_BAR (priv->progressbar), + message); + g_free (message); + } + else + { + gtk_progress_bar_pulse (GTK_PROGRESS_BAR (priv->progressbar)); + gtk_progress_bar_set_text (GTK_PROGRESS_BAR (priv->progressbar), + NULL); + } +} + +static void +midori_web_view_load_started_cb (GtkWidget* web_view, + WebKitWebFrame* web_frame, + MidoriBrowser* browser) +{ + if (web_view == midori_browser_get_current_web_view (browser)) + { + _midori_browser_update_interface (browser); + _midori_browser_set_statusbar_text (browser, NULL); + } +} + +static void +midori_web_view_progress_started_cb (GtkWidget* web_view, + guint progress, + MidoriBrowser* browser) +{ + if (web_view == midori_browser_get_current_web_view (browser)) + _midori_browser_update_progress (browser, progress); +} + +static void +midori_web_view_progress_changed_cb (GtkWidget* web_view, + guint progress, + MidoriBrowser* browser) +{ + if (web_view == midori_browser_get_current_web_view (browser)) + _midori_browser_update_progress (browser, progress); +} + +static void +midori_web_view_progress_done_cb (GtkWidget* web_view, + guint progress, + MidoriBrowser* browser) +{ + if (web_view == midori_browser_get_current_web_view (browser)) + _midori_browser_update_progress (browser, progress); +} + +static void +midori_web_view_load_done_cb (GtkWidget* web_view, + WebKitWebFrame* web_frame, + MidoriBrowser* browser) +{ + if (web_view == midori_browser_get_current_web_view (browser)) + { + _midori_browser_update_interface (browser); + _midori_browser_set_statusbar_text (browser, NULL); + } +} + +static void +midori_web_view_title_changed_cb (GtkWidget* web_view, + WebKitWebFrame* web_frame, + const gchar* title, + MidoriBrowser* browser) +{ + if (web_view == midori_browser_get_current_web_view (browser)) + { + const gchar* title = midori_web_view_get_display_title ( + MIDORI_WEB_VIEW (web_view)); + gchar* window_title = g_strconcat (title, " - ", + g_get_application_name (), NULL); + gtk_window_set_title (GTK_WINDOW (browser), window_title); + g_free (window_title); + } +} + +static void +midori_web_view_statusbar_text_changed_cb (MidoriWebView* web_view, + const gchar* text, + MidoriBrowser* browser) +{ + _midori_browser_set_statusbar_text (browser, text); +} + +static void +midori_web_view_element_motion_cb (MidoriWebView* web_View, + const gchar* link_uri, + MidoriBrowser* browser) +{ + _midori_browser_set_statusbar_text (browser, link_uri); +} + +static void +midori_web_view_load_committed_cb (GtkWidget* web_view, + WebKitWebFrame* web_frame, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + if (web_view == midori_browser_get_current_web_view (browser)) + { + const gchar* uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view)); + gtk_entry_set_text (GTK_ENTRY (priv->location), uri); + _midori_browser_set_statusbar_text (browser, NULL); + } +} + +static gboolean +midori_web_view_console_message_cb (GtkWidget* web_view, + const gchar* message, + gint line, + const gchar* sourceId, + MidoriBrowser* browser) +{ + // FIXME: We want this to appear in a panel + return FALSE; +} + +static void +midori_web_view_populate_popup_cb (GtkWidget* web_view, + GtkWidget* menu, + MidoriBrowser* browser) +{ + const gchar* uri = midori_web_view_get_link_uri (MIDORI_WEB_VIEW (web_view)); + if (uri) + { + // TODO: bookmark link + } + + if (webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view))) + { + // TODO: view selection source + } + + if (!uri && !webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view))) + { + // TODO: menu items + // undo close tab + // sep + // BookmarkNew + // SaveAs + // SourceView + // Print + } +} + +static gboolean +midori_web_view_leave_notify_event_cb (GtkWidget* web_view, + GdkEventCrossing* event, + MidoriBrowser* browser) +{ + _midori_browser_set_statusbar_text (browser, NULL); + return TRUE; +} + +static void +midori_web_view_new_tab_cb (GtkWidget* web_view, + const gchar* uri, + MidoriBrowser* browser) +{ + midori_browser_append_uri (browser, uri); +} + +static void +midori_web_view_new_window_cb (GtkWidget* web_view, + const gchar* uri, + MidoriBrowser* browser) +{ + g_signal_emit (browser, signals[NEW_WINDOW], 0, uri); +} + +static void +midori_web_view_close_cb (GtkWidget* web_view, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + if (priv->proxy_xbel_folder) + { + KatzeXbelItem* xbel_item = midori_web_view_get_proxy_xbel_item ( + MIDORI_WEB_VIEW (web_view)); + const gchar* uri = katze_xbel_bookmark_get_href (xbel_item); + if (priv->trash && uri && *uri) + midori_trash_prepend_xbel_item (priv->trash, xbel_item); + katze_xbel_folder_remove_item (priv->proxy_xbel_folder, xbel_item); + katze_xbel_item_unref (xbel_item); + } + GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, web_view); + guint n = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), scrolled); + gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook), n); + + _midori_browser_update_actions (browser); +} + +static gboolean +midori_web_view_destroy_cb (GtkWidget* widget, + MidoriBrowser* browser) +{ + _midori_browser_update_actions (browser); + return FALSE; +} + +static void +midori_browser_class_init (MidoriBrowserClass* class) +{ + + signals[QUIT] = g_signal_new( + "quit", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + 0, + 0, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[NEW_WINDOW] = g_signal_new( + "new-window", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriBrowserClass, new_window), + 0, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + GObjectClass* gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = midori_browser_finalize; + gobject_class->set_property = midori_browser_set_property; + gobject_class->get_property = midori_browser_get_property; + + GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT; + + /** + * MidoriBrowser::settings + * + * An associated settings instance that is shared among all web views. + * + * Setting this value is propagated to every present web view. Also + * every newly created web view will use this instance automatically. + */ + g_object_class_install_property (gobject_class, + PROP_SETTINGS, + g_param_spec_object ( + "settings", + "Settings", + "The associated settings", + MIDORI_TYPE_WEB_SETTINGS, + G_PARAM_READWRITE)); + + /** + * MidoriBrowser::statusbar-text + * + * The text that is displayed in the statusbar. + * + * This value reflects changes to the text visible in the statusbar, such + * as the uri of a hyperlink the mouse hovers over or the description of + * a menuitem. + * + * Setting this value changes the displayed text until the next change. + */ + g_object_class_install_property (gobject_class, + PROP_STATUSBAR_TEXT, + g_param_spec_string ( + "statusbar-text", + "Statusbar Text", + "The text that is displayed in the statusbar", + "", + flags)); + + /** + * MidoriBrowser::trash + * + * The trash, that collects all closed tabs and windows. + * + * This is actually a reference to a trash instance, so if a trash should + * be used it must be initially set. + * + * Note: In the future the trash might collect other types of items. + */ + g_object_class_install_property (gobject_class, + PROP_TRASH, + g_param_spec_object ( + "trash", + "Trash", + "The trash, collecting recently closed tabs and windows", + MIDORI_TYPE_TRASH, + G_PARAM_READWRITE)); + + g_type_class_add_private (class, sizeof (MidoriBrowserPrivate)); +} + +static void +_action_window_new_activate (GtkAction* action, + MidoriBrowser* browser) +{ + g_signal_emit (browser, signals[NEW_WINDOW], 0, "about:blank"); +} + +static void +_action_tab_new_activate (GtkAction* action, + MidoriBrowser* browser) +{ + midori_browser_append_uri (browser, "about:blank"); +} + +static void +_action_open_activate (GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* dialog = gtk_file_chooser_dialog_new ( + "Open file", GTK_WINDOW (browser), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_OPEN); + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + gchar* uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog)); + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + g_object_set (web_view, "uri", uri, NULL); + g_free (uri); + } + gtk_widget_destroy (dialog); +} + +static void +_action_tab_close_activate (GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + gtk_widget_destroy (web_view); +} + +static void +_action_window_close_activate (GtkAction* action, + MidoriBrowser* browser) +{ + gtk_widget_destroy (GTK_WIDGET (browser)); +} + +static void +_action_quit_activate (GtkAction* action, + MidoriBrowser* browser) +{ + gtk_main_quit (); +} + +static void +_action_edit_activate(GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser)); + gboolean can_cut = FALSE, can_copy = FALSE, can_paste = FALSE; + gboolean has_selection; + + if (WEBKIT_IS_WEB_VIEW (widget)) + { + WebKitWebView* web_view = WEBKIT_WEB_VIEW (widget); + can_cut = webkit_web_view_can_cut_clipboard (web_view); + can_copy = webkit_web_view_can_copy_clipboard (web_view); + can_paste = webkit_web_view_can_paste_clipboard (web_view); + } + else if (GTK_IS_EDITABLE (widget)) + { + GtkEditable* editable = GTK_EDITABLE (widget); + has_selection = gtk_editable_get_selection_bounds (editable, NULL, NULL); + can_cut = has_selection && gtk_editable_get_editable (editable); + can_copy = has_selection; + can_paste = gtk_editable_get_editable (editable); + } + + _action_set_sensitive (browser, "Cut", can_cut); + _action_set_sensitive (browser, "Copy", can_copy); + _action_set_sensitive (browser, "Paste", can_paste); + _action_set_sensitive (browser, "Delete", can_cut); + _action_set_sensitive (browser, "SelectAll", FALSE); +} + +static void +_action_cut_activate(GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser)); + if (G_LIKELY (widget)) + g_signal_emit_by_name (widget, "cut-clipboard"); +} + +static void +_action_copy_activate(GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser)); + if (G_LIKELY (widget)) + g_signal_emit_by_name (widget, "copy-clipboard"); +} + +static void +_action_paste_activate(GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser)); + if (G_LIKELY (widget)) + g_signal_emit_by_name (widget, "paste-clipboard"); +} + +static void +_action_delete_activate(GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser)); + if (G_LIKELY (widget)) + { + if (WEBKIT_IS_WEB_VIEW (widget)) + webkit_web_view_delete_selection (WEBKIT_WEB_VIEW (widget)); + else if (GTK_IS_EDITABLE(widget)) + gtk_editable_delete_selection (GTK_EDITABLE (widget)); + } +} + +static void +_action_select_all_activate(GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* widget = gtk_window_get_focus (GTK_WINDOW (browser)); + if (G_LIKELY (widget)) + { + if (GTK_IS_ENTRY (widget)) + gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1); + else + g_signal_emit_by_name (widget, "select-all"); + } +} + +static void +_action_find_activate(GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + if (GTK_WIDGET_VISIBLE (priv->find)) + { + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (web_view)); + gtk_toggle_tool_button_set_active ( + GTK_TOGGLE_TOOL_BUTTON (priv->find_highlight), FALSE); + gtk_widget_hide (priv->find); + } + else + { + GtkWidget* icon = gtk_image_new_from_stock (GTK_STOCK_FIND, + GTK_ICON_SIZE_MENU); + sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (priv->find_text), + SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE (icon)); + gtk_entry_set_text (GTK_ENTRY (priv->find_text), ""); + gtk_widget_show (priv->find); + gtk_widget_grab_focus (GTK_WIDGET (priv->find_text)); + } +} + +static void +_midori_browser_find (MidoriBrowser* browser, + gboolean forward) +{ + MidoriBrowserPrivate* priv = browser->priv; + + const gchar* text = gtk_entry_get_text (GTK_ENTRY (priv->find_text)); + const gboolean case_sensitive = gtk_toggle_tool_button_get_active ( + GTK_TOGGLE_TOOL_BUTTON(priv->find_case)); + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + if (GTK_WIDGET_VISIBLE (priv->find)) + webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (web_view)); + gboolean found = webkit_web_view_search_text (WEBKIT_WEB_VIEW (web_view), + text, case_sensitive, forward, TRUE); + if (GTK_WIDGET_VISIBLE (priv->find)) + { + GtkWidget* icon; + if (found) + icon = gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); + else + icon = gtk_image_new_from_stock (GTK_STOCK_STOP, GTK_ICON_SIZE_MENU); + sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (priv->find_text), + SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(icon)); + webkit_web_view_mark_text_matches (WEBKIT_WEB_VIEW (web_view), text, + case_sensitive, 0); + const gboolean highlight = gtk_toggle_tool_button_get_active ( + GTK_TOGGLE_TOOL_BUTTON (priv->find_highlight)); + webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW (web_view), + highlight); + } +} + +static void +_action_find_next_activate (GtkAction* action, + MidoriBrowser* browser) +{ + _midori_browser_find (browser, TRUE); +} + +static void +_action_find_previous_activate (GtkAction* action, + MidoriBrowser* browser) +{ + _midori_browser_find (browser, FALSE); +} + +static void +_find_highlight_toggled (GtkToggleToolButton* toolitem, + MidoriBrowser* browser) +{ + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + const gboolean highlight = gtk_toggle_tool_button_get_active (toolitem); + webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW (web_view), + highlight); +} + +static void +midori_browser_find_button_close_clicked_cb (GtkWidget* widget, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + gtk_widget_hide (priv->find); +} + +static void +midori_browser_navigationbar_notify_style_cb (GObject* object, + GParamSpec* arg1, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + if (config->toolbarStyle == CONFIG_TOOLBAR_DEFAULT) + { + gtk_toolbar_set_style (GTK_TOOLBAR(priv->navigationbar), + config_to_toolbarstyle (config->toolbarStyle)); + } +} + +static void +midori_browser_menu_trash_item_activate_cb (GtkWidget* menuitem, + MidoriBrowser* browser) +{ + // Create a new web view with an uri which has been closed before + KatzeXbelItem* item = g_object_get_data (G_OBJECT (menuitem), + "KatzeXbelItem"); + const gchar* uri = katze_xbel_bookmark_get_href (item); + midori_browser_append_uri (browser, uri); + katze_xbel_item_unref (item); +} + +static void +midori_browser_menu_trash_activate_cb (GtkWidget* widget, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkWidget* menu = gtk_menu_new (); + guint n = midori_trash_get_n_items (priv->trash); + GtkWidget* menuitem; + guint i; + for (i = 0; i < n; i++) + { + KatzeXbelItem* item = midori_trash_get_nth_xbel_item (priv->trash, i); + const gchar* title = katze_xbel_item_get_title (item); + const gchar* uri = katze_xbel_bookmark_get_href (item); + menuitem = gtk_image_menu_item_new_with_label (title ? title : uri); + // FIXME: Get the real icon + GtkWidget* icon = gtk_image_new_from_stock (GTK_STOCK_FILE, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); + gtk_menu_shell_append(GTK_MENU_SHELL (menu), menuitem); + g_object_set_data (G_OBJECT (menuitem), "KatzeXbelItem", item); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_browser_menu_trash_item_activate_cb), browser); + gtk_widget_show (menuitem); + } + + menuitem = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + GtkAction* action = gtk_action_group_get_action (priv->action_group, + "TrashEmpty"); + menuitem = gtk_action_create_menu_item (action); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + sokoke_widget_popup (widget, GTK_MENU (menu), NULL); +} + +static void +_action_preferences_activate (GtkAction* action, + MidoriBrowser* browser) +{ + // Show the preferences dialog. Create it if necessary. + static GtkWidget* dialog = NULL; + if (GTK_IS_DIALOG (dialog)) + gtk_window_present (GTK_WINDOW (dialog)); + else + { + dialog = prefs_preferences_dialog_new (browser); + gtk_widget_show (dialog); + } +} + +static void +_action_navigationbar_activate (GtkToggleAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + config->toolbarNavigation = gtk_toggle_action_get_active (action); + sokoke_widget_set_visible (priv->navigationbar, config->toolbarNavigation); +} + +static void +_action_bookmarkbar_activate (GtkToggleAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + config->toolbarBookmarks = gtk_toggle_action_get_active (action); + sokoke_widget_set_visible (priv->bookmarkbar, config->toolbarBookmarks); +} + +static void +_action_statusbar_activate (GtkToggleAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + config->toolbarStatus = gtk_toggle_action_get_active (action); + sokoke_widget_set_visible (priv->statusbar, config->toolbarStatus); +} + +static void +_action_reload_stop_activate (GtkAction* action, + MidoriBrowser* browser) +{ + gchar* stock_id; + g_object_get (action, "stock-id", &stock_id, NULL); + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + // Refresh or stop, depending on the stock id + if (!strcmp (stock_id, GTK_STOCK_REFRESH)) + { + /*GdkModifierType state = (GdkModifierType)0; + gint x, y; + gdk_window_get_pointer (NULL, &x, &y, &state); + gboolean from_cache = state & GDK_SHIFT_MASK;*/ + webkit_web_view_reload (WEBKIT_WEB_VIEW (web_view)); + } + else + webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view)); + g_free (stock_id); +} + +/*static void +_action_zoom_in_activate (GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + const gfloat zoom = webkit_web_view_get_text_multiplier ( + WEBKIT_WEB_VIEW (web_view)); + webkit_web_view_set_text_multiplier (WEBKIT_WEB_VIEW (web_view), zoom + 0.1); +}*/ + +/*static void +_action_zoom_out_activate (GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + const gfloat zoom = webkit_web_view_get_text_multiplier ( + WEBKIT_WEB_VIEW (web_view)); + webkit_web_view_set_text_multiplier (WEBKIT_WEB_VIEW (web_view), zoom - 0.1); +}*/ + +/*static void +_action_zoom_normal_activate (GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + webkit_web_view_set_text_multiplier (WEBKIT_WEB_VIEW (web_View, 1)); +}*/ + +/*static void +_action_source_view_activate (GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + gchar* source = webkit_web_view_copy_source (WEBKIT_WEB_VIEW (web_view)); + webkit_web_view_load_html_string (WEBKIT_WEB_VIEW (web_view), source, ""); + g_free (source); +}*/ + +static void +_action_fullscreen_activate (GtkAction* action, + MidoriBrowser* browser) +{ + GdkWindowState state = gdk_window_get_state (GTK_WIDGET (browser)->window); + if (state & GDK_WINDOW_STATE_FULLSCREEN) + gtk_window_unfullscreen (GTK_WINDOW (browser)); + else + gtk_window_fullscreen (GTK_WINDOW (browser)); +} + +static void +_action_back_activate (GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + webkit_web_view_go_back (WEBKIT_WEB_VIEW (web_view)); +} + +static void +_action_forward_activate (GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + webkit_web_view_go_forward (WEBKIT_WEB_VIEW (web_view)); +} + +static void +_action_home_activate (GtkAction* action, + MidoriBrowser* browser) +{ + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + g_object_set (web_view, "uri", config->homepage, NULL); +} + +static gboolean +midori_browser_location_key_press_event_cb (GtkWidget* widget, + GdkEventKey* event, + MidoriBrowser* browser) +{ + switch (event->keyval) + { + case GDK_Return: + { + const gchar* uri = gtk_entry_get_text (GTK_ENTRY (widget)); + if (uri) + { + gchar* new_uri = magic_uri (uri, TRUE); + // TODO: Use new_uri intermediately when completion is better + /* TODO Completion should be generated from history, that is + the uri as well as the title. */ + entry_completion_append (GTK_ENTRY (widget), uri); + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + g_object_set (web_view, "uri", new_uri, NULL); + g_free (new_uri); + } + return TRUE; + } + case GDK_Escape: + { + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + const gchar* uri = midori_web_view_get_display_uri ( + MIDORI_WEB_VIEW (web_view)); + gtk_entry_set_text (GTK_ENTRY (widget), uri); + return TRUE; + } + } + return FALSE; +} + +static void +_action_location_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + if (GTK_WIDGET_VISIBLE (priv->navigationbar)) + gtk_widget_grab_focus (priv->location); + else + { + // TODO: We should offer all of the location's features here + GtkWidget* dialog; + dialog = gtk_dialog_new_with_buttons ("Open location" + , GTK_WINDOW (browser) + , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR + , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL + , GTK_STOCK_JUMP_TO, GTK_RESPONSE_ACCEPT + , NULL); + gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_JUMP_TO); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_container_set_border_width ( + GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 5); + GtkWidget* hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + GtkWidget* label = gtk_label_new_with_mnemonic ("_Location:"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + GtkWidget* entry = gtk_entry_new (); + gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); + gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all( hbox); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), + GTK_RESPONSE_ACCEPT); + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + gtk_entry_set_text (GTK_ENTRY (priv->location) + , gtk_entry_get_text (GTK_ENTRY (entry))); + GdkEventKey event; + event.keyval = GDK_Return; + midori_browser_location_key_press_event_cb (priv->location, + &event, browser); + } + gtk_widget_destroy (dialog); + } +} + +static void +_action_search_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + if (GTK_WIDGET_VISIBLE (priv->search) + && GTK_WIDGET_VISIBLE (priv->navigationbar)) + gtk_widget_grab_focus (priv->search); + else + { + // TODO: We should offer all of the search's features here + GtkWidget* dialog = gtk_dialog_new_with_buttons ("Web search" + , GTK_WINDOW (browser) + , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR + , GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL + , GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT + , NULL); + gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_FIND); + gtk_container_set_border_width(GTK_CONTAINER (dialog), 5); + gtk_container_set_border_width ( + GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 5); + GtkWidget* hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + GtkWidget* label = gtk_label_new_with_mnemonic ("_Location:"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + GtkWidget* entry = gtk_entry_new (); + gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); + gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all (hbox); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), + GTK_RESPONSE_ACCEPT); + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + gtk_entry_set_text (GTK_ENTRY (priv->search) + , gtk_entry_get_text (GTK_ENTRY (entry))); + on_webSearch_activate (priv->search, browser); + } + gtk_widget_destroy (dialog); + } +} + +static void +midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser, + KatzeXbelItem* bookmark) +{ + MidoriBrowserPrivate* priv = browser->priv; + + gboolean new_bookmark = !bookmark; + GtkWidget* dialog = gtk_dialog_new_with_buttons ( + new_bookmark ? "New bookmark" : "Edit bookmark", + GTK_WINDOW (browser), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + new_bookmark ? GTK_STOCK_ADD : GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_icon_name (GTK_WINDOW (dialog), + new_bookmark ? GTK_STOCK_ADD : GTK_STOCK_REMOVE); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 5); + GtkSizeGroup* sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + if (new_bookmark) + bookmark = katze_xbel_bookmark_new (); + + GtkWidget* hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + GtkWidget* label = gtk_label_new_with_mnemonic ("_Title:"); + gtk_size_group_add_widget (sizegroup, label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + GtkWidget* entry_title = gtk_entry_new (); + gtk_entry_set_activates_default (GTK_ENTRY (entry_title), TRUE); + if (!new_bookmark) + { + const gchar* title = katze_xbel_item_get_title (bookmark); + gtk_entry_set_text (GTK_ENTRY (entry_title), title ? title : ""); + } + gtk_box_pack_start (GTK_BOX (hbox), entry_title, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all (hbox); + + hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + label = gtk_label_new_with_mnemonic ("_Description:"); + gtk_size_group_add_widget (sizegroup, label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + GtkWidget* entry_desc = gtk_entry_new (); + gtk_entry_set_activates_default (GTK_ENTRY (entry_desc), TRUE); + if (!new_bookmark) + { + const gchar* desc = katze_xbel_item_get_desc (bookmark); + gtk_entry_set_text (GTK_ENTRY (entry_desc), desc ? desc : ""); + } + gtk_box_pack_start (GTK_BOX (hbox), entry_desc, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all (hbox); + + GtkWidget* entry_uri = NULL; + if (katze_xbel_item_is_bookmark (bookmark)) + { + hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + label = gtk_label_new_with_mnemonic ("_Uri:"); + gtk_size_group_add_widget (sizegroup, label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + entry_uri = gtk_entry_new (); + gtk_entry_set_activates_default (GTK_ENTRY (entry_uri), TRUE); + if (!new_bookmark) + gtk_entry_set_text (GTK_ENTRY (entry_uri), + katze_xbel_bookmark_get_href (bookmark)); + gtk_box_pack_start (GTK_BOX(hbox), entry_uri, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all (hbox); + } + + GtkWidget* combo_folder = NULL; + if (new_bookmark) + { + hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + label = gtk_label_new_with_mnemonic ("_Folder:"); + gtk_size_group_add_widget (sizegroup, label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + combo_folder = gtk_combo_box_new_text (); + gtk_combo_box_append_text (GTK_COMBO_BOX (combo_folder), "Root"); + gtk_widget_set_sensitive (combo_folder, FALSE); + gtk_box_pack_start (GTK_BOX (hbox), combo_folder, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all (hbox); + } + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + katze_xbel_item_set_title (bookmark, + gtk_entry_get_text (GTK_ENTRY (entry_title))); + katze_xbel_item_set_desc (bookmark, + gtk_entry_get_text(GTK_ENTRY(entry_desc))); + if (katze_xbel_item_is_bookmark (bookmark)) + katze_xbel_bookmark_set_href (bookmark, + gtk_entry_get_text (GTK_ENTRY (entry_uri))); + + // FIXME: We want to choose a folder + if (new_bookmark) + { + katze_xbel_folder_append_item (bookmarks, bookmark); + GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks); + GtkTreeModel* treemodel = gtk_tree_view_get_model (treeview); + GtkTreeIter iter; + gtk_tree_store_insert_with_values (GTK_TREE_STORE (treemodel), + &iter, NULL, G_MAXINT, 0, bookmark, -1); + katze_xbel_item_ref (bookmark); + } + + // FIXME: update navigationbar + // FIXME: Update panel in other windows + } + gtk_widget_destroy (dialog); +} + +static void +midori_panel_bookmarks_row_activated_cb (GtkTreeView* treeview, + GtkTreePath* path, + GtkTreeViewColumn* column, + MidoriBrowser* browser) +{ + GtkTreeModel* model = gtk_tree_view_get_model (treeview); + GtkTreeIter iter; + if (gtk_tree_model_get_iter (model, &iter, path)) + { + KatzeXbelItem* item; + gtk_tree_model_get (model, &iter, 0, &item, -1); + if (katze_xbel_item_is_bookmark (item)) + { + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + const gchar* uri = katze_xbel_bookmark_get_href (item); + g_object_set (web_view, "uri", uri, NULL); + } + } +} + +static void +midori_panel_bookmarks_cursor_or_row_changed_cb (GtkTreeView* treeview, + MidoriBrowser* browser) +{ + GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview); + if (selection) + { + GtkTreeModel* model; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + KatzeXbelItem* item; + gtk_tree_model_get (model, &iter, 0, &item, -1); + + gboolean is_separator = katze_xbel_item_is_separator (item); + _action_set_sensitive (browser, "BookmarkEdit", !is_separator); + _action_set_sensitive (browser, "BookmarkDelete", TRUE); + } + else + { + _action_set_sensitive (browser, "BookmarkEdit", FALSE); + _action_set_sensitive (browser, "BookmarkDelete", FALSE); + } + } +} + +static void +_midori_panel_bookmarks_popup (GtkWidget* widget, + GdkEventButton* event, + KatzeXbelItem* item, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + gboolean is_bookmark = katze_xbel_item_is_bookmark (item); + + _action_set_sensitive (browser, "BookmarkOpen", is_bookmark); + _action_set_sensitive (browser, "BookmarkOpenTab", is_bookmark); + _action_set_sensitive (browser, "BookmarkOpenWindow", is_bookmark); + + sokoke_widget_popup (widget, GTK_MENU (priv->popup_bookmark), event); +} + +static gboolean +midori_panel_bookmarks_button_release_event_cb (GtkWidget* widget, + GdkEventButton* event, + MidoriBrowser* browser) +{ + if (event->button != 2 && event->button != 3) + return FALSE; + + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); + if (selection) + { + GtkTreeModel* model; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + KatzeXbelItem* item; + gtk_tree_model_get(model, &iter, 0, &item, -1); + if (event->button == 2 && katze_xbel_item_is_bookmark(item)) + { + const gchar* uri = katze_xbel_bookmark_get_href(item); + midori_browser_append_uri (browser, uri); + } + else + _midori_panel_bookmarks_popup(widget, event, item, browser); + return TRUE; + } + } + return FALSE; +} + +static void +midori_panel_bookmarks_popup_menu_cb (GtkWidget* widget, + MidoriBrowser* browser) +{ + GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); + if (selection) + { + GtkTreeModel* model; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + KatzeXbelItem* item; + gtk_tree_model_get(model, &iter, 0, &item, -1); + _midori_panel_bookmarks_popup(widget, NULL, item, browser); + } + } +} + +static void +_tree_store_insert_folder (GtkTreeStore* treestore, + GtkTreeIter* parent, + KatzeXbelItem* folder) +{ + guint n = katze_xbel_folder_get_n_items (folder); + guint i; + for (i = 0; i < n; i++) + { + KatzeXbelItem* item = katze_xbel_folder_get_nth_item (folder, i); + GtkTreeIter iter; + gtk_tree_store_insert_with_values (treestore, &iter, parent, n, + 0, item, -1); + katze_xbel_item_ref (item); + if (katze_xbel_item_is_folder (item)) + _tree_store_insert_folder (treestore, &iter, item); + } +} + +static void +midori_browser_bookmarks_item_render_icon_cb (GtkTreeViewColumn* column, + GtkCellRenderer* renderer, + GtkTreeModel* model, + GtkTreeIter* iter, + GtkWidget* treeview) +{ + KatzeXbelItem* item; + gtk_tree_model_get (model, iter, 0, &item, -1); + + if (G_UNLIKELY (!item)) + return; + if (G_UNLIKELY (!katze_xbel_item_get_parent (item))) + { + gtk_tree_store_remove (GTK_TREE_STORE (model), iter); + katze_xbel_item_unref (item); + return; + } + + // TODO: Would it be better to not do this on every redraw? + GdkPixbuf* pixbuf = NULL; + if (katze_xbel_item_is_bookmark (item)) + pixbuf = gtk_widget_render_icon (treeview, STOCK_BOOKMARK, + GTK_ICON_SIZE_MENU, NULL); + else if (katze_xbel_item_is_folder (item)) + pixbuf = gtk_widget_render_icon (treeview, GTK_STOCK_DIRECTORY, + GTK_ICON_SIZE_MENU, NULL); + g_object_set (renderer, "pixbuf", pixbuf, NULL); + if (pixbuf) + g_object_unref (pixbuf); +} + +static void +midori_browser_bookmarks_item_render_text_cb (GtkTreeViewColumn* column, + GtkCellRenderer* renderer, + GtkTreeModel* model, + GtkTreeIter* iter, + GtkWidget* treeview) +{ + KatzeXbelItem* item; + gtk_tree_model_get (model, iter, 0, &item, -1); + + if (G_UNLIKELY (!item)) + return; + if (G_UNLIKELY (!katze_xbel_item_get_parent (item))) + { + gtk_tree_store_remove (GTK_TREE_STORE (model), iter); + katze_xbel_item_unref (item); + return; + } + + if (katze_xbel_item_is_separator (item)) + g_object_set (renderer, "markup", "Separator", NULL); + else + g_object_set (renderer, "markup", NULL, + "text", katze_xbel_item_get_title(item), NULL); +} + +static void +_midori_browser_create_bookmark_menu (MidoriBrowser* browser, + KatzeXbelItem* folder, + GtkWidget* menu); + +static void +midori_browser_bookmark_menu_folder_activate_cb (GtkWidget* menuitem, + MidoriBrowser* browser) +{ + GtkWidget* menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menuitem)); + gtk_container_foreach(GTK_CONTAINER (menu), (GtkCallback) gtk_widget_destroy, NULL);//... + KatzeXbelItem* folder = (KatzeXbelItem*)g_object_get_data(G_OBJECT (menuitem), "KatzeXbelItem"); + _midori_browser_create_bookmark_menu (browser, folder, menu); + // Remove all menuitems when the menu is hidden. + // FIXME: We really *want* the line below, but it won't work like that + //g_signal_connect_after (menu, "hide", G_CALLBACK (gtk_container_foreach), gtk_widget_destroy); + gtk_widget_show (menuitem); +} + +static void +midori_browser_bookmarkbar_folder_activate_cb (GtkToolItem* toolitem, + MidoriBrowser* browser) +{ + GtkWidget* menu = gtk_menu_new(); + KatzeXbelItem* folder = (KatzeXbelItem*)g_object_get_data ( + G_OBJECT (toolitem), "KatzeXbelItem"); + _midori_browser_create_bookmark_menu (browser, folder, menu); + // Remove all menuitems when the menu is hidden. + // FIXME: We really *should* run the line below, but it won't work like that + /*g_signal_connect (menu, "hide", G_CALLBACK (gtk_container_foreach), + gtk_widget_destroy);*/ + sokoke_widget_popup (GTK_WIDGET (toolitem), GTK_MENU (menu), NULL); +} + +static void +midori_browser_menu_bookmarks_item_activate_cb (GtkWidget* widget, + MidoriBrowser* browser) +{ + KatzeXbelItem* item = (KatzeXbelItem*)g_object_get_data(G_OBJECT(widget), "KatzeXbelItem"); + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + g_object_set (web_view, "uri", katze_xbel_bookmark_get_href (item), NULL); +} + +static void +_midori_browser_create_bookmark_menu (MidoriBrowser* browser, + KatzeXbelItem* folder, + GtkWidget* menu) +{ + guint n = katze_xbel_folder_get_n_items (folder); + guint i; + for (i = 0; i < n; i++) + { + KatzeXbelItem* item = katze_xbel_folder_get_nth_item (folder, i); + const gchar* title = katze_xbel_item_is_separator (item) + ? "" : katze_xbel_item_get_title (item); + /* const gchar* desc = katze_xbel_item_is_separator (item) + ? "" : katze_xbel_item_get_desc (item); */ + GtkWidget* menuitem = NULL; + switch (katze_xbel_item_get_kind (item)) + { + case KATZE_XBEL_ITEM_KIND_FOLDER: + // FIXME: what about katze_xbel_folder_is_folded? + menuitem = gtk_image_menu_item_new_with_label (title); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), + gtk_image_new_from_stock (GTK_STOCK_DIRECTORY, + GTK_ICON_SIZE_MENU)); + GtkWidget* _menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), _menu); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_browser_bookmark_menu_folder_activate_cb), + browser); + g_object_set_data (G_OBJECT (menuitem), "KatzeXbelItem", item); + break; + case KATZE_XBEL_ITEM_KIND_BOOKMARK: + menuitem = gtk_image_menu_item_new_with_label (title); + GtkWidget* image = gtk_image_new_from_stock (STOCK_BOOKMARK, + GTK_ICON_SIZE_MENU); + gtk_widget_show (image); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), + image); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_browser_menu_bookmarks_item_activate_cb), + browser); + g_object_set_data (G_OBJECT (menuitem), "KatzeXbelItem", item); + break; + case KATZE_XBEL_ITEM_KIND_SEPARATOR: + menuitem = gtk_separator_menu_item_new (); + break; + default: + g_warning ("Unknown xbel item kind"); + } + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + } +} + +static void +_action_bookmark_new_activate (GtkAction* action, + MidoriBrowser* browser) +{ + midori_browser_edit_bookmark_dialog_new (browser, NULL); +} + +static void +_action_manage_search_engines_activate (GtkAction* action, + MidoriBrowser* browser) +{ + // Show the Manage search engines dialog. Create it if necessary. + static GtkWidget* dialog; + if (GTK_IS_DIALOG (dialog)) + gtk_window_present (GTK_WINDOW (dialog)); + else + { + dialog = webSearch_manageSearchEngines_dialog_new (browser); + gtk_widget_show (dialog); + } +} + +static void +_action_tab_previous_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n - 1); +} + +static void +_action_tab_next_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + // Advance one tab or jump to the first one if we are at the last one + gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); + if (n == gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)) - 1) + n = -1; + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n + 1); +} + +static void +midori_browser_window_menu_item_activate_cb (GtkWidget* widget, + GtkWidget* web_view) +{ + MidoriBrowser* browser = MIDORI_BROWSER (gtk_widget_get_toplevel (web_view)); + if (!browser) + { + g_warning ("Orphaned web view"); + return; + } + + MidoriBrowserPrivate* priv = browser->priv; + + GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, web_view); + guint n = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), scrolled); + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n); +} + +static const gchar* credits_authors[] = { + "Christian Dywan ", NULL }; +static const gchar* credits_documenters/*[]*/ = /*{ + */NULL/* }*/; +static const gchar* credits_artists[] = { + "Nancy Runge ", NULL }; + +static const gchar* license = + "This library is free software; you can redistribute it and/or\n" + "modify it under the terms of the GNU Lesser General Public\n" + "License as published by the Free Software Foundation; either\n" + "version 2.1 of the License, or (at your option) any later version.\n"; + +static void +_action_about_activate (GtkAction* action, + MidoriBrowser* browser) +{ + gtk_show_about_dialog (GTK_WINDOW (browser), + "logo-icon-name", gtk_window_get_icon_name (GTK_WINDOW (browser)), + "name", PACKAGE_NAME, + "version", PACKAGE_VERSION, + "comments", "A lightweight web browser.", + "copyright", "Copyright © 2007-2008 Christian Dywan", + "website", "http://software.twotoasts.de", + "authors", credits_authors, + "documenters", credits_documenters, + "artists", credits_artists, + "license", license, + "wrap-license", TRUE, + // "translator-credits", _("translator-credits"), + NULL); +} + +static void +midori_browser_location_changed_cb (GtkWidget* widget, + MidoriBrowser* browser) +{ + // Preserve changes to the uri + /*const gchar* newUri = gtk_entry_get_text(GTK_ENTRY(widget)); + katze_xbel_bookmark_set_href(browser->sessionItem, newUri);*/ + // FIXME: If we want this feature, this is the wrong approach +} + +static void +_action_panel_activate (GtkToggleAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + config->panelShow = gtk_toggle_action_get_active (action); + sokoke_widget_set_visible (priv->panel, config->panelShow); +} + +static void +_action_open_in_panel_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + const gchar* uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view)); + katze_assign (config->panelPageholder, g_strdup (uri)); + gint n = midori_panel_page_num (MIDORI_PANEL (priv->panel), + priv->panel_pageholder); + midori_panel_set_current_page (MIDORI_PANEL (priv->panel), n); + gtk_widget_show (priv->panel); + g_object_set (priv->panel_pageholder, "uri", config->panelPageholder, NULL); +} + + +static void +midori_panel_notify_position_cb (GObject* object, + GParamSpec* arg1, + MidoriBrowser* browser) +{ + config->winPanelPos = gtk_paned_get_position (GTK_PANED (object)); +} + +static gboolean +midori_panel_close_cb (MidoriPanel* panel, + MidoriBrowser* browser) +{ + config->panelShow = FALSE; + return FALSE; +} + +static void +gtk_notebook_switch_page_cb (GtkWidget* widget, + GtkNotebookPage* page, + guint page_num, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkWidget* web_view = midori_browser_get_current_web_view (browser); + const gchar* uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view)); + gtk_entry_set_text (GTK_ENTRY (priv->location), uri); + const gchar* title = midori_web_view_get_display_title ( + MIDORI_WEB_VIEW (web_view)); + gchar* window_title = g_strconcat (title, " - ", + g_get_application_name (), NULL); + gtk_window_set_title (GTK_WINDOW (browser), window_title); + g_free (window_title); + _midori_browser_set_statusbar_text (browser, NULL); + _midori_browser_update_interface (browser); +} + +static void +_action_bookmark_open_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks); + GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview); + if (selection) + { + GtkTreeModel* model; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + KatzeXbelItem* item; + gtk_tree_model_get (model, &iter, 0, &item, -1); + if (katze_xbel_item_is_bookmark (item)) + g_object_set(midori_browser_get_current_web_view (browser), + "uri", katze_xbel_bookmark_get_href(item), NULL); + } + } +} + +static void +_action_bookmark_open_tab_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks); + GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview); + if (selection) + { + GtkTreeModel* model; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + KatzeXbelItem* item; + gtk_tree_model_get (model, &iter, 0, &item, -1); + if (katze_xbel_item_is_bookmark (item)) + midori_browser_append_xbel_item (browser, item); + } + } +} + +static void +_action_bookmark_open_window_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks); + GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview); + if (selection) + { + GtkTreeModel* model; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + KatzeXbelItem* item; + gtk_tree_model_get (model, &iter, 0, &item, -1); + if (katze_xbel_item_is_bookmark (item)) + midori_browser_append_xbel_item (browser, item); + } + } +} + +static void +_action_bookmark_edit_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks); + GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview); + if (selection) + { + GtkTreeModel* model; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + KatzeXbelItem* item; + gtk_tree_model_get (model, &iter, 0, &item, -1); + if (!katze_xbel_item_is_separator (item)) + midori_browser_edit_bookmark_dialog_new (browser, item); + } + } +} + +static void +_action_trash_undo_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + // Reopen the most recent trash item + KatzeXbelItem* item = midori_trash_get_nth_xbel_item (priv->trash, 0); + midori_browser_append_xbel_item (browser, item); + midori_trash_remove_nth_item (priv->trash, 0); + _midori_browser_update_actions (browser); +} + +static void +_action_trash_empty_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + midori_trash_empty (priv->trash); + _midori_browser_update_actions (browser); +} + +static void +_action_bookmark_delete_activate (GtkAction* action, + MidoriBrowser* browser) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkTreeView* treeview = GTK_TREE_VIEW (priv->panel_bookmarks); + GtkTreeSelection* selection = gtk_tree_view_get_selection (treeview); + if (selection) + { + GtkTreeModel* model; + GtkTreeIter iter; + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + KatzeXbelItem* item; + gtk_tree_model_get (model, &iter, 0, &item, -1); + KatzeXbelItem* parent = katze_xbel_item_get_parent (item); + katze_xbel_folder_remove_item (parent, item); + katze_xbel_item_unref (item); + } + } +} + +// FIXME: Fill in a good description for each 'hm?' +static const GtkActionEntry entries[] = { + { "File", NULL, "_File" }, + { "WindowNew", STOCK_WINDOW_NEW, + NULL, "n", + "Open a new window", G_CALLBACK (_action_window_new_activate) }, + { "TabNew", STOCK_TAB_NEW, + NULL, "t", + "Open a new tab", G_CALLBACK (_action_tab_new_activate) }, + { "Open", GTK_STOCK_OPEN, + NULL, "o", + "Open a file", G_CALLBACK (_action_open_activate) }, + { "SaveAs", GTK_STOCK_SAVE_AS, + NULL, "s", + "Save to a file", NULL/*G_CALLBACK (_action_saveas_activate)*/ }, + { "TabClose", STOCK_TAB_CLOSE, + NULL, "w", + "Close the current tab", G_CALLBACK (_action_tab_close_activate) }, + { "WindowClose", STOCK_WINDOW_CLOSE, + NULL, "w", + "Close this window", G_CALLBACK (_action_window_close_activate) }, + { "PageSetup", GTK_STOCK_PROPERTIES, + "Pa_ge Setup", "", + "hm?", NULL/*G_CALLBACK (_action_page_setup_activate)*/ }, + { "PrintPreview", GTK_STOCK_PRINT_PREVIEW, + NULL, "", + "hm?", NULL/*G_CALLBACK (_action_print_preview_activate)*/ }, + { "Print", GTK_STOCK_PRINT, + NULL, "p", + "hm?", NULL/*G_CALLBACK (_action_print_activate)*/ }, + { "Quit", GTK_STOCK_QUIT, + NULL, "q", + "Quit the application", G_CALLBACK (_action_quit_activate) }, + + { "Edit", NULL, "_Edit", NULL, NULL, G_CALLBACK (_action_edit_activate) }, + { "Undo", GTK_STOCK_UNDO, + NULL, "z", + "Undo the last modification", NULL/*G_CALLBACK (_action_undo_activate)*/ }, + { "Redo", GTK_STOCK_REDO, + NULL, "z", + "Redo the last modification", NULL/*G_CALLBACK (_action_redo_activate)*/ }, + { "Cut", GTK_STOCK_CUT, + NULL, "x", + "Cut the selected text", G_CALLBACK (_action_cut_activate) }, + { "Copy", GTK_STOCK_COPY, + NULL, "c", + "Copy the selected text", G_CALLBACK (_action_copy_activate) }, + { "Copy_", GTK_STOCK_COPY, + NULL, "c", + "Copy the selected text", G_CALLBACK (_action_copy_activate) }, + { "Paste", GTK_STOCK_PASTE, + NULL, "v", + "Paste text from the clipboard", G_CALLBACK (_action_paste_activate) }, + { "Delete", GTK_STOCK_DELETE, + NULL, NULL, + "Delete the selected text", G_CALLBACK (_action_delete_activate) }, + { "SelectAll", GTK_STOCK_SELECT_ALL, + NULL, "a", + "Selected all text", G_CALLBACK (_action_select_all_activate) }, + { "FormFill", STOCK_FORM_FILL, + NULL, "", + "hm?", NULL/*G_CALLBACK (_action_form_fill_activate)*/ }, + { "Find", GTK_STOCK_FIND, + NULL, "f", + "hm?", G_CALLBACK (_action_find_activate) }, + { "FindNext", GTK_STOCK_GO_FORWARD, + "Find _Next", "g", + "hm?", G_CALLBACK (_action_find_next_activate) }, + { "FindPrevious", GTK_STOCK_GO_BACK, + "Find _Previous", "g", + "hm?", G_CALLBACK (_action_find_previous_activate) }, + { "FindQuick", GTK_STOCK_FIND, + "_Quick Find", "period", + "hm?", NULL/*G_CALLBACK (_action_find_quick_activate)*/ }, + { "Preferences", GTK_STOCK_PREFERENCES, + NULL, "p", + "hm?", G_CALLBACK (_action_preferences_activate) }, + + { "View", NULL, "_View" }, + { "Toolbars", NULL, "_Toolbars" }, + { "Reload", GTK_STOCK_REFRESH, + NULL, "r", + "Reload the current page", G_CALLBACK (_action_reload_stop_activate) }, + { "Stop", GTK_STOCK_REFRESH, + NULL, "r", + "Stop loading the current page", G_CALLBACK (_action_reload_stop_activate) }, + { "ReloadStop", GTK_STOCK_STOP, + NULL, "r", + "Reload the current page", G_CALLBACK (_action_reload_stop_activate) }, + { "ZoomIn", GTK_STOCK_ZOOM_IN, + NULL, "plus", + "hm?", NULL/*G_CALLBACK (_action_zoom_in_activate)*/ }, + { "ZoomOut", GTK_STOCK_ZOOM_OUT, + NULL, "minus", + "hm?", NULL/*G_CALLBACK (_action_zoom_out_activate)*/ }, + { "ZoomNormal", GTK_STOCK_ZOOM_100, + NULL, "0", + "hm?", NULL/*G_CALLBACK (_action_zoom_normal_activate)*/ }, + { "SourceView", STOCK_SOURCE_VIEW, + NULL, "", + "hm?", /*G_CALLBACK (_action_source_view_activate)*/ }, + { "SelectionSourceView", STOCK_SOURCE_VIEW, + "View Selection Source", "", + "hm?", NULL/*G_CALLBACK (_action_selection_source_view_activate)*/ }, + { "Fullscreen", GTK_STOCK_FULLSCREEN, + NULL, "F11", + "Toggle fullscreen view", G_CALLBACK (_action_fullscreen_activate) }, + + { "Go", NULL, "_Go" }, + { "Back", GTK_STOCK_GO_BACK, + NULL, "Left", + "hm?", G_CALLBACK (_action_back_activate) }, + { "Forward", GTK_STOCK_GO_FORWARD, + NULL, "Right", + "hm?", G_CALLBACK (_action_forward_activate) }, + { "Home", STOCK_HOMEPAGE, + NULL, "Home", + "hm?", G_CALLBACK (_action_home_activate) }, + { "Location", GTK_STOCK_JUMP_TO, + "Location...", "l", + "hm?", G_CALLBACK (_action_location_activate) }, + { "Search", GTK_STOCK_FIND, + "Web Search...", "f", + "hm?", G_CALLBACK (_action_search_activate) }, + { "OpenInPageholder", GTK_STOCK_JUMP_TO, + "Open in Page_holder...", "", + "hm?", G_CALLBACK (_action_open_in_panel_activate) }, + { "Trash", STOCK_USER_TRASH, + "Closed Tabs and Windows", "", + "Reopen a previously closed tab or window", NULL }, + { "TrashEmpty", GTK_STOCK_CLEAR, + "Empty Trash", "", + "hm?", G_CALLBACK (_action_trash_empty_activate) }, + + { "Bookmarks", NULL, "_Bookmarks" }, + { "BookmarkNew", STOCK_BOOKMARK_NEW, + NULL, "d", + "hm?", G_CALLBACK (_action_bookmark_new_activate) }, + { "BookmarksManage", NULL, + "_Manage Bookmarks", "b", + "hm?", NULL/*G_CALLBACK (_action_bookmarks_manage_activate)*/ }, + { "BookmarkOpen", GTK_STOCK_OPEN, + NULL, "", + "hm?", G_CALLBACK (_action_bookmark_open_activate) }, + { "BookmarkOpenTab", STOCK_TAB_NEW, + "Open in New _Tab", "", + "hm?", G_CALLBACK (_action_bookmark_open_tab_activate) }, + { "BookmarkOpenWindow", STOCK_WINDOW_NEW, + "Open in New _Window", "", + "hm?", G_CALLBACK (_action_bookmark_open_window_activate) }, + { "BookmarkEdit", GTK_STOCK_EDIT, + NULL, "", + "hm?", G_CALLBACK (_action_bookmark_edit_activate) }, + { "BookmarkDelete", GTK_STOCK_DELETE, + NULL, "", + "hm?", G_CALLBACK (_action_bookmark_delete_activate) }, + + { "Tools", NULL, "_Tools" }, + { "ManageSearchEngines", GTK_STOCK_PROPERTIES, + "_Manage Search Engines", "s", + "Add, edit and remove search engines...", + G_CALLBACK (_action_manage_search_engines_activate) }, + + { "Window", NULL, "_Window" }, + { "TabPrevious", GTK_STOCK_GO_BACK, + "_Previous Tab", "Page_Up", + "hm?", G_CALLBACK (_action_tab_previous_activate) }, + { "TabNext", GTK_STOCK_GO_FORWARD, + "_Next Tab", "Page_Down", + "hm?", G_CALLBACK (_action_tab_next_activate) }, + { "TabOverview", NULL, + "Tab _Overview", "", + "hm?", NULL/*G_CALLBACK (_action_tab_overview_activate)*/ }, + + { "Help", NULL, "_Help" }, + { "HelpContents", GTK_STOCK_HELP, + "_Contents", "F1", + "hm?", NULL/*G_CALLBACK (_action_help_contents_activate)*/ }, + { "About", GTK_STOCK_ABOUT, + NULL, "", + "hm?", G_CALLBACK (_action_about_activate) }, + }; + static const guint entries_n = G_N_ELEMENTS(entries); + +static const GtkToggleActionEntry toggle_entries[] = { + { "PrivateBrowsing", NULL, + "P_rivate Browsing", "", + "hm?", NULL/*G_CALLBACK (_action_private_browsing_activate)*/, + FALSE }, + { "WorkOffline", GTK_STOCK_DISCONNECT, + "_Work Offline", "", + "hm?", NULL/*G_CALLBACK (_action_work_offline_activate)*/, + FALSE }, + + { "Navigationbar", NULL, + "_Navigationbar", "", + "hm?", G_CALLBACK (_action_navigationbar_activate), + FALSE }, + { "Panel", NULL, + "_Panel", "F9", + "hm?", G_CALLBACK (_action_panel_activate), + FALSE }, + { "Bookmarkbar", NULL, + "_Bookmarkbar", "", + "hm?", G_CALLBACK (_action_bookmarkbar_activate), + FALSE }, + { "Downloadbar", NULL, + "_Downloadbar", "", + "hm?", NULL/*G_CALLBACK (_action_downloadbar_activate)*/, + FALSE }, + { "Statusbar", NULL, + "_Statusbar", "", + "hm?", G_CALLBACK (_action_statusbar_activate), + FALSE }, + }; + static const guint toggle_entries_n = G_N_ELEMENTS(toggle_entries); + +static void +midori_browser_window_state_event_cb (MidoriBrowser* browser, + GdkEventWindowState* event) +{ + MidoriBrowserPrivate* priv = browser->priv; + + if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) + { + if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) + { + gtk_widget_hide (priv->menubar); + g_object_set (priv->button_fullscreen, + "stock-id", GTK_STOCK_LEAVE_FULLSCREEN, NULL); + gtk_widget_show (priv->button_fullscreen); + } + else + { + gtk_widget_show (priv->menubar); + gtk_widget_hide (priv->button_fullscreen); + g_object_set (priv->button_fullscreen, + "stock-id", GTK_STOCK_FULLSCREEN, NULL); + } + } +} + +static void +midori_browser_size_allocate_cb (MidoriBrowser* browser, + GtkAllocation* allocation) +{ + GtkWidget* widget = GTK_WIDGET (browser); + + if (GTK_WIDGET_REALIZED (widget)) + { + GdkWindowState state = gdk_window_get_state (widget->window); + if (!(state & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN))) + { + config->winWidth = allocation->width; + config->winHeight = allocation->height; + } + } +} + +static const gchar* ui_markup = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + // Closed tabs shall be prepended here + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + // Bookmarks shall be appended here + "" + "" + "" + // Panel items shall be appended here + "" + "" + "" + "" + "" + "" + // All open tabs shall be appended here + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + +static void +midori_browser_init (MidoriBrowser* browser) +{ + browser->priv = MIDORI_BROWSER_GET_PRIVATE (browser); + + MidoriBrowserPrivate* priv = browser->priv; + + // Setup the window metrics + g_signal_connect (browser, "window-state-event", + G_CALLBACK (midori_browser_window_state_event_cb), NULL); + GdkScreen* screen = gtk_window_get_screen (GTK_WINDOW (browser)); + const gint default_width = (gint)gdk_screen_get_width (screen) / 1.7; + const gint default_height = (gint)gdk_screen_get_height (screen) / 1.7; + if (config->rememberWinSize) + { + if (!config->winWidth && !config->winHeight) + { + config->winWidth = default_width; + config->winHeight = default_width; + } + gtk_window_set_default_size (GTK_WINDOW (browser), + config->winWidth, config->winHeight); + } + else + gtk_window_set_default_size (GTK_WINDOW(browser), + default_width, default_height); + g_signal_connect (browser, "size-allocate", + G_CALLBACK (midori_browser_size_allocate_cb), NULL); + // FIXME: Use custom program icon + gtk_window_set_icon_name (GTK_WINDOW (browser), "web-browser"); + gtk_window_set_title (GTK_WINDOW (browser), g_get_application_name ()); + GtkWidget* vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (browser), vbox); + gtk_widget_show (vbox); + + // Let us see some ui manager magic + priv->action_group = gtk_action_group_new ("Browser"); + gtk_action_group_add_actions (priv->action_group, + entries, entries_n, browser); + gtk_action_group_add_toggle_actions (priv->action_group, + toggle_entries, toggle_entries_n, browser); + GtkUIManager* ui_manager = gtk_ui_manager_new (); + gtk_ui_manager_insert_action_group (ui_manager, priv->action_group, 0); + gtk_window_add_accel_group (GTK_WINDOW (browser), + gtk_ui_manager_get_accel_group (ui_manager)); + + GError* error = NULL; + if (!gtk_ui_manager_add_ui_from_string(ui_manager, ui_markup, -1, &error)) + { + // TODO: Should this be a message dialog? When does this happen? + g_message ("User interface couldn't be created: %s", error->message); + g_error_free (error); + } + + GtkAction* action; + // Make all actions except toplevel menus which lack a callback insensitive + // This will vanish once all actions are implemented + guint i; + for (i = 0; i < entries_n; i++) + { + action = gtk_action_group_get_action(priv->action_group, + entries[i].name); + gtk_action_set_sensitive (action, + entries[i].callback || !entries[i].tooltip); + } + for (i = 0; i < toggle_entries_n; i++) + { + action = gtk_action_group_get_action (priv->action_group, + toggle_entries[i].name); + gtk_action_set_sensitive (action, toggle_entries[i].callback != NULL); + } + + //_action_set_active(browser, "Downloadbar", config->toolbarDownloads); + + // Create the menubar + priv->menubar = gtk_ui_manager_get_widget (ui_manager, "/menubar"); + GtkWidget* menuitem = gtk_menu_item_new(); + gtk_widget_show (menuitem); + priv->throbber = katze_throbber_new(); + gtk_widget_show(priv->throbber); + gtk_container_add (GTK_CONTAINER (menuitem), priv->throbber); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_menu_item_set_right_justified (GTK_MENU_ITEM (menuitem), TRUE); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->menubar), menuitem); + gtk_box_pack_start (GTK_BOX (vbox), priv->menubar, FALSE, FALSE, 0); + menuitem = gtk_ui_manager_get_widget (ui_manager, "/menubar/Go/Trash"); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_browser_menu_trash_activate_cb), + browser); + priv->menu_bookmarks = gtk_menu_item_get_submenu (GTK_MENU_ITEM ( + gtk_ui_manager_get_widget (ui_manager, "/menubar/Bookmarks"))); + menuitem = gtk_separator_menu_item_new (); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu_bookmarks), menuitem); + priv->popup_bookmark = gtk_ui_manager_get_widget ( + ui_manager, "/popup_bookmark"); + g_object_ref (priv->popup_bookmark); + priv->menu_tools = gtk_menu_item_get_submenu (GTK_MENU_ITEM ( + gtk_ui_manager_get_widget (ui_manager, "/menubar/Tools"))); + menuitem = gtk_separator_menu_item_new(); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu_tools), menuitem); + priv->menu_window = gtk_menu_item_get_submenu (GTK_MENU_ITEM ( + gtk_ui_manager_get_widget (ui_manager, "/menubar/Window"))); + menuitem = gtk_separator_menu_item_new(); + gtk_widget_show (menuitem); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu_window), menuitem); + gtk_widget_show (priv->menubar); + _action_set_sensitive (browser, "PrivateBrowsing", FALSE); + _action_set_sensitive (browser, "WorkOffline", FALSE); + + // Create the navigationbar + priv->navigationbar = gtk_ui_manager_get_widget ( + ui_manager, "/toolbar_navigation"); + gtk_toolbar_set_style (GTK_TOOLBAR (priv->navigationbar), + config_to_toolbarstyle (config->toolbarStyle)); + GtkSettings* gtk_settings = gtk_widget_get_settings (priv->navigationbar); + g_signal_connect (gtk_settings, "notify::gtk-toolbar-style", + G_CALLBACK (midori_browser_navigationbar_notify_style_cb), + browser); + gtk_toolbar_set_icon_size (GTK_TOOLBAR (priv->navigationbar), + config_to_toolbariconsize (config->toolbarSmall)); + gtk_toolbar_set_show_arrow (GTK_TOOLBAR (priv->navigationbar), TRUE); + gtk_box_pack_start (GTK_BOX (vbox), priv->navigationbar, FALSE, FALSE, 0); + priv->button_tab_new = gtk_ui_manager_get_widget ( + ui_manager, "/toolbar_navigation/TabNew"); + g_object_set (_action_by_name (browser, "Back"), "is-important", TRUE, NULL); + + // Location + priv->location = sexy_icon_entry_new(); + entry_setup_completion (GTK_ENTRY (priv->location)); + priv->location_icon = gtk_image_new (); + sexy_icon_entry_set_icon (SEXY_ICON_ENTRY (priv->location) + , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE (priv->location_icon)); + sexy_icon_entry_add_clear_button (SEXY_ICON_ENTRY (priv->location)); + g_signal_connect (priv->location, "key-press-event", + G_CALLBACK (midori_browser_location_key_press_event_cb), + browser); + g_signal_connect (priv->location, "changed", + G_CALLBACK (midori_browser_location_changed_cb), browser); + GtkToolItem* toolitem = gtk_tool_item_new (); + gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE); + gtk_container_add (GTK_CONTAINER(toolitem), priv->location); + gtk_toolbar_insert (GTK_TOOLBAR (priv->navigationbar), toolitem, -1); + + // Search + priv->search = sexy_icon_entry_new (); + sexy_icon_entry_set_icon_highlight (SEXY_ICON_ENTRY (priv->search), + SEXY_ICON_ENTRY_PRIMARY, TRUE); + // TODO: Make this actively resizable or enlarge to fit contents? + // FIXME: The interface is somewhat awkward and ought to be rethought + // TODO: Display "show in context menu" search engines as "completion actions" + entry_setup_completion (GTK_ENTRY (priv->search)); + update_searchEngine (config->searchEngine, priv->search); + g_object_connect (priv->search, + "signal::icon-released", + on_webSearch_icon_released, browser, + "signal::key-press-event", + on_webSearch_key_down, browser, + "signal::scroll-event", + on_webSearch_scroll, browser, + "signal::activate", + on_webSearch_activate, browser, + NULL); + toolitem = gtk_tool_item_new (); + gtk_container_add (GTK_CONTAINER (toolitem), priv->search); + gtk_toolbar_insert (GTK_TOOLBAR (priv->navigationbar), toolitem, -1); + action = gtk_action_group_get_action (priv->action_group, "Trash"); + priv->button_trash = gtk_action_create_tool_item (action); + g_signal_connect (priv->button_trash, "clicked", + G_CALLBACK (midori_browser_menu_trash_activate_cb), browser); + gtk_toolbar_insert (GTK_TOOLBAR (priv->navigationbar), + GTK_TOOL_ITEM (priv->button_trash), -1); + sokoke_container_show_children (GTK_CONTAINER (priv->navigationbar)); + action = gtk_action_group_get_action (priv->action_group, "Fullscreen"); + priv->button_fullscreen = gtk_action_create_tool_item (action); + gtk_widget_hide (priv->button_fullscreen); + g_signal_connect (priv->button_fullscreen, "clicked", + G_CALLBACK (_action_fullscreen_activate), browser); + gtk_toolbar_insert (GTK_TOOLBAR (priv->navigationbar), + GTK_TOOL_ITEM (priv->button_fullscreen), -1); + _action_set_active (browser, "Navigationbar", config->toolbarNavigation); + + // Bookmarkbar + priv->bookmarkbar = gtk_toolbar_new (); + gtk_toolbar_set_icon_size (GTK_TOOLBAR (priv->bookmarkbar), + GTK_ICON_SIZE_MENU); + gtk_toolbar_set_style (GTK_TOOLBAR(priv->bookmarkbar), + GTK_TOOLBAR_BOTH_HORIZ); + _midori_browser_create_bookmark_menu (browser, bookmarks, + priv->menu_bookmarks); + for (i = 0; i < katze_xbel_folder_get_n_items (bookmarks); i++) + { + KatzeXbelItem* item = katze_xbel_folder_get_nth_item (bookmarks, i); + const gchar* title = katze_xbel_item_is_separator (item) + ? "" : katze_xbel_item_get_title (item); + const gchar* desc = katze_xbel_item_is_separator (item) + ? "" : katze_xbel_item_get_desc (item); + switch (katze_xbel_item_get_kind (item)) + { + case KATZE_XBEL_ITEM_KIND_FOLDER: + toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_DIRECTORY); + gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), title); + gtk_tool_item_set_is_important(toolitem, TRUE); + g_signal_connect (toolitem, "clicked", + G_CALLBACK (midori_browser_bookmarkbar_folder_activate_cb), + browser); + sokoke_tool_item_set_tooltip_text(toolitem, desc); + g_object_set_data (G_OBJECT (toolitem), "KatzeXbelItem", item); + break; + case KATZE_XBEL_ITEM_KIND_BOOKMARK: + toolitem = gtk_tool_button_new_from_stock (STOCK_BOOKMARK); + gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), title); + gtk_tool_item_set_is_important(toolitem, TRUE); + g_signal_connect (toolitem, "clicked", + G_CALLBACK (midori_browser_menu_bookmarks_item_activate_cb), + browser); + sokoke_tool_item_set_tooltip_text(toolitem, desc); + g_object_set_data (G_OBJECT (toolitem), "KatzeXbelItem", item); + break; + case KATZE_XBEL_ITEM_KIND_SEPARATOR: + toolitem = gtk_separator_tool_item_new (); + break; + default: + g_warning ("Unknown item kind"); + } + gtk_toolbar_insert (GTK_TOOLBAR (priv->bookmarkbar), toolitem, -1); + } + sokoke_container_show_children (GTK_CONTAINER (priv->bookmarkbar)); + gtk_box_pack_start (GTK_BOX (vbox), priv->bookmarkbar, FALSE, FALSE, 0); + _action_set_active (browser, "Bookmarkbar", config->toolbarBookmarks); + + // Superuser warning + GtkWidget* hbox; + if ((hbox = sokoke_superuser_warning_new ())) + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + // Create the panel + GtkWidget* hpaned = gtk_hpaned_new (); + gtk_paned_set_position (GTK_PANED (hpaned), config->winPanelPos); + g_signal_connect (hpaned, "notify::position", + G_CALLBACK (midori_panel_notify_position_cb), + browser); + gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0); + gtk_widget_show (hpaned); + priv->panel = g_object_new (MIDORI_TYPE_PANEL, + "shadow-type", GTK_SHADOW_IN, + "menu", priv->menu_tools, + NULL); + g_signal_connect (priv->panel, "close", + G_CALLBACK (midori_panel_close_cb), browser); + gtk_paned_pack1 (GTK_PANED (hpaned), priv->panel, FALSE, FALSE); + sokoke_widget_set_visible (priv->panel, config->panelShow); + _action_set_active (browser, "Panel", config->panelShow); + + // Bookmarks + GtkWidget* box = gtk_vbox_new (FALSE, 0); + GtkWidget* toolbar = gtk_ui_manager_get_widget (ui_manager, "/toolbar_bookmarks"); + gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_MENU); + gtk_box_pack_start (GTK_BOX (box), toolbar, FALSE, FALSE, 0); + GtkTreeViewColumn* column; + GtkCellRenderer* renderer_text; + GtkCellRenderer* renderer_pixbuf; + GtkTreeStore* treestore = gtk_tree_store_new (1, KATZE_TYPE_XBEL_ITEM); + GtkWidget* treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (treestore)); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); + column = gtk_tree_view_column_new (); + renderer_pixbuf = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE); + gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf, + (GtkTreeCellDataFunc)midori_browser_bookmarks_item_render_icon_cb, + treeview, NULL); + renderer_text = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer_text, FALSE); + gtk_tree_view_column_set_cell_data_func (column, renderer_text, + (GtkTreeCellDataFunc)midori_browser_bookmarks_item_render_text_cb, + treeview, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + _tree_store_insert_folder (GTK_TREE_STORE (treestore), NULL, bookmarks); + g_object_unref (treestore); + g_object_connect (treeview, + "signal::row-activated", + midori_panel_bookmarks_row_activated_cb, browser, + "signal::cursor-changed", + midori_panel_bookmarks_cursor_or_row_changed_cb, browser, + "signal::columns-changed", + midori_panel_bookmarks_cursor_or_row_changed_cb, browser, + "signal::button-release-event", + midori_panel_bookmarks_button_release_event_cb, browser, + "signal::popup-menu", + midori_panel_bookmarks_popup_menu_cb, browser, + NULL); + midori_panel_bookmarks_cursor_or_row_changed_cb (GTK_TREE_VIEW (treeview), + browser); + gtk_box_pack_start (GTK_BOX (box), treeview, FALSE, FALSE, 0); + priv->panel_bookmarks = treeview; + gtk_widget_show_all (box); + midori_panel_append_page (MIDORI_PANEL (priv->panel), + box, "vcard", "Bookmarks"); + action = _action_by_name (browser, "PanelBookmarks"); + + // Downloads + priv->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW, + "uri", "about:blank", + NULL); + gtk_widget_show (priv->panel_pageholder); + midori_panel_append_page (MIDORI_PANEL (priv->panel), + priv->panel_pageholder, + "package", "Downloads"); + + // Console + priv->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW, + "uri", "about:blank", + NULL); + gtk_widget_show (priv->panel_pageholder); + midori_panel_append_page (MIDORI_PANEL (priv->panel), + priv->panel_pageholder, + "terminal", "Console"); + + // History + priv->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW, + "uri", "about:blank", + NULL); + gtk_widget_show (priv->panel_pageholder); + midori_panel_append_page (MIDORI_PANEL (priv->panel), + priv->panel_pageholder, + "document-open-recent", "History"); + + // Pageholder + priv->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW, + "uri", config->panelPageholder, + NULL); + gtk_widget_show (priv->panel_pageholder); + midori_panel_append_page (MIDORI_PANEL (priv->panel), + priv->panel_pageholder, + GTK_STOCK_CONVERT, "Pageholder"); + + midori_panel_set_current_page (MIDORI_PANEL (priv->panel), + config->panelActive); + sokoke_widget_set_visible (priv->panel, config->panelShow); + + // Notebook, containing all web_views + priv->notebook = gtk_notebook_new (); + gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE); + gtk_paned_pack2 (GTK_PANED (hpaned), priv->notebook, FALSE, FALSE); + g_signal_connect_after (priv->notebook, "switch-page", + G_CALLBACK (gtk_notebook_switch_page_cb), + browser); + gtk_widget_show (priv->notebook); + + // Incremental findbar + priv->find = gtk_toolbar_new (); + gtk_toolbar_set_icon_size (GTK_TOOLBAR (priv->find), GTK_ICON_SIZE_MENU); + gtk_toolbar_set_style (GTK_TOOLBAR (priv->find), GTK_TOOLBAR_BOTH_HORIZ); + toolitem = gtk_tool_item_new (); + gtk_container_set_border_width (GTK_CONTAINER (toolitem), 6); + gtk_container_add (GTK_CONTAINER (toolitem), + gtk_label_new_with_mnemonic ("_Inline find:")); + gtk_toolbar_insert (GTK_TOOLBAR (priv->find), toolitem, -1); + priv->find_text = sexy_icon_entry_new (); + GtkWidget* icon = gtk_image_new_from_stock (GTK_STOCK_FIND, + GTK_ICON_SIZE_MENU); + sexy_icon_entry_set_icon (SEXY_ICON_ENTRY(priv->find_text), + SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(icon)); + sexy_icon_entry_add_clear_button (SEXY_ICON_ENTRY(priv->find_text)); + g_signal_connect (priv->find_text, "activate", + G_CALLBACK (_action_find_next_activate), browser); + toolitem = gtk_tool_item_new (); + gtk_container_add (GTK_CONTAINER (toolitem), priv->find_text); + gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE); + gtk_toolbar_insert (GTK_TOOLBAR(priv->find), toolitem, -1); + toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_GO_BACK); + gtk_tool_item_set_is_important (toolitem, TRUE); + g_signal_connect (toolitem, "clicked", + G_CALLBACK (_action_find_previous_activate), browser); + gtk_toolbar_insert (GTK_TOOLBAR (priv->find), toolitem, -1); + toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD); + gtk_tool_item_set_is_important (toolitem, TRUE); + g_signal_connect (toolitem, "clicked", + G_CALLBACK (_action_find_next_activate), browser); + gtk_toolbar_insert (GTK_TOOLBAR (priv->find), toolitem, -1); + priv->find_case = gtk_toggle_tool_button_new_from_stock ( + GTK_STOCK_SPELL_CHECK); + gtk_tool_button_set_label (GTK_TOOL_BUTTON (priv->find_case), "Match Case"); + gtk_tool_item_set_is_important (GTK_TOOL_ITEM (priv->find_case), TRUE); + gtk_toolbar_insert (GTK_TOOLBAR (priv->find), priv->find_case, -1); + priv->find_highlight = gtk_toggle_tool_button_new_from_stock ( + GTK_STOCK_SELECT_ALL); + g_signal_connect (priv->find_highlight, "toggled", + G_CALLBACK (_find_highlight_toggled), browser); + gtk_tool_button_set_label (GTK_TOOL_BUTTON (priv->find_highlight), + "Highlight Matches"); + gtk_tool_item_set_is_important (GTK_TOOL_ITEM (priv->find_highlight), TRUE); + gtk_toolbar_insert (GTK_TOOLBAR (priv->find), priv->find_highlight, -1); + toolitem = gtk_separator_tool_item_new (); + gtk_separator_tool_item_set_draw ( + GTK_SEPARATOR_TOOL_ITEM (toolitem), FALSE); + gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE); + gtk_toolbar_insert (GTK_TOOLBAR (priv->find), toolitem, -1); + toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE); + gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), "Close Findbar"); + g_signal_connect (toolitem, "clicked", + G_CALLBACK (midori_browser_find_button_close_clicked_cb), browser); + gtk_toolbar_insert (GTK_TOOLBAR (priv->find), toolitem, -1); + sokoke_container_show_children (GTK_CONTAINER (priv->find)); + gtk_box_pack_start (GTK_BOX (vbox), priv->find, FALSE, FALSE, 0); + + // Statusbar + // TODO: fix children overlapping statusbar border + priv->statusbar = gtk_statusbar_new (); + gtk_box_pack_start (GTK_BOX (vbox), priv->statusbar, FALSE, FALSE, 0); + priv->progressbar = gtk_progress_bar_new (); + // Setting the progressbar's height to 1 makes it fit in the statusbar + gtk_widget_set_size_request (priv->progressbar, -1, 1); + gtk_box_pack_start (GTK_BOX (priv->statusbar), priv->progressbar, + FALSE, FALSE, 3); + _action_set_active (browser, "Statusbar", config->toolbarStatus); + + g_object_unref (ui_manager); + + sokoke_widget_set_visible (priv->button_tab_new, config->toolbarNewTab); + sokoke_widget_set_visible (priv->search, config->toolbarWebSearch); + sokoke_widget_set_visible (priv->button_trash, config->toolbarClosedTabs); +} + +static void +midori_browser_finalize (GObject* object) +{ + MidoriBrowser* browser = MIDORI_BROWSER (object); + MidoriBrowserPrivate* priv = browser->priv; + + g_free (priv->uri); + g_free (priv->title); + g_free (priv->statusbar_text); + + if (priv->proxy_xbel_folder) + katze_xbel_item_unref (priv->proxy_xbel_folder); + + if (priv->settings) + g_object_unref (priv->settings); + if (priv->trash) + g_object_unref (priv->trash); + + G_OBJECT_CLASS (midori_browser_parent_class)->finalize (object); +} + +static void +midori_browser_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec) +{ + MidoriBrowser* browser = MIDORI_BROWSER (object); + MidoriBrowserPrivate* priv = browser->priv; + + switch (prop_id) + { + case PROP_STATUSBAR_TEXT: + _midori_browser_set_statusbar_text (browser, g_value_get_string (value)); + break; + case PROP_SETTINGS: + katze_object_assign (priv->settings, g_value_get_object (value)); + g_object_ref (priv->settings); + // FIXME: Assign settings to each web view + break; + case PROP_TRASH: + ; // FIXME: Disconnect handlers + katze_object_assign (priv->trash, g_value_get_object (value)); + g_object_ref (priv->trash); + // FIXME: Connect to updates + _midori_browser_update_actions (browser); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +midori_browser_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec) +{ + MidoriBrowser* browser = MIDORI_BROWSER (object); + MidoriBrowserPrivate* priv = browser->priv; + + switch (prop_id) + { + case PROP_STATUSBAR_TEXT: + g_value_set_string (value, priv->statusbar_text); + break; + case PROP_SETTINGS: + g_value_set_object (value, priv->settings); + break; + case PROP_TRASH: + g_value_set_object (value, priv->trash); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * midori_browser_new: + * + * Creates a new browser widget. + * + * A browser is a window with toolbars and one or multiple web views. + * + * Return value: a new #MidoriBrowser + **/ +GtkWidget* +midori_browser_new (void) +{ + MidoriBrowser* browser = g_object_new (MIDORI_TYPE_BROWSER, + NULL); + + return GTK_WIDGET (browser); +} + +/** + * midori_browser_append_tab: + * @browser: a #MidoriBrowser + * @widget: a tab + * + * Appends an arbitrary widget in the form of a new tab and creates an + * according item in the Window menu. + * + * Return value: the index of the new tab, or -1 in case of an error + **/ +gint +midori_browser_append_tab (MidoriBrowser* browser, + GtkWidget* widget) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), -1); + + MidoriBrowserPrivate* priv = browser->priv; + + GtkWidget* scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + GTK_WIDGET_SET_FLAGS (scrolled, GTK_CAN_FOCUS); + GtkWidget* child; + GObjectClass* gobject_class = G_OBJECT_GET_CLASS (widget); + if (GTK_WIDGET_CLASS (gobject_class)->set_scroll_adjustments_signal) + child = widget; + else + { + child = gtk_viewport_new (NULL, NULL); + gtk_widget_show (child); + gtk_container_add (GTK_CONTAINER (child), widget); + } + gtk_container_add (GTK_CONTAINER (scrolled), child); + gtk_widget_show (scrolled); + + GtkWidget* label = NULL; + GtkWidget* menuitem = NULL; + + if (MIDORI_IS_WEB_VIEW (widget)) + { + label = midori_web_view_get_proxy_tab_label (MIDORI_WEB_VIEW (widget)); + + menuitem = midori_web_view_get_proxy_menu_item (MIDORI_WEB_VIEW (widget)); + + if (priv->proxy_xbel_folder) + { + KatzeXbelItem* xbel_item = midori_web_view_get_proxy_xbel_item ( + MIDORI_WEB_VIEW (widget)); + katze_xbel_item_ref (xbel_item); + katze_xbel_folder_append_item (priv->proxy_xbel_folder, xbel_item); + } + + g_object_connect (widget, + "signal::navigation-requested", + midori_web_view_navigation_requested_cb, browser, + "signal::load-started", + midori_web_view_load_started_cb, browser, + "signal::load-committed", + midori_web_view_load_committed_cb, browser, + "signal::progress-started", + midori_web_view_progress_started_cb, browser, + "signal::progress-changed", + midori_web_view_progress_changed_cb, browser, + "signal::progress-done", + midori_web_view_progress_done_cb, browser, + "signal::load-done", + midori_web_view_load_done_cb, browser, + "signal::title-changed", + midori_web_view_title_changed_cb, browser, + "signal::status-bar-text-changed", + midori_web_view_statusbar_text_changed_cb, browser, + "signal::element-motion", + midori_web_view_element_motion_cb, browser, + "signal::console-message", + midori_web_view_console_message_cb, browser, + "signal::close", + midori_web_view_close_cb, browser, + "signal::new-tab", + midori_web_view_new_tab_cb, browser, + "signal::new-window", + midori_web_view_new_window_cb, browser, + "signal::populate-popup", + midori_web_view_populate_popup_cb, browser, + "signal::leave-notify-event", + midori_web_view_leave_notify_event_cb, browser, + "signal::destroy", + midori_web_view_destroy_cb, browser, + NULL); + } + + if (menuitem) + { + gtk_widget_show (menuitem); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_browser_window_menu_item_activate_cb), browser); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu_window), menuitem); + } + + guint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); + gtk_notebook_insert_page (GTK_NOTEBOOK (priv->notebook), scrolled, + label, n + 1); + #if GTK_CHECK_VERSION(2, 10, 0) + gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (priv->notebook), + scrolled, TRUE); + gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (priv->notebook), + scrolled, TRUE); + #endif + _midori_browser_update_actions (browser); + + n = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), scrolled); + if (!config->openTabsInTheBackground) + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n); + return n; +} + +/** + * midori_browser_remove_tab: + * @browser: a #MidoriBrowser + * @widget: a tab + * + * Removes an existing tab from the browser, including an associated menu item. + **/ +void +midori_browser_remove_tab (MidoriBrowser* browser, + GtkWidget* widget) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, widget); + gtk_container_remove (GTK_CONTAINER (priv->notebook), scrolled); + + // FIXME: Remove the menuitem if this is a web view +} + +/** + * midori_browser_append_xbel_item: + * @browser: a #MidoriBrowser + * @xbel_item: a bookmark + * + * Appends a #KatzeXbelItem in the form of a new tab. + * + * Return value: the index of the new tab, or -1 in case of an error + **/ +gint +midori_browser_append_xbel_item (MidoriBrowser* browser, + KatzeXbelItem* xbel_item) +{ + MidoriBrowserPrivate* priv = browser->priv; + + g_return_val_if_fail (katze_xbel_item_is_bookmark (xbel_item), -1); + + const gchar* uri = katze_xbel_bookmark_get_href (xbel_item); + const gchar* title = katze_xbel_item_get_title (xbel_item); + GtkWidget* web_view = g_object_new (MIDORI_TYPE_WEB_VIEW, + "uri", uri, + "title", title, + "settings", priv->settings, + NULL); + gtk_widget_show (web_view); + + return midori_browser_append_tab (browser, web_view); +} + +/** + * midori_browser_append_uri: + * + * Appends an uri in the form of a new tab. + * + * Return value: the index of the new tab, or -1 + **/ +gint +midori_browser_append_uri (MidoriBrowser* browser, + const gchar* uri) +{ + MidoriBrowserPrivate* priv = browser->priv; + + GtkWidget* web_view = g_object_new (MIDORI_TYPE_WEB_VIEW, + "uri", uri, + "settings", priv->settings, + NULL); + gtk_widget_show (web_view); + + return midori_browser_append_tab (browser, web_view); +} + +/** + * midori_browser_get_current_page: + * @browser: a #MidoriBrowser + * + * Determines the currently selected page. + * + * If there is no page present at all, %NULL is returned. + * + * Return value: the selected page, or %NULL + **/ +GtkWidget* +midori_browser_get_current_page (MidoriBrowser* browser) +{ + g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL); + + MidoriBrowserPrivate* priv = browser->priv; + + gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); + GtkWidget* widget = _midori_browser_child_for_scrolled (browser, + gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), n)); + return widget; +} + +/** + * midori_browser_get_current_web_view: + * @browser: a #MidoriBrowser + * + * Determines the currently selected web view. + * + * If there is no web view selected or if there is no tab present + * at all, %NULL is returned. + * + * See also midori_browser_get_current_page + * + * Return value: the selected web view, or %NULL + **/ +GtkWidget* +midori_browser_get_current_web_view (MidoriBrowser* browser) +{ + g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL); + + GtkWidget* web_view = midori_browser_get_current_page (browser); + return MIDORI_IS_WEB_VIEW (web_view) ? web_view : NULL; +} + +/** + * midori_browser_get_proxy_xbel_folder: + * @browser: a #MidoriBrowser + * + * Retrieves a proxy xbel folder representing the respective proxy xbel items + * of the present web views that can be used for session management. + * + * The folder is created on the first call and will be updated to reflect + * changes to all items automatically. + * + * Note that this implicitly creates proxy xbel items of all web views. + * + * Return value: the proxy #KatzeXbelItem + **/ +KatzeXbelItem* +midori_browser_get_proxy_xbel_folder (MidoriBrowser* browser) +{ + g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL); + + MidoriBrowserPrivate* priv = browser->priv; + + if (!priv->proxy_xbel_folder) + { + priv->proxy_xbel_folder = katze_xbel_folder_new (); + // FIXME: Fill in xbel items of all present web views + } + return priv->proxy_xbel_folder; +} diff --git a/src/midori-browser.h b/src/midori-browser.h new file mode 100644 index 00000000..1853563c --- /dev/null +++ b/src/midori-browser.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#ifndef __MIDORI_BROWSER_H__ +#define __MIDORI_BROWSER_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define MIDORI_TYPE_BROWSER \ + (midori_browser_get_type ()) +#define MIDORI_BROWSER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_BROWSER, MidoriBrowser)) +#define MIDORI_BROWSER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_BROWSER, MidoriBrowserClass)) +#define MIDORI_IS_BROWSER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_BROWSER)) +#define MIDORI_IS_BROWSER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_BROWSER)) +#define MIDORI_BROWSER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_BROWSER, MidoriBrowserClass)) + +typedef struct _MidoriBrowser MidoriBrowser; +typedef struct _MidoriBrowserPrivate MidoriBrowserPrivate; +typedef struct _MidoriBrowserClass MidoriBrowserClass; + +struct _MidoriBrowser +{ + GtkWindow parent_instance; + + MidoriBrowserPrivate* priv; +}; + +struct _MidoriBrowserClass +{ + GtkWindowClass parent_class; + + /* Signals */ + void + (*quit) (MidoriBrowser* browser); + void + (*new_window) (MidoriBrowser* browser, + const gchar* uri); +}; + +GType +midori_browser_get_type (void); + +GtkWidget* +midori_browser_new (void); + +gint +midori_browser_append_tab (MidoriBrowser* browser, + GtkWidget* widget); + +void +midori_browser_remove_tab (MidoriBrowser* browser, + GtkWidget* widget); + +gint +midori_browser_append_xbel_item (MidoriBrowser* browser, + KatzeXbelItem* xbel_item); + +gint +midori_browser_append_uri (MidoriBrowser* browser, + const gchar* uri); + +GtkWidget* +midori_browser_get_current_page (MidoriBrowser* browser); + +GtkWidget* +midori_browser_get_current_web_view (MidoriBrowser* browser); + +KatzeXbelItem* +midori_browser_get_proxy_xbel_folder (MidoriBrowser* browser); + +G_END_DECLS + +#endif /* __MIDORI_BROWSER_H__ */ diff --git a/src/midori-panel.c b/src/midori-panel.c new file mode 100644 index 00000000..4ff42779 --- /dev/null +++ b/src/midori-panel.c @@ -0,0 +1,515 @@ +/* + Copyright (C) 2007-2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#include "midori-panel.h" + +#include "sokoke.h" + +G_DEFINE_TYPE (MidoriPanel, midori_panel, GTK_TYPE_HBOX) + +struct _MidoriPanelPrivate +{ + GtkWidget* toolbar; + GtkWidget* toolbar_label; + GtkWidget* frame; + GtkWidget* notebook; + GSList* group; + GtkMenu* menu; +}; + +#define MIDORI_PANEL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + MIDORI_TYPE_PANEL, MidoriPanelPrivate)) + +enum +{ + PROP_0, + + PROP_SHADOW_TYPE, + PROP_MENU, + PROP_PAGE +}; + +enum { + CLOSE, + SWITCH_PAGE, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void +midori_panel_finalize (GObject* object); + +static void +midori_panel_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec); + +static void +midori_panel_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec); + +static gboolean +midori_panel_close_cb (MidoriPanel* panel) +{ + gtk_widget_hide (GTK_WIDGET (panel)); + return FALSE; +} + +static void +midori_cclosure_marshal_BOOLEAN__VOID (GClosure* closure, GValue* return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data) +{ + typedef gboolean(*GMarshalFunc_BOOLEAN__VOID) (gpointer data1, + gpointer data2); + register GMarshalFunc_BOOLEAN__VOID callback; + register GCClosure* cc = (GCClosure*) closure; + register gpointer data1, data2; + gboolean v_return; + + g_return_if_fail(return_value != NULL); + g_return_if_fail(n_param_values == 1); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer(param_values + 0); + } + else + { + data1 = g_value_peek_pointer(param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__VOID) (marshal_data ? marshal_data : cc->callback); + v_return = callback(data1, data2); + g_value_set_boolean (return_value, v_return); +} + +static void +midori_panel_class_init (MidoriPanelClass* class) +{ + + signals[CLOSE] = g_signal_new ( + "close", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriPanelClass, close), + g_signal_accumulator_true_handled, + NULL, + midori_cclosure_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, 0); + + signals[SWITCH_PAGE] = g_signal_new ( + "switch-page", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriPanelClass, switch_page), + 0, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); + + class->close = midori_panel_close_cb; + + GObjectClass* gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = midori_panel_finalize; + gobject_class->set_property = midori_panel_set_property; + gobject_class->get_property = midori_panel_get_property; + + GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT; + + g_object_class_install_property (gobject_class, + PROP_SHADOW_TYPE, + g_param_spec_enum ( + "shadow-type", + "Shadow Type", + "Appearance of the shadow around each panel", + GTK_TYPE_SHADOW_TYPE, + GTK_SHADOW_NONE, + flags)); + + g_object_class_install_property (gobject_class, + PROP_MENU, + g_param_spec_object ( + "menu", + "Menu", + "Menu to hold panel items", + GTK_TYPE_MENU, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_PAGE, + g_param_spec_int ( + "page", + "Page", + "The index of the current page", + -1, G_MAXINT, -1, + flags)); + + g_type_class_add_private (class, sizeof (MidoriPanelPrivate)); +} + +static void +midori_panel_button_close_clicked_cb (MidoriPanel* panel) +{ + g_signal_emit (panel, signals[CLOSE], 0); +} + +static void +midori_panel_init (MidoriPanel* panel) +{ + panel->priv = MIDORI_PANEL_GET_PRIVATE (panel); + + MidoriPanelPrivate* priv = panel->priv; + + // Create the sidebar + priv->toolbar = gtk_toolbar_new (); + gtk_toolbar_set_style (GTK_TOOLBAR (priv->toolbar), GTK_TOOLBAR_BOTH); + gtk_toolbar_set_icon_size (GTK_TOOLBAR (priv->toolbar), + GTK_ICON_SIZE_BUTTON); + gtk_toolbar_set_orientation (GTK_TOOLBAR (priv->toolbar), + GTK_ORIENTATION_VERTICAL); + gtk_box_pack_start (GTK_BOX (panel), priv->toolbar, FALSE, FALSE, 0); + gtk_widget_show_all (priv->toolbar); + GtkWidget* vbox = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (panel), vbox, TRUE, TRUE, 0); + + // Create the titlebar + GtkWidget* labelbar = gtk_toolbar_new (); + gtk_toolbar_set_icon_size (GTK_TOOLBAR (labelbar), GTK_ICON_SIZE_MENU); + gtk_toolbar_set_style (GTK_TOOLBAR (labelbar), GTK_TOOLBAR_ICONS); + GtkToolItem* toolitem = gtk_tool_item_new (); + gtk_tool_item_set_expand (toolitem, TRUE); + priv->toolbar_label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (priv->toolbar_label), 0, 0.5); + gtk_container_add (GTK_CONTAINER (toolitem), priv->toolbar_label); + gtk_container_set_border_width (GTK_CONTAINER (toolitem), 6); + gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1); + toolitem = gtk_tool_button_new_from_stock (GTK_STOCK_CLOSE); + gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), "Close panel"); + sokoke_tool_item_set_tooltip_text (GTK_TOOL_ITEM (toolitem), "Close panel"); + g_signal_connect (toolitem, "clicked", + G_CALLBACK (midori_panel_button_close_clicked_cb), panel); + gtk_toolbar_insert (GTK_TOOLBAR (labelbar), toolitem, -1); + gtk_box_pack_start (GTK_BOX (vbox), labelbar, FALSE, FALSE, 0); + gtk_widget_show_all (vbox); + + // Create the notebook + priv->notebook = gtk_notebook_new (); + gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE); + priv->frame = gtk_frame_new (NULL); + gtk_container_add (GTK_CONTAINER (priv->frame), priv->notebook); + gtk_box_pack_start (GTK_BOX (vbox), priv->frame, TRUE, TRUE, 0); + gtk_widget_show_all (priv->frame); +} + +static void +midori_panel_finalize (GObject* object) +{ + MidoriPanel* panel = MIDORI_PANEL (object); + MidoriPanelPrivate* priv = panel->priv; + + if (priv->menu) + { + // FIXME: Remove all menu items + } + + G_OBJECT_CLASS (midori_panel_parent_class)->finalize (object); +} + +static void +midori_panel_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec) +{ + MidoriPanel* panel = MIDORI_PANEL (object); + MidoriPanelPrivate* priv = panel->priv; + + switch (prop_id) + { + case PROP_SHADOW_TYPE: + gtk_frame_set_shadow_type (GTK_FRAME (priv->frame), + g_value_get_enum (value)); + break; + case PROP_MENU: + katze_object_assign (priv->menu, g_value_get_object (value)); + // FIXME: Move existing items to the new menu + break; + case PROP_PAGE: + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), + g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +midori_panel_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec) +{ + MidoriPanel* panel = MIDORI_PANEL (object); + MidoriPanelPrivate* priv = panel->priv; + + switch (prop_id) + { + case PROP_SHADOW_TYPE: + g_value_set_enum (value, + gtk_frame_get_shadow_type (GTK_FRAME (priv->frame))); + break; + case PROP_MENU: + g_value_set_object (value, priv->menu); + break; + case PROP_PAGE: + g_value_set_int (value, + gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * midori_panel_new: + * + * Creates a new empty panel. + * + * Return value: a new #MidoriPanel + **/ +GtkWidget* +midori_panel_new (void) +{ + MidoriPanel* panel = g_object_new (MIDORI_TYPE_PANEL, + NULL); + + return GTK_WIDGET (panel); +} + +static void +midori_panel_menu_item_activate_cb (GtkWidget* widget, + MidoriPanel* panel) +{ + GtkWidget* child = g_object_get_data (G_OBJECT (widget), "page"); + guint n = midori_panel_page_num (panel, child); + midori_panel_set_current_page (panel, n); + g_signal_emit (panel, signals[SWITCH_PAGE], 0, n); +} + +/** + * midori_panel_append_page: + * @panel: a #MidoriPanel + * @child: the child widget + * @icon: a stock ID or icon name, or %NULL + * @label: a string to use as the label, or %NULL + * + * Appends a new page to the panel. + * + * If @icon is an icon name, the according image is used as an + * icon for this page. + * + * If @label is given, it is used as the label of this page. + * + * In the case of an error, -1 is returned. + * + * Return value: the index of the new page, or -1 + **/ +gint +midori_panel_append_page (MidoriPanel* panel, + GtkWidget* child, + const gchar* icon, + const gchar* label) +{ + g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1); + g_return_val_if_fail (GTK_IS_WIDGET (child), -1); + + MidoriPanelPrivate* priv = panel->priv; + + GtkWidget* scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + GTK_WIDGET_SET_FLAGS (scrolled, GTK_CAN_FOCUS); + gtk_widget_show (scrolled); + GtkWidget* widget; + GObjectClass* gobject_class = G_OBJECT_GET_CLASS (child); + if (GTK_WIDGET_CLASS (gobject_class)->set_scroll_adjustments_signal) + widget = child; + else + { + widget = gtk_viewport_new (NULL, NULL); + gtk_widget_show (widget); + gtk_container_add (GTK_CONTAINER (widget), child); + } + gtk_container_add (GTK_CONTAINER (scrolled), widget); + gtk_container_add (GTK_CONTAINER (priv->notebook), scrolled); + + guint n = midori_panel_page_num (panel, child); + + const gchar* text = label ? label : "Untitled"; + + GtkWidget* image; + GtkToolItem* toolitem = gtk_radio_tool_button_new (priv->group); + priv->group = gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON ( + toolitem)); + gtk_tool_button_set_label (GTK_TOOL_BUTTON (toolitem), text); + if (icon) + { + image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_BUTTON); + gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolitem), image); + } + g_object_set_data (G_OBJECT (toolitem), "page", child); + g_signal_connect (toolitem, "clicked", + G_CALLBACK (midori_panel_menu_item_activate_cb), panel); + gtk_widget_show_all (GTK_WIDGET (toolitem)); + gtk_toolbar_insert (GTK_TOOLBAR (priv->toolbar), toolitem, -1); + + if (priv->menu) + { + GtkWidget* menuitem = gtk_image_menu_item_new_with_label (text); + if (icon) + { + image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), + image); + } + gtk_widget_show_all (menuitem); + g_object_set_data (G_OBJECT (menuitem), "page", child); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_panel_menu_item_activate_cb), + panel); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menuitem); + } + + return n; +} + +/** + * midori_panel_get_current_page: + * @panel: a #MidoriPanel + * + * Retrieves the index of the currently selected page. + * + * If @panel has no children, -1 is returned. + * + * Return value: the index of the current page, or -1 + **/ +gint +midori_panel_get_current_page (MidoriPanel* panel) +{ + g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1); + + MidoriPanelPrivate* priv = panel->priv; + + return gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); +} + +/** + * midori_panel_get_nth_page: + * @panel: a #MidoriPanel + * + * Retrieves the child widget of the nth page. + * + * If @panel has no children, -1 is returned. + * + * Return value: the child widget of the new page, or -1 + **/ +GtkWidget* +midori_panel_get_nth_page (MidoriPanel* panel, + guint page_num) +{ + g_return_val_if_fail (MIDORI_IS_PANEL (panel), NULL); + + MidoriPanelPrivate* priv = panel->priv; + + return gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), page_num); +} + +/** + * midori_panel_get_n_pages: + * @panel: a #MidoriPanel + * + * Retrieves the number of pages contained in the panel. + * + * Return value: the number of pages + **/ +guint +midori_panel_get_n_pages (MidoriPanel* panel) +{ + g_return_val_if_fail (MIDORI_IS_PANEL (panel), 0); + + MidoriPanelPrivate* priv = panel->priv; + + return gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)); +} + +static GtkWidget* +_midori_panel_scrolled_for_child (MidoriPanel* panel, + GtkWidget* child) +{ + GtkWidget* scrolled = gtk_widget_get_parent (GTK_WIDGET (child)); + if (GTK_IS_VIEWPORT (scrolled)) + scrolled = gtk_widget_get_parent (scrolled); + return scrolled; +} + +/** + * midori_panel_page_num: + * @panel: a #MidoriPanel + * + * Retrieves the index of the page associated to @widget. + * + * If @panel has no children, -1 is returned. + * + * Return value: the index of page associated to @widget, or -1 + **/ +gint +midori_panel_page_num (MidoriPanel* panel, + GtkWidget* child) +{ + g_return_val_if_fail (MIDORI_IS_PANEL (panel), -1); + + MidoriPanelPrivate* priv = panel->priv; + + GtkWidget* scrolled = _midori_panel_scrolled_for_child (panel, child); + return gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), scrolled); +} + +/** + * midori_panel_set_current_page: + * @panel: a #MidoriPanel + * @n: index of the page to switch to, or -1 to mean the last page + * + * Switches to the page with the given index. + * + * The child must be visible, otherwise the underlying GtkNotebook will + * silently ignore the attempt to switch the page. + **/ +void +midori_panel_set_current_page (MidoriPanel* panel, + gint n) +{ + g_return_if_fail (MIDORI_IS_PANEL (panel)); + + MidoriPanelPrivate* priv = panel->priv; + + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n); +} diff --git a/src/midori-panel.h b/src/midori-panel.h new file mode 100644 index 00000000..c4772039 --- /dev/null +++ b/src/midori-panel.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#ifndef __MIDORI_PANEL_H__ +#define __MIDORI_PANEL_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define MIDORI_TYPE_PANEL \ + (midori_panel_get_type ()) +#define MIDORI_PANEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_PANEL, MidoriPanel)) +#define MIDORI_PANEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_PANEL, MidoriPanelClass)) +#define MIDORI_IS_PANEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_PANEL)) +#define MIDORI_IS_PANEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_PANEL)) +#define MIDORI_PANEL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_PANEL, MidoriPanelClass)) + +typedef struct _MidoriPanel MidoriPanel; +typedef struct _MidoriPanelPrivate MidoriPanelPrivate; +typedef struct _MidoriPanelClass MidoriPanelClass; + +struct _MidoriPanel +{ + GtkFrame parent_instance; + + MidoriPanelPrivate* priv; +}; + +struct _MidoriPanelClass +{ + GtkFrameClass parent_class; + + /* Signals */ + gboolean + (*close) (MidoriPanel* panel); + + void + (*switch_page) (MidoriPanel* panel, + gint page); +}; + +GType +midori_panel_get_type (void); + +GtkWidget* +midori_panel_new (void); + +gint +midori_panel_append_page (MidoriPanel* panel, + GtkWidget* child, + const gchar* icon, + const gchar* label); + +gint +midori_panel_get_current_page (MidoriPanel* panel); + +GtkWidget* +midori_panel_get_nth_page (MidoriPanel* panel, + guint page_num); + +guint +midori_panel_get_n_pages (MidoriPanel* panel); + +gint +midori_panel_page_num (MidoriPanel* panel, + GtkWidget* child); + +void +midori_panel_set_current_page (MidoriPanel* panel, + gint n); + +G_END_DECLS + +#endif /* __MIDORI_PANEL_H__ */ diff --git a/src/midori-trash.c b/src/midori-trash.c new file mode 100644 index 00000000..d3f8f6a6 --- /dev/null +++ b/src/midori-trash.c @@ -0,0 +1,327 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#include "midori-trash.h" + +#include "sokoke.h" + +G_DEFINE_TYPE (MidoriTrash, midori_trash, G_TYPE_OBJECT) + +struct _MidoriTrashPrivate +{ + guint limit; + KatzeXbelItem* xbel_folder; +}; + +#define MIDORI_TRASH_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + MIDORI_TYPE_TRASH, MidoriTrashPrivate)) + +enum +{ + PROP_0, + + PROP_LIMIT +}; + +enum { + INSERTED, + REMOVED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void +midori_trash_finalize (GObject* object); + +static void +midori_trash_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec); + +static void +midori_trash_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec); + +static void +midori_trash_class_init (MidoriTrashClass* class) +{ + signals[INSERTED] = g_signal_new( + "inserted", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriTrashClass, inserted), + 0, + NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, + G_TYPE_UINT); + + signals[REMOVED] = g_signal_new( + "removed", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriTrashClass, removed), + 0, + NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, + G_TYPE_UINT); + + GObjectClass* gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = midori_trash_finalize; + gobject_class->set_property = midori_trash_set_property; + gobject_class->get_property = midori_trash_get_property; + + GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT; + + g_object_class_install_property (gobject_class, + PROP_LIMIT, + g_param_spec_uint ( + "limit", + "Limit", + "The maximum number of items", + 0, G_MAXUINT, 10, + flags)); + + g_type_class_add_private (class, sizeof (MidoriTrashPrivate)); +} + + + +static void +midori_trash_init (MidoriTrash* trash) +{ + trash->priv = MIDORI_TRASH_GET_PRIVATE (trash); + + MidoriTrashPrivate* priv = trash->priv; + + priv->xbel_folder = katze_xbel_folder_new (); +} + +static void +midori_trash_finalize (GObject* object) +{ + MidoriTrash* trash = MIDORI_TRASH (object); + MidoriTrashPrivate* priv = trash->priv; + + katze_xbel_item_unref (priv->xbel_folder); + + G_OBJECT_CLASS (midori_trash_parent_class)->finalize (object); +} + +static void +midori_trash_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec) +{ + MidoriTrash* trash = MIDORI_TRASH (object); + MidoriTrashPrivate* priv = trash->priv; + + switch (prop_id) + { + case PROP_LIMIT: + priv->limit = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +midori_trash_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec) +{ + MidoriTrash* trash = MIDORI_TRASH (object); + MidoriTrashPrivate* priv = trash->priv; + + switch (prop_id) + { + case PROP_LIMIT: + g_value_set_uint (value, priv->limit); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * midori_trash_new: + * @limit: the maximum number of items + * + * Creates a new #MidoriTrash that can contain a specified number of items, + * meaning that each additional item will replace the oldest existing item. + * + * The value 0 for @limit actually means that there is no limit. + * + * You will typically want to assign this to a #MidoriBrowser. + * + * Return value: a new #MidoriTrash + **/ +MidoriTrash* +midori_trash_new (guint limit) +{ + MidoriTrash* trash = g_object_new (MIDORI_TYPE_TRASH, + "limit", limit, + NULL); + + return trash; +} + +/** + * midori_trash_is_empty: + * @trash: a #MidoriTrash + * + * Determines whether the @trash contains no items. + * + * Return value: %TRUE if there are no items, %FALSE otherwise + **/ +gboolean +midori_trash_is_empty (MidoriTrash* trash) +{ + g_return_val_if_fail (MIDORI_IS_TRASH (trash), FALSE); + + MidoriTrashPrivate* priv = trash->priv; + + return katze_xbel_folder_is_empty (priv->xbel_folder); +} + +/** + * midori_trash_get_n_items: + * @trash: a #MidoriTrash + * + * Determines the number of items in @trash. + * + * Return value: the current number of items + **/ +guint +midori_trash_get_n_items (MidoriTrash* trash) +{ + g_return_val_if_fail (MIDORI_IS_TRASH (trash), 0); + + MidoriTrashPrivate* priv = trash->priv; + + return katze_xbel_folder_get_n_items (priv->xbel_folder); +} + +/** + * midori_trash_get_nth_xbel_item: + * @trash: a #MidoriTrash + * @n: the index of an item + * + * Retrieve an item contained in @trash by its index. + * + * Note that you mustn't unref this item. + * + * Return value: the index at the given index or %NULL + **/ +KatzeXbelItem* +midori_trash_get_nth_xbel_item (MidoriTrash* trash, + guint n) +{ + g_return_val_if_fail (MIDORI_IS_TRASH (trash), 0); + + MidoriTrashPrivate* priv = trash->priv; + + return katze_xbel_folder_get_nth_item (priv->xbel_folder, n); +} + +/** + * midori_trash_prepend_xbel_item: + * @trash: a #MidoriTrash + * @xbel_item: a #KatzeXbelItem + * + * Prepends a #KatzeXbelItem to @trash. + * + * The item is copied. If there is a limit set, the oldest item is + * removed automatically. + * + * Return value: %TRUE if there are no items, %FALSE otherwise + **/ +void +midori_trash_prepend_xbel_item (MidoriTrash* trash, + KatzeXbelItem* xbel_item) +{ + g_return_if_fail (MIDORI_IS_TRASH (trash)); + + MidoriTrashPrivate* priv = trash->priv; + + KatzeXbelItem* copy = katze_xbel_item_copy (xbel_item); + katze_xbel_folder_prepend_item (priv->xbel_folder, copy); + g_signal_emit (trash, signals[INSERTED], 0, 0); + guint n = katze_xbel_folder_get_n_items (priv->xbel_folder); + if (n > 10) + { + KatzeXbelItem* item = katze_xbel_folder_get_nth_item (priv->xbel_folder, + n - 1); + g_signal_emit (trash, signals[REMOVED], 0, n - 1); + katze_xbel_item_unref (item); + } +} + +/** + * midori_trash_remove_nth_item: + * @trash: a #MidoriTrash + * @n: the index of an item + * + * Removes the item at the specified position from @trash. + * + * Nothing happens if the function fails. + **/ +void +midori_trash_remove_nth_item (MidoriTrash* trash, + guint n) +{ + g_return_if_fail (MIDORI_IS_TRASH (trash)); + + MidoriTrashPrivate* priv = trash->priv; + + KatzeXbelItem* item = katze_xbel_folder_get_nth_item (priv->xbel_folder, n); + if (!n) + return; + katze_xbel_folder_remove_item (priv->xbel_folder, item); + g_signal_emit (trash, signals[REMOVED], 0, n); + katze_xbel_item_unref (item); +} + +/** + * midori_trash_empty: + * @trash: a #MidoriTrash + * + * Deletes all items currently contained in @trash. + **/ +void +midori_trash_empty (MidoriTrash* trash) +{ + g_return_if_fail (MIDORI_IS_TRASH (trash)); + + MidoriTrashPrivate* priv = trash->priv; + + guint n = katze_xbel_folder_get_n_items (priv->xbel_folder); + guint i; + for (i = 0; i < n; i++) + { + KatzeXbelItem* item = katze_xbel_folder_get_nth_item (priv->xbel_folder, + i); + g_signal_emit (trash, signals[REMOVED], 0, i); + katze_xbel_item_unref (item); + } +} diff --git a/src/midori-trash.h b/src/midori-trash.h new file mode 100644 index 00000000..bc711792 --- /dev/null +++ b/src/midori-trash.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#ifndef __MIDORI_TRASH_H__ +#define __MIDORI_TRASH_H__ + +#include + +G_BEGIN_DECLS + +#define MIDORI_TYPE_TRASH \ + (midori_trash_get_type ()) +#define MIDORI_TRASH(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_TRASH, MidoriTrash)) +#define MIDORI_TRASH_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_TRASH, MidoriTrashClass)) +#define MIDORI_IS_TRASH(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_TRASH)) +#define MIDORI_IS_TRASH_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_TRASH)) +#define MIDORI_TRASH_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_TRASH, MidoriTrashClass)) + +typedef struct _MidoriTrash MidoriTrash; +typedef struct _MidoriTrashPrivate MidoriTrashPrivate; +typedef struct _MidoriTrashClass MidoriTrashClass; + +struct _MidoriTrash +{ + GObject parent_instance; + + MidoriTrashPrivate* priv; +}; + +struct _MidoriTrashClass +{ + GObjectClass parent_class; + + /* Signals */ + void + (*inserted) (MidoriTrash* trash, + guint n); + void + (*removed) (MidoriTrash* trash, + guint n); +}; + +GType +midori_trash_get_type (void); + +MidoriTrash* +midori_trash_new (guint limit); + +gboolean +midori_trash_is_empty (MidoriTrash* trash); + +guint +midori_trash_get_n_items (MidoriTrash* trash); + +KatzeXbelItem* +midori_trash_get_nth_xbel_item (MidoriTrash* trash, + guint n); + +void +midori_trash_prepend_xbel_item (MidoriTrash* trash, + KatzeXbelItem* xbel_item); + +void +midori_trash_remove_nth_item (MidoriTrash* trash, + guint n); + +void +midori_trash_empty (MidoriTrash* trash); + +G_END_DECLS + +#endif /* __MIDORI_TRASH_H__ */ diff --git a/src/midori-websettings.c b/src/midori-websettings.c new file mode 100644 index 00000000..0fd34ebd --- /dev/null +++ b/src/midori-websettings.c @@ -0,0 +1,200 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#include "midori-webview.h" + +#include "sokoke.h" + +G_DEFINE_TYPE (MidoriWebSettings, midori_web_settings, WEBKIT_TYPE_WEB_SETTINGS) + +struct _MidoriWebSettingsPrivate +{ + gint tab_label_size; + gboolean close_button; + gboolean middle_click_goto; +}; + +#define MIDORI_WEB_SETTINGS_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettingsPrivate)) + +enum +{ + PROP_0, + + PROP_TAB_LABEL_SIZE, + PROP_CLOSE_BUTTON, + PROP_MIDDLE_CLICK_GOTO +}; + +static void +midori_web_settings_finalize (GObject* object); + +static void +midori_web_settings_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec); + +static void +midori_web_settings_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec); + +static void +midori_web_settings_class_init (MidoriWebSettingsClass* class) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = midori_web_settings_finalize; + gobject_class->set_property = midori_web_settings_set_property; + gobject_class->get_property = midori_web_settings_get_property; + + GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT; + + g_object_class_install_property (gobject_class, + PROP_TAB_LABEL_SIZE, + g_param_spec_int ( + "tab-label-size", + "Tab Label Size", + "The desired tab label size", + 0, G_MAXINT, 10, + flags)); + + g_object_class_install_property (gobject_class, + PROP_CLOSE_BUTTON, + g_param_spec_boolean ( + "close-button", + "Close Button", + "Whether the associated tab has a close button", + FALSE, + flags)); + + g_object_class_install_property (gobject_class, + PROP_MIDDLE_CLICK_GOTO, + g_param_spec_boolean ( + "middle-click-goto", + "Middle Click Goto", + "Load an uri from the selection via middle click", + FALSE, + flags)); + + g_type_class_add_private (class, sizeof (MidoriWebSettingsPrivate)); +} + + + +static void +midori_web_settings_init (MidoriWebSettings* web_settings) +{ + web_settings->priv = MIDORI_WEB_SETTINGS_GET_PRIVATE (web_settings); +} + +static void +midori_web_settings_finalize (GObject* object) +{ + G_OBJECT_CLASS (midori_web_settings_parent_class)->finalize (object); +} + +static void +midori_web_settings_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec) +{ + MidoriWebSettings* web_settings = MIDORI_WEB_SETTINGS (object); + MidoriWebSettingsPrivate* priv = web_settings->priv; + + switch (prop_id) + { + case PROP_TAB_LABEL_SIZE: + priv->tab_label_size = g_value_get_int (value); + break; + case PROP_CLOSE_BUTTON: + priv->close_button = g_value_get_boolean (value); + break; + case PROP_MIDDLE_CLICK_GOTO: + priv->middle_click_goto = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +midori_web_settings_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec) +{ + MidoriWebSettings* web_settings = MIDORI_WEB_SETTINGS (object); + MidoriWebSettingsPrivate* priv = web_settings->priv; + + switch (prop_id) + { + case PROP_TAB_LABEL_SIZE: + g_value_set_int (value, priv->tab_label_size); + break; + case PROP_CLOSE_BUTTON: + g_value_set_boolean (value, priv->close_button); + break; + case PROP_MIDDLE_CLICK_GOTO: + g_value_set_boolean (value, priv->middle_click_goto); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * midori_web_settings_new: + * + * Creates a new #MidoriWebSettings instance with default values. + * + * You will typically want to assign this to a #MidoriWebView or #MidoriBrowser. + * + * Return value: a new #MidoriWebSettings + **/ +MidoriWebSettings* +midori_web_settings_new (void) +{ + MidoriWebSettings* web_settings = g_object_new (MIDORI_TYPE_WEB_SETTINGS, + NULL); + + return web_settings; +} + +/** + * midori_web_settings_copy: + * + * Copies an existing #MidoriWebSettings instance. + * + * Return value: a new #MidoriWebSettings + **/ +MidoriWebSettings* +midori_web_settings_copy (MidoriWebSettings* web_settings) +{ + g_return_val_if_fail (MIDORI_IS_WEB_SETTINGS (web_settings), NULL); + + MidoriWebSettingsPrivate* priv = web_settings->priv; + + MidoriWebSettings* copy; + copy = MIDORI_WEB_SETTINGS (webkit_web_settings_copy (WEBKIT_WEB_SETTINGS (web_settings))); + g_object_set (copy, + "tab-label-size", priv->tab_label_size, + "close-button", priv->close_button, + "middle-click-goto", priv->middle_click_goto, + NULL); + + return copy; +} diff --git a/src/midori-websettings.h b/src/midori-websettings.h new file mode 100644 index 00000000..8ea40206 --- /dev/null +++ b/src/midori-websettings.h @@ -0,0 +1,89 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#ifndef __MIDORI_WEB_SETTINGS_H__ +#define __MIDORI_WEB_SETTINGS_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define MIDORI_TYPE_WEB_SETTINGS \ + (midori_web_settings_get_type ()) +#define MIDORI_WEB_SETTINGS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettings)) +#define MIDORI_WEB_SETTINGS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettingsClass)) +#define MIDORI_IS_WEB_SETTINGS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_WEB_SETTINGS)) +#define MIDORI_IS_WEB_SETTINGS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_WEB_SETTINGS)) +#define MIDORI_WEB_SETTINGS_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_WEB_SETTINGS, MidoriWebSettingsClass)) + +typedef struct _MidoriWebSettings MidoriWebSettings; +typedef struct _MidoriWebSettingsPrivate MidoriWebSettingsPrivate; +typedef struct _MidoriWebSettingsClass MidoriWebSettingsClass; + +struct _MidoriWebSettings +{ + WebKitWebSettings parent_instance; + + MidoriWebSettingsPrivate* priv; +}; + +struct _MidoriWebSettingsClass +{ + WebKitWebSettingsClass parent_class; + + /* Signals */ + void + (*progress_started) (MidoriWebSettings* web_settings, + guint progress); + void + (*progress_changed) (MidoriWebSettings* web_settings, + guint progress); + void + (*progress_done) (MidoriWebSettings* web_settings, + guint progress); + void + (*load_done) (MidoriWebSettings* web_settings, + WebKitWebFrame* frame); + void + (*statusbar_text_changed) (MidoriWebSettings* web_settings, + const gchar* text); + void + (*element_motion) (MidoriWebSettings* web_settings, + const gchar* link_uri); + void + (*close) (MidoriWebSettings* web_settings); + void + (*new_tab) (MidoriWebSettings* web_settings, + const gchar* uri); + void + (*new_window) (MidoriWebSettings* web_settings, + const gchar* uri); +}; + +GType +midori_web_settings_get_type (void); + +MidoriWebSettings* +midori_web_settings_new (void); + +MidoriWebSettings* +midori_web_settings_copy (MidoriWebSettings* web_settings); + +G_END_DECLS + +#endif /* __MIDORI_WEB_SETTINGS_H__ */ diff --git a/src/midori-webview.c b/src/midori-webview.c new file mode 100644 index 00000000..60f33492 --- /dev/null +++ b/src/midori-webview.c @@ -0,0 +1,1039 @@ +/* + Copyright (C) 2007-2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#include "midori-webview.h" + +#include "sokoke.h" + +#include +#include + +G_DEFINE_TYPE (MidoriWebView, midori_web_view, WEBKIT_TYPE_WEB_VIEW) + +struct _MidoriWebViewPrivate +{ + GtkWidget* tab_icon; + GtkWidget* tab_label; + GtkWidget* tab_close; + GdkPixbuf* icon; + gchar* uri; + gchar* title; + gboolean is_loading; + gint progress; + gchar* statusbar_text; + gchar* link_uri; + + gint tab_label_size; + gboolean close_button; + gboolean middle_click_goto; + MidoriWebSettings* settings; + + GtkWidget* proxy_menu_item; + GtkWidget* proxy_tab_label; + KatzeXbelItem* proxy_xbel_item; +}; + +#define MIDORI_WEB_VIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + MIDORI_TYPE_WEB_VIEW, MidoriWebViewPrivate)) + +enum +{ + PROP_0, + + PROP_ICON, + PROP_URI, + PROP_TITLE, + PROP_STATUSBAR_TEXT, + PROP_SETTINGS +}; + +enum { + LOAD_STARTED, + PROGRESS_STARTED, + PROGRESS_CHANGED, + PROGRESS_DONE, + LOAD_DONE, + ELEMENT_MOTION, + CLOSE, + NEW_TAB, + NEW_WINDOW, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void +midori_web_view_finalize (GObject* object); + +static void +midori_web_view_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec); + +static void +midori_web_view_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec); + +/*static WebKitWebView* +midori_web_view_create_web_view (WebKitWebView* web_view) +{ + MidoriWebView* new_web_view = NULL; + g_signal_emit (web_view, signals[NEW_WINDOW], 0, &new_web_view); + if (new_web_view) + return WEBKIT_WEB_VIEW (new_web_view); + return WEBKIT_WEB_VIEW (midori_web_view_new ()); +}*/ + +static void +midori_web_view_class_init (MidoriWebViewClass* class) +{ + signals[PROGRESS_STARTED] = g_signal_new ( + "progress-started", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriWebViewClass, progress_started), + 0, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); + + signals[PROGRESS_CHANGED] = g_signal_new ( + "progress-changed", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriWebViewClass, progress_changed), + 0, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); + + signals[PROGRESS_DONE] = g_signal_new ( + "progress-done", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriWebViewClass, progress_done), + 0, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); + + signals[LOAD_DONE] = g_signal_new ( + "load-done", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriWebViewClass, load_done), + 0, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + WEBKIT_TYPE_WEB_FRAME); + + signals[ELEMENT_MOTION] = g_signal_new( + "element-motion", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriWebViewClass, element_motion), + 0, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + signals[CLOSE] = g_signal_new( + "close", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriWebViewClass, close), + 0, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[NEW_TAB] = g_signal_new( + "new-tab", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriWebViewClass, new_tab), + 0, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[NEW_WINDOW] = g_signal_new( + "new-window", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET (MidoriWebViewClass, new_window), + 0, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + /*WEBKIT_WEB_VIEW_CLASS (class)->create_web_view = g_signal_new ("create-web-view", + G_TYPE_FROM_CLASS(class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + G_STRUCT_OFFSET(MidoriWebViewClass, create_web_view), + 0, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + MIDORI_TYPE_WEB_VIEW);*/ + + GObjectClass* gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = midori_web_view_finalize; + gobject_class->set_property = midori_web_view_set_property; + gobject_class->get_property = midori_web_view_get_property; + + GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT; + + g_object_class_install_property (gobject_class, + PROP_ICON, + g_param_spec_object ( + "icon", + "Icon", + "The icon of the loaded page", + GDK_TYPE_PIXBUF, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_URI, + g_param_spec_string ( + "uri", + "Uri", + "The current uri of the loaded page", + "about:blank", + flags)); + + g_object_class_install_property (gobject_class, + PROP_TITLE, + g_param_spec_string ( + "title", + "Title", + "The current title of the loaded page", + NULL, + flags)); + + g_object_class_install_property (gobject_class, + PROP_STATUSBAR_TEXT, + g_param_spec_string ( + "statusbar-text", + "Statusbar Text", + "The text that is displayed in the statusbar", + "", + flags)); + + g_object_class_install_property (gobject_class, + PROP_SETTINGS, + g_param_spec_object ( + "settings", + "Settings", + "The associated settings", + MIDORI_TYPE_WEB_SETTINGS, + G_PARAM_READWRITE)); + + g_type_class_add_private (class, sizeof (MidoriWebViewPrivate)); +} + +/*static void +webkit_web_view_load_started (MidoriWebView* web_view, + WebKitWebFrame* web_frame) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + priv->is_loading = TRUE; + priv->progress = -1; + katze_throbber_set_animated(KATZE_THROBBER(priv->tab_icon), TRUE); +}*/ + +static void +_midori_web_view_set_uri (MidoriWebView* web_view, + const gchar* uri) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + katze_assign (priv->uri, g_strdup (uri)); + if (priv->proxy_xbel_item) + { + const gchar* uri = midori_web_view_get_display_uri (web_view); + katze_xbel_bookmark_set_href (priv->proxy_xbel_item, uri); + } + g_object_set (web_view, "title", NULL, NULL); +} + +static void +webkit_web_view_load_committed (MidoriWebView* web_view, + WebKitWebFrame* web_frame) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + priv->progress = 0; + const gchar* uri = webkit_web_frame_get_uri (web_frame); + _midori_web_view_set_uri (web_view, uri); +} + +static void +webkit_web_view_load_started (MidoriWebView* web_view, + WebKitWebFrame* web_frame) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + // FIXME: This is a hack, until signals are fixed upstream + priv->is_loading = TRUE; + if (priv->tab_icon) + katze_throbber_set_animated (KATZE_THROBBER (priv->tab_icon), TRUE); + + priv->progress = 0; + g_signal_emit (web_view, signals[PROGRESS_STARTED], 0, priv->progress); +} + +static void +webkit_web_view_progress_changed (MidoriWebView* web_view, gint progress) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + priv->progress = progress; + g_signal_emit (web_view, signals[PROGRESS_CHANGED], 0, priv->progress); +} + +static void +webkit_web_view_load_finished (MidoriWebView* web_view) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + priv->progress = 100; + g_signal_emit (web_view, signals[PROGRESS_DONE], 0, priv->progress); +} + +static void +webkit_web_frame_load_done (WebKitWebFrame* web_frame, gboolean success, + MidoriWebView* web_view) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + priv->is_loading = FALSE; + priv->progress = -1; + if (priv->tab_icon) + katze_throbber_set_animated (KATZE_THROBBER (priv->tab_icon), FALSE); + g_signal_emit (web_view, signals[LOAD_DONE], 0, web_frame); +} + +static void +webkit_web_view_title_changed (MidoriWebView* web_view, + WebKitWebFrame* web_frame, const gchar* title) +{ + g_object_set (web_view, "title", title, NULL); +} + +static void +webkit_web_view_statusbar_text_changed (MidoriWebView* web_view, + const gchar* text) +{ + g_object_set (web_view, "statusbar-text", text, NULL); +} + +static void +webkit_web_view_hovering_over_link (MidoriWebView* web_view, + const gchar* tooltip, + const gchar* link_uri) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + katze_assign (priv->link_uri, g_strdup (link_uri)); + g_signal_emit (web_view, signals[ELEMENT_MOTION], 0, link_uri); +} + +static gboolean +gtk_widget_button_press_event (MidoriWebView* web_view, + GdkEventButton* event) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + GdkModifierType state = (GdkModifierType)0; + gint x, y; + gdk_window_get_pointer (NULL, &x, &y, &state); + switch (event->button) + { + case 1: + if (!priv->link_uri) + return FALSE; + if (state & GDK_SHIFT_MASK) + { + // Open link in new window + g_signal_emit (web_view, signals[NEW_WINDOW], 0, priv->link_uri); + return TRUE; + } + else if(state & GDK_MOD1_MASK) + { + // Open link in new tab + g_signal_emit (web_view, signals[NEW_TAB], 0, priv->link_uri); + return TRUE; + } + break; + case 2: + if (state & GDK_CONTROL_MASK) + { + // FIXME: Reset font multiplier or zoom level + return TRUE; + } + else + { + if (!priv->link_uri) + return FALSE; + // Open link in new tab + g_signal_emit (web_view, signals[NEW_TAB], 0, priv->link_uri); + return TRUE; + } + break; + case 3: + return FALSE; + } + return FALSE; +} + +static gboolean +gtk_widget_button_press_event_after (MidoriWebView* web_view, + GdkEventButton* event) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + if (event->button == 2 && priv->middle_click_goto) + { + GtkClipboard* clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY); + gchar* uri = gtk_clipboard_wait_for_text (clipboard); + if (uri && strchr (uri, '.') && !strchr (uri, ' ')) + { + g_object_set (web_view, "uri", uri, NULL); + g_free (uri); + return TRUE; + } + } + return FALSE; +} + +static gboolean +gtk_widget_scroll_event (MidoriWebView* web_view, + GdkEventScroll* event) +{ + GdkModifierType state = (GdkModifierType)0; + gint x, y; + gdk_window_get_pointer (NULL, &x, &y, &state); + if (state & GDK_CONTROL_MASK) + { + // FIXME: Increase or decrease the font multiplier or zoom level + if (event->direction == GDK_SCROLL_DOWN) + ; + else if(event->direction == GDK_SCROLL_UP) + ; + return TRUE; + } + else + return FALSE; +} + +static void +midori_web_view_menu_new_tab_activate (GtkWidget* action, + MidoriBrowser* browser) +{ + // FIXME: Open a new tab and load the uri +} + +static void +webkit_web_view_populate_popup_cb (GtkWidget* web_view, + GtkWidget* menu) +{ + const gchar* uri = midori_web_view_get_link_uri (MIDORI_WEB_VIEW (web_view)); + if (uri) + { + // new tab + } + + if (webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view))) + { + // selected uri in tab + } +} + +static void +_midori_web_view_update_tab_label_size (MidoriWebView* web_view) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + if (priv->tab_label) + { + if (priv->tab_label_size > -1) + { + gint width, height; + sokoke_widget_get_text_size (priv->tab_label, "M", + &width, &height); + gtk_widget_set_size_request (priv->tab_label, + width * priv->tab_label_size, -1); + gtk_label_set_ellipsize (GTK_LABEL (priv->tab_label), + PANGO_ELLIPSIZE_END); + } + else + { + gtk_widget_set_size_request (priv->tab_label, -1, -1); + gtk_label_set_ellipsize (GTK_LABEL (priv->tab_label), + PANGO_ELLIPSIZE_NONE); + } + } +} + +static void +_midori_web_view_update_settings (MidoriWebView* web_view) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + g_object_get (G_OBJECT (priv->settings), + "tab-label-size", &priv->tab_label_size, + "close-button", &priv->close_button, + "middle-click-goto", &priv->middle_click_goto, + NULL); +} + +static void +midori_web_view_settings_notify (MidoriWebSettings* web_settings, + GParamSpec* pspec, + MidoriWebView* web_view) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + const gchar* name = g_intern_string (pspec->name); + GValue value = {0, }; + g_value_init (&value, pspec->value_type); + g_object_get_property (G_OBJECT (priv->settings), name, &value); + + if (name == g_intern_string ("tab-label-size")) + { + priv->tab_label_size = g_value_get_int (&value); + _midori_web_view_update_tab_label_size (web_view); + } + else if (name == g_intern_string ("close-button")) + { + priv->close_button = g_value_get_boolean (&value); + if (priv->tab_close) + sokoke_widget_set_visible (priv->tab_close, priv->close_button); + } + else if (name == g_intern_string ("middle-click-goto")) + priv->middle_click_goto = g_value_get_boolean (&value); + else if (!g_object_class_find_property (G_OBJECT_GET_CLASS (web_settings), + name)) + g_warning("Unexpected setting '%s'", name); + g_value_unset(&value); +} + +static void +midori_web_view_init (MidoriWebView* web_view) +{ + web_view->priv = MIDORI_WEB_VIEW_GET_PRIVATE (web_view); + + MidoriWebViewPrivate* priv = web_view->priv; + priv->is_loading = FALSE; + priv->progress = -1; + + priv->settings = midori_web_settings_new (); + _midori_web_view_update_settings (web_view); + g_signal_connect (priv->settings, "notify", + G_CALLBACK(midori_web_view_settings_notify), web_view); + + WebKitWebFrame* web_frame; + web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view)); + + g_object_connect (web_view, + //"signal::load-started", + //webkit_web_view_load_started, NULL, + "signal::load-committed", + webkit_web_view_load_committed, NULL, + "signal::load-started", + webkit_web_view_load_started, NULL, + "signal::load-progress-changed", + webkit_web_view_progress_changed, NULL, + "signal::load-finished", + webkit_web_view_load_finished, NULL, + //"signal::load-done", + //webkit_web_view_load_done, NULL, + "signal::title-changed", + webkit_web_view_title_changed, NULL, + "signal::status-bar-text-changed", + webkit_web_view_statusbar_text_changed, NULL, + "signal::hovering-over-link", + webkit_web_view_hovering_over_link, NULL, + "signal::button-press-event", + gtk_widget_button_press_event, NULL, + "signal_after::button-press-event", + gtk_widget_button_press_event_after, NULL, + "signal::scroll-event", + gtk_widget_scroll_event, NULL, + "signal::populate-popup", + webkit_web_view_populate_popup_cb, browser, + NULL); + g_object_connect (web_frame, + "signal::load-done", + webkit_web_frame_load_done, web_view, + NULL); +} + +static void +midori_web_view_finalize (GObject* object) +{ + MidoriWebView* web_view = MIDORI_WEB_VIEW (object); + MidoriWebViewPrivate* priv = web_view->priv; + + if (priv->icon) + g_object_unref (priv->icon); + g_free (priv->uri); + g_free (priv->title); + g_free (priv->statusbar_text); + g_free (priv->link_uri); + + if (priv->proxy_menu_item) + gtk_widget_destroy (priv->proxy_menu_item); + if (priv->proxy_xbel_item) + katze_xbel_item_unref (priv->proxy_xbel_item); + + if (priv->settings) + g_object_unref (priv->settings); + + G_OBJECT_CLASS (midori_web_view_parent_class)->finalize (object); +} + +static void +midori_web_view_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec) +{ + MidoriWebView* web_view = MIDORI_WEB_VIEW (object); + MidoriWebViewPrivate* priv = web_view->priv; + + switch (prop_id) + { + case PROP_ICON: + katze_object_assign (priv->icon, g_value_get_object (value)); + g_object_ref (priv->icon); + if (priv->tab_icon) + katze_throbber_set_static_pixbuf (KATZE_THROBBER (priv->tab_icon), + priv->icon); + break; + case PROP_URI: + // FIXME: Autocomplete the uri + webkit_web_view_open (WEBKIT_WEB_VIEW (web_view), + g_value_get_string (value)); + break; + case PROP_TITLE: + katze_assign (priv->title, g_value_dup_string (value)); + const gchar* title = midori_web_view_get_display_title (web_view); + if (priv->tab_label) + { + gtk_label_set_text (GTK_LABEL (priv->tab_label), title); + sokoke_widget_set_tooltip_text (priv->tab_label, title); + } + if (priv->proxy_menu_item) + gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN ( + priv->proxy_menu_item))), title); + if (priv->proxy_xbel_item) + katze_xbel_item_set_title (priv->proxy_xbel_item, title); + break; + case PROP_STATUSBAR_TEXT: + katze_assign (priv->statusbar_text, g_value_dup_string (value)); + break; + case PROP_SETTINGS: + g_signal_handlers_disconnect_by_func (priv->settings, + midori_web_view_settings_notify, + web_view); + katze_object_assign (priv->settings, g_value_get_object (value)); + g_object_ref (priv->settings); + _midori_web_view_update_settings (web_view); + g_signal_connect (priv->settings, "notify", + G_CALLBACK (midori_web_view_settings_notify), web_view); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +midori_web_view_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec) +{ + MidoriWebView* web_view = MIDORI_WEB_VIEW (object); + MidoriWebViewPrivate* priv = web_view->priv; + + switch (prop_id) + { + case PROP_ICON: + g_value_set_object (value, priv->icon); + break; + case PROP_URI: + g_value_set_string (value, priv->uri); + break; + case PROP_TITLE: + g_value_set_string (value, priv->title); + break; + case PROP_STATUSBAR_TEXT: + g_value_set_string (value, priv->statusbar_text); + break; + case PROP_SETTINGS: + g_value_set_object (value, priv->settings); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * midori_web_view_new: + * + * Creates a new web view widget. + * + * Return value: a new #MidoriWebView + **/ +GtkWidget* +midori_web_view_new (void) +{ + MidoriWebView* web_view = g_object_new (MIDORI_TYPE_WEB_VIEW, + NULL); + + return GTK_WIDGET (web_view); +} + +/** + * midori_web_view_get_proxy_menu_item: + * @web_view: a #MidoriWebView + * + * Retrieves a proxy menu item that is typically added to a Window menu + * and which on activation switches to the right window/ tab. + * + * The item is created on the first call and will be updated to reflect + * changes to the icon and title automatically. + * + * Note: The item is only valid as the web view is embedded in a #GtkNotebook. + * + * Return value: the proxy #GtkMenuItem or %NULL + **/ +GtkWidget* +midori_web_view_get_proxy_menu_item (MidoriWebView* web_view) +{ + g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), FALSE); + + MidoriWebViewPrivate* priv = web_view->priv; + + if (!priv->proxy_menu_item) + { + const gchar* title = midori_web_view_get_display_title (web_view); + GtkWidget* menu_item = gtk_image_menu_item_new_with_label (title); + GtkWidget* icon = gtk_image_new_from_stock (GTK_STOCK_FILE, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), icon); + + priv->proxy_menu_item = menu_item; + } + return priv->proxy_menu_item; +} + +/** + * midori_web_view_get_proxy_tab_icon: + * @web_view: a #MidoriWebView + * + * Retrieves a proxy tab icon that is typically used in a tab label. + * + * The icon is created on the first call and will be updated to reflect + * loading progress and changes of the actual icon. + * + * Note: If a proxy tab label has been created before, this represents + * the existing icon used in the label. + * + * Return value: the proxy #GtkImage + **/ +GtkWidget* +midori_web_view_get_proxy_tab_icon (MidoriWebView* web_view) +{ + g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL); + + MidoriWebViewPrivate* priv = web_view->priv; + + if (!priv->tab_icon) + { + priv->tab_icon = katze_throbber_new (); + katze_throbber_set_pixbuf (KATZE_THROBBER(priv->tab_icon), priv->icon); + } + return priv->tab_icon; +} + +static gboolean +midori_web_view_tab_label_button_release_event (GtkWidget* tab_label, + GdkEventButton* event, + MidoriWebView* web_view) +{ + MidoriWebViewPrivate* priv = web_view->priv; + + if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) + { + // Toggle the label visibility on double click + GtkWidget* child = gtk_bin_get_child (GTK_BIN (tab_label)); + GList* children = gtk_container_get_children (GTK_CONTAINER (child)); + child = (GtkWidget*)g_list_nth_data (children, 1); + gboolean visible = gtk_widget_get_child_visible (GTK_WIDGET (child)); + gtk_widget_set_child_visible (GTK_WIDGET (child), !visible); + gint width, height; + sokoke_widget_get_text_size(tab_label, "M", &width, &height); + gtk_widget_set_size_request (child, !visible + ? width * priv->tab_label_size : 0, !visible ? -1 : 0); + g_list_free (children); + return TRUE; + } + else if (event->button == 2) + { + // Close the web view on middle click + g_signal_emit (web_view, signals[CLOSE], 0); + return TRUE; + } + + return FALSE; +} + +static void +midori_web_view_tab_close_style_set (GtkWidget* tab_close, + GtkStyle* previous_style, + MidoriWebView* web_view) +{ + GtkSettings* gtk_settings = gtk_widget_get_settings (tab_close); + gint width, height; + gtk_icon_size_lookup_for_settings (gtk_settings, GTK_ICON_SIZE_BUTTON, + &width, &height); + gtk_widget_set_size_request (tab_close, width + 2, height + 2); +} + +static void +midori_web_view_tab_close_clicked (GtkWidget* tab_close, + MidoriWebView* web_view) +{ + g_signal_emit (web_view, signals[CLOSE], 0); +} + +/** + * midori_web_view_get_proxy_tab_label: + * @web_view: a #MidoriWebView + * + * Retrieves a proxy tab label that is typically used as the label of + * a #GtkNotebook page. + * + * The label is created on the first call and will be updated to reflect + * changes to the icon and title automatically. + * + * The icon embedded in the label will reflect the loading status of the + * web view. + * + * Note: This fails if a proxy tab icon has been created already. + * + * Return value: the proxy #GtkEventBox + **/ +GtkWidget* +midori_web_view_get_proxy_tab_label (MidoriWebView* web_view) +{ + g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL); + + MidoriWebViewPrivate* priv = web_view->priv; + + GtkWidget* proxy_tab_icon = priv->tab_icon; + g_return_val_if_fail (!proxy_tab_icon, NULL); + + if (!priv->proxy_tab_label) + { + priv->tab_icon = katze_throbber_new (); + katze_throbber_set_pixbuf (KATZE_THROBBER(priv->tab_icon), priv->icon); + + GtkWidget* event_box = gtk_event_box_new (); + gtk_event_box_set_visible_window(GTK_EVENT_BOX (event_box), FALSE); + GtkWidget* hbox = gtk_hbox_new (FALSE, 1); + gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (hbox)); + gtk_box_pack_start (GTK_BOX (hbox), priv->tab_icon, FALSE, FALSE, 0); + const gchar* title = midori_web_view_get_display_title (web_view); + priv->tab_label = gtk_label_new (title); + gtk_misc_set_alignment (GTK_MISC (priv->tab_label), 0.0, 0.5); + // TODO: make the tab initially look "unvisited" until it's focused + gtk_box_pack_start (GTK_BOX (hbox), priv->tab_label, FALSE, FALSE, 0); + priv->proxy_tab_label = event_box; + _midori_web_view_update_tab_label_size (web_view); + + GtkWidget* close_button = gtk_button_new (); + gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE); + gtk_button_set_focus_on_click (GTK_BUTTON (close_button), FALSE); + GtkRcStyle* rcstyle = gtk_rc_style_new (); + rcstyle->xthickness = rcstyle->ythickness = 0; + gtk_widget_modify_style(close_button, rcstyle); + GtkWidget* image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, + GTK_ICON_SIZE_MENU); + gtk_button_set_image (GTK_BUTTON(close_button), image); + gtk_box_pack_start (GTK_BOX (hbox), close_button, FALSE, FALSE, 0); + gtk_widget_show_all (GTK_WIDGET (event_box)); + if (!priv->close_button) + gtk_widget_hide (close_button); + priv->tab_close = close_button; + + g_signal_connect(priv->proxy_tab_label, "button-release-event", + G_CALLBACK(midori_web_view_tab_label_button_release_event), + web_view); + g_signal_connect(priv->tab_close, "style-set", + G_CALLBACK(midori_web_view_tab_close_style_set), + web_view); + g_signal_connect(priv->tab_close, "clicked", + G_CALLBACK(midori_web_view_tab_close_clicked), + web_view); + } + return priv->proxy_tab_label; +} + +/** + * midori_web_view_get_proxy_xbel_item: + * @web_view: a #MidoriWebView + * + * Retrieves a proxy xbel item that can be used for bookmark storage as + * well as session management. + * + * The item is created on the first call and will be updated to reflect + * changes to the title and href automatically. + * + * Note: Currently the item is always a bookmark, but this might change + * in the future. + * + * Return value: the proxy #KatzeXbelItem + **/ +KatzeXbelItem* +midori_web_view_get_proxy_xbel_item (MidoriWebView* web_view) +{ + g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL); + + MidoriWebViewPrivate* priv = web_view->priv; + + if (!priv->proxy_xbel_item) + { + priv->proxy_xbel_item = katze_xbel_bookmark_new (); + const gchar* uri = midori_web_view_get_display_uri (web_view); + katze_xbel_bookmark_set_href (priv->proxy_xbel_item, uri); + const gchar* title = midori_web_view_get_display_title (web_view); + katze_xbel_item_set_title (priv->proxy_xbel_item, title); + } + return priv->proxy_xbel_item; +} + +/** + * midori_web_view_is_loading: + * @web_view: a #MidoriWebView + * + * Determines whether currently a page is being loaded or not. + * + * Return value: %TRUE if a page is being loaded, %FALSE otherwise + **/ +gint +midori_web_view_is_loading (MidoriWebView* web_view) +{ + g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), -1); + + MidoriWebViewPrivate* priv = web_view->priv; + return priv->is_loading; +} + +/** + * midori_web_view_get_progress: + * @web_view: a #MidoriWebView + * + * Retrieves the current loading progress in percent or -1 if no data + * has been loaded so far. + * + * The value is undefined if no loading is in progress. + * + * Return value: the current loading progress or -1 + **/ +gint +midori_web_view_get_progress (MidoriWebView* web_view) +{ + g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), -1); + + MidoriWebViewPrivate* priv = web_view->priv; + return priv->progress; +} + +/** + * midori_web_view_get_uri: + * @web_view: a #MidoriWebView + * + * Retrieves a string that is suitable for displaying, particularly an + * empty uri is represented as "about:blank". + * + * You can assume that the string is not %NULL. + * + * Return value: an uri string + **/ +const gchar* +midori_web_view_get_display_uri (MidoriWebView* web_view) +{ + g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), "about:blank"); + + MidoriWebViewPrivate* priv = web_view->priv; + return priv->uri ? priv->uri : "about:blank"; +} + +/** + * midori_web_view_get_display_title: + * @web_view: a #MidoriWebView + * + * Retrieves a string that is suitable for displaying as a title. Most of the + * time this will be the title or the current uri. + * + * You can assume that the string is not %NULL. + * + * Return value: a title string + **/ +const gchar* +midori_web_view_get_display_title (MidoriWebView* web_view) +{ + g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), "about:blank"); + + MidoriWebViewPrivate* priv = web_view->priv; + + if (priv->title) + return priv->title; + if (priv->uri) + return priv->uri; + return "about:blank"; +} + +/** + * midori_web_view_get_link_uri: + * @web_view: a #MidoriWebView + * + * Retrieves the uri of the currently focused link, particularly while the + * mouse hovers a link or a context menu is being opened. + * + * Return value: an uri string, or %NULL if there is no link focussed + **/ +const gchar* +midori_web_view_get_link_uri (MidoriWebView* web_view) +{ + g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL); + + MidoriWebViewPrivate* priv = web_view->priv; + return priv->link_uri; +} diff --git a/src/midori-webview.h b/src/midori-webview.h new file mode 100644 index 00000000..5b506218 --- /dev/null +++ b/src/midori-webview.h @@ -0,0 +1,118 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#ifndef __MIDORI_WEB_VIEW_H__ +#define __MIDORI_WEB_VIEW_H__ + +#include + +#include +#include "midori-websettings.h" + +G_BEGIN_DECLS + +#define MIDORI_TYPE_WEB_VIEW \ + (midori_web_view_get_type ()) +#define MIDORI_WEB_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_WEB_VIEW, MidoriWebView)) +#define MIDORI_WEB_VIEW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_WEB_VIEW, MidoriWebViewClass)) +#define MIDORI_IS_WEB_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_WEB_VIEW)) +#define MIDORI_IS_WEB_VIEW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_WEB_VIEW)) +#define MIDORI_WEB_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_WEB_VIEW, MidoriWebViewClass)) + +typedef struct _MidoriWebView MidoriWebView; +typedef struct _MidoriWebViewPrivate MidoriWebViewPrivate; +typedef struct _MidoriWebViewClass MidoriWebViewClass; + +struct _MidoriWebView +{ + WebKitWebView parent_instance; + + MidoriWebViewPrivate* priv; +}; + +struct _MidoriWebViewClass +{ + WebKitWebViewClass parent_class; + + /* Signals */ + void + (*progress_started) (MidoriWebView* web_view, + guint progress); + void + (*progress_changed) (MidoriWebView* web_view, + guint progress); + void + (*progress_done) (MidoriWebView* web_view, + guint progress); + void + (*load_done) (MidoriWebView* web_view, + WebKitWebFrame* frame); + void + (*statusbar_text_changed) (MidoriWebView* web_view, + const gchar* text); + void + (*element_motion) (MidoriWebView* web_view, + const gchar* link_uri); + void + (*close) (MidoriWebView* web_view); + void + (*new_tab) (MidoriWebView* web_view, + const gchar* uri); + void + (*new_window) (MidoriWebView* web_view, + const gchar* uri); + void + (*create_web_view) (MidoriWebView* web_view, + MidoriWebView* new_web_view); +}; + +GType +midori_web_view_get_type (void); + +GtkWidget* +midori_web_view_new (void); + +void +midori_web_view_set_settings (MidoriWebView* web_view, + MidoriWebSettings* web_settings); + +GtkWidget* +midori_web_view_get_proxy_menu_item (MidoriWebView* web_view); + +GtkWidget* +midori_web_view_get_proxy_tab_label (MidoriWebView* web_view); + +KatzeXbelItem* +midori_web_view_get_proxy_xbel_item (MidoriWebView* web_view); + +gboolean +midori_web_view_is_loading (MidoriWebView* web_view); + +gint +midori_web_view_get_progress (MidoriWebView* web_view); + +const gchar* +midori_web_view_get_display_uri (MidoriWebView* web_view); + +const gchar* +midori_web_view_get_display_title (MidoriWebView* web_view); + +const gchar* +midori_web_view_get_link_uri (MidoriWebView* web_view); + +G_END_DECLS + +#endif /* __MIDORI_WEB_VIEW_H__ */ diff --git a/src/prefs.c b/src/prefs.c index d5bcc6d7..e4cd0836 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -152,62 +152,45 @@ static void on_prefs_userStylesheetUri_file_set(GtkWidget* widget, CPrefs* prefs static void on_prefs_toolbarstyle_changed(GtkWidget* widget, CPrefs* prefs) { config->toolbarStyle = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); - gtk_toolbar_set_style(GTK_TOOLBAR(prefs->browser->navibar) - , config_to_toolbarstyle(config->toolbarStyle)); + /*gtk_toolbar_set_style(GTK_TOOLBAR(prefs->browser->navibar) + , config_to_toolbarstyle(config->toolbarStyle));*/ } static void on_prefs_toolbarSmall_toggled(GtkWidget* widget, CPrefs* prefs) { config->toolbarSmall = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(prefs->browser->navibar) - , config_to_toolbariconsize(config->toolbarSmall)); + /*gtk_toolbar_set_icon_size(GTK_TOOLBAR(prefs->browser->navibar) + , config_to_toolbariconsize(config->toolbarSmall));*/ } static void on_prefs_tabClose_toggled(GtkWidget* widget, CPrefs* prefs) { config->tabClose = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - GList* items = browsers; - do - { - CBrowser* browser = (CBrowser*)items->data; - sokoke_widget_set_visible(browser->webView_close, config->tabClose); - } - while((items = g_list_next(items))); - g_list_free(items); + g_object_set(webSettings, "close-button", config->tabClose, NULL); } static void on_prefs_tabSize_changed(GtkWidget* widget, CPrefs* prefs) { config->tabSize = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); - gint w, h; - sokoke_widget_get_text_size(prefs->browser->webView_name, "M", &w, &h); - GList* items = browsers; - do - { - CBrowser* browser = (CBrowser*)items->data; - gtk_widget_set_size_request(GTK_WIDGET(browser->webView_name) - , w * config->tabSize, -1); - } - while((items = g_list_next(items))); - g_list_free(items); + g_object_set(webSettings, "tab-label-size", config->tabSize, NULL); } static void on_prefs_toolbarWebSearch_toggled(GtkWidget* widget, CPrefs* prefs) { config->toolbarWebSearch = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - sokoke_widget_set_visible(prefs->browser->webSearch, config->toolbarWebSearch); + //sokoke_widget_set_visible(prefs->browser->webSearch, config->toolbarWebSearch); } static void on_prefs_toolbarNewTab_toggled(GtkWidget* widget, CPrefs* prefs) { config->toolbarNewTab = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - sokoke_widget_set_visible(prefs->browser->newTab, config->toolbarNewTab); + //sokoke_widget_set_visible(prefs->browser->newTab, config->toolbarNewTab); } static void on_prefs_toolbarClosedTabs_toggled(GtkWidget* widget, CPrefs* prefs) { config->toolbarClosedTabs = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - sokoke_widget_set_visible(prefs->browser->closedTabs, config->toolbarClosedTabs); + //sokoke_widget_set_visible(prefs->browser->closedTabs, config->toolbarClosedTabs); } static gboolean on_prefs_locationsearch_focus_out(GtkWidget* widget @@ -233,7 +216,10 @@ static void on_prefs_protocols_render_icon(GtkTreeViewColumn* column gchar* path; if((path = g_find_program_in_path(binary))) { - GtkIconTheme* icon_theme = get_icon_theme(prefs->treeview); + GdkScreen* screen = gtk_widget_get_screen(prefs->treeview); + if(!screen) + screen = gdk_screen_get_default(); + GtkIconTheme* icon_theme = gtk_icon_theme_get_for_screen(screen); if(g_path_is_absolute(binary)) { g_free(path); path = g_path_get_basename(binary); @@ -308,16 +294,14 @@ static void on_prefs_protocols_combobox_changed(GtkWidget* widget, CPrefs* prefs gtk_widget_set_sensitive(prefs->add, command == NULL); } -GtkWidget* prefs_preferences_dialog_new(CBrowser* browser) +GtkWidget* prefs_preferences_dialog_new(MidoriBrowser* browser) { gchar* dialogTitle = g_strdup_printf("%s Preferences", g_get_application_name()); GtkWidget* dialog = gtk_dialog_new_with_buttons(dialogTitle - , GTK_WINDOW(browser->window) + , GTK_WINDOW(browser) , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR - , GTK_STOCK_HELP - , GTK_RESPONSE_HELP - , GTK_STOCK_CLOSE - , GTK_RESPONSE_CLOSE + , GTK_STOCK_HELP, GTK_RESPONSE_HELP + , GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE , NULL); gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_PREFERENCES); // TODO: Implement some kind of help function @@ -326,7 +310,6 @@ GtkWidget* prefs_preferences_dialog_new(CBrowser* browser) CPrefs* prefs = g_new0(CPrefs, 1); prefs->browser = browser; - //prefs->window = dialog; g_signal_connect(dialog, "response", G_CALLBACK(g_free), prefs); // TODO: Do we want tooltips for explainations or can we omit that? @@ -334,7 +317,7 @@ GtkWidget* prefs_preferences_dialog_new(CBrowser* browser) // TODO: Take multiple windows into account when applying changes GtkWidget* xfce_heading; if((xfce_heading = sokoke_xfce_header_new( - gtk_window_get_icon_name(GTK_WINDOW(browser->window)), dialogTitle))) + gtk_window_get_icon_name(GTK_WINDOW(browser)), dialogTitle))) gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox) , xfce_heading, FALSE, FALSE, 0); g_free(dialogTitle); diff --git a/src/prefs.h b/src/prefs.h index 7576095e..e56d2087 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -12,7 +12,7 @@ #ifndef __PREFS_H__ #define __PREFS_H__ 1 -#include "browser.h" +#include "midori-browser.h" #include @@ -20,8 +20,7 @@ typedef struct { - CBrowser* browser; - //GtkWidget* window; + MidoriBrowser* browser; GtkWidget* userStylesheetUri; GtkWidget* treeview; GtkWidget* combobox; @@ -38,6 +37,6 @@ enum // -- Declarations GtkWidget* -prefs_preferences_dialog_new(CBrowser*); +prefs_preferences_dialog_new(MidoriBrowser*); #endif /* !__PREFS_H__ */ diff --git a/src/search.c b/src/search.c index a40a10d3..26afcb5e 100644 --- a/src/search.c +++ b/src/search.c @@ -12,7 +12,7 @@ #include "search.h" #include "sokoke.h" -#include "../katze/katze.h" +#include #include #include diff --git a/src/sokoke.c b/src/sokoke.c index ea0c6f49..8bcca67f 100644 --- a/src/sokoke.c +++ b/src/sokoke.c @@ -34,18 +34,6 @@ void sokoke_combo_box_add_strings(GtkComboBox* combobox va_end(args); } -void sokoke_radio_action_set_current_value(GtkRadioAction* action - , gint currentValue) -{ - // Activates the group member with the given value - #if GTK_CHECK_VERSION(2, 10, 0) - gtk_radio_action_set_current_value(action, currentValue); - #else - // TODO: Implement this for older gtk - UNIMPLEMENTED - #endif -} - void sokoke_widget_set_visible(GtkWidget* widget, gboolean visible) { // Show or hide the widget @@ -304,86 +292,3 @@ void sokoke_menu_item_set_accel(GtkMenuItem* menuitem, const gchar* path g_free(accel); } } - -gboolean sokoke_entry_can_undo(GtkEntry* entry) -{ - // TODO: Can we undo the last input? - return FALSE; -} - -gboolean sokoke_entry_can_redo(GtkEntry* entry) -{ - // TODO: Can we redo the last input? - return FALSE; -} - -void sokoke_entry_undo(GtkEntry* entry) -{ - // TODO: Implement undo - UNIMPLEMENTED -} - -void sokoke_entry_redo(GtkEntry* entry) -{ - // TODO: Implement redo - UNIMPLEMENTED -} - -static gboolean sokoke_on_undo_entry_key_down(GtkEntry* widget, GdkEventKey* event - , gpointer userdata) -{ - switch(event->keyval) - { - case GDK_Undo: - sokoke_entry_undo(widget); - return FALSE; - case GDK_Redo: - sokoke_entry_redo(widget); - return FALSE; - default: - return FALSE; - } -} - -static void sokoke_on_undo_entry_populate_popup(GtkEntry* entry, GtkMenu* menu - , gpointer userdata) -{ - // Enhance the entry's menu with undo and redo items. - GtkWidget* menuitem = gtk_separator_menu_item_new(); - gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuitem); - gtk_widget_show(menuitem); - menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_REDO, NULL); - g_signal_connect(menuitem, "activate", G_CALLBACK(sokoke_entry_redo), userdata); - gtk_widget_set_sensitive(menuitem, sokoke_entry_can_redo(entry)); - gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuitem); - gtk_widget_show(menuitem); - menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_UNDO, NULL); - g_signal_connect(menuitem, "activate", G_CALLBACK(sokoke_entry_undo), userdata); - gtk_widget_set_sensitive(menuitem, sokoke_entry_can_undo(entry)); - gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menuitem); - gtk_widget_show(menuitem); -} - -gboolean sokoke_entry_get_can_undo(GtkEntry* entry) -{ - // TODO: Is this entry undo enabled? - return FALSE; -} - -void sokoke_entry_set_can_undo(GtkEntry* entry, gboolean canUndo) -{ - if(canUndo) - { - g_signal_connect(entry, "key-press-event" - , G_CALLBACK(sokoke_on_undo_entry_key_down), NULL); - g_signal_connect(entry, "populate-popup" - , G_CALLBACK(sokoke_on_undo_entry_populate_popup), NULL); - } - else - { - g_signal_handlers_disconnect_by_func(entry - , G_CALLBACK(sokoke_on_undo_entry_key_down), NULL); - g_signal_handlers_disconnect_by_func(entry - , G_CALLBACK(sokoke_on_undo_entry_populate_popup), NULL); - } -} diff --git a/src/sokoke.h b/src/sokoke.h index 995e2481..74e751be 100644 --- a/src/sokoke.h +++ b/src/sokoke.h @@ -20,9 +20,6 @@ void sokoke_combo_box_add_strings(GtkComboBox*, const gchar*, ...); -void -sokoke_radio_action_set_current_value(GtkRadioAction*, gint); - void sokoke_widget_set_visible(GtkWidget*, gboolean); @@ -70,22 +67,4 @@ sokoke_widget_get_text_size(GtkWidget*, const gchar*, gint*, gint*); void sokoke_menu_item_set_accel(GtkMenuItem*, const gchar*, const gchar*, GdkModifierType); -gboolean -sokoke_entry_can_undo(GtkEntry*); - -gboolean -sokoke_entry_can_redo(GtkEntry*); - -void -sokoke_entry_undo(GtkEntry*); - -void -sokoke_entry_redo(GtkEntry*); - -gboolean -sokoke_entry_get_can_undo(GtkEntry*); - -void -sokoke_entry_set_can_undo(GtkEntry*, gboolean); - #endif /* !__SOKOKE_H__ */ diff --git a/src/ui.h b/src/ui.h index 787fdd41..bc5d6a8b 100644 --- a/src/ui.h +++ b/src/ui.h @@ -12,246 +12,4 @@ #ifndef __UI_H__ #define __UI_H__ 1 -// -- Credits - -static const gchar* credits_authors[] = { "Christian Dywan ", NULL }; -static const gchar* credits_documenters/*[]*/ = /*{ */NULL/* }*/; -static const gchar* credits_artists[] = { "Nancy Runge ", NULL }; - -// -- Licenses - -static const gchar* license = - "This library is free software; you can redistribute it and/or\n" - "modify it under the terms of the GNU Lesser General Public\n" - "License as published by the Free Software Foundation; either\n" - "version 2.1 of the License, or (at your option) any later version.\n"; - -// -- User interface description - -static const gchar* ui_markup = - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - // Closed tabs shall be prepended here - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - // Bookmarks shall be appended here - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - // TODO: Insert widgets and custom tools here - "" - "" - "" - "" - "" - "" - "" - "" - "" - // All open tabs shall be appended here - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - ""; - #endif /* !__UI_H__ */ diff --git a/src/webSearch.c b/src/webSearch.c index 8390571c..a7a4d6ae 100644 --- a/src/webSearch.c +++ b/src/webSearch.c @@ -19,12 +19,12 @@ #include #include -void update_searchEngine(guint index, CBrowser* browser) +void update_searchEngine(guint index, GtkWidget* search) { guint n = g_list_length(searchEngines); // Display a default icon in case we have no engines if(!n) - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->webSearch), SEXY_ICON_ENTRY_PRIMARY + sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(search), SEXY_ICON_ENTRY_PRIMARY , GTK_IMAGE(gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU))); // Change the icon and default text according to the chosen engine else @@ -34,24 +34,24 @@ void update_searchEngine(guint index, CBrowser* browser) index = 0; SearchEngine* engine = (SearchEngine*)g_list_nth_data(searchEngines, index); GdkPixbuf* pixbuf = load_web_icon(search_engine_get_icon(engine) - , GTK_ICON_SIZE_MENU, browser->navibar); - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(browser->webSearch) + , GTK_ICON_SIZE_MENU, search); + sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(search) , SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(gtk_image_new_from_pixbuf(pixbuf))); g_object_unref(pixbuf); - sokoke_entry_set_default_text(GTK_ENTRY(browser->webSearch) + sokoke_entry_set_default_text(GTK_ENTRY(search) , search_engine_get_short_name(engine)); config->searchEngine = index; } } -void on_webSearch_engine_activate(GtkWidget* widget, CBrowser* browser) +void on_webSearch_engine_activate(GtkWidget* widget, MidoriBrowser* browser) { guint index = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "engine")); - update_searchEngine(index, browser); + update_searchEngine(index, widget); } void on_webSearch_icon_released(GtkWidget* widget, SexyIconEntryPosition* pos - , gint button, CBrowser* browser) + , gint button, MidoriBrowser* browser) { GtkWidget* menu = gtk_menu_new(); guint n = g_list_length(searchEngines); @@ -84,14 +84,14 @@ void on_webSearch_icon_released(GtkWidget* widget, SexyIconEntryPosition* pos gtk_widget_show(menuitem); } - menuitem = gtk_separator_menu_item_new(); + /*menuitem = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); gtk_widget_show(menuitem); GtkAction* action = gtk_action_group_get_action( browser->actiongroup, "ManageSearchEngines"); menuitem = gtk_action_create_menu_item(action); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); - gtk_widget_show(menuitem); + gtk_widget_show(menuitem);*/ sokoke_widget_popup(widget, GTK_MENU(menu), NULL); } @@ -299,16 +299,16 @@ static void on_webSearch_remove(GtkWidget* widget, CWebSearch* webSearch) gtk_list_store_remove(GTK_LIST_STORE(liststore), &iter); search_engine_free(searchEngine); searchEngines = g_list_remove(searchEngines, searchEngine); - update_searchEngine(config->searchEngine, webSearch->browser); + //update_searchEngine(config->searchEngine, webSearch->browser); webSearch_toggle_edit_buttons(g_list_nth(searchEngines, 0) != NULL, webSearch); // FIXME: we want to allow undo of some kind } -GtkWidget* webSearch_manageSearchEngines_dialog_new(CBrowser* browser) +GtkWidget* webSearch_manageSearchEngines_dialog_new(MidoriBrowser* browser) { const gchar* dialogTitle = "Manage search engines"; GtkWidget* dialog = gtk_dialog_new_with_buttons(dialogTitle - , GTK_WINDOW(browser->window) + , GTK_WINDOW(browser) , GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR , GTK_STOCK_HELP , GTK_RESPONSE_HELP @@ -394,7 +394,7 @@ GtkWidget* webSearch_manageSearchEngines_dialog_new(CBrowser* browser) return dialog; } -gboolean on_webSearch_key_down(GtkWidget* widget, GdkEventKey* event, CBrowser* browser) +gboolean on_webSearch_key_down(GtkWidget* widget, GdkEventKey* event, MidoriBrowser* browser) { GdkModifierType state = (GdkModifierType)0; gint x, y; gdk_window_get_pointer(NULL, &x, &y, &state); @@ -403,25 +403,25 @@ gboolean on_webSearch_key_down(GtkWidget* widget, GdkEventKey* event, CBrowser* switch(event->keyval) { case GDK_Up: - update_searchEngine(config->searchEngine - 1, browser); + //update_searchEngine(config->searchEngine - 1, browser); return TRUE; case GDK_Down: - update_searchEngine(config->searchEngine + 1, browser); + //update_searchEngine(config->searchEngine + 1, browser); return TRUE; } return FALSE; } -gboolean on_webSearch_scroll(GtkWidget* webView, GdkEventScroll* event, CBrowser* browser) +gboolean on_webSearch_scroll(GtkWidget* webView, GdkEventScroll* event, MidoriBrowser* browser) { if(event->direction == GDK_SCROLL_DOWN) - update_searchEngine(config->searchEngine + 1, browser); + ;//update_searchEngine(config->searchEngine + 1, browser); else if(event->direction == GDK_SCROLL_UP) - update_searchEngine(config->searchEngine - 1, browser); + ;//update_searchEngine(config->searchEngine - 1, browser); return TRUE; } -void on_webSearch_activate(GtkWidget* widget, CBrowser* browser) +void on_webSearch_activate(GtkWidget* widget, MidoriBrowser* browser) { const gchar* keywords = gtk_entry_get_text(GTK_ENTRY(widget)); gchar* url; @@ -436,6 +436,7 @@ void on_webSearch_activate(GtkWidget* widget, CBrowser* browser) else search = g_strconcat(url, " ", keywords, NULL); entry_completion_append(GTK_ENTRY(widget), keywords); - webkit_web_view_open(WEBKIT_WEB_VIEW(get_nth_webView(-1, browser)), search); + GtkWidget* webView = midori_browser_get_current_web_view(browser); + webkit_web_view_open(WEBKIT_WEB_VIEW(webView), search); g_free(search); } diff --git a/src/webSearch.h b/src/webSearch.h index 3cefc395..cefa89be 100644 --- a/src/webSearch.h +++ b/src/webSearch.h @@ -12,7 +12,7 @@ #ifndef __WEBSEARCH_H__ #define __WEBSEARCH_H__ 1 -#include "browser.h" +#include "midori-browser.h" #include #include @@ -22,7 +22,7 @@ typedef struct { - CBrowser* browser; + MidoriBrowser* browser; GtkWidget* window; GtkWidget* treeview; GtkWidget* edit; @@ -38,24 +38,24 @@ enum // -- Declarations void -update_searchEngine(guint, CBrowser*); +update_searchEngine(guint, GtkWidget*); void -on_webSearch_icon_released(GtkWidget*, SexyIconEntryPosition*, gint, CBrowser*); +on_webSearch_icon_released(GtkWidget*, SexyIconEntryPosition*, gint, MidoriBrowser*); void -on_webSearch_engine_activate(GtkWidget*, CBrowser*); +on_webSearch_engine_activate(GtkWidget*, MidoriBrowser*); void -on_webSearch_activate(GtkWidget*, CBrowser*); +on_webSearch_activate(GtkWidget*, MidoriBrowser*); GtkWidget* -webSearch_manageSearchEngines_dialog_new(CBrowser*); +webSearch_manageSearchEngines_dialog_new(MidoriBrowser*); gboolean -on_webSearch_key_down(GtkWidget*, GdkEventKey*, CBrowser*); +on_webSearch_key_down(GtkWidget*, GdkEventKey*, MidoriBrowser*); gboolean -on_webSearch_scroll(GtkWidget*, GdkEventScroll*, CBrowser*); +on_webSearch_scroll(GtkWidget*, GdkEventScroll*, MidoriBrowser*); #endif /* !__WEBSEARCH_H__ */ diff --git a/src/webView.c b/src/webView.c deleted file mode 100644 index be91e220..00000000 --- a/src/webView.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - Copyright (C) 2007-2008 Christian Dywan - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - See the file COPYING for the full license text. -*/ - -#include "webView.h" - -#include "helpers.h" -#include "sokoke.h" -#include "../katze/katze.h" - -#include - -WebKitNavigationResponse on_webView_navigation_requested(GtkWidget* webView - , WebKitWebFrame* frame, WebKitNetworkRequest* networkRequest) -{ - WebKitNavigationResponse response = WEBKIT_NAVIGATION_RESPONSE_ACCEPT; - // TODO: Ask webkit wether it knows the protocol for "unknown protcol" - // TODO: This isn't the place for uri scheme handling - const gchar* uri = webkit_network_request_get_uri(networkRequest); - gchar* protocol = strtok(g_strdup(uri), ":"); - if(spawn_protocol_command(protocol, uri)) - response = WEBKIT_NAVIGATION_RESPONSE_IGNORE; - g_free(protocol); - return response; -} - -void on_webView_title_changed(GtkWidget* webView, WebKitWebFrame* frame - , const gchar* title, CBrowser* browser) -{ - const gchar* newTitle; - if(title) - newTitle = title; - else - newTitle = webkit_web_frame_get_uri(frame); - katze_xbel_item_set_title(browser->sessionItem, newTitle); - gtk_label_set_text(GTK_LABEL(browser->webView_name), newTitle); - sokoke_widget_set_tooltip_text(gtk_widget_get_parent( - gtk_widget_get_parent(browser->webView_name)), newTitle); - gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN( - browser->webView_menu))), newTitle); - if(webView == get_nth_webView(-1, browser)) - { - gchar* windowTitle = g_strconcat(newTitle, " - ", PACKAGE_NAME, NULL); - gtk_window_set_title(GTK_WINDOW(browser->window), windowTitle); - g_free(windowTitle); - } -} - -void on_webView_icon_changed(GtkWidget* webView, WebKitWebFrame* widget - , CBrowser* browser) -{ - // TODO: Implement icon updates; currently this isn't ever called anyway - const gchar* icon = NULL; - UNIMPLEMENTED - if(icon) - { - gtk_label_set_text(GTK_LABEL(browser->webView_name), "icon"); - gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN( - browser->webView_menu))), "icon"); - if(webView == get_nth_webView(-1, browser)) - { - gchar* windowTitle = g_strconcat("icon", " - ", PACKAGE_NAME, NULL); - gtk_window_set_title(GTK_WINDOW(browser->window), windowTitle); - g_free(windowTitle); - } - } -} - -void on_webView_load_started(GtkWidget* webView, WebKitWebFrame* widget - , CBrowser* browser) -{ - browser->loadedPercent = 0; - update_favicon(browser); - if(webView == get_nth_webView(-1, browser)) - { - update_gui_state(browser); - update_statusbar(browser); - } -} - -void on_webView_load_committed(GtkWidget* webView, WebKitWebFrame* frame - , CBrowser* browser) -{ - const gchar* uri = webkit_web_frame_get_uri(frame); - gchar* newUri = g_strdup(uri ? uri : ""); - katze_xbel_bookmark_set_href(browser->sessionItem, newUri); - if(webView == get_nth_webView(-1, browser)) - { - gtk_entry_set_text(GTK_ENTRY(browser->location), newUri); - gtk_label_set_text(GTK_LABEL(browser->webView_name), newUri); - katze_assign(browser->statusMessage, NULL); - } -} - -void on_webView_load_changed(GtkWidget* webView, gint progress, CBrowser* browser) -{ - browser->loadedPercent = progress; - if(webView == get_nth_webView(-1, browser)) - update_statusbar(browser); -} - -void on_webView_load_finished(GtkWidget* webView, WebKitWebFrame* widget - , CBrowser* browser) -{ - browser->loadedPercent = -1; - update_favicon(browser); - if(webView == get_nth_webView(-1, browser)) - update_gui_state(browser); -} - -void on_webView_status_message(GtkWidget* webView, const gchar* text, CBrowser* browser) -{ - katze_assign(browser->statusMessage, g_strdup(text)); - update_statusbar(browser); -} - -void on_webView_selection_changed(GtkWidget* webView, CBrowser* browser) -{ - UNIMPLEMENTED -} - -gboolean on_webView_console_message(GtkWidget* webView - , const gchar* message, gint line, const gchar* sourceId, CBrowser* browser) -{ - return FALSE; -} - -void on_webView_link_hover(GtkWidget* webView, const gchar* tooltip - , const gchar* uri, CBrowser* browser) -{ - katze_assign(browser->statusMessage, g_strdup(uri)); - update_statusbar(browser); - katze_assign(browser->elementUri, g_strdup(uri)); -} - -/* -GtkWidget* on_webView_window_open(GtkWidget* webView, const gchar* sUri - , CBrowser* browser) -{ - // A window is created - // TODO: Respect config->iNewPages - // TODO: Find out if this comes from a script or a click - // TODO: Block scripted popups, return NULL and show status icon - CBrowser* newBrowser = browser_new(config->openPopupsInTabs ? browser : NULL); - return newBrowser->webView; -} -*/ - -void webView_popup(GtkWidget* webView, GdkEventButton* event, CBrowser* browser) -{ - gboolean isLink = browser->elementUri != NULL; // Did we right-click a link? - gboolean haveLinks = FALSE; // TODO: Are several links selected? - gboolean isImage = FALSE; // TODO: Did we right-click an image? - gboolean isEditable = webkit_web_view_can_paste_clipboard(WEBKIT_WEB_VIEW(webView)); - gboolean hasSelection = webkit_web_view_has_selection(WEBKIT_WEB_VIEW(webView)); - - update_edit_items(browser); - - // Download manager available? - const gchar* downloadManager = g_datalist_get_data(&config->protocols_commands, "download"); - gboolean canDownload = downloadManager && *downloadManager; - - action_set_visible("LinkTabNew", isLink, browser); - action_set_visible("LinkTabCurrent", isLink, browser); - action_set_visible("LinkWindowNew", isLink, browser); - - action_set_visible("LinkSaveAs", isLink, browser); - action_set_visible("LinkSaveWith", isLink && canDownload, browser); - action_set_visible("LinkCopy", isLink, browser); - action_set_visible("LinkBookmarkNew", isLink, browser); - - action_set_visible("SelectionLinksNewTabs", haveLinks && hasSelection, browser); - action_set_visible("SelectionTextTabNew", haveLinks && hasSelection, browser); - action_set_visible("SelectionTextTabCurrent", haveLinks && hasSelection, browser); - action_set_visible("SelectionTextWindowNew", haveLinks && hasSelection, browser); - - action_set_visible("ImageViewTabNew", isImage, browser); - action_set_visible("ImageViewTabCurrent", isImage, browser); - action_set_visible("ImageSaveAs", isImage, browser); - action_set_visible("ImageSaveWith", isImage && canDownload, browser); - action_set_visible("ImageCopy", isImage, browser); - - action_set_visible("Copy_", hasSelection || isEditable, browser); - action_set_visible("SelectionSearch", hasSelection, browser); - action_set_visible("SelectionSearchWith", hasSelection, browser); - action_set_visible("SelectionSourceView", hasSelection, browser); - - action_set_visible("SourceView", !hasSelection, browser); - - if(isEditable) - sokoke_widget_popup(webView, GTK_MENU(browser->popup_editable), event); - else if(isLink || isImage || hasSelection) - sokoke_widget_popup(webView, GTK_MENU(browser->popup_element), event); - else - sokoke_widget_popup(webView, GTK_MENU(browser->popup_webView), event); -} - -gboolean on_webView_button_press(GtkWidget* webView, GdkEventButton* event - , CBrowser* browser) -{ - GdkModifierType state = (GdkModifierType)0; - gint x, y; - gdk_window_get_pointer(NULL, &x, &y, &state); - switch(event->button) - { - case 1: - if(!browser->elementUri) - return FALSE; - if(state & GDK_SHIFT_MASK) - { - // Open link in new window - CBrowser* curBrowser = browser_new(NULL); - webkit_web_view_open(WEBKIT_WEB_VIEW(curBrowser->webView), browser->elementUri); - return TRUE; - } - else if(state & GDK_MOD1_MASK) - { - // Open link in new tab - CBrowser* curBrowser = browser_new(browser); - webkit_web_view_open(WEBKIT_WEB_VIEW(curBrowser->webView), browser->elementUri); - return TRUE; - } - break; - case 2: - if(state & GDK_CONTROL_MASK) - { - //webkit_web_view_set_text_size(WEBKIT_WEB_VIEW(webView), 1); - return TRUE; - } - else - { - if(!browser->elementUri) - return FALSE; - // Open link in new tab - CBrowser* curBrowser = browser_new(browser); - webkit_web_view_open(WEBKIT_WEB_VIEW(curBrowser->webView), browser->elementUri); - return TRUE; - } - break; - case 3: - webView_popup(webView, event, browser); - return TRUE; - } - return FALSE; -} - -gboolean on_webView_button_press_after(GtkWidget* webView, GdkEventButton* event - , CBrowser* browser) -{ - if(event->button == 2 && config->middleClickGoto) - { - GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); - gchar* text = gtk_clipboard_wait_for_text(clipboard); - gchar* uri = NULL; - if(text && strchr(text, '.') && !strchr(text, ' ')) - uri = magic_uri(text, FALSE); - g_free(text); - if(uri) - { - webkit_web_view_open(WEBKIT_WEB_VIEW(browser->webView), uri); - g_free(uri); - return TRUE; - } - } - return FALSE; -} - -void on_webView_popup(GtkWidget* webView, CBrowser* browser) -{ - webView_popup(webView, NULL, browser); -} - -gboolean on_webView_scroll(GtkWidget* webView, GdkEventScroll* event - , CBrowser* browser) -{ - GdkModifierType state = (GdkModifierType)0; - gint x, y; - gdk_window_get_pointer(NULL, &x, &y, &state); - if(state & GDK_CONTROL_MASK) - { - /*const gfloat size = webkit_web_view_get_text_size(WEBKIT_WEB_VIEW(webView)); - if(event->direction == GDK_SCROLL_DOWN) - webkit_web_view_set_text_size(WEBKIT_WEB_VIEW(webView), size + 0.1); - else if(event->direction == GDK_SCROLL_UP) - webView_set_text_size(WEBKIT_WEB_VIEW(webView), size - 0.1);*/ - return TRUE; - } - else - return FALSE; -} - -gboolean on_webView_leave(GtkWidget* webView, GdkEventCrossing* event, CBrowser* browser) -{ - katze_assign(browser->statusMessage, NULL); - update_statusbar(browser); - return TRUE; -} - -void on_webView_destroy(GtkWidget* widget, CBrowser* browser) -{ - // Update browser list, free memory and possibly quit - GList* tmp = g_list_find(browsers, browser); - browsers = g_list_delete_link(browsers, tmp); - g_free(browser->elementUri); - g_free(browser->statusMessage); - // FIXME: Multiple windows are not taken into account - if(!g_list_nth(browsers, 0)) - { - g_object_unref(browser->actiongroup); - g_object_unref(browser->popup_bookmark); - g_object_unref(browser->popup_webView); - g_object_unref(browser->popup_element); - g_object_unref(browser->popup_editable); - guint i; - guint n = katze_xbel_folder_get_n_items(bookmarks); - for(i = 0; i < n; i++) - katze_xbel_item_unref(katze_xbel_folder_get_nth_item(bookmarks, i)); - gtk_main_quit(); - } -} - -// webView actions begin here - -GtkWidget* webView_new(GtkWidget** scrolled) -{ - *scrolled = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(*scrolled) - , GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - GTK_WIDGET_SET_FLAGS(*scrolled, GTK_CAN_FOCUS); - GtkWidget* webView = webkit_web_view_new(); - gtk_container_add(GTK_CONTAINER(*scrolled), webView); - return webView; -} - -void webView_open(GtkWidget* webView, const gchar* uri) -{ - webkit_web_view_open(WEBKIT_WEB_VIEW(webView), uri); - // We need to check the browser first - // No browser means this is a panel - CBrowser* browser = get_browser_from_webView(webView); - if(browser) - { - katze_xbel_bookmark_set_href(browser->sessionItem, uri); - katze_xbel_item_set_title(browser->sessionItem, ""); - } -} - -void webView_close(GtkWidget* webView, CBrowser* browser) -{ - browser = get_browser_from_webView(webView); - const gchar* uri = katze_xbel_bookmark_get_href(browser->sessionItem); - katze_xbel_folder_remove_item(session, browser->sessionItem); - if(uri && *uri) - { - katze_xbel_folder_prepend_item(tabtrash, browser->sessionItem); - guint n = katze_xbel_folder_get_n_items(tabtrash); - if(n > 10) - { - KatzeXbelItem* item = katze_xbel_folder_get_nth_item(tabtrash, n - 1); - katze_xbel_item_unref(item); - } - } - else - katze_xbel_item_unref(browser->sessionItem); - gtk_widget_destroy(browser->webView_menu); - gtk_notebook_remove_page(GTK_NOTEBOOK(browser->webViews) - , get_webView_index(webView, browser)); - update_browser_actions(browser); -} diff --git a/src/webView.h b/src/webView.h deleted file mode 100644 index 552b571b..00000000 --- a/src/webView.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright (C) 2007 Christian Dywan - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - See the file COPYING for the full license text. -*/ - -#ifndef __webView_H__ -#define __webView_H__ 1 - -#include -#include "browser.h" -#include "debug.h" - -#include - -WebKitNavigationResponse -on_webView_navigation_requested(GtkWidget* webView, WebKitWebFrame* frame - , WebKitNetworkRequest* networkRequest); - -void -on_webView_title_changed(GtkWidget*, WebKitWebFrame*, const gchar*, CBrowser*); - -void -on_webView_icon_changed(GtkWidget*, WebKitWebFrame*, CBrowser*); - -void -on_webView_load_started(GtkWidget* , WebKitWebFrame*, CBrowser*); - -void -on_webView_load_committed(GtkWidget* , WebKitWebFrame*, CBrowser*); - -void -on_webView_load_changed(GtkWidget*, gint progress, CBrowser*); - -void -on_webView_load_finished(GtkWidget*, WebKitWebFrame*, CBrowser*); - -void -on_webView_status_message(GtkWidget*, const gchar*, CBrowser*); - -void -on_webView_selection_changed(GtkWidget*, CBrowser*); - -gboolean -on_webView_console_message(GtkWidget*, const gchar*, gint, const gchar*, CBrowser*); - -void -on_webView_link_hover(GtkWidget*, const gchar*, const gchar*, CBrowser*); - -/* -GtkWidget* -on_webView_window_open(GtkWidget*, const gchar*, CBrowser*); -*/ - -gboolean -on_webView_button_press(GtkWidget*, GdkEventButton*, CBrowser*); - -gboolean -on_webView_button_press_after(GtkWidget*, GdkEventButton*, CBrowser*); - -void -on_webView_popup(GtkWidget*, CBrowser*); - -gboolean -on_webView_scroll(GtkWidget*, GdkEventScroll*, CBrowser*); - -gboolean -on_webView_leave(GtkWidget*, GdkEventCrossing*, CBrowser*); - -void -on_webView_destroy(GtkWidget*, CBrowser*); - -GtkWidget* -webView_new(GtkWidget**); - -void -webView_open(GtkWidget*, const gchar*); - -void -webView_close(GtkWidget*, CBrowser*); - -#endif /* !__webView_H__ */