From 62838fdf58183de24573c0a7afd358bea94741c6 Mon Sep 17 00:00:00 2001 From: Christian Dywan Date: Fri, 26 Sep 2008 23:13:46 +0200 Subject: [PATCH] Implement tabs in individual processes The approach is rather plump, Midori can be run in a plug mode that creates a GtkPlug, while the normal instance knows how to embed it. Communication between browser and tabs is done via named pipes which are portable. The feature is not complete right now, there are expected regressions, but it works. As a bonus, we implement Not found pages. --- midori/Makefile.am | 3 +- midori/main.c | 109 +- midori/midori-browser.c | 1265 +++++++------------- midori/midori-browser.h | 13 +- midori/midori-panel.c | 5 + midori/midori-source.c | 191 +++ midori/midori-source.h | 47 + midori/midori-view.c | 2451 +++++++++++++++++++++++++++++++++++++++ midori/midori-view.h | 161 +++ midori/midori-webview.c | 1214 ------------------- midori/midori-webview.h | 125 -- midori/sokoke.c | 35 +- midori/sokoke.h | 3 + 13 files changed, 3406 insertions(+), 2216 deletions(-) create mode 100644 midori/midori-source.c create mode 100644 midori/midori-source.h create mode 100644 midori/midori-view.c create mode 100644 midori/midori-view.h delete mode 100644 midori/midori-webview.c delete mode 100644 midori/midori-webview.h diff --git a/midori/Makefile.am b/midori/Makefile.am index ffe49e56..3c327a3f 100644 --- a/midori/Makefile.am +++ b/midori/Makefile.am @@ -28,7 +28,8 @@ midori_SOURCES = \ midori-panel.c midori-panel.h \ midori-addons.c midori-addons.h \ midori-console.c midori-console.h \ - midori-webview.c midori-webview.h \ + midori-view.c midori-view.h \ + midori-source.c midori-source.h \ midori-websettings.c midori-websettings.h \ midori-preferences.c midori-preferences.h \ midori-searchentry.c midori-searchentry.h \ diff --git a/midori/main.c b/midori/main.c index de898e2d..fac85f03 100644 --- a/midori/main.c +++ b/midori/main.c @@ -13,6 +13,7 @@ #include #endif +#include "midori-view.h" #include "midori-app.h" #include "midori-websettings.h" #include "midori-browser.h" @@ -367,25 +368,76 @@ _simple_xml_element (const gchar* name, } static gchar* -katze_xbel_array_to_xml (KatzeArray* array, - GError** error) +katze_item_to_data (KatzeItem* item) +{ + gchar* markup; + + g_return_val_if_fail (KATZE_IS_ITEM (item), NULL); + + markup = NULL; + if (KATZE_IS_ARRAY (item)) + { + GString* _markup = g_string_new (NULL); + guint n = katze_array_get_length (KATZE_ARRAY (item)); + guint i; + for (i = 0; i < n; i++) + { + KatzeItem* _item = katze_array_get_nth_item (KATZE_ARRAY (item), i); + gchar* item_markup = katze_item_to_data (_item); + g_string_append (_markup, item_markup); + g_free (item_markup); + } + /* gchar* folded = item->folded ? NULL : g_strdup_printf (" folded=\"no\""); */ + gchar* title = _simple_xml_element ("title", katze_item_get_name (item)); + gchar* desc = _simple_xml_element ("desc", katze_item_get_text (item)); + markup = g_strdup_printf ("\n%s%s%s\n", + "" /* folded ? folded : "" */, + title, desc, + g_string_free (_markup, FALSE)); + /* g_free (folded); */ + g_free (title); + g_free (desc); + } + else if (katze_item_get_uri (item)) + { + gchar* href_escaped = g_markup_escape_text (katze_item_get_uri (item), -1); + gchar* href = g_strdup_printf (" href=\"%s\"", href_escaped); + g_free (href_escaped); + gchar* title = _simple_xml_element ("title", katze_item_get_name (item)); + gchar* desc = _simple_xml_element ("desc", katze_item_get_text (item)); + markup = g_strdup_printf ("\n%s%s%s\n", + href, + title, desc, + ""); + g_free (href); + g_free (title); + g_free (desc); + } + else + markup = g_strdup ("\n"); + return markup; +} + +static gchar* +katze_array_to_xml (KatzeArray* array, + GError** error) { GString* inner_markup; guint i, n; - KatzeXbelItem* item; + KatzeItem* item; gchar* item_xml; gchar* title; gchar* desc; gchar* outer_markup; - g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_XBEL_ITEM), NULL); + g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_ITEM), NULL); inner_markup = g_string_new (NULL); n = katze_array_get_length (array); for (i = 0; i < n; i++) { item = katze_array_get_nth_item (array, i); - item_xml = katze_xbel_item_to_data (item); + item_xml = katze_item_to_data (item); g_string_append (inner_markup, item_xml); g_free (item_xml); } @@ -415,10 +467,10 @@ katze_array_to_file (KatzeArray* array, gchar* data; FILE* fp; - g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_XBEL_ITEM), FALSE); + g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_ITEM), FALSE); g_return_val_if_fail (filename, FALSE); - if (!(data = katze_xbel_array_to_xml (array, error))) + if (!(data = katze_array_to_xml (array, error))) return FALSE; if (!(fp = fopen (filename, "w"))) { @@ -468,6 +520,7 @@ int main (int argc, char** argv) { + guint socket_id; gboolean version; gchar** uris; MidoriApp* app; @@ -475,12 +528,16 @@ main (int argc, GError* error; GOptionEntry entries[] = { - { "version", 'v', 0, G_OPTION_ARG_NONE, &version, + { "id", 'i', 0, G_OPTION_ARG_INT, &socket_id, + N_("Internal identifier"), NULL }, + { "version", 'v', 0, G_OPTION_ARG_NONE, &version, N_("Display program version"), NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &uris, N_("URIs"), NULL }, { NULL } }; + GtkWidget* view; + GtkWidget* plug; MidoriStartup load_on_startup; gchar* homepage; KatzeArray* search_engines; @@ -498,6 +555,7 @@ main (int argc, g_set_application_name (_("Midori")); /* Parse cli options */ + socket_id = 0; version = FALSE; uris = NULL; error = NULL; @@ -509,6 +567,22 @@ main (int argc, return 1; } + stock_items_init (); + + if (socket_id) + { + /* If an ID was specified we create a view in a plug. + This allows us to open views in separate processes. */ + view = g_object_new (MIDORI_TYPE_VIEW, "socket-id", socket_id, NULL); + gtk_widget_show (view); + plug = gtk_plug_new (socket_id); + gtk_container_add (GTK_CONTAINER (plug), view); + g_signal_connect (plug, "destroy", G_CALLBACK (gtk_main_quit), NULL); + gtk_widget_show (plug); + gtk_main (); + return 0; + } + if (version) { g_print ( @@ -539,6 +613,8 @@ main (int argc, return 1; } + sokoke_remember_argv0 (argv[0]); + app = midori_app_new (); if (midori_app_instance_is_running (app)) { @@ -691,14 +767,19 @@ main (int argc, } g_free (config_path); - stock_items_init (); - - KatzeArray* trash = katze_array_new (KATZE_TYPE_XBEL_ITEM); + KatzeArray* trash = katze_array_new (KATZE_TYPE_ITEM); guint n = katze_xbel_folder_get_n_items (xbel_trash); for (i = 0; i < n; i++) { - KatzeXbelItem* item = katze_xbel_folder_get_nth_item (xbel_trash, i); - katze_array_add_item (trash, item); + KatzeXbelItem* xbel_item = katze_xbel_folder_get_nth_item (xbel_trash, i); + if (!katze_xbel_item_is_separator (xbel_item)) + { + KatzeItem* item = g_object_new (KATZE_TYPE_ITEM, + "name", katze_xbel_item_get_title (xbel_item), + "uri", katze_xbel_bookmark_get_href (xbel_item), + NULL); + katze_array_add_item (trash, item); + } } katze_xbel_item_unref (xbel_trash); g_signal_connect_after (trash, "add-item", @@ -719,7 +800,7 @@ main (int argc, midori_app_add_browser (app, browser); gtk_widget_show (GTK_WIDGET (browser)); - KatzeArray* session = midori_browser_get_proxy_xbel_array (browser); + KatzeArray* session = midori_browser_get_proxy_array (browser); n = katze_xbel_folder_get_n_items (_session); for (i = 0; i < n; i++) { diff --git a/midori/midori-browser.c b/midori/midori-browser.c index 9828b507..91c2a9bb 100644 --- a/midori/midori-browser.c +++ b/midori/midori-browser.c @@ -15,7 +15,8 @@ #include "midori-browser.h" -#include "midori-webview.h" +#include "midori-view.h" +#include "midori-source.h" #include "midori-preferences.h" #include "midori-panel.h" #include "midori-addons.h" @@ -34,10 +35,6 @@ #endif #include #include -#if HAVE_GTKSOURCEVIEW -#include -#include -#endif #include struct _MidoriBrowser @@ -76,10 +73,8 @@ struct _MidoriBrowser gchar* statusbar_text; MidoriWebSettings* settings; KatzeXbelItem* bookmarks; - GList* tab_titles; - GList* close_buttons; - KatzeArray* proxy_xbel_array; + KatzeArray* proxy_array; KatzeArray* trash; KatzeArray* search_engines; }; @@ -105,8 +100,6 @@ enum enum { WINDOW_OBJECT_CLEARED, - STATUSBAR_TEXT_CHANGED, - ELEMENT_MOTION, NEW_WINDOW, ADD_TAB, @@ -163,56 +156,15 @@ _action_set_active (MidoriBrowser* browser, gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), active); } -static const gchar* -_midori_browser_get_tab_uri (MidoriBrowser* browser, - GtkWidget* widget) -{ - const gchar* uri; - - if (MIDORI_IS_WEB_VIEW (widget)) - return midori_web_view_get_display_uri (MIDORI_WEB_VIEW (widget)); - - uri = g_object_get_data (G_OBJECT (widget), "browser-tab-uri"); - return uri ? uri : "file://"; -} - -/* Note: The return value is valid only - until the next call to this function */ -static const gchar* -_midori_browser_get_tab_title (MidoriBrowser* browser, - GtkWidget* widget) -{ - const gchar* uri; - static gchar* title = NULL; - - if (MIDORI_IS_WEB_VIEW (widget)) - return midori_web_view_get_display_title (MIDORI_WEB_VIEW (widget)); - - uri = g_object_get_data (G_OBJECT (widget), "browser-tab-uri"); - if (g_str_has_prefix (uri, "view-source:")) - { - g_free (title); - title = g_strconcat (_("Source"), ": ", uri, NULL); - return title; - } - return "untitled"; -} - static void _midori_browser_open_uri (MidoriBrowser* browser, const gchar* uri) { - GtkWidget* web_view; - gint n; + GtkWidget* view; - web_view = midori_browser_get_current_web_view (browser); - if (web_view) - webkit_web_view_open (WEBKIT_WEB_VIEW (web_view), uri); - else - { - n = midori_browser_add_uri (browser, uri); - midori_browser_set_current_page (browser, n); - } + view = midori_browser_get_current_tab (browser); + if (view) + midori_view_set_uri (MIDORI_VIEW (view), uri); } static void @@ -238,35 +190,41 @@ _midori_browser_update_actions (MidoriBrowser* browser) static void _midori_browser_update_interface (MidoriBrowser* browser) { + GtkWidget* view; gboolean loading; - GtkWidget* widget; - GtkWidget* web_view; + gboolean can_reload; GtkAction* action; - widget = midori_browser_get_current_tab (browser); - web_view = widget && MIDORI_IS_WEB_VIEW (widget) ? widget : NULL; - loading = web_view != NULL - && midori_web_view_get_load_status (MIDORI_WEB_VIEW (web_view)) + view = midori_browser_get_current_tab (browser); + loading = midori_view_get_load_status (MIDORI_VIEW (view)) != MIDORI_LOAD_FINISHED; + can_reload = midori_view_can_reload (MIDORI_VIEW (view)); - _action_set_sensitive (browser, "Reload", web_view != NULL && !loading); - _action_set_sensitive (browser, "Stop", web_view != NULL && loading); - _action_set_sensitive (browser, "Back", web_view != NULL - && webkit_web_view_can_go_back (WEBKIT_WEB_VIEW (web_view))); - _action_set_sensitive (browser, "Forward", web_view != NULL - && webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW (web_view))); + _action_set_sensitive (browser, "Reload", can_reload && !loading); + _action_set_sensitive (browser, "Stop", can_reload && loading); + _action_set_sensitive (browser, "Back", + midori_view_can_go_back (MIDORI_VIEW (view))); + _action_set_sensitive (browser, "Forward", + midori_view_can_go_forward (MIDORI_VIEW (view))); - _action_set_sensitive (browser, "Print", web_view != NULL); - _action_set_sensitive (browser, "ZoomIn", web_view != NULL); - _action_set_sensitive (browser, "ZoomOut", web_view != NULL); - _action_set_sensitive (browser, "ZoomNormal", web_view != NULL - && webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view)) != 1.0); - #if HAVE_GIO - _action_set_sensitive (browser, "SourceView", web_view != NULL); - #endif - _action_set_sensitive (browser, "FindNext", web_view != NULL); - _action_set_sensitive (browser, "FindPrevious", web_view != NULL); - /* _action_set_sensitive (browser, "FindQuick", web_view != NULL); */ + _action_set_sensitive (browser, "Print", + midori_view_can_print (MIDORI_VIEW (view))); + _action_set_sensitive (browser, "ZoomIn", + midori_view_can_zoom_in (MIDORI_VIEW (view))); + _action_set_sensitive (browser, "ZoomOut", + midori_view_can_zoom_out (MIDORI_VIEW (view))); + _action_set_sensitive (browser, "ZoomNormal", + midori_view_get_zoom_level (MIDORI_VIEW (view)) != 1.0); + _action_set_sensitive (browser, "SourceView", + midori_view_can_view_source (MIDORI_VIEW (view))); + _action_set_sensitive (browser, "Find", + midori_view_can_find (MIDORI_VIEW (view))); + _action_set_sensitive (browser, "FindNext", + midori_view_can_find (MIDORI_VIEW (view))); + _action_set_sensitive (browser, "FindPrevious", + midori_view_can_find (MIDORI_VIEW (view))); + /* _action_set_sensitive (browser, "FindQuick", + midori_view_can_find (MIDORI_VIEW (view))); */ action = gtk_action_group_get_action (browser->action_group, "ReloadStop"); if (!loading) @@ -275,7 +233,7 @@ _midori_browser_update_interface (MidoriBrowser* browser) g_object_set (action, "stock-id", GTK_STOCK_REFRESH, "tooltip", _("Reload the current page"), - "sensitive", web_view != NULL, NULL); + "sensitive", can_reload, NULL); gtk_widget_hide (browser->progressbar); if (!GTK_WIDGET_VISIBLE (browser->statusbar)) if (!sokoke_object_get_boolean (browser->settings, @@ -294,13 +252,13 @@ _midori_browser_update_interface (MidoriBrowser* browser) if (!GTK_WIDGET_VISIBLE (browser->navigationbar)) gtk_widget_show (browser->navigationbar); g_object_set (_action_by_name (browser, "Location"), "progress", - midori_web_view_get_progress (MIDORI_WEB_VIEW (web_view)), NULL); + midori_view_get_progress (MIDORI_VIEW (view)), NULL); } } katze_throbber_set_animated (KATZE_THROBBER (browser->throbber), loading); /* FIXME: This won't work due to a bug in GtkIconEntry */ - /* if (web_view && midori_web_view_get_news_feeds (MIDORI_WEB_VIEW (web_view))) + /* if (view && midori_view_get_news_feeds (MIDORI_VIEW (view))) gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY ( gtk_bin_get_child (GTK_BIN (browser->location))), GTK_ICON_ENTRY_SECONDARY, STOCK_NEWS_FEED); @@ -310,26 +268,6 @@ _midori_browser_update_interface (MidoriBrowser* browser) GTK_ICON_ENTRY_SECONDARY, NULL);*/ } -static GtkWidget* -_midori_browser_scrolled_for_child (MidoriBrowser* browser, - 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* browser, - 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 void _midori_browser_set_statusbar_text (MidoriBrowser* browser, const gchar* text) @@ -351,16 +289,16 @@ _midori_browser_set_current_page_smartly (MidoriBrowser* browser, static void _midori_browser_update_progress (MidoriBrowser* browser, - MidoriWebView* web_view) + MidoriView* view) { MidoriLocationAction* action; gdouble progress; gchar* message; action = MIDORI_LOCATION_ACTION (_action_by_name (browser, "Location")); - progress = midori_web_view_get_progress (web_view); + progress = midori_view_get_progress (view); /* When we are finished, we don't want to *see* progress anymore */ - if (midori_web_view_get_load_status (web_view) == MIDORI_LOAD_FINISHED) + if (midori_view_get_load_status (view) == MIDORI_LOAD_FINISHED) progress = 0.0; if (progress > 0.0) { @@ -383,35 +321,55 @@ _midori_browser_update_progress (MidoriBrowser* browser, } static void -midori_web_view_window_object_cleared_cb (GtkWidget* web_view, - WebKitWebFrame* web_frame, - JSGlobalContextRef js_context, - JSObjectRef js_window, - MidoriBrowser* browser) +_midori_browser_activate_action (MidoriBrowser* browser, + const gchar* name) { - g_signal_emit (browser, signals[WINDOW_OBJECT_CLEARED], 0, - web_frame, js_context, js_window); + GtkAction* action = _action_by_name (browser, name); + if (action) + gtk_action_activate (action); + else + g_warning (_("Unexpected action '%s'."), name); } static void -midori_web_view_notify_load_status_cb (GtkWidget* web_view, - GParamSpec* pspec, - MidoriBrowser* browser) +midori_view_notify_icon_cb (MidoriView* view, + GParamSpec* pspec, + MidoriBrowser* browser) { const gchar* uri; GtkAction* action; - uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view)); + uri = midori_view_get_display_uri (MIDORI_VIEW (view)); + action = _action_by_name (browser, "Location"); + midori_location_action_set_icon_for_uri ( + MIDORI_LOCATION_ACTION (action), midori_view_get_icon (view), uri); +} + +static void +midori_view_notify_load_status_cb (GtkWidget* view, + GParamSpec* pspec, + MidoriBrowser* browser) +{ + const gchar* uri; + GtkAction* action; + + uri = midori_view_get_display_uri (MIDORI_VIEW (view)); action = _action_by_name (browser, "Location"); - if (midori_web_view_get_load_status (MIDORI_WEB_VIEW (web_view)) + if (midori_view_get_load_status (MIDORI_VIEW (view)) == MIDORI_LOAD_COMMITTED) midori_location_action_add_uri ( MIDORI_LOCATION_ACTION (action), uri); - - if (web_view == midori_browser_get_current_web_view (browser)) + else if (midori_view_get_load_status (MIDORI_VIEW (view)) + == MIDORI_LOAD_FINISHED) { - if (midori_web_view_get_load_status (MIDORI_WEB_VIEW (web_view)) + /* g_signal_emit (browser, signals[WINDOW_OBJECT_CLEARED], 0, + web_frame, js_context, js_window); */ + } + + if (view == midori_browser_get_current_tab (browser)) + { + if (midori_view_get_load_status (MIDORI_VIEW (view)) == MIDORI_LOAD_COMMITTED) { midori_location_action_set_uri ( @@ -427,79 +385,15 @@ midori_web_view_notify_load_status_cb (GtkWidget* web_view, } static void -midori_web_view_notify_progress_cb (GtkWidget* web_view, - GParamSpec* pspec, - MidoriBrowser* browser) +midori_view_notify_progress_cb (GtkWidget* view, + GParamSpec* pspec, + MidoriBrowser* browser) { - if (web_view == midori_browser_get_current_web_view (browser)) - _midori_browser_update_progress (browser, MIDORI_WEB_VIEW (web_view)); -} - -static void -midori_web_view_notify_title_cb (GtkWidget* web_view, - GParamSpec* pspec, - MidoriBrowser* browser) -{ - const gchar* uri; - const gchar* title; - GtkAction* action; - gchar* window_title; - - uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view)); - title = midori_web_view_get_display_title (MIDORI_WEB_VIEW (web_view)); - action = _action_by_name (browser, "Location"); - midori_location_action_set_title_for_uri ( - MIDORI_LOCATION_ACTION (action), title, uri); - - if (web_view == midori_browser_get_current_web_view (browser)) - { - 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_notify_zoom_level_cb (GtkWidget* web_view, - GParamSpec* pspec, - MidoriBrowser* browser) -{ - if (web_view == midori_browser_get_current_web_view (browser)) - _action_set_sensitive (browser, "ZoomNormal", - webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view)) != 1.0); -} - -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_icon_ready_cb (MidoriWebView* web_view, - GdkPixbuf* icon, - MidoriBrowser* browser) -{ - const gchar* uri; - GtkAction* action; - - uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view)); - action = _action_by_name (browser, "Location"); - midori_location_action_set_icon_for_uri ( - MIDORI_LOCATION_ACTION (action), icon, uri); + if (view == midori_browser_get_current_tab (browser)) + _midori_browser_update_progress (browser, MIDORI_VIEW (view)); } +/* static void midori_web_view_news_feed_ready_cb (MidoriWebView* web_view, const gchar* href, @@ -511,80 +405,53 @@ midori_web_view_news_feed_ready_cb (MidoriWebView* web_view, midori_location_action_set_secondary_icon (MIDORI_LOCATION_ACTION ( _action_by_name (browser, "Location")), STOCK_NEWS_FEED); } +*/ -static gboolean -midori_web_view_console_message_cb (GtkWidget* web_view, - const gchar* message, - guint line, - const gchar* source_id, - MidoriBrowser* browser) +static void +midori_view_notify_title_cb (GtkWidget* view, + GParamSpec* pspec, + MidoriBrowser* browser) { - midori_console_add (MIDORI_CONSOLE (browser->panel_console), - message, line, source_id); - return TRUE; + const gchar* uri; + const gchar* title; + GtkAction* action; + gchar* window_title; + + uri = midori_view_get_display_uri (MIDORI_VIEW (view)); + title = midori_view_get_display_title (MIDORI_VIEW (view)); + action = _action_by_name (browser, "Location"); + midori_location_action_set_title_for_uri ( + MIDORI_LOCATION_ACTION (action), title, uri); + + if (view == midori_browser_get_current_tab (browser)) + { + window_title = g_strconcat (title, " - ", + g_get_application_name (), NULL); + gtk_window_set_title (GTK_WINDOW (browser), window_title); + g_free (window_title); + } } -static gboolean -midori_web_view_button_press_event_cb (MidoriWebView* web_view, - GdkEventButton* event, - MidoriBrowser* browser) +static void +midori_view_notify_zoom_level_cb (GtkWidget* view, + GParamSpec* pspec, + MidoriBrowser* browser) { - GdkModifierType state = (GdkModifierType)0; - gint x, y; - const gchar* link_uri; - guint n; - gboolean background; + if (view == midori_browser_get_current_tab (browser)) + _action_set_sensitive (browser, "ZoomNormal", + midori_view_get_zoom_level (MIDORI_VIEW (view)) != 1.0); +} - gdk_window_get_pointer (NULL, &x, &y, &state); - link_uri = midori_web_view_get_link_uri (web_view); +static void +midori_view_notify_statusbar_text_cb (MidoriView* view, + GParamSpec* pspec, + MidoriBrowser* browser) +{ + gchar* text; - switch (event->button) - { - case 1: - if (!link_uri) - return FALSE; - if (state & GDK_SHIFT_MASK) - { - /* Open link in new window */ - g_signal_emit (browser, signals[NEW_WINDOW], 0, link_uri); - return TRUE; - } - else if (state & GDK_MOD1_MASK) - { - /* Open link in new tab */ - n = midori_browser_add_uri (browser, link_uri); - background = sokoke_object_get_boolean (browser->settings, - "open-tabs-in-the-background"); - if (state & GDK_CONTROL_MASK) - background = !background; - if (!background) - midori_browser_set_current_page (browser, n); - return TRUE; - } - break; - case 2: - if (link_uri) - { - /* Open link in new tab */ - n = midori_browser_add_uri (browser, link_uri); - background = sokoke_object_get_boolean (browser->settings, - "open-tabs-in-the-background"); - if (state & GDK_CONTROL_MASK) - background = !background; - if (!background) - midori_browser_set_current_page (browser, n); - return TRUE; - } - else if (state & GDK_CONTROL_MASK) - { - webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), 1.0); - return FALSE; /* Allow Ctrl + Middle click */ - } - break; - case 3: - return FALSE; - } - return FALSE; + g_object_get (view, "statusbar-text", &text, NULL); + _midori_browser_set_statusbar_text (browser, text); + g_free (text); } static void @@ -607,12 +474,12 @@ midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser, if (new_bookmark) { - GtkWidget* widget = midori_browser_get_current_tab (browser); + GtkWidget* view = midori_browser_get_current_tab (browser); bookmark = katze_xbel_bookmark_new (); katze_xbel_item_set_title (bookmark, - _midori_browser_get_tab_title (browser, widget)); + midori_view_get_display_title (MIDORI_VIEW (view))); katze_xbel_bookmark_set_href (bookmark, - _midori_browser_get_tab_uri (browser, widget)); + midori_view_get_display_uri (MIDORI_VIEW (view))); } GtkWidget* hbox = gtk_hbox_new (FALSE, 8); @@ -707,74 +574,19 @@ midori_browser_edit_bookmark_dialog_new (MidoriBrowser* browser, } static void -midori_web_view_bookmark_add_cb (GtkWidget* menuitem, - GtkWidget* web_view) +midori_view_add_bookmark_cb (GtkWidget* menuitem, + const gchar* uri, + GtkWidget* view) { - const gchar* uri; KatzeXbelItem* xbel_item; MidoriBrowser* browser; - uri = midori_web_view_get_link_uri (MIDORI_WEB_VIEW (web_view)); xbel_item = katze_xbel_bookmark_new (); katze_xbel_bookmark_set_href (xbel_item, uri); browser = (MidoriBrowser*)gtk_widget_get_toplevel (menuitem); midori_browser_edit_bookmark_dialog_new (browser, xbel_item); } -static void -midori_web_view_populate_popup_cb (GtkWidget* web_view, - GtkWidget* menu, - MidoriBrowser* browser) -{ - gboolean has_selection; - const gchar* uri; - GtkAction* action; - GtkWidget* menuitem; - - if (MIDORI_IS_WEB_VIEW (web_view) - && midori_web_view_has_selection (MIDORI_WEB_VIEW (web_view))) - has_selection = TRUE; - else - has_selection = FALSE; - - uri = midori_web_view_get_link_uri (MIDORI_WEB_VIEW (web_view)); - if (uri) - { - action = _action_by_name (browser, "BookmarkAdd"); - menuitem = sokoke_action_create_popup_menu_item (action); - g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_web_view_bookmark_add_cb), web_view); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - } - - if (has_selection) - { - /* TODO: view selection source */ - } - - if (!uri && !has_selection) - { - action = _action_by_name (browser, "UndoTabClose"); - menuitem = sokoke_action_create_popup_menu_item (action); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - menuitem = gtk_separator_menu_item_new (); - gtk_widget_show (menuitem); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - action = _action_by_name (browser, "BookmarkAdd"); - menuitem = sokoke_action_create_popup_menu_item (action); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - action = _action_by_name (browser, "SaveAs"); - menuitem = sokoke_action_create_popup_menu_item (action); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - action = _action_by_name (browser, "SourceView"); - menuitem = sokoke_action_create_popup_menu_item (action); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - action = _action_by_name (browser, "Print"); - menuitem = sokoke_action_create_popup_menu_item (action); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - } -} - static gboolean midori_browser_tab_leave_notify_event_cb (GtkWidget* widget, GdkEventCrossing* event, @@ -785,18 +597,37 @@ midori_browser_tab_leave_notify_event_cb (GtkWidget* widget, } static void -midori_web_view_new_tab_cb (GtkWidget* web_view, - const gchar* uri, - MidoriBrowser* browser) +midori_view_activate_action_cb (GtkWidget* view, + const gchar* action, + MidoriBrowser* browser) +{ + _midori_browser_activate_action (browser, action); +} + +static void +midori_view_console_message_cb (GtkWidget* view, + const gchar* message, + gint line, + const gchar* source_id, + MidoriBrowser* browser) +{ + midori_console_add (MIDORI_CONSOLE (browser->panel_console), + message, line, source_id); +} + +static void +midori_view_new_tab_cb (GtkWidget* view, + const gchar* uri, + MidoriBrowser* browser) { gint n = midori_browser_add_uri (browser, uri); _midori_browser_set_current_page_smartly (browser, n); } static void -midori_web_view_new_window_cb (GtkWidget* web_view, - const gchar* uri, - MidoriBrowser* browser) +midori_view_new_window_cb (GtkWidget* view, + const gchar* uri, + MidoriBrowser* browser) { g_signal_emit (browser, signals[NEW_WINDOW], 0, uri); } @@ -805,18 +636,17 @@ static gboolean midori_browser_tab_destroy_cb (GtkWidget* widget, MidoriBrowser* browser) { - KatzeXbelItem* xbel_item; + KatzeItem* item; const gchar* uri; - if (browser->proxy_xbel_array && MIDORI_IS_WEB_VIEW (widget)) + if (browser->proxy_array && MIDORI_IS_VIEW (widget)) { - xbel_item = midori_web_view_get_proxy_xbel_item ( - MIDORI_WEB_VIEW (widget)); - uri = katze_xbel_bookmark_get_href (xbel_item); + item = midori_view_get_proxy_item (MIDORI_VIEW (widget)); + uri = katze_item_get_uri (item); if (browser->trash && uri && *uri) - katze_array_add_item (browser->trash, xbel_item); - katze_array_remove_item (browser->proxy_xbel_array, xbel_item); - katze_xbel_item_unref (xbel_item); + katze_array_add_item (browser->trash, item); + katze_array_remove_item (browser->proxy_array, item); + g_object_unref (item); } _midori_browser_update_actions (browser); @@ -844,243 +674,88 @@ midori_browser_window_menu_item_activate_cb (GtkWidget* menuitem, midori_browser_set_current_tab (browser, widget); } -static void -_update_label_size (GtkWidget* label, - gint size) -{ - gint width, height; - - if (size > -1) - { - sokoke_widget_get_text_size (label, "M", &width, &height); - gtk_widget_set_size_request (label, width * size, -1); - gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); - } - else - { - gtk_widget_set_size_request (label, -1, -1); - gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_NONE); - } -} - -static gboolean -midori_browser_tab_label_button_release_event (GtkWidget* tab_label, - GdkEventButton* event, - GtkWidget* widget) -{ - if (event->button == 2) - { - /* Close the widget on middle click */ - gtk_widget_destroy (widget); - return TRUE; - } - - return FALSE; -} - -static void -midori_browser_tab_icon_style_set (GtkWidget* tab_icon, - GtkStyle* previous_style) -{ - GtkSettings* gtk_settings; - gint width, height; - - gtk_settings = gtk_widget_get_settings (tab_icon); - gtk_icon_size_lookup_for_settings (gtk_settings, GTK_ICON_SIZE_MENU, - &width, &height); - gtk_widget_set_size_request (tab_icon, width + 2, height + 2); -} - -static void -midori_browser_tab_close_clicked (GtkWidget* tab_close, - GtkWidget* widget) -{ - gtk_widget_destroy (widget); -} - static void _midori_browser_add_tab (MidoriBrowser* browser, - GtkWidget* widget) + GtkWidget* view) { - GtkWidget* scrolled; - GtkWidget* child; - GObjectClass* gobject_class; - GdkPixbuf* icon; - GtkWidget* tab_icon; - const gchar* title; - GtkWidget* tab_title; + GtkWidget* tab_label; GtkWidget* menuitem; - KatzeXbelItem* xbel_item; - GtkWidget* event_box; - GtkWidget* hbox; - GtkWidget* close_button; - GtkRcStyle* rcstyle; - GtkWidget* image; + KatzeItem* item; guint n; - scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - GTK_WIDGET_SET_FLAGS (scrolled, GTK_CAN_FOCUS); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), + GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (view), GTK_SHADOW_ETCHED_IN); - gobject_class = G_OBJECT_GET_CLASS (widget); - if (GTK_WIDGET_CLASS (gobject_class)->set_scroll_adjustments_signal) - child = widget; - else + + tab_label = midori_view_get_proxy_tab_label (MIDORI_VIEW (view)); + menuitem = midori_view_get_proxy_menu_item (MIDORI_VIEW (view)); + + if (browser->proxy_array) { - child = gtk_viewport_new (NULL, NULL); - gtk_widget_show (child); - gtk_container_add (GTK_CONTAINER (child), widget); + item = midori_view_get_proxy_item (MIDORI_VIEW (view)); + g_object_ref (item); + katze_array_add_item (browser->proxy_array, item); } - gtk_container_add (GTK_CONTAINER (scrolled), child); - gtk_widget_show (scrolled); - if (MIDORI_IS_WEB_VIEW (widget)) - { - tab_icon = midori_web_view_get_proxy_tab_icon (MIDORI_WEB_VIEW (widget)); - tab_title = midori_web_view_get_proxy_tab_title (MIDORI_WEB_VIEW (widget)); - menuitem = midori_web_view_get_proxy_menu_item (MIDORI_WEB_VIEW (widget)); + g_object_connect (view, + "signal::notify::icon", + midori_view_notify_icon_cb, browser, + "signal::notify::load-status", + midori_view_notify_load_status_cb, browser, + "signal::notify::progress", + midori_view_notify_progress_cb, browser, + /* "signal::news-feed-ready", + midori_view_news_feed_ready_cb, browser, */ + "signal::notify::title", + midori_view_notify_title_cb, browser, + "signal::notify::zoom-level", + midori_view_notify_zoom_level_cb, browser, + "signal::notify::statusbar-text", + midori_view_notify_statusbar_text_cb, browser, + "signal::activate-action", + midori_view_activate_action_cb, browser, + "signal::console-message", + midori_view_console_message_cb, browser, + "signal::new-tab", + midori_view_new_tab_cb, browser, + "signal::new-window", + midori_view_new_window_cb, browser, + "signal::add-bookmark", + midori_view_add_bookmark_cb, browser, + NULL); - if (browser->proxy_xbel_array) - { - xbel_item = midori_web_view_get_proxy_xbel_item ( - MIDORI_WEB_VIEW (widget)); - katze_xbel_item_ref (xbel_item); - katze_array_add_item (browser->proxy_xbel_array, xbel_item); - } - - g_object_connect (widget, - "signal::window-object-cleared", - midori_web_view_window_object_cleared_cb, browser, - "signal::notify::progress", - midori_web_view_notify_progress_cb, browser, - "signal::notify::mload-status", - midori_web_view_notify_load_status_cb, browser, - "signal::icon-ready", - midori_web_view_icon_ready_cb, browser, - "signal::news-feed-ready", - midori_web_view_news_feed_ready_cb, browser, - "signal::notify::title", - midori_web_view_notify_title_cb, browser, - "signal::notify::zoom-level", - midori_web_view_notify_zoom_level_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::new-tab", - midori_web_view_new_tab_cb, browser, - "signal::new-window", - midori_web_view_new_window_cb, browser, - "signal::button-press-event", - midori_web_view_button_press_event_cb, browser, - "signal::populate-popup", - midori_web_view_populate_popup_cb, browser, - NULL); - } - else - { - if (GTK_IS_TEXT_VIEW (widget)) - icon = gtk_widget_render_icon (widget, GTK_STOCK_EDIT, - GTK_ICON_SIZE_MENU, NULL); - else - icon = gtk_widget_render_icon (widget, GTK_STOCK_FILE, - GTK_ICON_SIZE_MENU, NULL); - tab_icon = katze_throbber_new (); - katze_throbber_set_static_pixbuf (KATZE_THROBBER (tab_icon), icon); - title = _midori_browser_get_tab_title (browser, widget); - tab_title = gtk_label_new (title); - menuitem = sokoke_image_menu_item_new_ellipsized (title); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), - gtk_image_new_from_pixbuf (icon)); - g_object_unref (icon); - - if (browser->proxy_xbel_array) - { - xbel_item = katze_xbel_bookmark_new (); - katze_xbel_item_set_title (xbel_item, title); - katze_xbel_bookmark_set_href (xbel_item, - _midori_browser_get_tab_uri (browser, widget)); - katze_array_add_item (browser->proxy_xbel_array, xbel_item); - } - } - g_object_set_data (G_OBJECT (widget), "browser-tab-icon", tab_icon); - browser->tab_titles = g_list_prepend (browser->tab_titles, tab_title); - - g_signal_connect (tab_icon, "style-set", - G_CALLBACK (midori_browser_tab_icon_style_set), NULL); - g_signal_connect (widget, "leave-notify-event", + g_signal_connect (view, "leave-notify-event", G_CALLBACK (midori_browser_tab_leave_notify_event_cb), browser); - event_box = gtk_event_box_new (); - gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE); - hbox = gtk_hbox_new (FALSE, 1); - gtk_container_border_width (GTK_CONTAINER (hbox), 2); - gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (hbox)); - gtk_misc_set_alignment (GTK_MISC (tab_icon), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (hbox), tab_icon, FALSE, FALSE, 0); - gtk_misc_set_alignment (GTK_MISC (tab_title), 0.0, 0.5); - /* TODO: make the tab initially look "unvisited" until it's focused */ - gtk_box_pack_start (GTK_BOX (hbox), tab_title, FALSE, TRUE, 0); - _update_label_size (tab_title, - sokoke_object_get_int (browser->settings, "tab-label-size")); - - 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); - rcstyle = gtk_rc_style_new (); - rcstyle->xthickness = rcstyle->ythickness = 0; - gtk_widget_modify_style (close_button, rcstyle); - g_object_unref (rcstyle); - image = katze_throbber_new (); - katze_throbber_set_static_stock_id (KATZE_THROBBER (image), GTK_STOCK_CLOSE); - gtk_button_set_image (GTK_BUTTON (close_button), image); - gtk_misc_set_alignment (GTK_MISC (image), 0.0, 0.0); - gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0); - gtk_widget_show_all (GTK_WIDGET (event_box)); - if (!sokoke_object_get_boolean (browser->settings, "close-buttons-on-tabs")) - gtk_widget_hide (close_button); - browser->close_buttons = g_list_prepend (browser->close_buttons, close_button); - - g_signal_connect (event_box, "button-release-event", - G_CALLBACK (midori_browser_tab_label_button_release_event), widget); - g_signal_connect (close_button, "style-set", - G_CALLBACK (midori_browser_tab_icon_style_set), NULL); - g_signal_connect (close_button, "clicked", - G_CALLBACK (midori_browser_tab_close_clicked), widget); - if (sokoke_object_get_boolean (browser->settings, "open-tabs-next-to-current")) { n = gtk_notebook_get_current_page (GTK_NOTEBOOK (browser->notebook)); - gtk_notebook_insert_page (GTK_NOTEBOOK (browser->notebook), scrolled, - event_box, n + 1); + gtk_notebook_insert_page (GTK_NOTEBOOK (browser->notebook), view, + tab_label, n + 1); } else - gtk_notebook_append_page (GTK_NOTEBOOK (browser->notebook), scrolled, - event_box); + gtk_notebook_append_page (GTK_NOTEBOOK (browser->notebook), view, + tab_label); #if GTK_CHECK_VERSION(2, 10, 0) gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (browser->notebook), - scrolled, TRUE); + view, TRUE); gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (browser->notebook), - scrolled, TRUE); + view, TRUE); #endif gtk_widget_show (menuitem); g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_browser_window_menu_item_activate_cb), scrolled); + G_CALLBACK (midori_browser_window_menu_item_activate_cb), view); gtk_menu_shell_append (GTK_MENU_SHELL (browser->menu_window), menuitem); /* We want the tab to be removed if the widget is destroyed */ - g_signal_connect_swapped (widget, "destroy", + g_signal_connect_swapped (view, "destroy", G_CALLBACK (gtk_widget_destroy), menuitem); - g_signal_connect_swapped (widget, "destroy", - G_CALLBACK (gtk_widget_destroy), scrolled); - g_signal_connect (widget, "destroy", + g_signal_connect (view, "destroy", G_CALLBACK (midori_browser_tab_destroy_cb), browser); _midori_browser_update_actions (browser); @@ -1088,20 +763,9 @@ _midori_browser_add_tab (MidoriBrowser* browser, static void _midori_browser_remove_tab (MidoriBrowser* browser, - GtkWidget* widget) + GtkWidget* view) { - gtk_widget_destroy (widget); -} - -static void -_midori_browser_activate_action (MidoriBrowser* browser, - const gchar* name) -{ - GtkAction* action = _action_by_name (browser, name); - if (action) - gtk_action_activate (action); - else - g_warning (_("Unexpected action '%s'."), name); + gtk_widget_destroy (view); } static void @@ -1165,17 +829,6 @@ midori_browser_class_init (MidoriBrowserClass* class) G_TYPE_POINTER, G_TYPE_POINTER); - signals[ELEMENT_MOTION] = g_signal_new ( - "element-motion", - G_TYPE_FROM_CLASS (class), - (GSignalFlags)(G_SIGNAL_RUN_LAST), - G_STRUCT_OFFSET (MidoriBrowserClass, element_motion), - 0, - NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - signals[NEW_WINDOW] = g_signal_new ( "new-window", G_TYPE_FROM_CLASS (class), @@ -1415,9 +1068,9 @@ _action_open_activate (GtkAction* action, gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_OPEN); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (browser)); - /* base the start folder on the current web view's uri if it is local */ - GtkWidget* widget = midori_browser_get_current_tab (browser); - if ((uri = (gchar*)_midori_browser_get_tab_uri (browser, widget))) + /* base the start folder on the current view's uri if it is local */ + GtkWidget* view = midori_browser_get_current_tab (browser); + if ((uri = (gchar*)midori_view_get_display_uri (MIDORI_VIEW (view)))) { gchar* filename = g_filename_from_uri (uri, NULL, NULL); if (filename) @@ -1469,9 +1122,9 @@ static void _action_print_activate (GtkAction* action, MidoriBrowser* browser) { - GtkWidget* web_view = midori_browser_get_current_tab (browser); - if (web_view) - webkit_web_view_execute_script (WEBKIT_WEB_VIEW (web_view), "print ();"); + GtkWidget* view = midori_browser_get_current_tab (browser); + if (view) + midori_view_print (MIDORI_VIEW (view)); } static void @@ -1489,12 +1142,12 @@ _action_edit_activate (GtkAction* action, gboolean can_cut = FALSE, can_copy = FALSE, can_paste = FALSE; gboolean has_selection, can_select_all = FALSE; - if (WEBKIT_IS_WEB_VIEW (widget)) + if (MIDORI_IS_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); + MidoriView* view = MIDORI_VIEW (widget); + can_cut = midori_view_can_cut_clipboard (view); + can_copy = midori_view_can_copy_clipboard (view); + can_paste = midori_view_can_paste_clipboard (view); can_select_all = TRUE; } else if (GTK_IS_EDITABLE (widget)) @@ -1725,10 +1378,12 @@ static void midori_browser_menu_trash_item_activate_cb (GtkWidget* menuitem, MidoriBrowser* browser) { + KatzeItem* item; + gint n; + /* Create a new web view with an uri which has been closed before */ - KatzeXbelItem* item = g_object_get_data (G_OBJECT (menuitem), - "KatzeXbelItem"); - gint n = midori_browser_add_xbel_item (browser, item); + item = g_object_get_data (G_OBJECT (menuitem), "KatzeItem"); + n = midori_browser_add_item (browser, item); midori_browser_set_current_page (browser, n); katze_array_remove_item (browser->trash, item); _midori_browser_update_actions (browser); @@ -1740,7 +1395,7 @@ midori_browser_menu_trash_activate_cb (GtkWidget* widget, { GtkWidget* menu; guint i, n; - KatzeXbelItem* item; + KatzeItem* item; const gchar* title; const gchar* uri; GtkWidget* menuitem; @@ -1752,14 +1407,14 @@ midori_browser_menu_trash_activate_cb (GtkWidget* widget, for (i = 0; i < n; i++) { item = katze_array_get_nth_item (browser->trash, i); - title = katze_xbel_item_get_title (item); - uri = katze_xbel_bookmark_get_href (item); + title = katze_item_get_name (item); + uri = katze_item_get_uri (item); menuitem = sokoke_image_menu_item_new_ellipsized (title ? title : uri); /* FIXME: Get the real icon */ 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_object_set_data (G_OBJECT (menuitem), "KatzeItem", item); g_signal_connect (menuitem, "activate", G_CALLBACK (midori_browser_menu_trash_item_activate_cb), browser); gtk_widget_show (menuitem); @@ -1830,19 +1485,23 @@ _action_reload_stop_activate (GtkAction* action, MidoriBrowser* browser) { gchar* stock_id; + GtkWidget* view; + GdkModifierType state = (GdkModifierType)0; + gint x, y; + gboolean from_cache; + g_object_get (action, "stock-id", &stock_id, NULL); - GtkWidget* web_view = midori_browser_get_current_web_view (browser); + view = midori_browser_get_current_tab (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)); + from_cache = state & GDK_SHIFT_MASK; + midori_view_reload (MIDORI_VIEW (view), !from_cache); } else - webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view)); + midori_view_stop_loading (MIDORI_VIEW (view)); g_free (stock_id); } @@ -1850,139 +1509,50 @@ static void _action_zoom_in_activate (GtkAction* action, MidoriBrowser* browser) { - GtkWidget* web_view = midori_browser_get_current_web_view (browser); - if (web_view) - webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view)); + GtkWidget* view = midori_browser_get_current_tab (browser); + if (view) + midori_view_set_zoom_level (MIDORI_VIEW (view), + midori_view_get_zoom_level (MIDORI_VIEW (view)) + 0.25f); } static void _action_zoom_out_activate (GtkAction* action, MidoriBrowser* browser) { - GtkWidget* web_view = midori_browser_get_current_web_view (browser); - if (web_view) - webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view)); + GtkWidget* view = midori_browser_get_current_tab (browser); + if (view) + midori_view_set_zoom_level (MIDORI_VIEW (view), + midori_view_get_zoom_level (MIDORI_VIEW (view)) - 0.25f); } static void _action_zoom_normal_activate (GtkAction* action, MidoriBrowser* browser) { - GtkWidget* web_view = midori_browser_get_current_web_view (browser); - if (web_view) - webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), 1.0); + GtkWidget* view = midori_browser_get_current_tab (browser); + if (view) + midori_view_set_zoom_level (MIDORI_VIEW (view), 1.0f); } static void _action_source_view_activate (GtkAction* action, MidoriBrowser* browser) { - GtkWidget* web_view; - const gchar* uri; - #if HAVE_GIO - GFile* file; - gchar* tag; - #if HAVE_GTKSOURCEVIEW - GFileInfo* info; - const gchar* content_type; - #endif - #endif - gchar* contents; - gchar* contents_utf8; - #if HAVE_GTKSOURCEVIEW - GtkSourceBuffer* buffer; - #if HAVE_GIO - GtkSourceLanguageManager* language_manager; - GtkSourceLanguage* language; - #endif - #else - GtkTextBuffer* buffer; - #endif - GtkWidget* text_view; + GtkWidget* view; + GtkWidget* source_view; + gchar* uri; gint n; - if (!(web_view = midori_browser_get_current_web_view (browser))) + if (!(view = midori_browser_get_current_tab (browser))) return; - uri = midori_web_view_get_display_uri (MIDORI_WEB_VIEW (web_view)); - - contents = NULL; - - #if HAVE_GIO - file = g_file_new_for_uri (uri); - tag = NULL; - #if HAVE_GTKSOURCEVIEW - content_type = NULL; - #endif - if (g_file_load_contents (file, NULL, &contents, NULL, &tag, NULL)) - { - #if HAVE_GTKSOURCEVIEW - info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, - G_FILE_QUERY_INFO_NONE, NULL, NULL); - content_type = g_file_info_get_content_type (info); - #endif - g_object_unref (file); - } - if (contents && !g_utf8_validate (contents, -1, NULL)) - { - contents_utf8 = g_convert (contents, -1, "UTF-8", "ISO-8859-1", - NULL, NULL, NULL); - g_free (contents); - } - else - #endif - contents_utf8 = contents; - - #if HAVE_GTKSOURCEVIEW - buffer = gtk_source_buffer_new (NULL); - gtk_source_buffer_set_highlight_syntax (buffer, TRUE); - #if HAVE_GIO - if (content_type) - { - language_manager = gtk_source_language_manager_get_default (); - if (!strcmp (content_type, "text/html")) - { - language = gtk_source_language_manager_get_language ( - language_manager, "html"); - gtk_source_buffer_set_language (buffer, language); - } - else if (!strcmp (content_type, "text/css")) - { - language = gtk_source_language_manager_get_language ( - language_manager, "css"); - gtk_source_buffer_set_language (buffer, language); - } - else if (!strcmp (content_type, "text/javascript")) - { - language = gtk_source_language_manager_get_language ( - language_manager, "js"); - gtk_source_buffer_set_language (buffer, language); - } - } - #endif - #else - buffer = gtk_text_buffer_new (NULL); - #endif - if (contents_utf8) - gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), contents_utf8, -1); - #if HAVE_GTKSOURCEVIEW - text_view = gtk_source_view_new_with_buffer (buffer); - gtk_source_view_set_show_line_numbers (GTK_SOURCE_VIEW (text_view), TRUE); - #else - text_view = gtk_text_view_new_with_buffer (buffer); - #endif - gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE); - g_object_set_data (G_OBJECT (text_view), "browser-tab-uri", - g_strconcat ("view-source:", uri, NULL)); - gtk_widget_show (text_view); - n = midori_browser_add_tab (browser, text_view); + uri = g_strdup_printf ("view-source:%s", + midori_view_get_display_uri (MIDORI_VIEW (view))); + source_view = midori_view_new_with_uri (uri); + g_free (uri); + gtk_widget_show (source_view); + n = midori_browser_add_tab (browser, source_view); midori_browser_set_current_page (browser, n); - - g_object_unref (buffer); - g_free (contents_utf8); - #if HAVE_GIO - g_free (tag); - #endif } static void @@ -2000,16 +1570,18 @@ 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)); + GtkWidget* view = midori_browser_get_current_tab (browser); + if (view) + midori_view_go_back (MIDORI_VIEW (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)); + GtkWidget* view = midori_browser_get_current_tab (browser); + if (view) + midori_view_go_forward (MIDORI_VIEW (view)); } static void @@ -2060,8 +1632,7 @@ _action_location_reset_uri (GtkAction* action, { const gchar* uri; - uri = _midori_browser_get_tab_uri (browser, - midori_browser_get_current_tab (browser)); + uri = midori_browser_get_current_uri (browser); midori_location_action_set_uri (MIDORI_LOCATION_ACTION (action), uri); } @@ -2109,7 +1680,7 @@ _action_location_secondary_icon_released (GtkAction* action, GtkWidget* widget, MidoriBrowser* browser) { - MidoriWebView* web_view; + MidoriView* view; KatzeArray* news_feeds; GtkWidget* menu; guint n, i; @@ -2118,10 +1689,10 @@ _action_location_secondary_icon_released (GtkAction* action, const gchar* title; GtkWidget* menuitem; - web_view = (MidoriWebView*)midori_browser_get_current_web_view (browser); - if (web_view) + view = (MidoriView*)midori_browser_get_current_tab (browser); + if (view) { - news_feeds = midori_web_view_get_news_feeds (web_view); + news_feeds = NULL /* midori_view_get_news_feeds (view) */; n = news_feeds ? katze_array_get_length (news_feeds) : 0; if (n) { @@ -2565,15 +2136,19 @@ static void _action_open_in_panel_activate (GtkAction* action, MidoriBrowser* browser) { - GtkWidget* widget = midori_browser_get_current_tab (browser); - const gchar* uri = _midori_browser_get_tab_uri (browser, widget); + GtkWidget* view; + const gchar* uri; + gint n; + + view = midori_browser_get_current_tab (browser); + uri = midori_view_get_display_uri (MIDORI_VIEW (view)); /* FIXME: Don't assign the uri here, update it properly while navigating */ g_object_set (browser->settings, "last-pageholder-uri", uri, NULL); - gint n = midori_panel_page_num (MIDORI_PANEL (browser->panel), - browser->panel_pageholder); + n = midori_panel_page_num (MIDORI_PANEL (browser->panel), + browser->panel_pageholder); midori_panel_set_current_page (MIDORI_PANEL (browser->panel), n); gtk_widget_show (browser->panel); - g_object_set (browser->panel_pageholder, "uri", uri, NULL); + midori_view_set_uri (MIDORI_VIEW (browser->panel_pageholder), uri); } @@ -2600,18 +2175,18 @@ gtk_notebook_switch_page_cb (GtkWidget* notebook, guint page_num, MidoriBrowser* browser) { - GtkWidget* widget; + GtkWidget* view; const gchar* uri; GtkAction* action; const gchar* title; gchar* window_title; - widget = midori_browser_get_current_tab (browser); - uri = _midori_browser_get_tab_uri (browser, widget); + view = midori_browser_get_current_tab (browser); + uri = midori_view_get_display_uri (MIDORI_VIEW (view)); action = _action_by_name (browser, "Location"); midori_location_action_set_uri (MIDORI_LOCATION_ACTION (action), uri); - title = _midori_browser_get_tab_title (browser, widget); + title = midori_view_get_display_title (MIDORI_VIEW (view)); window_title = g_strconcat (title, " - ", g_get_application_name (), NULL); gtk_window_set_title (GTK_WINDOW (browser), window_title); @@ -2621,8 +2196,7 @@ gtk_notebook_switch_page_cb (GtkWidget* notebook, _midori_browser_set_statusbar_text (browser, NULL); _midori_browser_update_interface (browser); - if (MIDORI_IS_WEB_VIEW (widget)) - _midori_browser_update_progress (browser, MIDORI_WEB_VIEW (widget)); + _midori_browser_update_progress (browser, MIDORI_VIEW (view)); } static void @@ -2639,8 +2213,8 @@ _action_bookmark_open_activate (GtkAction* action, { 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); + _midori_browser_open_uri (browser, + katze_xbel_bookmark_get_href (item)); } } @@ -2711,13 +2285,13 @@ _action_undo_tab_close_activate (GtkAction* action, MidoriBrowser* browser) { guint last; - KatzeXbelItem* item; + KatzeItem* item; guint n; /* Reopen the most recent trash item */ last = katze_array_get_length (browser->trash) - 1; item = katze_array_get_nth_item (browser->trash, last); - n = midori_browser_add_xbel_item (browser, item); + n = midori_browser_add_item (browser, item); midori_browser_set_current_page (browser, n); katze_array_remove_item (browser->trash, item); _midori_browser_update_actions (browser); @@ -3474,7 +3048,7 @@ midori_browser_init (MidoriBrowser* browser) STOCK_BOOKMARKS, _("Bookmarks")); /* Transfers */ - GtkWidget* panel = midori_web_view_new (); + GtkWidget* panel = midori_view_new (); gtk_widget_show (panel); midori_panel_append_page (MIDORI_PANEL (browser->panel), panel, NULL, @@ -3490,16 +3064,14 @@ midori_browser_init (MidoriBrowser* browser) STOCK_CONSOLE, _("Console")); /* History */ - panel = midori_web_view_new (); + panel = midori_view_new (); gtk_widget_show (panel); midori_panel_append_page (MIDORI_PANEL (browser->panel), panel, NULL, STOCK_HISTORY, _("History")); /* Pageholder */ - browser->panel_pageholder = g_object_new (MIDORI_TYPE_WEB_VIEW, - "uri", "", - NULL); + browser->panel_pageholder = midori_view_new (); gtk_widget_show (browser->panel_pageholder); midori_panel_append_page (MIDORI_PANEL (browser->panel), browser->panel_pageholder, NULL, @@ -3531,7 +3103,7 @@ midori_browser_init (MidoriBrowser* browser) panel, toolbar, STOCK_EXTENSIONS, _("Extensions")); - /* Notebook, containing all web_views */ + /* Notebook, containing all views */ browser->notebook = gtk_notebook_new (); /* Remove the inner border between scrollbars and the window border */ rcstyle = gtk_rc_style_new (); @@ -3635,9 +3207,6 @@ midori_browser_init (MidoriBrowser* browser) _action_set_sensitive (browser, "ZoomIn", FALSE); _action_set_sensitive (browser, "ZoomOut", FALSE); #endif - - browser->tab_titles = NULL; - browser->close_buttons = NULL; } static void @@ -3646,8 +3215,8 @@ midori_browser_dispose (GObject* object) MidoriBrowser* browser = MIDORI_BROWSER (object); /* We are done, the session mustn't change anymore */ - if (browser->proxy_xbel_array) - katze_object_assign (browser->proxy_xbel_array, NULL); + if (browser->proxy_array) + katze_object_assign (browser->proxy_array, NULL); G_OBJECT_CLASS (midori_browser_parent_class)->dispose (object); } @@ -3658,8 +3227,6 @@ midori_browser_finalize (GObject* object) MidoriBrowser* browser = MIDORI_BROWSER (object); g_free (browser->statusbar_text); - g_list_free (browser->tab_titles); - g_list_free (browser->close_buttons); if (browser->settings) g_object_unref (browser->settings); @@ -3719,8 +3286,6 @@ _midori_browser_update_settings (MidoriBrowser* browser) gint tab_label_size; gboolean close_buttons_on_tabs; - guint i, n; - g_object_get (browser->settings, "remember-last-window-size", &remember_last_window_size, "last-window-width", &last_window_width, @@ -3770,7 +3335,8 @@ _midori_browser_update_settings (MidoriBrowser* browser) gtk_paned_set_position (GTK_PANED (gtk_widget_get_parent (browser->panel)), last_panel_position); midori_panel_set_current_page (MIDORI_PANEL (browser->panel), last_panel_page); - g_object_set (browser->panel_pageholder, "uri", last_pageholder_uri, NULL); + midori_view_set_uri (MIDORI_VIEW (browser->panel_pageholder), + last_pageholder_uri); _action_set_active (browser, "Navigationbar", show_navigationbar); _action_set_active (browser, "Bookmarkbar", show_bookmarkbar); @@ -3782,16 +3348,6 @@ _midori_browser_update_settings (MidoriBrowser* browser) sokoke_widget_set_visible (browser->search, show_web_search); sokoke_widget_set_visible (browser->button_trash, show_trash); - /* We assume that tab_titles has the same length as close_buttons */ - n = g_list_length (browser->tab_titles); - for (i = 0; i < n; i++) - { - _update_label_size (g_list_nth_data (browser->tab_titles, i), - tab_label_size); - sokoke_widget_set_visible (g_list_nth_data (browser->close_buttons, i), - close_buttons_on_tabs); - } - g_free (last_pageholder_uri); } @@ -3802,8 +3358,6 @@ midori_browser_settings_notify (MidoriWebSettings* web_settings, { const gchar* name; GValue value = {0, }; - guint i; - guint n; name = g_intern_string (pspec->name); g_value_init (&value, pspec->value_type); @@ -3823,20 +3377,6 @@ midori_browser_settings_notify (MidoriWebSettings* web_settings, else if (name == g_intern_string ("show-trash")) sokoke_widget_set_visible (browser->button_trash, g_value_get_boolean (&value)); - else if (name == g_intern_string ("tab-label-size")) - { - n = g_list_length (browser->tab_titles); - for (i = 0; i < n; i++) - _update_label_size (g_list_nth_data (browser->tab_titles, i), - g_value_get_int (&value)); - } - else if (name == g_intern_string ("close-buttons-on-tabs")) - { - n = g_list_length (browser->close_buttons); - for (i = 0; i < n; i++) - sokoke_widget_set_visible (g_list_nth_data (browser->close_buttons, i), - 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); @@ -3946,11 +3486,8 @@ midori_browser_set_property (GObject* object, _midori_browser_update_settings (browser); g_signal_connect (browser->settings, "notify", G_CALLBACK (midori_browser_settings_notify), browser); - /* FIXME: Assigning settings must be conditional, if web view or not */ - /* FIXME: Assign settings only if the same settings object was used */ gtk_container_foreach (GTK_CONTAINER (browser->notebook), - (GtkCallback) midori_web_view_set_settings, - browser->settings); + (GtkCallback) midori_view_set_settings, browser->settings); break; case PROP_BOOKMARKS: ; /* FIXME: Disconnect handlers */ @@ -4056,63 +3593,100 @@ midori_browser_new (void) /** * midori_browser_add_tab: * @browser: a #MidoriBrowser - * @widget: a tab + * @widget: a view * - * Appends an arbitrary widget in the form of a new tab and creates an + * Appends a view 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_add_tab (MidoriBrowser* browser, - GtkWidget* widget) + GtkWidget* view) { - GtkWidget* scrolled; - - g_signal_emit (browser, signals[ADD_TAB], 0, widget); - scrolled = _midori_browser_scrolled_for_child (browser, widget); - return gtk_notebook_page_num (GTK_NOTEBOOK (browser->notebook), scrolled); + g_signal_emit (browser, signals[ADD_TAB], 0, view); + return gtk_notebook_page_num (GTK_NOTEBOOK (browser->notebook), view); } /** * midori_browser_remove_tab: * @browser: a #MidoriBrowser - * @widget: a tab + * @widget: a view * - * Removes an existing tab from the browser, including an associated menu item. + * Removes an existing view from the browser, + * including an associated menu item. **/ void midori_browser_remove_tab (MidoriBrowser* browser, - GtkWidget* widget) + GtkWidget* view) { - g_signal_emit (browser, signals[REMOVE_TAB], 0, widget); + g_signal_emit (browser, signals[REMOVE_TAB], 0, view); } /** - * midori_browser_add_xbel_item: + * midori_browser_add_item: * @browser: a #MidoriBrowser - * @xbel_item: a bookmark + * @xbel_item: an XBEL item * - * Appends a #KatzeXbelItem in the form of a new tab. + * Appends a new view as described by @item. + * + * Note: Currently this will always be a #MidoriWebView. + * + * Return value: the index of the new view, or -1 in case of an error + **/ +gint +midori_browser_add_xbel_item (MidoriBrowser* browser, + KatzeXbelItem* item) +{ + const gchar* uri; + const gchar* title; + GtkWidget* view; + + g_return_val_if_fail (katze_xbel_item_is_bookmark (item), -1); + + uri = katze_xbel_bookmark_get_href (item); + title = katze_xbel_item_get_title (item); + view = g_object_new (MIDORI_TYPE_VIEW, + "title", title, + "settings", browser->settings, + NULL); + midori_view_set_uri (MIDORI_VIEW (view), uri); + gtk_widget_show (view); + + return midori_browser_add_tab (browser, view); +} + +/** + * midori_browser_add_item: + * @browser: a #MidoriBrowser + * @item: an item + * + * Appends a new view as described by @item. + * + * Note: Currently this will always be a #MidoriWebView. * * Return value: the index of the new tab, or -1 in case of an error **/ gint -midori_browser_add_xbel_item (MidoriBrowser* browser, - KatzeXbelItem* xbel_item) +midori_browser_add_item (MidoriBrowser* browser, + KatzeItem* item) { - g_return_val_if_fail (katze_xbel_item_is_bookmark (xbel_item), -1); + const gchar* uri; + const gchar* title; + GtkWidget* view; - 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", browser->settings, - NULL); - gtk_widget_show (web_view); + g_return_val_if_fail (KATZE_IS_ITEM (item), -1); - return midori_browser_add_tab (browser, web_view); + uri = katze_item_get_uri (item); + title = katze_item_get_name (item); + view = g_object_new (MIDORI_TYPE_VIEW, + "title", title, + "settings", browser->settings, + NULL); + midori_view_set_uri (MIDORI_VIEW (view), uri); + gtk_widget_show (view); + + return midori_browser_add_tab (browser, view); } /** @@ -4120,23 +3694,25 @@ midori_browser_add_xbel_item (MidoriBrowser* browser, * @browser: a #MidoriBrowser * @uri: an URI * - * Appends an uri in the form of a new tab. + * Appends an uri in the form of a new view. * - * Return value: the index of the new tab, or -1 + * Note: Currently this will always be a #MidoriView. + * + * Return value: the index of the new view, or -1 **/ gint midori_browser_add_uri (MidoriBrowser* browser, const gchar* uri) { - GtkWidget* web_view; + GtkWidget* view; - web_view = g_object_new (MIDORI_TYPE_WEB_VIEW, - "uri", uri, - "settings", browser->settings, - NULL); - gtk_widget_show (web_view); + view = g_object_new (MIDORI_TYPE_VIEW, + "settings", browser->settings, + NULL); + midori_view_set_uri (MIDORI_VIEW (view), uri); + gtk_widget_show (view); - return midori_browser_add_tab (browser, web_view); + return midori_browser_add_tab (browser, view); } /** @@ -4157,21 +3733,21 @@ midori_browser_activate_action (MidoriBrowser* browser, * midori_browser_get_current_uri: * @browser: a #MidoriBrowser * - * Determines the URI loaded in the current page. + * Determines the URI loaded in the current view. * - * If there is no page present at all, %NULL is returned. + * If there is no view present at all, %NULL is returned. * * Return value: the current URI, or %NULL **/ const gchar* midori_browser_get_current_uri (MidoriBrowser* browser) { - GtkWidget* widget; + GtkWidget* view; g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL); - widget = midori_browser_get_current_web_view (browser); - return _midori_browser_get_tab_uri (browser, widget); + view = midori_browser_get_current_tab (browser); + return midori_view_get_display_uri (MIDORI_VIEW (view)); } /** @@ -4187,13 +3763,14 @@ void midori_browser_set_current_page (MidoriBrowser* browser, gint n) { + GtkWidget* view; + gtk_notebook_set_current_page (GTK_NOTEBOOK (browser->notebook), n); - GtkWidget* scrolled = gtk_notebook_get_nth_page (GTK_NOTEBOOK (browser->notebook), n); - GtkWidget* widget = _midori_browser_child_for_scrolled (browser, scrolled); - if (widget && !strcmp (_midori_browser_get_tab_uri (browser, widget), "")) + view = gtk_notebook_get_nth_page (GTK_NOTEBOOK (browser->notebook), n); + if (view && midori_view_is_blank (MIDORI_VIEW (view))) gtk_action_activate (_action_by_name (browser, "Location")); else - gtk_widget_grab_focus (widget); + gtk_widget_grab_focus (view); } /** @@ -4217,23 +3794,27 @@ midori_browser_get_current_page (MidoriBrowser* browser) /** * midori_browser_set_current_tab: * @browser: a #MidoriBrowser - * @widget: a #GtkWidget + * @view: a #GtkWidget * - * Switches to the page containing @widget. + * Switches to the page containing @view. * * The widget will also grab the focus automatically. **/ void midori_browser_set_current_tab (MidoriBrowser* browser, - GtkWidget* widget) + GtkWidget* view) { - GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, widget); - gint n = gtk_notebook_page_num (GTK_NOTEBOOK (browser->notebook), scrolled); + gint n; + + g_return_if_fail (MIDORI_IS_BROWSER (browser)); + g_return_if_fail (GTK_IS_WIDGET (view)); + + n = gtk_notebook_page_num (GTK_NOTEBOOK (browser->notebook), view); gtk_notebook_set_current_page (GTK_NOTEBOOK (browser->notebook), n); - if (widget && !strcmp (_midori_browser_get_tab_uri (browser, widget), "")) + if (view && midori_view_is_blank (MIDORI_VIEW (view))) gtk_action_activate (_action_by_name (browser, "Location")); else - gtk_widget_grab_focus (widget); + gtk_widget_grab_focus (view); } /** @@ -4244,57 +3825,37 @@ midori_browser_set_current_tab (MidoriBrowser* browser, * * If there is no tab present at all, %NULL is returned. * + * See also midori_browser_get_current_page(). + * * Return value: the selected tab, or %NULL **/ GtkWidget* midori_browser_get_current_tab (MidoriBrowser* browser) { + gint n; + g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL); - gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (browser->notebook)); + n = gtk_notebook_get_current_page (GTK_NOTEBOOK (browser->notebook)); if (n >= 0) { - GtkWidget* widget = _midori_browser_child_for_scrolled (browser, - gtk_notebook_get_nth_page (GTK_NOTEBOOK (browser->notebook), n)); - return widget; + return gtk_notebook_get_nth_page (GTK_NOTEBOOK (browser->notebook), n); } else return NULL; } /** - * midori_browser_get_current_web_view: + * midori_browser_get_proxy_array: * @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_tab (browser); - return MIDORI_IS_WEB_VIEW (web_view) ? web_view : NULL; -} - -/** - * midori_browser_get_proxy_xbel_array: - * @browser: a #MidoriBrowser - * - * Retrieves a proxy xbel array representing the respective proxy xbel items - * of the present web views that can be used for session management. + * Retrieves a proxy array representing the respective proxy items + * of the present 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. + * Note that this implicitly creates proxy items of all views. * * Note: Calling this function doesn't add a reference and the browser * may release its reference at some point. @@ -4302,16 +3863,16 @@ midori_browser_get_current_web_view (MidoriBrowser* browser) * Return value: the proxy #KatzeArray **/ KatzeArray* -midori_browser_get_proxy_xbel_array (MidoriBrowser* browser) +midori_browser_get_proxy_array (MidoriBrowser* browser) { g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL); - if (!browser->proxy_xbel_array) + if (!browser->proxy_array) { - browser->proxy_xbel_array = katze_array_new (KATZE_TYPE_XBEL_ITEM); - /* FIXME: Fill in xbel items of all present web views */ + browser->proxy_array = katze_array_new (KATZE_TYPE_ITEM); + /* FIXME: Fill in items of all present views */ } - return browser->proxy_xbel_array; + return browser->proxy_array; } /** diff --git a/midori/midori-browser.h b/midori/midori-browser.h index 42bff3f5..1a79087f 100644 --- a/midori/midori-browser.h +++ b/midori/midori-browser.h @@ -56,10 +56,10 @@ struct _MidoriBrowserClass void (*add_tab) (MidoriBrowser* browser, - GtkWidget* widget); + GtkWidget* view); void (*remove_tab) (MidoriBrowser* browser, - GtkWidget* widget); + GtkWidget* view); void (*activate_action) (MidoriBrowser* browser, const gchar* name); @@ -85,6 +85,10 @@ gint midori_browser_add_xbel_item (MidoriBrowser* browser, KatzeXbelItem* xbel_item); +gint +midori_browser_add_item (MidoriBrowser* browser, + KatzeItem* item); + gint midori_browser_add_uri (MidoriBrowser* browser, const gchar* uri); @@ -110,11 +114,8 @@ midori_browser_set_current_tab (MidoriBrowser* browser, GtkWidget* midori_browser_get_current_tab (MidoriBrowser* browser); -GtkWidget* -midori_browser_get_current_web_view (MidoriBrowser* browser); - KatzeArray* -midori_browser_get_proxy_xbel_array (MidoriBrowser* browser); +midori_browser_get_proxy_array (MidoriBrowser* browser); void midori_browser_quit (MidoriBrowser* browser); diff --git a/midori/midori-panel.c b/midori/midori-panel.c index 2e71895d..10e51b6b 100644 --- a/midori/midori-panel.c +++ b/midori/midori-panel.c @@ -373,6 +373,10 @@ midori_panel_append_page (MidoriPanel* panel, g_return_val_if_fail (stock_id != NULL, -1); g_return_val_if_fail (label != NULL, -1); + if (GTK_IS_SCROLLED_WINDOW (child)) + scrolled = child; + else + { scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, @@ -389,6 +393,7 @@ midori_panel_append_page (MidoriPanel* panel, gtk_container_add (GTK_CONTAINER (widget), child); } gtk_container_add (GTK_CONTAINER (scrolled), widget); + } gtk_container_add (GTK_CONTAINER (panel->notebook), scrolled); if (!toolbar) diff --git a/midori/midori-source.c b/midori/midori-source.c new file mode 100644 index 00000000..ce3131bb --- /dev/null +++ b/midori/midori-source.c @@ -0,0 +1,191 @@ +/* + 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. +*/ + +#if HAVE_CONFIG_H + #include +#endif + +#include "midori-source.h" + +#include +#if HAVE_GIO + #include +#endif +#include +#if HAVE_GTKSOURCEVIEW + #include + #include + + #define MidoriSourceView GtkSourceView + #define MidoriSourceViewClass GtkSourceViewClass + #define MIDORI_TYPE_SOURCE_VIEW GTK_TYPE_SOURCE_VIEW +#else + #define MidoriSourceView GtkTextView + #define MidoriSourceViewClass GtkTextViewClass + #define MIDORI_TYPE_SOURCE_VIEW GTK_TYPE_TEXT_VIEW +#endif + +struct _MidoriSource +{ + MidoriSourceView parent_instance; +}; + +struct _MidoriSourceClass +{ + MidoriSourceViewClass parent_class; +}; + +G_DEFINE_TYPE (MidoriSource, midori_source, MIDORI_TYPE_SOURCE_VIEW); + +static void +midori_source_finalize (GObject* object); + +static void +midori_source_class_init (MidoriSourceClass* class) +{ + GObjectClass* gobject_class; + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = midori_source_finalize; +} + +static void +midori_source_init (MidoriSource* source) +{ + #if HAVE_GTKSOURCEVIEW + GtkSourceBuffer* buffer; + #else + GtkTextBuffer* buffer; + #endif + + #if HAVE_GTKSOURCEVIEW + buffer = gtk_source_buffer_new (NULL); + gtk_source_buffer_set_highlight_syntax (buffer, TRUE); + gtk_source_view_set_show_line_numbers (GTK_SOURCE_VIEW (source), TRUE); + #else + buffer = gtk_text_buffer_new (NULL); + #endif + gtk_text_view_set_buffer (GTK_TEXT_VIEW (source), GTK_TEXT_BUFFER (buffer)); + gtk_text_view_set_editable (GTK_TEXT_VIEW (source), FALSE); +} + +static void +midori_source_finalize (GObject* object) +{ + G_OBJECT_CLASS (midori_source_parent_class)->finalize (object); +} + +/** + * midori_source_new: + * @uri: a view-source: URI + * + * Creates a new source widget. + * + * Return value: a new #MidoriSource + **/ +GtkWidget* +midori_source_new (const gchar* uri) +{ + MidoriSource* source = g_object_new (MIDORI_TYPE_SOURCE, + /*"uri", uri,*/ + NULL); + midori_source_set_uri (source, uri); + + return GTK_WIDGET (source); +} + +void +midori_source_set_uri (MidoriSource* source, + const gchar* uri) +{ + #if HAVE_GIO + GFile* file; + gchar* tag; + #if HAVE_GTKSOURCEVIEW + GFileInfo* info; + const gchar* content_type; + #endif + #endif + gchar* contents; + gchar* contents_utf8; + GtkTextBuffer* buffer; + #if HAVE_GTKSOURCEVIEW + #if HAVE_GIO + GtkSourceLanguageManager* language_manager; + GtkSourceLanguage* language; + #endif + #endif + + g_return_if_fail (MIDORI_IS_SOURCE (source)); + + contents = NULL; + + #if HAVE_GIO + file = g_file_new_for_uri (uri); + tag = NULL; + #if HAVE_GTKSOURCEVIEW + content_type = NULL; + #endif + if (g_file_load_contents (file, NULL, &contents, NULL, &tag, NULL)) + { + #if HAVE_GTKSOURCEVIEW + info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + G_FILE_QUERY_INFO_NONE, NULL, NULL); + content_type = g_file_info_get_content_type (info); + #endif + g_object_unref (file); + } + if (contents && !g_utf8_validate (contents, -1, NULL)) + { + contents_utf8 = g_convert (contents, -1, "UTF-8", "ISO-8859-1", + NULL, NULL, NULL); + g_free (contents); + } + else + #endif + contents_utf8 = contents; + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source)); + #if HAVE_GTKSOURCEVIEW + #if HAVE_GIO + if (content_type) + { + language_manager = gtk_source_language_manager_get_default (); + if (!strcmp (content_type, "text/html")) + { + language = gtk_source_language_manager_get_language ( + language_manager, "html"); + gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), language); + } + else if (!strcmp (content_type, "text/css")) + { + language = gtk_source_language_manager_get_language ( + language_manager, "css"); + gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), language); + } + else if (!strcmp (content_type, "text/javascript")) + { + language = gtk_source_language_manager_get_language ( + language_manager, "js"); + gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), language); + } + } + #endif + #endif + if (contents_utf8) + gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), contents_utf8, -1); + + g_object_unref (buffer); + g_free (contents_utf8); + #if HAVE_GIO + g_free (tag); + #endif +} diff --git a/midori/midori-source.h b/midori/midori-source.h new file mode 100644 index 00000000..e7b18783 --- /dev/null +++ b/midori/midori-source.h @@ -0,0 +1,47 @@ +/* + 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_SOURCE_H__ +#define __MIDORI_SOURCE_H__ + +#include + +G_BEGIN_DECLS + +#define MIDORI_TYPE_SOURCE \ + (midori_source_get_type ()) +#define MIDORI_SOURCE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_SOURCE, MidoriSource)) +#define MIDORI_SOURCE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_SOURCE, MidoriSourceClass)) +#define MIDORI_IS_SOURCE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_SOURCE)) +#define MIDORI_IS_SOURCE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_SOURCE)) +#define MIDORI_SOURCE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_SOURCE, MidoriSourceClass)) + +typedef struct _MidoriSource MidoriSource; +typedef struct _MidoriSourceClass MidoriSourceClass; + +GType +midori_source_get_type (void); + +GtkWidget* +midori_source_new (const gchar* uri); + +void +midori_source_set_uri (MidoriSource* source, + const gchar* uri); + +G_END_DECLS + +#endif /* __MIDORI_SOURCE_H__ */ diff --git a/midori/midori-view.c b/midori/midori-view.c new file mode 100644 index 00000000..14986c9b --- /dev/null +++ b/midori/midori-view.c @@ -0,0 +1,2451 @@ +/* + 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. +*/ + +#if HAVE_CONFIG_H + #include +#endif + +#include "midori-view.h" +#include "midori-source.h" + +#include "midori-stock.h" + +#include "compat.h" +#include "sokoke.h" +#include "gjs.h" + +#include +#include +#if HAVE_GIO + #include +#endif +#include +#include + +/* This is unstable API, so we need to declare it */ +gchar* +webkit_web_view_get_selected_text (WebKitWebView* web_view); + +struct _MidoriView +{ + GtkScrolledWindow parent_instance; + + gint socket_id; + GIOChannel* input; + FILE* output; + + gchar* command_cache; + gchar* premature_uri; + gchar* uri; + gchar* title; + GdkPixbuf* icon; + gdouble progress; + MidoriLoadStatus load_status; + gchar* statusbar_text; + gchar* link_uri; + gboolean has_selection; + gchar* selected_text; + gboolean can_cut_clipboard; + gboolean can_copy_clipboard; + gboolean can_paste_clipboard; + gfloat zoom_level; + MidoriWebSettings* settings; + GtkWidget* web_view; + gboolean window_object_cleared; + + gchar* download_manager; + gint tab_label_size; + gboolean close_buttons_on_tabs; + + GtkWidget* menu_item; + GtkWidget* tab_label; + GtkWidget* tab_icon; + GtkWidget* tab_title; + GtkWidget* tab_close; + KatzeItem* item; +}; + +struct _MidoriViewClass +{ + GtkScrolledWindowClass parent_class; +}; + +G_DEFINE_TYPE (MidoriView, midori_view, GTK_TYPE_SCROLLED_WINDOW) + +GType +midori_load_status_get_type (void) +{ + static GType type = 0; + if (!type) + { + static const GEnumValue values[] = { + { MIDORI_LOAD_PROVISIONAL, "MIDORI_LOAD_PROVISIONAL", N_("Load Provisional") }, + { MIDORI_LOAD_COMMITTED, "MIDORI_LOAD_COMMITTED", N_("Load Committed") }, + { MIDORI_LOAD_FINISHED, "MIDORI_LOAD_FINISHED", N_("Load Finished") }, + { 0, NULL, NULL } + }; + type = g_enum_register_static ("MidoriLoadStatus", values); + } + return type; +} + +enum +{ + PROP_0, + + PROP_SOCKET_ID, + PROP_URI, + PROP_TITLE, + PROP_ICON, + PROP_LOAD_STATUS, + PROP_PROGRESS, + PROP_ZOOM_LEVEL, + PROP_STATUSBAR_TEXT, + PROP_SETTINGS +}; + +enum { + ACTIVATE_ACTION, + CONSOLE_MESSAGE, + NEW_TAB, + NEW_WINDOW, + ADD_BOOKMARK, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void +midori_view_finalize (GObject* object); + +static void +midori_view_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec); + +static void +midori_view_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec); + +static void +midori_cclosure_marshal_VOID__STRING_INT_STRING (GClosure* closure, + GValue* return_value, + guint n_param_values, + const GValue* param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void(*GMarshalFunc_VOID__STRING_INT_STRING) (gpointer data1, + gpointer arg_1, + gint arg_2, + gpointer arg_3, + gpointer data2); + register GMarshalFunc_VOID__STRING_INT_STRING callback; + register GCClosure* cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 4); + + 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_VOID__STRING_INT_STRING) (marshal_data + ? marshal_data : cc->callback); + callback (data1, + (gchar*)g_value_get_string (param_values + 1), + g_value_get_int (param_values + 2), + (gchar*)g_value_get_string (param_values + 3), + data2); +} + +static void +midori_view_class_init (MidoriViewClass* class) +{ + GObjectClass* gobject_class; + GParamFlags flags; + + signals[ACTIVATE_ACTION] = g_signal_new ( + "activate-action", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + 0, + 0, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + signals[CONSOLE_MESSAGE] = g_signal_new ( + "console-message", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + 0, + 0, + NULL, + midori_cclosure_marshal_VOID__STRING_INT_STRING, + G_TYPE_NONE, 3, + G_TYPE_STRING, + G_TYPE_INT, + G_TYPE_STRING); + + signals[NEW_TAB] = g_signal_new ( + "new-tab", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + 0, + 0, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + signals[NEW_WINDOW] = g_signal_new ( + "new-window", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + 0, + 0, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + signals[ADD_BOOKMARK] = g_signal_new ( + "add-bookmark", + G_TYPE_FROM_CLASS (class), + (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), + 0, + 0, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = midori_view_finalize; + gobject_class->set_property = midori_view_set_property; + gobject_class->get_property = midori_view_get_property; + + flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT; + + g_object_class_install_property (gobject_class, + PROP_SOCKET_ID, + g_param_spec_uint ( + "socket-id", + _("Socket ID"), + _("The ID of a socket"), + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (gobject_class, + PROP_URI, + g_param_spec_string ( + "uri", + _("Uri"), + _("The URI of the currently loaded page"), + "about:blank", + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_TITLE, + g_param_spec_string ( + "title", + _("Title"), + _("The title of the currently loaded page"), + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_ICON, + g_param_spec_object ( + "icon", + _("Icon"), + _("The icon of the view"), + GDK_TYPE_PIXBUF, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_LOAD_STATUS, + g_param_spec_enum ( + "load-status", + _("Load Status"), + _("The current loading status"), + MIDORI_TYPE_LOAD_STATUS, + MIDORI_LOAD_FINISHED, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_PROGRESS, + g_param_spec_double ( + "progress", + _("Progress"), + _("The current loading progress"), + 0.0, 1.0, 0.0, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_ZOOM_LEVEL, + g_param_spec_float ( + "zoom-level", + _("Zoom Level"), + _("The current zoom level"), + G_MINFLOAT, + G_MAXFLOAT, + 1.0f, + G_PARAM_READWRITE)); + + 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"), + "", + G_PARAM_READWRITE)); + + 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)); +} + +#define midori_view_is_socket(view) !view->socket_id +#define midori_view_is_plug(view) view->socket_id > 0 + +#if 0 + #define midori_debug g_debug +#else + #define midori_debug(...) ; +#endif + +/** + * int_to_str + * @in: an integer + * + * Converts an integer to a string. + * + * The returned string is valid until + * the next call to this function. + * + * Return value: a string + **/ +static const gchar* +int_to_str (gint in) +{ + static gchar* out = NULL; + g_free (out); + out = g_strdup_printf ("%d", in); + return out; +} + +/** + * float_to_str + * @in: a float + * + * Converts a float to a string. + * + * The returned string is valid until + * the next call to this function. + * + * Return value: a string + **/ +static const gchar* +float_to_str (gfloat in) +{ + static gchar* out = NULL; + g_free (out); + out = g_strdup_printf ("%f", in); + return out; +} + + +static void +send_command (MidoriView* view, + const gchar* command, + const gchar* argument) +{ + gchar* data; + gchar* cache; + + if (argument) + data = g_strdup_printf ("%s %s", command, argument); + else + data = g_strdup (command); + + if (!view->output) + { + /* The output is not ready, so we cache for now */ + cache = g_strdup_printf ("%s\n%s", + view->command_cache ? view->command_cache : "", data); + katze_assign (view->command_cache, cache); + midori_debug ("!view->output, caching command: %s", command); + return; + } + + fwrite (data, strlen (data) + 1, 1, view->output); + fflush (view->output); + + g_free (data); +} + +static void +midori_view_notify_uri_cb (MidoriView* view, + GParamSpec pspec) +{ + if (midori_view_is_socket (view) && view->item) + katze_item_set_uri (view->item, view->uri); + + if (midori_view_is_plug (view)) + /* We must not send a NULL string here */ + send_command (view, "uri", view->uri ? view->uri : ""); +} + +static void +midori_view_notify_icon_cb (MidoriView* view, + GParamSpec pspec) +{ + if (view->tab_icon) + katze_throbber_set_static_pixbuf (KATZE_THROBBER (view->tab_icon), + view->icon); + if (view->menu_item) + gtk_image_menu_item_set_image ( + GTK_IMAGE_MENU_ITEM (view->menu_item), + gtk_image_new_from_pixbuf (view->icon)); +} + +#if HAVE_GIO +void +loadable_icon_finish_cb (GdkPixbuf* icon, + GAsyncResult* res, + MidoriView* view) +{ + GdkPixbuf* pixbuf; + GInputStream* stream; + GError* error; + GdkPixbuf* pixbuf_scaled; + gint icon_width, icon_height; + + pixbuf = NULL; + stream = g_loadable_icon_load_finish (G_LOADABLE_ICON (icon), + res, NULL, NULL); + if (stream) + { + error = NULL; + pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, &error); + if (error) + midori_debug ("Icon couldn't be loaded: %s", error->message); + g_object_unref (stream); + } + if (!pixbuf) + pixbuf = gtk_widget_render_icon (GTK_WIDGET (view), + GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); + + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height); + pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height, + GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); + katze_object_assign (view->icon, pixbuf_scaled); + g_object_notify (G_OBJECT (view), "icon"); +} + +void +file_info_finish_cb (GFile* icon_file, + GAsyncResult* res, + MidoriView* view) +{ + GFileInfo* info; + const gchar* content_type; + GIcon* icon; + GFile* parent; + GFile* file; + GdkPixbuf* pixbuf; + gint icon_width, icon_height; + GdkPixbuf* pixbuf_scaled; + + info = g_file_query_info_finish (G_FILE (icon_file), res, NULL); + if (info) + { + content_type = g_file_info_get_content_type (info); + if (g_str_has_prefix (content_type, "image/")) + { + icon = g_file_icon_new (icon_file); + g_loadable_icon_load_async (G_LOADABLE_ICON (icon), + 0, NULL, (GAsyncReadyCallback)loadable_icon_finish_cb, view); + return; + } + } + + file = g_file_get_parent (icon_file); + parent = g_file_get_parent (file); + /* We need to check if file equals the parent due to a GIO bug */ + if (parent && !g_file_equal (file, parent)) + { + icon_file = g_file_get_child (parent, "favicon.ico"); + g_file_query_info_async (icon_file, + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + G_FILE_QUERY_INFO_NONE, 0, NULL, + (GAsyncReadyCallback)file_info_finish_cb, view); + return; + } + + pixbuf = gtk_widget_render_icon (GTK_WIDGET (view), + GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height); + pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height, + GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); + + view->icon = pixbuf_scaled; + g_object_notify (G_OBJECT (view), "icon"); +} +#endif + +static void +_midori_web_view_load_icon (MidoriView* view) +{ + #if HAVE_GIO + GFile* file; + GFile* icon_file; + #endif + GdkPixbuf* pixbuf; + gint icon_width, icon_height; + GdkPixbuf* pixbuf_scaled; + + #if HAVE_GIO + if (view->uri) + { + file = g_file_new_for_uri (view->uri); + icon_file = g_file_get_child (file, "favicon.ico"); + g_file_query_info_async (icon_file, + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + G_FILE_QUERY_INFO_NONE, 0, NULL, + (GAsyncReadyCallback)file_info_finish_cb, view); + return; + } + #endif + + pixbuf = gtk_widget_render_icon (GTK_WIDGET (view), + GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height); + pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height, + GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); + + view->icon = pixbuf_scaled; + g_object_notify (G_OBJECT (view), "icon"); +} + +static void +midori_view_notify_load_status_cb (MidoriView* view, + GParamSpec pspec) +{ + g_object_get (G_OBJECT (view), "load-status", &view->load_status, NULL); + + if (midori_view_is_socket (view)) + { + if (view->tab_icon) + katze_throbber_set_animated (KATZE_THROBBER (view->tab_icon), + view->load_status != MIDORI_LOAD_FINISHED); + } + + if (midori_view_is_plug (view)) + send_command (view, "load-status", int_to_str (view->load_status)); + + if (!midori_view_is_plug (view)) + if (view->load_status == MIDORI_LOAD_COMMITTED) + _midori_web_view_load_icon (view); +} + +static void +midori_view_notify_progress_cb (MidoriView* view, + GParamSpec pspec) +{ + g_object_get (G_OBJECT (view), "progress", &view->progress, NULL); + + if (midori_view_is_plug (view)) + send_command (view, "progress", float_to_str (view->progress)); +} + +static void +midori_view_action_cb (MidoriView* view, + const gchar* action) +{ + if (midori_view_is_socket (view)) + return; + + send_command (view, "activate-action", action); +} + +static void +midori_view_console_message_cb (MidoriView* view, + const gchar* message, + gint line, + const gchar* source_id) +{ + gchar* argument; + + if (midori_view_is_socket (view)) + return; + + argument = g_strdup_printf ("%s %d %s", message, line, source_id); + send_command (view, "console-message", argument); + g_free (argument); +} + +static void +midori_view_new_tab_cb (MidoriView* view, + const gchar* uri) +{ + if (midori_view_is_socket (view)) + return; + + send_command (view, "new-tab", uri); +} + +static void +midori_view_new_window_cb (MidoriView* view, + const gchar* uri) +{ + if (midori_view_is_socket (view)) + return; + + send_command (view, "new-window", uri); +} + +static void +midori_view_add_bookmark_cb (MidoriView* view, + const gchar* uri) +{ + if (midori_view_is_socket (view)) + return; + + send_command (view, "add-bookmark", uri); +} + +static void +receive_status (MidoriView* view, + const gchar* command) +{ + if (!strncmp (command, "uri ", 4)) + { + katze_assign (view->uri, g_strdup (&command[4])); + g_object_notify (G_OBJECT (view), "uri"); + } + else if (!strncmp (command, "title ", 6)) + { + g_object_set (view, "title", &command[6], NULL); + } + else if (!strncmp (command, "load-status ", 12)) + { + view->load_status = (MidoriLoadStatus)atoi (&command[12]); + g_object_notify (G_OBJECT (view), "load-status"); + } + else if (!strncmp (command, "progress ", 9)) + { + view->progress = atof (&command[9]); + g_object_notify (G_OBJECT (view), "progress"); + } + else if (!strncmp (command, "zoom-level ", 11)) + { + view->zoom_level = atof (&command[11]); + g_object_notify (G_OBJECT (view), "zoom-level"); + } + else if (!strncmp (command, "statusbar-text ", 15)) + { + g_object_set (view, "statusbar-text", &command[15], NULL); + } + else if (!strncmp (command, "activate-action ", 16)) + { + g_signal_emit (view, signals[ACTIVATE_ACTION], 0, &command[16]); + } + else if (!strncmp (command, "console-message ", 16)) + { + /* FIXME: Implement */ + } + else if (!strncmp (command, "new-tab ", 8)) + { + g_signal_emit (view, signals[NEW_TAB], 0, &command[8]); + } + else if (!strncmp (command, "new-window ", 11)) + { + g_signal_emit (view, signals[NEW_WINDOW], 0, &command[11]); + } + else if (!strncmp (command, "add-bookmark ", 13)) + { + g_signal_emit (view, signals[ADD_BOOKMARK], 0, &command[13]); + } + else if (!strncmp (command, "clipboard ", 10)) + { + view->can_cut_clipboard = atof (&command[10]); + view->can_copy_clipboard = atof (&command[12]); + view->can_paste_clipboard = atof (&command[14]); + midori_debug ("clipboards: %s => %d, %d, %d", + &command[10], + atoi (&command[10]), atoi (&command[12]), atoi (&command[14])); + } + else if (g_str_has_prefix (command, "**")) + { + g_print ("%s\n", command); + } + else + { + midori_debug ("receive_status: unknown command '%s'", command); + } +} + +static void +receive_command (MidoriView* view, + const gchar* command) +{ + if (!strncmp (command, "set-uri ", 8)) + midori_view_set_uri (view, &command[8]); + else if (!strncmp (command, "set-zoom-level ", 15)) + midori_view_set_zoom_level (view, atof (&command[15]) / 10); + else if (!strncmp (command, "reload ", 7)) + midori_view_reload (view, atoi (&command[7])); + else if (!strncmp (command, "stop-loading", 12)) + midori_view_stop_loading (view); + else if (!strncmp (command, "go-back", 7)) + midori_view_go_back (view); + else if (!strncmp (command, "go-forward", 10)) + midori_view_go_forward (view); + else if (!strncmp (command, "print", 5)) + midori_view_print (view); + else if (!strncmp (command, "download-manager ", 17)) + { + katze_assign (view->download_manager, g_strdup (&command[17])); + } + else if (g_str_has_prefix (command, "**")) + g_print ("%s\n", command); + else + midori_debug ("receive_command: unknown command '%s'", command); +} + +static gboolean +io_input_watch_cb (GIOChannel* source, + GIOCondition condition, + MidoriView* view) +{ + gchar* buffer; + GError* error; + + error = NULL; + switch (condition) + { + case G_IO_PRI: + case G_IO_IN: + if (g_io_channel_read_line (source, + &buffer, NULL, NULL, &error) == G_IO_STATUS_NORMAL) + { + if (view->socket_id) + receive_command (view, buffer); + else + receive_status (view, buffer); + g_free (buffer); + } + else + { + g_warning ("Communication error: %s", error->message); + g_error_free (error); + } + break; + case G_IO_ERR: + case G_IO_NVAL: + g_warning ("Invalid operation"); + return FALSE; + case G_IO_HUP: + midori_debug ("Tab closed"); + return FALSE; + default: + g_warning ("Unexpected condition"); + return FALSE; + } + + return TRUE; +} + +static void +webkit_web_view_load_started_cb (WebKitWebView* web_view, + WebKitWebFrame* web_frame, + MidoriView* view) +{ + view->window_object_cleared = FALSE; + + view->load_status = MIDORI_LOAD_PROVISIONAL; + g_object_notify (G_OBJECT (view), "load-status"); + + view->progress = 0.0; + g_object_notify (G_OBJECT (view), "progress"); +} + +static void +webkit_web_view_window_object_cleared_cb (WebKitWebView* web_view, + WebKitWebFrame* web_frame, + JSGlobalContextRef js_context, + JSObjectRef js_window, + MidoriView* view) +{ + view->window_object_cleared = TRUE; +} + +static void +webkit_web_view_load_committed_cb (WebKitWebView* web_view, + WebKitWebFrame* web_frame, + MidoriView* view) +{ + const gchar* uri; + GdkPixbuf* icon; + + uri = webkit_web_frame_get_uri (web_frame); + katze_assign (view->uri, g_strdup (uri)); + g_object_notify (G_OBJECT (view), "uri"); + g_object_set (view, "title", NULL, NULL); + + icon = gtk_widget_render_icon (GTK_WIDGET (view), + GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); + katze_object_assign (view->icon, icon); + g_object_notify (G_OBJECT (view), "icon"); + + view->load_status = MIDORI_LOAD_COMMITTED; + g_object_notify (G_OBJECT (view), "load-status"); +} + +static void +webkit_web_view_progress_changed_cb (WebKitWebView* web_view, + gint progress, + MidoriView* view) +{ + view->progress = progress ? progress / 100.0 : 0.0; + g_object_notify (G_OBJECT (view), "progress"); +} + +/* +static void +gjs_value_links_foreach_cb (GjsValue* link, + MidoriView* view) +{ + const gchar* type; +#if HAVE_GIO + const gchar* rel; + GFile* icon_file; + GIcon* icon; +#endif + + if (gjs_value_is_object (link) && gjs_value_has_attribute (link, "href")) + { + if (gjs_value_has_attribute (link, "type")) + { + type = gjs_value_get_attribute_string (link, "type"); + if (!strcmp (type, "application/rss+xml") + || !strcmp (type, "application/x.atom+xml") + || !strcmp (type, "application/atom+xml")) + { + katze_array_add_item (view->news_feeds, link); + g_signal_emit_by_name (view, "news-feed-ready", + gjs_value_get_attribute_string (link, "href"), type, + gjs_value_has_attribute (link, "title") + ? gjs_value_get_attribute_string (link, "title") : NULL); + } + } +#if HAVE_GIO + if (gjs_value_has_attribute (link, "rel")) + { + rel = gjs_value_get_attribute_string (link, "rel"); + if (!strcmp (rel, "icon") || !strcmp (rel, "shortcut icon")) + { + icon_file = g_file_new_for_uri ( + gjs_value_get_attribute_string (link, "href")); + icon = g_file_icon_new (icon_file); + g_loadable_icon_load_async (G_LOADABLE_ICON (icon), + 0, NULL, (GAsyncReadyCallback)loadable_icon_finish_cb, view); + } + } +#endif + } +} +*/ + +static void +webkit_web_frame_load_done_cb (WebKitWebFrame* web_frame, + gboolean success, + MidoriView* view) +{ + gchar* data; + JSContextRef js_context; + JSValueRef js_window; + /* GjsValue* value; + GjsValue* document; + GjsValue* links; */ + + if (!success) + { + midori_debug ("'%s' not found.", view->uri); + data = g_strdup_printf ("error:404 %s ", view->uri ? view->uri : ""); + midori_view_set_uri (view, data); + g_free (data); + return; + } + + /* If WebKit didn't emit the signal due to a bug, we will */ + if (!view->window_object_cleared) + { + js_context = webkit_web_frame_get_global_context (web_frame); + js_window = JSContextGetGlobalObject (js_context); + g_signal_emit_by_name (view->web_view, "window-object-cleared", + web_frame, js_context, js_window); + } + + /* value = gjs_value_new (webkit_web_frame_get_global_context (web_frame), NULL); + document = gjs_value_get_by_name (value, "document"); + links = gjs_value_get_elements_by_tag_name (document, "link"); + katze_array_clear (web_view->news_feeds); + gjs_value_foreach (links, (GjsCallback)gjs_value_links_foreach_cb, web_view); + g_object_unref (links); + g_object_unref (document); + g_object_unref (value); */ + + view->load_status = MIDORI_LOAD_FINISHED; + g_object_notify (G_OBJECT (view), "load-status"); +} + +static void +webkit_web_view_load_finished_cb (WebKitWebView* web_view, + WebKitWebFrame* web_frame, + MidoriView* view) +{ + view->progress = 1.0; + g_object_notify (G_OBJECT (view), "progress"); +} + +static void +webkit_web_view_title_changed_cb (WebKitWebView* web_view, + WebKitWebFrame* web_frame, + const gchar* title, + MidoriView* view) +{ + g_object_set (view, "title", title, NULL); +} + +static void +webkit_web_view_statusbar_text_changed_cb (WebKitWebView* web_view, + const gchar* text, + MidoriView* view) +{ + g_object_set (G_OBJECT (view), "statusbar-text", text, NULL); +} + +static void +webkit_web_view_hovering_over_link_cb (WebKitWebView* web_view, + const gchar* tooltip, + const gchar* link_uri, + MidoriView* view) +{ + katze_assign (view->link_uri, g_strdup (link_uri)); + g_object_set (G_OBJECT (view), "statusbar-text", link_uri, NULL); +} + +static gboolean +gtk_widget_button_press_event_cb (WebKitWebView* web_view, + GdkEventButton* event, + MidoriView* view) +{ + GdkModifierType state; + gint x, y; + GtkClipboard* clipboard; + gchar* uri; + gchar* new_uri; + const gchar* link_uri; + + gdk_window_get_pointer (NULL, &x, &y, &state); + link_uri = midori_view_get_link_uri (MIDORI_VIEW (view)); + + switch (event->button) + { + case 1: + if (!link_uri) + return FALSE; + if (state & GDK_SHIFT_MASK) + { + /* Open link in new window */ + g_signal_emit_by_name (view, "new-window", link_uri); + return TRUE; + } + else if (state & GDK_MOD1_MASK) + { + /* Open link in new tab */ + g_signal_emit_by_name (view, "new-tab", link_uri); + /* FIXME: Open in the background as appropriate */ + /* background = sokoke_object_get_boolean (browser->settings, + "open-tabs-in-the-background"); + if (state & GDK_CONTROL_MASK) + background = !background; + if (background) + open_tab_in_the_background */ + return TRUE; + } + break; + case 2: + if (link_uri) + { + /* Open link in new tab */ + g_signal_emit_by_name (view, "new-tab", link_uri); + /* FIXME: Open in the background as appropriate */ + /* background = sokoke_object_get_boolean (browser->settings, + "open-tabs-in-the-background"); + if (state & GDK_CONTROL_MASK) + background = !background; + if (background) + open_tab_in_the_background */ + return TRUE; + } + else if (state & GDK_CONTROL_MASK) + { + midori_view_set_zoom_level (MIDORI_VIEW (view), 1.0); + return FALSE; /* Allow Ctrl + Middle click */ + } + else if (TRUE /*middle-click-opens-selection*/) + { + state = (GdkModifierType) event->state; + clipboard = gtk_clipboard_get_for_display ( + gtk_widget_get_display (GTK_WIDGET (view)), + GDK_SELECTION_PRIMARY); + uri = gtk_clipboard_wait_for_text (clipboard); + if (uri && strchr (uri, '.') && !strchr (uri, ' ')) + { + new_uri = sokoke_magic_uri (uri, NULL); + if (state & GDK_CONTROL_MASK) + g_signal_emit_by_name (view, "new-tab", new_uri); + else + { + midori_view_set_uri (MIDORI_VIEW (view), new_uri); + gtk_widget_grab_focus (GTK_WIDGET (view)); + } + g_free (new_uri); + g_free (uri); + return TRUE; + } + } + break; + } + + return FALSE; +} + +static gboolean +gtk_widget_button_release_event_cb (WebKitWebView* web_view, + GdkEventButton* event, + MidoriView* view) +{ + GtkClipboard* clipboard; + gchar* text; + + /* Emulate the primary clipboard, which WebKit doesn't support */ + text = webkit_web_view_get_selected_text (WEBKIT_WEB_VIEW (web_view)); + clipboard = gtk_clipboard_get_for_display ( + gtk_widget_get_display (GTK_WIDGET (web_view)), GDK_SELECTION_PRIMARY); + gtk_clipboard_set_text (clipboard, text, -1); + g_free (text); + return FALSE; +} + +static gboolean +gtk_widget_scroll_event_cb (WebKitWebView* web_view, + GdkEventScroll* event, + MidoriView* view) +{ + GdkModifierType state = (GdkModifierType)0; + gint x, y; + + gdk_window_get_pointer (NULL, &x, &y, &state); + if (state & GDK_CONTROL_MASK) + { + if (event->direction == GDK_SCROLL_DOWN) + webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view)); + else if(event->direction == GDK_SCROLL_UP) + webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view)); + return TRUE; + } + else + return FALSE; +} + +static void +midori_web_view_menu_new_tab_activate_cb (GtkWidget* widget, + MidoriView* view) +{ + g_signal_emit (view, signals[NEW_TAB], 0, view->link_uri); +} + +static void +midori_web_view_menu_new_window_activate_cb (GtkWidget* widget, + MidoriView* view) +{ + g_signal_emit (view, signals[NEW_WINDOW], 0, view->link_uri); +} + +static void +midori_web_view_menu_download_activate_cb (GtkWidget* widget, + MidoriView* view) +{ + sokoke_spawn_program (view->download_manager, view->link_uri); +} + +static void +midori_web_view_menu_add_bookmark_activate_cb (GtkWidget* widget, + MidoriView* view) +{ + g_signal_emit (view, signals[ADD_BOOKMARK], 0, view->link_uri); +} + +static void +midori_web_view_menu_action_activate_cb (GtkWidget* widget, + MidoriView* view) +{ + const gchar* action = g_object_get_data (G_OBJECT (widget), "action"); + g_signal_emit_by_name (view, "activate-action", action); +} + +static void +webkit_web_view_populate_popup_cb (WebKitWebView* web_view, + GtkWidget* menu, + MidoriView* view) +{ + GtkWidget* menuitem; + GtkWidget* icon; + gchar* stock_id; + GdkScreen* screen; + GtkIconTheme* icon_theme; + GList* items; + + /* We do not want to modify the Edit menu. + The only reliable indicator is inspecting the first item. */ + items = gtk_container_get_children (GTK_CONTAINER (menu)); + menuitem = (GtkWidget*)g_list_nth_data (items, 0); + if (GTK_IS_IMAGE_MENU_ITEM (menuitem)) + { + icon = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (menuitem)); + gtk_image_get_stock (GTK_IMAGE (icon), &stock_id, NULL); + if (!strcmp (stock_id, GTK_STOCK_CUT)) + return; + } + + if (view->link_uri) + { + menuitem = gtk_image_menu_item_new_with_mnemonic ( + _("Open Link in New _Tab")); + screen = gtk_widget_get_screen (GTK_WIDGET (view)); + icon_theme = gtk_icon_theme_get_for_screen (screen); + if (gtk_icon_theme_has_icon (icon_theme, STOCK_TAB_NEW)) + { + icon = gtk_image_new_from_stock (STOCK_TAB_NEW, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); + } + gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 1); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), view); + gtk_widget_show (menuitem); + /* hack to implement New Window */ + items = gtk_container_get_children (GTK_CONTAINER (menu)); + menuitem = (GtkWidget*)g_list_nth_data (items, 2); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_web_view_menu_new_window_activate_cb), view); + menuitem = (GtkWidget*)g_list_nth_data (items, 3); + /* hack to disable non-functional Download File */ + gtk_widget_set_sensitive (menuitem, FALSE); + g_list_free (items); + if (view->download_manager && *view->download_manager) + { + menuitem = gtk_image_menu_item_new_with_mnemonic ( + _("Download Link with Download _Manager")); + icon = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); + gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 4); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_web_view_menu_download_activate_cb), view); + gtk_widget_show (menuitem); + } + menuitem = gtk_image_menu_item_new_from_stock (STOCK_BOOKMARK_ADD, NULL); + gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 5); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_web_view_menu_add_bookmark_activate_cb), view); + gtk_widget_show (menuitem); + } + + if (!view->link_uri && midori_view_has_selection (view)) + { + if (strchr (view->selected_text, '.') + && !strchr (view->selected_text, ' ')) + { + menuitem = gtk_image_menu_item_new_with_mnemonic ( + _("Open URL in New _Tab")); + icon = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); + gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, -1); + g_object_set_data (G_OBJECT (menuitem), "uri", view->selected_text); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), view); + gtk_widget_show (menuitem); + } + /* FIXME: view selection source */ + } + + if (!view->link_uri && !midori_view_has_selection (view)) + { + /* FIXME: Make this sensitive only when there is a tab to undo */ + menuitem = gtk_image_menu_item_new_with_mnemonic (_("Undo Close Tab")); + icon = gtk_image_new_from_stock (GTK_STOCK_UNDELETE, 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), "action", "UndoTabClose"); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_web_view_menu_action_activate_cb), view); + gtk_widget_show (menuitem); + menuitem = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + menuitem = gtk_image_menu_item_new_from_stock (STOCK_BOOKMARK_ADD, NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_object_set_data (G_OBJECT (menuitem), "action", "BookmarkAdd"); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_web_view_menu_action_activate_cb), view); + gtk_widget_show (menuitem); + menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE_AS, NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_object_set_data (G_OBJECT (menuitem), "action", "SaveAs"); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_web_view_menu_action_activate_cb), view); + gtk_widget_show (menuitem); + /* FIXME: Make this sensitive once it's implemented */ + gtk_widget_set_sensitive (menuitem, FALSE); + menuitem = gtk_image_menu_item_new_with_mnemonic (_("View _Source")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_object_set_data (G_OBJECT (menuitem), "action", "SourceView"); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_web_view_menu_action_activate_cb), view); + gtk_widget_show (menuitem); + #if !HAVE_GIO + gtk_widget_set_sensitive (menuitem, FALSE); + #endif + menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PRINT, NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_object_set_data (G_OBJECT (menuitem), "action", "Print"); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_web_view_menu_action_activate_cb), view); + gtk_widget_show (menuitem); + } +} + +static void +webkit_web_view_console_message_cb (GtkWidget* web_view, + const gchar* message, + guint line, + const gchar* source_id, + MidoriView* view) +{ + g_signal_emit_by_name (view, "console-message", message, line, source_id); +} + +static gboolean +gtk_widget_focus_out_event_cb (GtkWidget* web_view, + GdkEventFocus* event, + MidoriView* view) +{ + gchar* data; + + data = g_strdup_printf ("%d %d %d", + midori_view_can_cut_clipboard (view), + midori_view_can_copy_clipboard (view), + midori_view_can_paste_clipboard (view)); + send_command (view, "clipboard", data); + g_free (data); + + return FALSE; +} + +static void +midori_view_realize (MidoriView* view) +{ + WebKitWebFrame* web_frame; + + view->web_view = webkit_web_view_new (); + /* Adjustments are not created automatically */ + g_object_set (view, "hadjustment", NULL, "vadjustment", NULL, NULL); + + /* FIXME: Strictly we should send a command to query + the policy or send it as an argument */ + /* The socket view is not supposed to scroll at all */ + if (midori_view_is_socket (view)) + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view), + GTK_POLICY_NEVER, GTK_POLICY_NEVER); + /* The plug view should use the policy of the socket */ + if (midori_view_is_plug (view)) + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + gtk_widget_show (view->web_view); + + web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (view->web_view)); + + g_object_connect (view->web_view, + "signal::load-started", + webkit_web_view_load_started_cb, view, + "signal::window-object-cleared", + webkit_web_view_window_object_cleared_cb, view, + "signal::load-committed", + webkit_web_view_load_committed_cb, view, + "signal::load-progress-changed", + webkit_web_view_progress_changed_cb, view, + "signal::load-finished", + webkit_web_view_load_finished_cb, view, + "signal::title-changed", + webkit_web_view_title_changed_cb, view, + "signal::status-bar-text-changed", + webkit_web_view_statusbar_text_changed_cb, view, + "signal::hovering-over-link", + webkit_web_view_hovering_over_link_cb, view, + "signal::button-press-event", + gtk_widget_button_press_event_cb, view, + "signal::button-release-event", + gtk_widget_button_release_event_cb, view, + "signal::scroll-event", + gtk_widget_scroll_event_cb, view, + "signal::populate-popup", + webkit_web_view_populate_popup_cb, view, + "signal::console-message", + webkit_web_view_console_message_cb, view, + "signal::focus-out-event", + gtk_widget_focus_out_event_cb, view, + NULL); + g_object_connect (web_frame, + "signal::load-done", + webkit_web_frame_load_done_cb, view, + NULL); + + gtk_container_add (GTK_CONTAINER (view), view->web_view); + if (view->premature_uri) + { + midori_debug ("Loading premature uri '%s' now", view->premature_uri); + midori_view_set_uri (view, view->premature_uri); + } + katze_assign (view->premature_uri, NULL); +} + +static void +gtk_socket_realize_cb (GtkWidget* socket, + MidoriView* view) +{ + gchar* socket_id; + GError* error; + gboolean success; + gint stdin; + gint stdout; + gchar* argv[] = { NULL, "--id", NULL, NULL }; + + /* Sockets are not supported on all platforms, + so fallback to working without any socket or plug. */ + if (!gtk_socket_get_id (GTK_SOCKET (socket))) + { + gtk_widget_destroy (socket); + midori_view_realize (view); + return; + } + + socket_id = g_strdup_printf ("%d", gtk_socket_get_id (GTK_SOCKET (socket))); + argv[0] = (gchar*)sokoke_remember_argv0 (NULL); + argv[2] = socket_id; + error = NULL; + success = g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, + &stdin, &stdout, NULL, &error); + g_free (socket_id); + + if (!success) + { + /* Fallback to operating without a socket */ + view->socket_id = 0; + midori_view_realize (view); + + g_error_free (error); + return; + } + + view->output = fdopen (stdin, "w"); + view->input = g_io_channel_unix_new (stdout); + g_io_channel_set_close_on_unref (view->input, TRUE); + g_io_add_watch (view->input, + G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_NVAL | G_IO_HUP, + (GIOFunc)io_input_watch_cb, view); + + if (view->command_cache) + { + /* Send cached commands if any */ + fwrite (view->command_cache, + strlen (view->command_cache) + 1, 1, view->output); + katze_assign (view->command_cache, NULL); + fflush (view->output); + } +} + +static gboolean +gtk_socket_plug_removed_cb (GtkWidget* socket, + MidoriView* view) +{ + if (view->output) + { + fclose (view->output); + view->output = NULL; + } + + if (view->input) + { + g_io_channel_unref (view->input); + view->input = NULL; + } + + midori_debug ("'%s' died.", view->uri); + send_command (view, "set-uri error:died", view->uri ? view->uri : ""); + if (GTK_WIDGET_REALIZED (view)) + gtk_socket_realize_cb (socket, view); + + return TRUE; +} + +static void +midori_view_realize_cb (MidoriView* view) +{ + GtkWidget* plug; + GtkWidget* socket; + + if (midori_view_is_plug (view)) + { + plug = gtk_plug_new (view->socket_id); + midori_view_realize (view); + gtk_widget_show (plug); + + view->input = g_io_channel_unix_new (0); /* 0 is stdin */ + g_io_channel_set_close_on_unref (view->input, TRUE); + g_io_add_watch (view->input, + G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP, + (GIOFunc)io_input_watch_cb, view); + view->output = fdopen (1, "w"); /* 1 is stdout */ + } + else if (midori_view_is_socket (view)) + { + socket = gtk_socket_new (); + g_signal_connect (socket, "realize", + G_CALLBACK (gtk_socket_realize_cb), view); + g_signal_connect (socket, "plug-removed", + G_CALLBACK (gtk_socket_plug_removed_cb), view); + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (view), + GTK_WIDGET (socket)); + gtk_widget_show (socket); + } +} + +static void +midori_view_init (MidoriView* view) +{ + view->command_cache = NULL; + view->premature_uri = NULL; + view->uri = NULL; + view->title = NULL; + view->icon = gtk_widget_render_icon (GTK_WIDGET (view), GTK_STOCK_FILE, + GTK_ICON_SIZE_MENU, NULL); + view->progress = 0.0; + view->load_status = MIDORI_LOAD_FINISHED; + view->statusbar_text = NULL; + view->link_uri = NULL; + view->selected_text = NULL; + view->settings = NULL; + view->item = NULL; + + view->download_manager = NULL; + + g_object_connect (view, + "signal::notify::uri", + midori_view_notify_uri_cb, NULL, + "signal::notify::icon", + midori_view_notify_icon_cb, NULL, + "signal::notify::load-status", + midori_view_notify_load_status_cb, NULL, + "signal::notify::progress", + midori_view_notify_progress_cb, NULL, + "signal::realize", + midori_view_realize_cb, NULL, + "signal::activate-action", + midori_view_action_cb, NULL, + "signal::console-message", + midori_view_console_message_cb, NULL, + "signal::new-tab", + midori_view_new_tab_cb, NULL, + "signal::new-window", + midori_view_new_window_cb, NULL, + "signal::add-bookmark", + midori_view_add_bookmark_cb, NULL, + NULL); +} + +static void +midori_view_finalize (GObject* object) +{ + MidoriView* view; + /* WebKitWebFrame* web_frame; */ + + view = MIDORI_VIEW (object); + + g_free (view->command_cache); + g_free (view->premature_uri); + g_free (view->uri); + g_free (view->title); + if (view->icon) + g_object_unref (view->icon); + g_free (view->statusbar_text); + g_free (view->link_uri); + g_free (view->selected_text); + if (view->settings) + g_object_unref (view->settings); + if (view->item) + g_object_unref (view->item); + + g_free (view->download_manager); + + /* web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (view->web_view)); + g_signal_handlers_disconnect_by_func (web_frame, + webkit_web_frame_load_done, view); */ + + G_OBJECT_CLASS (midori_view_parent_class)->finalize (object); +} + +static void +midori_view_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec) +{ + MidoriView* view; + + view = MIDORI_VIEW (object); + + switch (prop_id) + { + case PROP_SOCKET_ID: + view->socket_id = g_value_get_uint (value); + break; + case PROP_TITLE: + katze_assign (view->title, g_value_dup_string (value)); + if (!midori_view_is_plug (view)) + { + #define title midori_view_get_display_title (view) + if (view->tab_label) + { + gtk_label_set_text (GTK_LABEL (view->tab_title), title); + gtk_widget_set_tooltip_text (view->tab_title, title); + } + if (view->menu_item) + gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN ( + view->menu_item))), title); + if (view->item) + katze_item_set_name (view->item, title); + #undef title + } + if (midori_view_is_plug (view)) + /* We must not send a NULL string here */ + send_command (view, "title", view->title ? view->title : ""); + break; + case PROP_ZOOM_LEVEL: + midori_view_set_zoom_level (view, g_value_get_float (value)); + if (midori_view_is_plug (view)) + send_command (view, "zoom-level", float_to_str (view->zoom_level)); + break; + case PROP_STATUSBAR_TEXT: + katze_assign (view->statusbar_text, g_value_dup_string (value)); + if (midori_view_is_plug (view)) + /* We must not send a NULL string here */ + send_command (view, "statusbar-text", + view->statusbar_text ? view->statusbar_text : ""); + break; + case PROP_SETTINGS: + midori_view_set_settings (view, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +midori_view_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec) +{ + MidoriView* view = MIDORI_VIEW (object); + + switch (prop_id) + { + case PROP_SOCKET_ID: + g_value_set_uint (value, view->socket_id); + break; + case PROP_URI: + g_value_set_string (value, view->uri); + break; + case PROP_TITLE: + g_value_set_string (value, view->title); + break; + case PROP_PROGRESS: + g_value_set_double (value, midori_view_get_progress (view)); + break; + case PROP_LOAD_STATUS: + g_value_set_enum (value, midori_view_get_load_status (view)); + break; + case PROP_ZOOM_LEVEL: + g_value_set_float (value, midori_view_get_zoom_level (view)); + break; + case PROP_STATUSBAR_TEXT: + g_value_set_string (value, view->statusbar_text); + break; + case PROP_SETTINGS: + g_value_set_object (value, view->settings); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * midori_view_new: + * @view: a #MidoriView + * + * Creates a new view. + * + * Return value: a new #MidoriView + **/ +GtkWidget* +midori_view_new (void) +{ + return g_object_new (MIDORI_TYPE_VIEW, NULL); +} + +/** + * midori_view_new_with_uri: + * @view: a #MidoriView + * @uri: an URI + * + * Creates a new view with a particular URI. + * + * This constructor supports opaque views and is + * in fact currently the only way to create them. + * + * The only currently supported opaque view is + * the source view, implementing a #MidoriSource. + * Pass an URI prefixed with "view-source:" in + * order to create a source view. + * + * Return value: a new #MidoriView + **/ +GtkWidget* +midori_view_new_with_uri (const gchar* uri) +{ + MidoriView* view; + gchar* title; + GtkWidget* widget; + + view = g_object_new (MIDORI_TYPE_VIEW, NULL); + + if (uri && g_str_has_prefix (uri, "view-source:")) + { + view->socket_id = -1; + katze_assign (view->uri, g_strdup (uri)); + g_object_notify (G_OBJECT (view), "uri"); + title = g_strdup_printf ("%s - %s", _("Source"), &uri[12]); + g_object_set (view, "title", title, NULL); + g_free (title); + katze_object_assign (view->icon, + gtk_widget_render_icon (GTK_WIDGET (view), + GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU, NULL)); + widget = midori_source_new (&uri[12]); + /* Adjustments are not created automatically */ + g_object_set (view, "hadjustment", NULL, "vadjustment", NULL, NULL); + gtk_container_add (GTK_CONTAINER (view), widget); + gtk_widget_show (widget); + } + else + midori_view_set_uri (view, uri); + + return (GtkWidget*)view; +} + +static void +_update_label_size (GtkWidget* label, + gint size) +{ + gint width, height; + + if (size > -1) + { + sokoke_widget_get_text_size (label, "M", &width, &height); + gtk_widget_set_size_request (label, width * size, -1); + gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); + } + else + { + gtk_widget_set_size_request (label, -1, -1); + gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_NONE); + } +} + +static void +_midori_view_update_settings (MidoriView* view) +{ + g_object_get (view->settings, + "download-manager", &view->download_manager, + "close-buttons-on-tabs", &view->close_buttons_on_tabs, + NULL); + + if (midori_view_is_socket (view)) + send_command (view, "download-manager", view->download_manager); +} + +static void +midori_view_settings_notify_cb (MidoriWebSettings* settings, + GParamSpec* pspec, + MidoriView* view) +{ + const gchar* name; + GValue value = { 0, }; + + name = g_intern_string (g_param_spec_get_name (pspec)); + g_value_init (&value, pspec->value_type); + g_object_get_property (G_OBJECT (view->settings), name, &value); + + if (name == g_intern_string ("download-manager")) + { + katze_assign (view->download_manager, g_value_dup_string (&value)); + if (midori_view_is_socket (view)) + send_command (view, "download-manager", view->download_manager); + } + else if (name == g_intern_string ("tab-label-size")) + { + view->tab_label_size = g_value_get_int (&value); + if (!midori_view_is_plug (view)) + _update_label_size (view->tab_title, + sokoke_object_get_int (view->settings, "tab-label-size")); + } + else if (name == g_intern_string ("close-buttons-on-tabs")) + { + view->close_buttons_on_tabs = g_value_get_boolean (&value); + sokoke_widget_set_visible (view->tab_close, + view->close_buttons_on_tabs); + } + + g_value_unset (&value); +} + +/** + * midori_view_set_settings: + * @view: a #MidoriView + * @settings: a #MidoriWebSettings + * + * Assigns a settings instance to the view. + **/ +void +midori_view_set_settings (MidoriView* view, + MidoriWebSettings* settings) +{ + if (view->settings) + g_signal_handlers_disconnect_by_func (view->settings, + midori_view_settings_notify_cb, view); + katze_object_assign (view->settings, g_object_ref (settings)); + /* FIXME: Propagate settings to the web view */ + _midori_view_update_settings (view); + g_signal_connect (settings, "notify", + G_CALLBACK (midori_view_settings_notify_cb), view); + g_object_notify (G_OBJECT (view), "settings"); +} + +/** + * midori_view_load_status: + * @web_view: a #MidoriView + * + * Determines the current loading status of a view. + * + * Return value: the current #MidoriLoadStatus + **/ +MidoriLoadStatus +midori_view_get_load_status (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), MIDORI_LOAD_FINISHED); + + return view->load_status; +} + +/** + * midori_view_get_progress: + * @view: a #MidoriView + * + * Retrieves the current loading progress as + * a fraction between 0.0 and 1.0. + * + * Return value: the current loading progress + **/ +gdouble +midori_view_get_progress (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), 0.0); + + return view->progress; +} + +/** + * midori_view_set_uri: + * @view: a #MidoriView + * + * Opens the specified URI in the view. + * + * FIXME: + * If the view doesn't allow changing the URI it + * will automatically request a new tab. + **/ +void +midori_view_set_uri (MidoriView* view, + const gchar* uri) +{ + gchar* data; + + g_return_if_fail (MIDORI_IS_VIEW (view)); + + if (midori_view_is_socket (view)) + /* We must not send a NULL string here */ + send_command (view, "set-uri", uri ? uri : ""); + else + { + if (!view->web_view) + { + /* An URI is requested before the view was realized. + We special case this to load it when we are ready. */ + midori_debug ("Deferring premature uri '%s'", uri); + katze_assign (view->premature_uri, g_strdup (uri)); + return; + } + midori_debug ("Opening URI: %s", uri); + /* This is not prefectly elegant, but creating an + error page inline is the simplest solution. */ + if (g_str_has_prefix (uri, "error:")) + { + data = NULL; + if (!strncmp (uri, "error:died ", 11)) + { + katze_assign (view->uri, g_strdup (&uri[11])); + data = g_strdup_printf ( + "Page died - %s" + "

Page died - %s

" + "

The page you were navigating on died." + "

Try to load the page again, " + "or move on to another page." + "", + view->uri, view->uri, view->uri); + } + else if (!strncmp (uri, "error:404 ", 10)) + { + katze_assign (view->uri, g_strdup (&uri[10])); + data = g_strdup_printf ( + "Not found - %s" + "

Not found - %s

" + "

The page you were opening doesn't exist." + "

Try to load the page again, " + "or move on to another page." + "", + view->uri, view->uri, view->uri); + } + if (data) + { + webkit_web_view_load_html_string ( + WEBKIT_WEB_VIEW (view->web_view), data, view->uri); + g_free (data); + g_object_notify (G_OBJECT (view), "uri"); + return; + } + } + else + { + katze_assign (view->uri, g_strdup (uri)); + webkit_web_view_open (WEBKIT_WEB_VIEW (view->web_view), uri); + } + } +} + +/** + * midori_view_is_blank: + * @view: a #MidoriView + * + * Determines whether the view is currently empty. + **/ +gboolean +midori_view_is_blank (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), TRUE); + + return !(view->uri && *view->uri); +} + +/** + * midori_view_get_icon: + * @view: a #MidoriView + * + * Retrieves the icon of the view. + * + * Return value: a #GdkPixbuf + **/ +GdkPixbuf* +midori_view_get_icon (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL); + + return view->icon; +} + +/** + * midori_view_get_display_uri: + * @view: a #MidoriView + * + * 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_view_get_display_uri (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), "about:blank"); + + if (view->uri && *view->uri) + return view->uri; + return "about:blank"; +} + +/** + * midori_view_get_display_title: + * @view: a #MidoriView + * + * 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_view_get_display_title (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), "about:blank"); + + if (view->title && *view->title) + return view->title; + return midori_view_get_display_uri (view); +} + +/** + * midori_view_get_link_uri: + * @view: a #MidoriView + * + * 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_view_get_link_uri (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL); + + return view->link_uri; +} + +/** + * midori_view_has_selection: + * @view: a #MidoriView + * + * Determines whether something in the view is selected. + * + * This function returns %FALSE if there is a selection + * that effectively only consists of whitespace. + * + * Return value: %TRUE if effectively there is a selection + **/ +gboolean +midori_view_has_selection (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE); + + if (midori_view_is_socket (view)) + return view->has_selection; + else + { + view->selected_text = webkit_web_view_get_selected_text ( + WEBKIT_WEB_VIEW (view->web_view)); + if (view->selected_text && *view->selected_text) + return TRUE; + return FALSE; + } +} + +/** + * midori_view_get_selected_text: + * @view: a #MidoriView + * + * Retrieves the currently selected text. + * + * Return value: the selected text, or %NULL + **/ +const gchar* +midori_view_get_selected_text (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL); + + if (midori_view_is_socket (view)) + return view->selected_text; + else if (midori_view_has_selection (view)) + return midori_view_get_selected_text (view); + else + return NULL; +} + +/** + * midori_view_can_cut_clipboard: + * @view: a #MidoriView + * + * Determines whether a selection can be cut. + * + * Return value: %TRUE if a selection can be cut + **/ +gboolean +midori_view_can_cut_clipboard (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE); + + if (midori_view_is_socket (view)) + return view->can_cut_clipboard; + else if (view->web_view) + { + view->can_cut_clipboard = webkit_web_view_can_cut_clipboard ( + WEBKIT_WEB_VIEW (view->web_view)); + return view->can_cut_clipboard; + } + return FALSE; +} + +/** + * midori_view_can_copy_clipboard: + * @view: a #MidoriView + * + * Determines whether a selection can be copied. + * + * Return value: %TRUE if a selection can be copied + **/ +gboolean +midori_view_can_copy_clipboard (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE); + + if (midori_view_is_socket (view)) + return view->can_copy_clipboard; + else if (view->web_view) + { + view->can_copy_clipboard = webkit_web_view_can_copy_clipboard ( + WEBKIT_WEB_VIEW (view->web_view)); + return view->can_copy_clipboard; + } + return FALSE; +} + +/** + * midori_view_can_paste_clipboard: + * @view: a #MidoriView + * + * Determines whether a selection can be pasted. + * + * Return value: %TRUE if a selection can be pasted + **/ +gboolean +midori_view_can_paste_clipboard (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE); + + if (midori_view_is_socket (view)) + return view->can_paste_clipboard; + else if (view->web_view) + { + view->can_paste_clipboard = webkit_web_view_can_paste_clipboard ( + WEBKIT_WEB_VIEW (view->web_view)); + return view->can_paste_clipboard; + } + return FALSE; +} + +/** + * midori_view_get_proxy_menu_item: + * @view: a #MidoriView + * + * 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. + * + * The menu item is valid until it is removed from its container. + * + * Return value: the proxy #GtkMenuItem + **/ +GtkWidget* +midori_view_get_proxy_menu_item (MidoriView* view) +{ + const gchar* title; + + g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL); + + if (!view->menu_item) + { + title = midori_view_get_display_title (view); + view->menu_item = sokoke_image_menu_item_new_ellipsized (title); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (view->menu_item), + gtk_image_new_from_pixbuf (view->icon)); + + g_signal_connect (view->menu_item, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &view->menu_item); + } + return view->menu_item; +} + +static gboolean +midori_view_tab_label_button_release_event (GtkWidget* tab_label, + GdkEventButton* event, + GtkWidget* widget) +{ + if (event->button == 2) + { + /* Close the widget on middle click */ + gtk_widget_destroy (widget); + return TRUE; + } + + return FALSE; +} + +static void +midori_view_tab_icon_style_set (GtkWidget* tab_icon, + GtkStyle* previous_style) +{ + GtkSettings* gtk_settings; + gint width, height; + + gtk_settings = gtk_widget_get_settings (tab_icon); + gtk_icon_size_lookup_for_settings (gtk_settings, GTK_ICON_SIZE_MENU, + &width, &height); + gtk_widget_set_size_request (tab_icon, width + 2, height + 2); +} + +static void +midori_view_tab_close_clicked (GtkWidget* tab_close, + GtkWidget* widget) +{ + gtk_widget_destroy (widget); +} + +/** + * midori_view_get_proxy_tab_label: + * @view: a #MidoriView + * + * Retrieves a proxy tab label that is typically used when + * adding the view to a notebook. + * + * The label is created on the first call and will be updated to reflect + * changes of the loading progress and title. + * + * The label is valid until it is removed from its container. + * + * Return value: the proxy #GtkEventBox + **/ +GtkWidget* +midori_view_get_proxy_tab_label (MidoriView* view) +{ + GtkWidget* event_box; + GtkWidget* hbox; + GtkRcStyle* rcstyle; + GtkWidget* image; + + g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL); + + if (!view->tab_label) + { + view->tab_icon = katze_throbber_new (); + katze_throbber_set_static_pixbuf (KATZE_THROBBER (view->tab_icon), + midori_view_get_icon (view)); + + view->tab_title = gtk_label_new (midori_view_get_display_title (view)); + + event_box = gtk_event_box_new (); + gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE); + hbox = gtk_hbox_new (FALSE, 1); + gtk_container_border_width (GTK_CONTAINER (hbox), 2); + gtk_container_add (GTK_CONTAINER (event_box), GTK_WIDGET (hbox)); + gtk_misc_set_alignment (GTK_MISC (view->tab_icon), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), view->tab_icon, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (view->tab_title), 0.0, 0.5); + /* TODO: make the tab initially look "unvisited" until it's focused */ + gtk_box_pack_start (GTK_BOX (hbox), view->tab_title, FALSE, TRUE, 0); + if (view->settings) + _update_label_size (view->tab_title, + sokoke_object_get_int (view->settings, "tab-label-size")); + + view->tab_close = gtk_button_new (); + gtk_button_set_relief (GTK_BUTTON (view->tab_close), GTK_RELIEF_NONE); + gtk_button_set_focus_on_click (GTK_BUTTON (view->tab_close), FALSE); + rcstyle = gtk_rc_style_new (); + rcstyle->xthickness = rcstyle->ythickness = 0; + gtk_widget_modify_style (view->tab_close, rcstyle); + g_object_unref (rcstyle); + image = katze_throbber_new (); + katze_throbber_set_static_stock_id (KATZE_THROBBER (image), + GTK_STOCK_CLOSE); + gtk_button_set_image (GTK_BUTTON (view->tab_close), image); + gtk_misc_set_alignment (GTK_MISC (image), 0.0, 0.0); + gtk_box_pack_end (GTK_BOX (hbox), view->tab_close, FALSE, FALSE, 0); + gtk_widget_show_all (GTK_WIDGET (event_box)); + + if (view->settings && + !sokoke_object_get_boolean (view->settings, "close-buttons-on-tabs")) + gtk_widget_hide (view->tab_close); + + g_signal_connect (event_box, "button-release-event", + G_CALLBACK (midori_view_tab_label_button_release_event), view); + g_signal_connect (view->tab_close, "style-set", + G_CALLBACK (midori_view_tab_icon_style_set), NULL); + g_signal_connect (view->tab_close, "clicked", + G_CALLBACK (midori_view_tab_close_clicked), view); + + view->tab_label = event_box; + g_signal_connect (view->tab_label, "destroy", + G_CALLBACK (gtk_widget_destroyed), + &view->tab_label); + } + return view->tab_label; +} + +/** + * midori_view_get_proxy_item: + * @view: a #MidoriView + * + * Retrieves a proxy 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 uri automatically. + * + * Return value: the proxy #KatzeItem + **/ +KatzeItem* +midori_view_get_proxy_item (MidoriView* view) +{ + const gchar* uri; + const gchar* title; + + g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL); + + if (!view->item) + { + view->item = katze_item_new (); + uri = midori_view_get_display_uri (view); + katze_item_set_uri (view->item, uri); + title = midori_view_get_display_title (view); + katze_item_set_name (view->item, title); + } + return view->item; +} + +/** + * midori_view_get_zoom_level: + * @view: a #MidoriView + * + * Determines the current zoom level of the view. + * + * Return value: the current zoom level + **/ +gfloat +midori_view_get_zoom_level (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), 1.0); + + if (midori_view_is_socket (view)) + return view->zoom_level; + else if (view->web_view) + return webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (view->web_view)); + return FALSE; +} + +/** + * midori_view_set_zoom_level: + * @view: a #MidoriView + * @zoom_level: the new zoom level + * + * Sets the current zoom level of the view. + **/ +void +midori_view_set_zoom_level (MidoriView* view, + gfloat zoom_level) +{ + g_return_if_fail (MIDORI_IS_VIEW (view)); + + if (midori_view_is_socket (view)) + send_command (view, "set-zoom-level", float_to_str (zoom_level)); + else + webkit_web_view_set_zoom_level ( + WEBKIT_WEB_VIEW (view->web_view), zoom_level); +} + +#define can_do(what) \ +gboolean \ +midori_view_can_##what (MidoriView* view) \ +{ \ + g_return_val_if_fail (MIDORI_IS_VIEW (view), FALSE); \ +\ + return view->socket_id > -1; \ +} + +can_do (zoom_in) +can_do (zoom_out) +can_do (reload) +can_do (go_back) +can_do (go_forward) +can_do (print) +#if HAVE_GIO + can_do (view_source) +#else + gboolean midori_view_can_view_source (MidoriView* view) + { + return FALSE; + } +#endif +can_do (find) + +/** + * midori_view_reload: + * @view: a #MidoriView + * @from_cache: whether to allow caching + * + * Reloads the view. + * + * Note: The @from_cache value is currently ignored. + **/ +void +midori_view_reload (MidoriView* view, + gboolean from_cache) +{ + g_return_if_fail (MIDORI_IS_VIEW (view)); + + if (midori_view_is_socket (view)) + send_command (view, "reload", int_to_str (from_cache)); + else + webkit_web_view_reload (WEBKIT_WEB_VIEW (view->web_view)); +} + +/** + * midori_view_stop_loading + * @view: a #MidoriView + * + * Stops loading the view if it is currently loading. + **/ +void +midori_view_stop_loading (MidoriView* view) +{ + g_return_if_fail (MIDORI_IS_VIEW (view)); + + if (midori_view_is_socket (view)) + send_command (view, "stop-loading", NULL); + else + webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (view->web_view)); +} + +/** + * midori_view_go_back + * @view: a #MidoriView + * + * Goes back one page in the view. + **/ +void +midori_view_go_back (MidoriView* view) +{ + g_return_if_fail (MIDORI_IS_VIEW (view)); + + if (midori_view_is_socket (view)) + send_command (view, "go-back", NULL); + else + webkit_web_view_go_back (WEBKIT_WEB_VIEW (view->web_view)); +} + +/** + * midori_view_go_forward + * @view: a #MidoriView + * + * Goes forward one page in the view. + **/ +void +midori_view_go_forward (MidoriView* view) +{ + g_return_if_fail (MIDORI_IS_VIEW (view)); + + if (midori_view_is_socket (view)) + send_command (view, "go-forward", NULL); + else + webkit_web_view_go_forward (WEBKIT_WEB_VIEW (view->web_view)); +} + +/** + * midori_view_print + * @view: a #MidoriView + * + * Prints the contents of the view. + **/ +void +midori_view_print (MidoriView* view) +{ + g_return_if_fail (MIDORI_IS_VIEW (view)); + + if (midori_view_is_socket (view)) + send_command (view, "print", NULL); + else + webkit_web_view_execute_script ( + WEBKIT_WEB_VIEW (view->web_view), "print();"); +} diff --git a/midori/midori-view.h b/midori/midori-view.h new file mode 100644 index 00000000..96b5d22e --- /dev/null +++ b/midori/midori-view.h @@ -0,0 +1,161 @@ +/* + 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_VIEW_H__ +#define __MIDORI_VIEW_H__ + +#include "midori-websettings.h" + +#include + +G_BEGIN_DECLS + +typedef enum +{ + MIDORI_LOAD_PROVISIONAL, + MIDORI_LOAD_COMMITTED, + MIDORI_LOAD_FINISHED +} MidoriLoadStatus; + +GType +midori_load_status_get_type (void) G_GNUC_CONST; + +#define MIDORI_TYPE_LOAD_STATUS \ + (midori_load_status_get_type ()) + +#define MIDORI_TYPE_VIEW \ + (midori_view_get_type ()) +#define MIDORI_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_VIEW, MidoriView)) +#define MIDORI_VIEW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_VIEW, MidoriViewClass)) +#define MIDORI_IS_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_VIEW)) +#define MIDORI_IS_VIEW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_VIEW)) +#define MIDORI_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_VIEW, MidoriViewClass)) + +typedef struct _MidoriView MidoriView; +typedef struct _MidoriViewClass MidoriViewClass; + +GType +midori_view_get_type (void); + +GtkWidget* +midori_view_new (void); + +GtkWidget* +midori_view_new_with_uri (const gchar* uri); + +void +midori_view_set_settings (MidoriView* view, + MidoriWebSettings* settings); + +gdouble +midori_view_get_progress (MidoriView* view); + +MidoriLoadStatus +midori_view_get_load_status (MidoriView* view); + +void +midori_view_set_uri (MidoriView* view, + const gchar* uri); + +gboolean +midori_view_is_blank (MidoriView* view); + +const gchar* +midori_view_get_display_uri (MidoriView* view); + +const gchar* +midori_view_get_display_title (MidoriView* view); + +GdkPixbuf* +midori_view_get_icon (MidoriView* view); + +const gchar* +midori_view_get_link_uri (MidoriView* view); + +gboolean +midori_view_has_selection (MidoriView* view); + +const gchar* +midori_view_get_selected_text (MidoriView* view); + +gboolean +midori_view_can_cut_clipboard (MidoriView* view); + +gboolean +midori_view_can_copy_clipboard (MidoriView* view); + +gboolean +midori_view_can_paste_clipboard (MidoriView* view); + +GtkWidget* +midori_view_get_proxy_menu_item (MidoriView* view); + +GtkWidget* +midori_view_get_proxy_tab_label (MidoriView* view); + +KatzeItem* +midori_view_get_proxy_item (MidoriView* view); + +gfloat +midori_view_get_zoom_level (MidoriView* view); + +gboolean +midori_view_can_zoom_in (MidoriView* view); + +gboolean +midori_view_can_zoom_out (MidoriView* view); + +void +midori_view_set_zoom_level (MidoriView* view, + gfloat zoom_level); + +gboolean +midori_view_can_reload (MidoriView* view); + +void +midori_view_reload (MidoriView* view, + gboolean from_cache); + +void +midori_view_stop_loading (MidoriView* view); + +gboolean +midori_view_can_go_back (MidoriView* view); + +void +midori_view_go_back (MidoriView* view); + +gboolean +midori_view_can_go_forward (MidoriView* view); + +void +midori_view_go_forward (MidoriView* view); + +gboolean +midori_view_can_print (MidoriView* view); + +void +midori_view_print (MidoriView* view); + +gboolean +midori_view_can_view_source (MidoriView* view); + +gboolean +midori_view_can_find (MidoriView* view); + +G_END_DECLS + +#endif /* __MIDORI_VIEW_H__ */ diff --git a/midori/midori-webview.c b/midori/midori-webview.c deleted file mode 100644 index 754529b0..00000000 --- a/midori/midori-webview.c +++ /dev/null @@ -1,1214 +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. -*/ - -#if HAVE_CONFIG_H - #include -#endif - -#include "midori-webview.h" -#include "midori-stock.h" - -#include "compat.h" -#include "sokoke.h" -#include "gjs.h" - -#include -#if HAVE_GIO - #include -#endif -#include -#include - -/* This is unstable API, so we need to declare it */ -gchar* -webkit_web_view_get_selected_text (WebKitWebView* web_view); - -struct _MidoriWebView -{ - WebKitWebView parent_instance; - gboolean window_object_cleared; - - GdkPixbuf* icon; - gchar* uri; - gchar* title; - gdouble progress; - MidoriLoadStatus load_status; - gchar* statusbar_text; - gchar* link_uri; - KatzeArray* news_feeds; - - MidoriWebSettings* settings; - - GtkWidget* menu_item; - GtkWidget* tab_icon; - GtkWidget* tab_title; - KatzeXbelItem* xbel_item; -}; - -G_DEFINE_TYPE (MidoriWebView, midori_web_view, WEBKIT_TYPE_WEB_VIEW) - -GType -midori_load_status_get_type (void) -{ - static GType type = 0; - if (!type) - { - static const GEnumValue values[] = { - { MIDORI_LOAD_PROVISIONAL, "MIDORI_LOAD_PROVISIONAL", N_("Load Provisional") }, - { MIDORI_LOAD_COMMITTED, "MIDORI_LOAD_COMMITTED", N_("Load Committed") }, - { MIDORI_LOAD_FINISHED, "MIDORI_LOAD_FINISHED", N_("Load Finished") }, - { 0, NULL, NULL } - }; - type = g_enum_register_static ("MidoriLoadStatus", values); - } - return type; -} - -enum -{ - PROP_0, - - PROP_URI, - PROP_TITLE, - PROP_PROGRESS, - PROP_MLOAD_STATUS, - PROP_STATUSBAR_TEXT, - PROP_SETTINGS -}; - -enum { - ICON_READY, - NEWS_FEED_READY, - ELEMENT_MOTION, - 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 void -midori_cclosure_marshal_VOID__STRING_STRING_STRING (GClosure* closure, - GValue* return_value, - guint n_param_values, - const GValue* param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - typedef void(*GMarshalFunc_VOID__STRING_STRING_STRING) (gpointer data1, - const gchar* arg_1, - const gchar* arg_2, - const gchar* arg_3, - gpointer data2); - register GMarshalFunc_VOID__STRING_STRING_STRING callback; - register GCClosure* cc = (GCClosure*) closure; - register gpointer data1, data2; - - g_return_if_fail (n_param_values == 4); - - 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_VOID__STRING_STRING_STRING) (marshal_data - ? marshal_data : cc->callback); - callback (data1, - g_value_get_string (param_values + 1), - g_value_get_string (param_values + 2), - g_value_get_string (param_values + 3), - data2); -} - -static void -midori_web_view_class_init (MidoriWebViewClass* class) -{ - signals[ICON_READY] = g_signal_new ( - "icon-ready", - G_TYPE_FROM_CLASS (class), - (GSignalFlags)(G_SIGNAL_RUN_LAST), - G_STRUCT_OFFSET (MidoriWebViewClass, icon_ready), - 0, - NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - GDK_TYPE_PIXBUF); - - signals[NEWS_FEED_READY] = g_signal_new ( - "news-feed-ready", - G_TYPE_FROM_CLASS (class), - (GSignalFlags)(G_SIGNAL_RUN_LAST), - G_STRUCT_OFFSET (MidoriWebViewClass, news_feed_ready), - 0, - NULL, - midori_cclosure_marshal_VOID__STRING_STRING_STRING, - G_TYPE_NONE, 3, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_STRING); - - signals[ELEMENT_MOTION] = g_signal_new ( - "element-motion", - G_TYPE_FROM_CLASS (class), - (GSignalFlags)(G_SIGNAL_RUN_LAST), - G_STRUCT_OFFSET (MidoriWebViewClass, element_motion), - 0, - NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - - 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__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - - 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); - - 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; - - if (!g_object_class_find_property (gobject_class, "uri")) - g_object_class_install_property (gobject_class, - PROP_URI, - g_param_spec_string ( - "uri", - "Uri", - _("The URI of the currently loaded page"), - "", - flags)); - - if (!g_object_class_find_property (gobject_class, "title")) - g_object_class_install_property (gobject_class, - PROP_TITLE, - g_param_spec_string ( - "title", - "Title", - _("The title of the currently loaded page"), - NULL, - flags)); - - if (!g_object_class_find_property (gobject_class, "progress")) - g_object_class_install_property (gobject_class, - PROP_PROGRESS, - g_param_spec_double ( - "progress", - "Progress", - _("The current loading progress"), - 0.0, 1.0, 0.0, - G_PARAM_READABLE)); - - g_object_class_install_property (gobject_class, - PROP_MLOAD_STATUS, - g_param_spec_enum ( - "mload-status", - "Load Status", - _("The current loading status"), - MIDORI_TYPE_LOAD_STATUS, - MIDORI_LOAD_FINISHED, - G_PARAM_READABLE)); - - if (!g_object_class_find_property (gobject_class, "statusbar-text")) - 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"), - "", - G_PARAM_READABLE)); - - g_object_class_override_property (gobject_class, - PROP_SETTINGS, - "settings"); -} - -static void -webkit_web_view_load_started (MidoriWebView* web_view, - WebKitWebFrame* web_frame) -{ - web_view->window_object_cleared = FALSE; - - web_view->load_status = MIDORI_LOAD_PROVISIONAL; - g_object_notify (G_OBJECT (web_view), "mload-status"); - if (web_view->tab_icon) - katze_throbber_set_animated (KATZE_THROBBER (web_view->tab_icon), TRUE); - - web_view->progress = 0.0; - g_object_notify (G_OBJECT (web_view), "progress"); -} - -static void -webkit_web_view_window_object_cleared_cb (MidoriWebView* web_view, - WebKitWebFrame* web_frame, - JSGlobalContextRef js_context, - JSObjectRef js_window) -{ - web_view->window_object_cleared = TRUE; -} - -#if HAVE_GIO -void -loadable_icon_finish_cb (GdkPixbuf* icon, - GAsyncResult* res, - MidoriWebView* web_view) -{ - GInputStream* stream; - GdkPixbuf* pixbuf; - GdkPixbuf* pixbuf_scaled; - gint icon_width, icon_height; - - pixbuf = NULL; - stream = g_loadable_icon_load_finish (G_LOADABLE_ICON (icon), - res, NULL, NULL); - if (stream) - { - pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, NULL); - g_object_unref (stream); - } - if (!pixbuf) - pixbuf = gtk_widget_render_icon (GTK_WIDGET (web_view), - GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); - - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height); - pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height, - GDK_INTERP_BILINEAR); - g_object_unref (pixbuf); - web_view->icon = pixbuf_scaled; - g_signal_emit (web_view, signals[ICON_READY], 0, web_view->icon); -} - -void -file_info_finish_cb (GFile* icon_file, - GAsyncResult* res, - MidoriWebView* web_view) -{ - GFileInfo* info; - const gchar* content_type; - GIcon* icon; - GFile* parent; - GFile* file; - GdkPixbuf* pixbuf; - gint icon_width, icon_height; - GdkPixbuf* pixbuf_scaled; - - info = g_file_query_info_finish (G_FILE (icon_file), res, NULL); - if (info) - { - content_type = g_file_info_get_content_type (info); - if (g_str_has_prefix (content_type, "image/")) - { - icon = g_file_icon_new (icon_file); - g_loadable_icon_load_async (G_LOADABLE_ICON (icon), - 0, NULL, (GAsyncReadyCallback)loadable_icon_finish_cb, web_view); - return; - } - } - - file = g_file_get_parent (icon_file); - parent = g_file_get_parent (file); - /* We need to check if file equals the parent due to a GIO bug */ - if (parent && !g_file_equal (file, parent)) - { - icon_file = g_file_get_child (parent, "favicon.ico"); - g_file_query_info_async (icon_file, - G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, - G_FILE_QUERY_INFO_NONE, 0, NULL, - (GAsyncReadyCallback)file_info_finish_cb, web_view); - return; - } - - pixbuf = gtk_widget_render_icon (GTK_WIDGET (web_view), - GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height); - pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height, - GDK_INTERP_BILINEAR); - g_object_unref (pixbuf); - - web_view->icon = pixbuf_scaled; - g_signal_emit (web_view, signals[ICON_READY], 0, web_view->icon); -} -#endif - -static void -_midori_web_view_load_icon (MidoriWebView* web_view) -{ - #if HAVE_GIO - GFile* file; - GFile* icon_file; - #endif - GdkPixbuf* pixbuf; - gint icon_width, icon_height; - GdkPixbuf* pixbuf_scaled; - - #if HAVE_GIO - if (web_view->uri) - { - file = g_file_new_for_uri (web_view->uri); - icon_file = g_file_get_child (file, "favicon.ico"); - g_file_query_info_async (icon_file, - G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, - G_FILE_QUERY_INFO_NONE, 0, NULL, - (GAsyncReadyCallback)file_info_finish_cb, web_view); - return; - } - #endif - - pixbuf = gtk_widget_render_icon (GTK_WIDGET (web_view), - GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height); - pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, icon_width, icon_height, - GDK_INTERP_BILINEAR); - g_object_unref (pixbuf); - - web_view->icon = pixbuf_scaled; - g_signal_emit (web_view, signals[ICON_READY], 0, web_view->icon); -} - -static void -webkit_web_view_load_committed (MidoriWebView* web_view, - WebKitWebFrame* web_frame) -{ - const gchar* uri; - GdkPixbuf* icon; - - uri = webkit_web_frame_get_uri (web_frame); - katze_assign (web_view->uri, g_strdup (uri)); - if (web_view->xbel_item) - { - uri = midori_web_view_get_display_uri (web_view); - katze_xbel_bookmark_set_href (web_view->xbel_item, uri); - } - g_object_notify (G_OBJECT (web_view), "uri"); - g_object_set (web_view, "title", NULL, NULL); - - icon = gtk_widget_render_icon (GTK_WIDGET (web_view), - GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); - katze_object_assign (web_view->icon, icon); - _midori_web_view_load_icon (web_view); - - if (web_view->tab_icon) - katze_throbber_set_static_pixbuf (KATZE_THROBBER (web_view->tab_icon), - icon); - - if (web_view->menu_item) - gtk_image_menu_item_set_image ( - GTK_IMAGE_MENU_ITEM (web_view->menu_item), - gtk_image_new_from_pixbuf (icon)); - - web_view->load_status = MIDORI_LOAD_COMMITTED; - g_object_notify (G_OBJECT (web_view), "mload-status"); -} - -static void -webkit_web_view_icon_ready (MidoriWebView* web_view, - GdkPixbuf* icon) -{ - if (web_view->tab_icon) - katze_throbber_set_static_pixbuf (KATZE_THROBBER (web_view->tab_icon), - icon); - if (web_view->menu_item) - gtk_image_menu_item_set_image ( - GTK_IMAGE_MENU_ITEM (web_view->menu_item), - gtk_image_new_from_pixbuf (icon)); -} - -static void -webkit_web_view_progress_changed (MidoriWebView* web_view, gint progress) -{ - web_view->progress = progress ? progress / 100.0 : 0.0; - g_object_notify (G_OBJECT (web_view), "progress"); -} - -static void -gjs_value_links_foreach_cb (GjsValue* link, - MidoriWebView* web_view) -{ - const gchar* type; -#if HAVE_GIO - const gchar* rel; - GFile* icon_file; - GIcon* icon; -#endif - - if (gjs_value_is_object (link) && gjs_value_has_attribute (link, "href")) - { - if (gjs_value_has_attribute (link, "type")) - { - type = gjs_value_get_attribute_string (link, "type"); - if (!strcmp (type, "application/rss+xml") - || !strcmp (type, "application/x.atom+xml") - || !strcmp (type, "application/atom+xml")) - { - katze_array_add_item (web_view->news_feeds, link); - g_signal_emit (web_view, signals[NEWS_FEED_READY], 0, - gjs_value_get_attribute_string (link, "href"), type, - gjs_value_has_attribute (link, "title") - ? gjs_value_get_attribute_string (link, "title") : NULL); - } - } -#if HAVE_GIO - if (gjs_value_has_attribute (link, "rel")) - { - rel = gjs_value_get_attribute_string (link, "rel"); - if (!strcmp (rel, "icon") || !strcmp (rel, "shortcut icon")) - { - icon_file = g_file_new_for_uri ( - gjs_value_get_attribute_string (link, "href")); - icon = g_file_icon_new (icon_file); - g_loadable_icon_load_async (G_LOADABLE_ICON (icon), - 0, NULL, (GAsyncReadyCallback)loadable_icon_finish_cb, web_view); - } - } -#endif - } -} - -static void -webkit_web_frame_load_done (WebKitWebFrame* web_frame, - gboolean success, - MidoriWebView* web_view) -{ - JSContextRef js_context; - JSValueRef js_window; - GjsValue* value; - GjsValue* document; - GjsValue* links; - - /* If WebKit didn't emit the signal due to a bug, we will */ - if (!web_view->window_object_cleared) - { - js_context = webkit_web_frame_get_global_context (web_frame); - js_window = JSContextGetGlobalObject (js_context); - g_signal_emit_by_name (web_view, "window-object-cleared", - web_frame, js_context, js_window); - } - - value = gjs_value_new (webkit_web_frame_get_global_context (web_frame), NULL); - document = gjs_value_get_by_name (value, "document"); - links = gjs_value_get_elements_by_tag_name (document, "link"); - katze_array_clear (web_view->news_feeds); - gjs_value_foreach (links, (GjsCallback)gjs_value_links_foreach_cb, web_view); - g_object_unref (links); - g_object_unref (document); - g_object_unref (value); - - if (web_view->tab_icon) - katze_throbber_set_animated (KATZE_THROBBER (web_view->tab_icon), - FALSE); - web_view->load_status = MIDORI_LOAD_FINISHED; - g_object_notify (G_OBJECT (web_view), "mload-status"); -} - -static void -webkit_web_view_load_finished (MidoriWebView* web_view) -{ - web_view->progress = 1.0; - g_object_notify (G_OBJECT (web_view), "progress"); -} - -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) -{ - katze_assign (web_view->statusbar_text, g_strdup (text)); - g_object_notify (G_OBJECT (web_view), "statusbar-text"); -} - -static void -webkit_web_view_hovering_over_link (MidoriWebView* web_view, - const gchar* tooltip, - const gchar* link_uri) -{ - katze_assign (web_view->link_uri, g_strdup (link_uri)); - g_signal_emit (web_view, signals[ELEMENT_MOTION], 0, link_uri); -} - -static gboolean -gtk_widget_button_press_event_after (MidoriWebView* web_view, - GdkEventButton* event) -{ - GdkModifierType state; - GtkClipboard* clipboard; - gchar* uri; - gchar* new_uri; - - if (event->button == 2 && sokoke_object_get_boolean - (web_view->settings, "middle-click-opens-selection")) - { - state = (GdkModifierType) event->state; - clipboard = gtk_clipboard_get_for_display ( - gtk_widget_get_display (GTK_WIDGET (web_view)), - GDK_SELECTION_PRIMARY); - uri = gtk_clipboard_wait_for_text (clipboard); - if (uri && strchr (uri, '.') && !strchr (uri, ' ')) - { - new_uri = sokoke_magic_uri (uri, NULL); - if (state & GDK_CONTROL_MASK) - g_signal_emit (web_view, signals[NEW_TAB], 0, new_uri); - else - { - g_object_set (web_view, "uri", new_uri, NULL); - gtk_widget_grab_focus (GTK_WIDGET (web_view)); - } - g_free (new_uri); - g_free (uri); - return TRUE; - } - } - return FALSE; -} - -static gboolean -gtk_widget_button_release_event (MidoriWebView* web_view, - GdkEventButton* event) -{ - GtkClipboard* clipboard; - gchar* text; - - /* Emulate the primary clipboard, which WebKit doesn't support */ - text = webkit_web_view_get_selected_text (WEBKIT_WEB_VIEW (web_view)); - clipboard = gtk_clipboard_get_for_display ( - gtk_widget_get_display (GTK_WIDGET (web_view)), GDK_SELECTION_PRIMARY); - gtk_clipboard_set_text (clipboard, text, -1); - g_free (text); - 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) - { - if (event->direction == GDK_SCROLL_DOWN) - webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view)); - else if(event->direction == GDK_SCROLL_UP) - webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view)); - return TRUE; - } - else - return FALSE; -} - -static void -midori_web_view_menu_new_tab_activate_cb (GtkWidget* widget, - MidoriWebView* web_view) -{ - const gchar* uri = g_object_get_data (G_OBJECT (widget), "uri"); - g_signal_emit (web_view, signals[NEW_TAB], 0, uri); -} - -static void -midori_web_view_menu_new_window_activate_cb (GtkWidget* widget, - MidoriWebView* web_view) -{ - const gchar* uri = g_object_get_data (G_OBJECT (widget), "uri"); - g_signal_emit (web_view, signals[NEW_WINDOW], 0, uri); -} - -static void -midori_web_view_menu_download_activate_cb (GtkWidget* widget, - MidoriWebView* web_view) -{ - gchar* program; - const gchar* uri; - - g_object_get (web_view->settings, "download-manager", &program, NULL); - uri = g_object_get_data (G_OBJECT (widget), "uri"); - sokoke_spawn_program (program, uri); - g_free (program); -} - -static void -webkit_web_view_populate_popup_cb (GtkWidget* web_view, - GtkWidget* menu) -{ - const gchar* uri; - GtkWidget* menuitem; - GdkScreen* screen; - GtkIconTheme* icon_theme; - GtkWidget* icon; - gchar* text; - GList* items; - gchar* program; - - uri = midori_web_view_get_link_uri (MIDORI_WEB_VIEW (web_view)); - if (uri) - { - menuitem = gtk_image_menu_item_new_with_mnemonic ( - _("Open Link in New _Tab")); - screen = gtk_widget_get_screen (web_view); - icon_theme = gtk_icon_theme_get_for_screen (screen); - if (gtk_icon_theme_has_icon (icon_theme, STOCK_TAB_NEW)) - { - icon = gtk_image_new_from_stock (STOCK_TAB_NEW, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); - } - gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 1); - g_object_set_data (G_OBJECT (menuitem), "uri", (gchar*)uri); - g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), web_view); - gtk_widget_show (menuitem); - /* hack to implement New Window */ - items = gtk_container_get_children (GTK_CONTAINER (menu)); - menuitem = (GtkWidget*)g_list_nth_data (items, 2); - g_object_set_data (G_OBJECT (menuitem), "uri", (gchar*)uri); - g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_web_view_menu_new_window_activate_cb), web_view); - menuitem = (GtkWidget*)g_list_nth_data (items, 3); - /* hack to disable non-functional Download File */ - gtk_widget_set_sensitive (menuitem, FALSE); - g_list_free (items); - g_object_get (MIDORI_WEB_VIEW (web_view)->settings, - "download-manager", &program, NULL); - if (program && *program) - { - menuitem = gtk_image_menu_item_new_with_mnemonic ( - _("Download Link with Download _Manager")); - icon = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, - GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); - gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, 4); - g_object_set_data (G_OBJECT (menuitem), "uri", (gchar*)uri); - g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_web_view_menu_download_activate_cb), web_view); - gtk_widget_show (menuitem); - } - } - - if (!uri && midori_web_view_has_selection (MIDORI_WEB_VIEW (web_view))) - { - text = webkit_web_view_get_selected_text (WEBKIT_WEB_VIEW (web_view)); - if (text && strchr (text, '.') && !strchr (text, ' ')) - { - menuitem = gtk_image_menu_item_new_with_mnemonic ( - _("Open URL in New _Tab")); - icon = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, - GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); - gtk_menu_shell_insert (GTK_MENU_SHELL (menu), menuitem, -1); - g_object_set_data (G_OBJECT (menuitem), "uri", text); - g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_web_view_menu_new_tab_activate_cb), web_view); - gtk_widget_show (menuitem); - } - /* text should be const, but it is allocated, so we must free it */ - g_free (text); - } -} - -static void -midori_web_view_init (MidoriWebView* web_view) -{ - web_view->icon = gtk_widget_render_icon (GTK_WIDGET (web_view), - GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); - web_view->progress = 0.0; - web_view->load_status = MIDORI_LOAD_FINISHED; - web_view->news_feeds = katze_array_new (GJS_TYPE_VALUE); - - web_view->settings = midori_web_settings_new (); - g_object_set (web_view, "WebKitWebView::settings", web_view->settings, NULL); - - 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::window-object-cleared", - webkit_web_view_window_object_cleared_cb, NULL, - "signal::load-committed", - webkit_web_view_load_committed, NULL, - "signal::icon-ready", - webkit_web_view_icon_ready, NULL, - "signal::load-progress-changed", - webkit_web_view_progress_changed, NULL, - "signal::load-finished", - webkit_web_view_load_finished, 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_after, NULL, - "signal::button-release-event", - gtk_widget_button_release_event, NULL, - "signal::scroll-event", - gtk_widget_scroll_event, NULL, - "signal::populate-popup", - webkit_web_view_populate_popup_cb, NULL, - 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; - WebKitWebFrame* web_frame; - - web_view = MIDORI_WEB_VIEW (object); - - if (web_view->icon) - g_object_unref (web_view->icon); - g_free (web_view->uri); - g_free (web_view->title); - g_free (web_view->statusbar_text); - g_free (web_view->link_uri); - g_object_unref (web_view->news_feeds); - - if (web_view->settings) - g_object_unref (web_view->settings); - - if (web_view->xbel_item) - katze_xbel_item_unref (web_view->xbel_item); - - web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view)); - g_signal_handlers_disconnect_by_func (web_frame, - webkit_web_frame_load_done, web_view); - - 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); - - switch (prop_id) - { - case PROP_URI: - { - const gchar* uri = g_value_get_string (value); - if (uri && *uri) - webkit_web_view_open (WEBKIT_WEB_VIEW (web_view), uri); - break; - } - case PROP_TITLE: - katze_assign (web_view->title, g_value_dup_string (value)); - const gchar* title = midori_web_view_get_display_title (web_view); - if (web_view->tab_title) - { - gtk_label_set_text (GTK_LABEL (web_view->tab_title), title); - gtk_widget_set_tooltip_text (web_view->tab_title, title); - } - if (web_view->menu_item) - gtk_label_set_text (GTK_LABEL (gtk_bin_get_child (GTK_BIN ( - web_view->menu_item))), title); - if (web_view->xbel_item) - katze_xbel_item_set_title (web_view->xbel_item, title); - break; - case PROP_SETTINGS: - katze_object_assign (web_view->settings, g_value_get_object (value)); - g_object_ref (web_view->settings); - g_object_set (object, "WebKitWebView::settings", web_view->settings, NULL); - 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); - - switch (prop_id) - { - case PROP_URI: - g_value_set_string (value, web_view->uri); - break; - case PROP_TITLE: - g_value_set_string (value, web_view->title); - break; - case PROP_PROGRESS: - g_value_set_double (value, web_view->progress); - break; - case PROP_MLOAD_STATUS: - g_value_set_enum (value, web_view->load_status); - break; - case PROP_STATUSBAR_TEXT: - g_value_set_string (value, web_view->statusbar_text); - break; - case PROP_SETTINGS: - g_value_set_object (value, web_view->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_set_settings: - * @web_view: a #MidoriWebView - * @web_settings: a #MidoriWebSettings - * - * Assigns a settings instance to the web view. - **/ -void -midori_web_view_set_settings (MidoriWebView* web_view, - MidoriWebSettings* web_settings) -{ - g_object_set (web_view, "settings", web_settings, NULL); -} - -/** - * 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) -{ - const gchar* title; - - g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), FALSE); - - if (!web_view->menu_item) - { - title = midori_web_view_get_display_title (web_view); - web_view->menu_item = sokoke_image_menu_item_new_ellipsized (title); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (web_view->menu_item), - gtk_image_new_from_pixbuf (web_view->icon)); - - g_signal_connect (web_view->menu_item, "destroy", - G_CALLBACK (gtk_widget_destroyed), - &web_view->menu_item); - } - return web_view->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); - - if (!web_view->tab_icon) - { - web_view->tab_icon = katze_throbber_new (); - katze_throbber_set_static_pixbuf (KATZE_THROBBER (web_view->tab_icon), - web_view->icon); - - g_signal_connect (web_view->tab_icon, "destroy", - G_CALLBACK (gtk_widget_destroyed), - &web_view->tab_icon); - } - return web_view->tab_icon; -} - -/** - * midori_web_view_get_proxy_tab_title: - * @web_view: a #MidoriWebView - * - * Retrieves a proxy tab title that is typically used as the label - * of a #GtkNotebook page. - * - * The title is created on the first call and will be updated to - * reflect changes automatically. - * - * Return value: the proxy #GtkLabel - **/ -GtkWidget* -midori_web_view_get_proxy_tab_title (MidoriWebView* web_view) -{ - const gchar* title; - - g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL); - - if (!web_view->tab_title) - { - title = midori_web_view_get_display_title (web_view); - web_view->tab_title = gtk_label_new (title); - - g_signal_connect (web_view->tab_title, "destroy", - G_CALLBACK (gtk_widget_destroyed), - &web_view->tab_title); - } - return web_view->tab_title; -} - -/** - * 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) -{ - const gchar* uri; - const gchar* title; - - g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL); - - if (!web_view->xbel_item) - { - web_view->xbel_item = katze_xbel_bookmark_new (); - uri = midori_web_view_get_display_uri (web_view); - katze_xbel_bookmark_set_href (web_view->xbel_item, uri); - title = midori_web_view_get_display_title (web_view); - katze_xbel_item_set_title (web_view->xbel_item, title); - } - return web_view->xbel_item; -} - -/** - * midori_web_view_load_status: - * @web_view: a #MidoriWebView - * - * Determines the current loading status of a page. - * - * Return value: the current #MidoriLoadStatus - **/ -MidoriLoadStatus -midori_web_view_get_load_status (MidoriWebView* web_view) -{ - g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), MIDORI_LOAD_FINISHED); - - return web_view->load_status; -} - -/** - * midori_web_view_get_progress: - * @web_view: a #MidoriWebView - * - * Retrieves the current loading progress as - * a fraction between 0.0 and 1.0. - * - * Return value: the current loading progress - **/ -gdouble -midori_web_view_get_progress (MidoriWebView* web_view) -{ - g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), 0.0); - - return web_view->progress; -} - -/** - * midori_web_view_get_display_uri: - * @web_view: a #MidoriWebView - * - * Retrieves a string that is suitable for displaying, particularly an - * empty URI is represented as "". - * - * 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), ""); - - return web_view->uri ? web_view->uri : ""; -} - -/** - * 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"); - - if (web_view->title) - return web_view->title; - if (web_view->uri) - return web_view->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); - - return web_view->link_uri; -} - -/** - * midori_web_view_get_news_feeds: - * @web_view: a #MidoriWebView - * - * Retrieves a list of news feeds for the current page - * or %NULL if there are no feeds at all. - * - * Return value: a #KatzeArray, or %NULL - **/ -KatzeArray* -midori_web_view_get_news_feeds (MidoriWebView* web_view) -{ - g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), NULL); - - if (!katze_array_is_empty (web_view->news_feeds)) - return web_view->news_feeds; - return NULL; -} - -/** - * midori_web_view_has_selection: - * @web_view: a #MidoriWebView - * - * Determines whether something on the page is selected. - * - * By contrast to webkit_web_view_has_selection() this - * returns %FALSE if there is a selection that - * effectively only consists of whitespace. - * - * Return value: %TRUE if effectively there is a selection - **/ -gboolean -midori_web_view_has_selection (MidoriWebView* web_view) -{ - gchar* text; - - g_return_val_if_fail (MIDORI_IS_WEB_VIEW (web_view), FALSE); - - text = webkit_web_view_get_selected_text (WEBKIT_WEB_VIEW (web_view)); - if (text && *text) - { - g_free (text); - return TRUE; - } - g_free (text); - return FALSE; -} diff --git a/midori/midori-webview.h b/midori/midori-webview.h deleted file mode 100644 index 8773c1e4..00000000 --- a/midori/midori-webview.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - 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 "midori-websettings.h" - -#include -#include - -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 _MidoriWebViewClass MidoriWebViewClass; - -struct _MidoriWebViewClass -{ - WebKitWebViewClass parent_class; - - /* Signals */ - void - (*icon_ready) (MidoriWebView* web_view, - GdkPixbuf* icon); - void - (*news_feed_ready) (MidoriWebView* web_view, - const gchar* href, - const gchar* type, - const gchar* title); - void - (*load_done) (MidoriWebView* web_view, - WebKitWebFrame* frame); - 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); -}; - -typedef enum -{ - MIDORI_LOAD_PROVISIONAL, - MIDORI_LOAD_COMMITTED, - MIDORI_LOAD_FINISHED -} MidoriLoadStatus; - -GType -midori_load_status_get_type (void) G_GNUC_CONST; - -#define MIDORI_TYPE_LOAD_STATUS \ - (midori_load_status_get_type ()) - -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_icon (MidoriWebView* web_view); - -GtkWidget* -midori_web_view_get_proxy_tab_title (MidoriWebView* web_view); - -KatzeXbelItem* -midori_web_view_get_proxy_xbel_item (MidoriWebView* web_view); - -gdouble -midori_web_view_get_progress (MidoriWebView* web_view); - -MidoriLoadStatus -midori_web_view_get_load_status (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); - -KatzeArray* -midori_web_view_get_news_feeds (MidoriWebView* web_view); - -gboolean -midori_web_view_has_selection (MidoriWebView* web_view); - -G_END_DECLS - -#endif /* __MIDORI_WEB_VIEW_H__ */ diff --git a/midori/sokoke.c b/midori/sokoke.c index 9af538b5..4efd01c8 100644 --- a/midori/sokoke.c +++ b/midori/sokoke.c @@ -24,6 +24,32 @@ #include #include +/** + * sokoke_remember_argv0: + * @argv0: the contents of argv[0] or %NULL + * + * Stores or retrieves the value of argv[0]. + * + * Call it with a string for argv0 to store. + * + * Passing %NULL for argv0 will preserve + * a previously stored value. + * + * Return value: the contents of argv[0] or %NULL + **/ +const gchar* +sokoke_remember_argv0 (const gchar* argv0) +{ + static const gchar* remembered_argv0 = NULL; + + if (argv0) + remembered_argv0 = argv0; + + g_return_val_if_fail (remembered_argv0 != NULL, NULL); + + return remembered_argv0; +} + static void error_dialog (const gchar* short_message, const gchar* detailed_message) @@ -260,9 +286,10 @@ sokoke_widget_popup (GtkWidget* widget, event_time = gtk_get_current_event_time (); } - if (!gtk_menu_get_attach_widget(menu)) + if (!gtk_menu_get_attach_widget (menu)) gtk_menu_attach_to_widget (menu, widget, NULL); + if (widget) { SokokePopupInfo info = { widget, pos }; @@ -350,7 +377,7 @@ sokoke_superuser_warning_new (void) gtk_widget_modify_fg (GTK_WIDGET (label), GTK_STATE_NORMAL, >K_WIDGET (label)->style->fg[GTK_STATE_SELECTED]); gtk_widget_show (label); - gtk_container_add (GTK_CONTAINER(hbox), GTK_WIDGET (label)); + gtk_container_add (GTK_CONTAINER (hbox), GTK_WIDGET (label)); gtk_widget_show (hbox); return hbox; } @@ -399,7 +426,7 @@ sokoke_on_entry_focus_in_event (GtkEntry* entry, if (has_default) { gtk_entry_set_text (entry, ""); - g_object_set_data (G_OBJECT(entry), "sokoke_has_default", + g_object_set_data (G_OBJECT (entry), "sokoke_has_default", GINT_TO_POINTER (0)); sokoke_widget_set_pango_font_style (GTK_WIDGET (entry), PANGO_STYLE_NORMAL); @@ -418,7 +445,7 @@ sokoke_on_entry_focus_out_event (GtkEntry* entry, const gchar* default_text = (const gchar*)g_object_get_data ( G_OBJECT (entry), "sokoke_default_text"); gtk_entry_set_text (entry, default_text); - g_object_set_data (G_OBJECT(entry), + g_object_set_data (G_OBJECT (entry), "sokoke_has_default", GINT_TO_POINTER (1)); sokoke_widget_set_pango_font_style (GTK_WIDGET (entry), PANGO_STYLE_ITALIC); diff --git a/midori/sokoke.h b/midori/sokoke.h index c40ba2bd..46edc48e 100644 --- a/midori/sokoke.h +++ b/midori/sokoke.h @@ -19,6 +19,9 @@ /* Many themes need this hack for small toolbars to work */ #define GTK_ICON_SIZE_SMALL_TOOLBAR GTK_ICON_SIZE_BUTTON +const gchar* +sokoke_remember_argv0 (const gchar* argv0); + gboolean sokoke_spawn_program (const gchar* command, const gchar* argument);