diff --git a/katze/katze-net.c b/katze/katze-net.c index c4cdbaea..d781b9b8 100644 --- a/katze/katze-net.c +++ b/katze/katze-net.c @@ -27,7 +27,6 @@ struct _KatzeNet { GObject parent_instance; - GHashTable* memory; gchar* cache_path; guint cache_size; @@ -53,18 +52,9 @@ katze_net_class_init (KatzeNetClass* class) gobject_class->finalize = katze_net_finalize; } -static void -katze_net_object_maybe_unref (gpointer object) -{ - if (object) - g_object_unref (object); -} - static void katze_net_init (KatzeNet* net) { - net->memory = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, katze_net_object_maybe_unref); net->cache_path = g_build_filename (g_get_user_cache_dir (), PACKAGE_NAME, NULL); @@ -76,7 +66,6 @@ katze_net_finalize (GObject* object) { KatzeNet* net = KATZE_NET (object); - g_hash_table_destroy (net->memory); katze_assign (net->cache_path, NULL); G_OBJECT_CLASS (katze_net_parent_class)->finalize (object); @@ -147,7 +136,7 @@ katze_net_priv_free (KatzeNetPriv* priv) g_free (priv); } -static gchar* +gchar* katze_net_get_cached_path (KatzeNet* net, const gchar* uri, const gchar* subfolder) @@ -383,242 +372,3 @@ katze_net_load_uri (KatzeNet* net, g_idle_add ((GSourceFunc)katze_net_default_cb, priv); } -typedef struct -{ - KatzeNet* net; - gchar* icon_file; - KatzeNetIconCb icon_cb; - GtkWidget* widget; - gpointer user_data; -} KatzeNetIconPriv; - -static void -katze_net_icon_priv_free (KatzeNetIconPriv* priv) -{ - g_free (priv->icon_file); - if (priv->widget) - g_object_unref (priv->widget); - g_free (priv); -} - -static gboolean -katze_net_icon_status_cb (KatzeNetRequest* request, - KatzeNetIconPriv* priv) -{ - switch (request->status) - { - case KATZE_NET_VERIFIED: - if (request->mime_type && - !g_str_has_prefix (request->mime_type, "image/")) - { - katze_net_icon_priv_free (priv); - return FALSE; - } - break; - case KATZE_NET_MOVED: - break; - default: - katze_net_icon_priv_free (priv); - return FALSE; - } - - return TRUE; -} - -static void -katze_net_icon_transfer_cb (KatzeNetRequest* request, - KatzeNetIconPriv* priv) -{ - GdkPixbuf* pixbuf; - FILE* fp; - GdkPixbuf* pixbuf_scaled; - gint icon_width, icon_height; - size_t ret; - GtkSettings* settings; - - if (request->status == KATZE_NET_MOVED) - return; - - pixbuf = NULL; - if (request->data) - { - if ((fp = fopen (priv->icon_file, "wb"))) - { - ret = fwrite (request->data, 1, request->length, fp); - fclose (fp); - if ((ret - request->length) != 0) - { - g_warning ("Error writing to file %s " - "in katze_net_icon_transfer_cb()", priv->icon_file); - } - pixbuf = gdk_pixbuf_new_from_file (priv->icon_file, NULL); - } - else - pixbuf = katze_pixbuf_new_from_buffer ((guchar*)request->data, - request->length, request->mime_type, NULL); - if (pixbuf) - g_object_ref (pixbuf); - g_hash_table_insert (priv->net->memory, - g_strdup (priv->icon_file), pixbuf); - } - - if (!priv->icon_cb) - { - katze_net_icon_priv_free (priv); - return; - } - - if (!pixbuf) - { - if (priv->widget) - pixbuf = gtk_widget_render_icon (priv->widget, - GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); - else - { - priv->icon_cb (NULL, priv->user_data); - katze_net_icon_priv_free (priv); - return; - } - } - - if (priv->widget) - settings = gtk_widget_get_settings (priv->widget); - else - settings = gtk_settings_get_for_screen (gdk_screen_get_default ()); - - gtk_icon_size_lookup_for_settings (settings, 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); - - priv->icon_cb (pixbuf_scaled, priv->user_data); - katze_net_icon_priv_free (priv); -} - -/** - * katze_net_load_icon: - * @net: a #KatzeNet - * @uri: an URI string, or %NULL - * @icon_cb: function to call upon completion - * @widget: a related #GtkWidget, or %NULL - * @user_data: data to pass to the callback - * - * Requests a transfer of an icon for @uri. This is - * implemented by looking for a favicon.ico, an - * image according to the file type or even a - * generated icon. The provided icon is intended - * for user interfaces and not guaranteed to be - * the same over multiple requests, plus it may - * be scaled to fit the menu icon size. - * - * Pass a valid #GtkWidget to @widget if you want - * a themed default icon in case of a missing icon, - * otherwise %NULL will be returned in that case. - * - * The caller is expected to use the returned icon - * and update it if @icon_cb is called. - * - * Depending on whether the icon was previously - * cached or @uri is a local resource, the returned - * icon may already be the final one. - * - * Note that both the returned #GdkPixbuf and the - * icon passed to @icon_cb are newly allocated and - * the caller owns the reference. - * - * Since 0.1.2 @widget can be %NULL. - * - * Return value: a #GdkPixbuf, or %NULL - **/ -GdkPixbuf* -katze_net_load_icon (KatzeNet* net, - const gchar* uri, - KatzeNetIconCb icon_cb, - GtkWidget* widget, - gpointer user_data) -{ - KatzeNetIconPriv* priv; - gchar* icon_uri; - gchar* icon_file; - GdkPixbuf* pixbuf; - gint icon_width, icon_height; - GdkPixbuf* pixbuf_scaled; - GtkSettings* settings; - - g_return_val_if_fail (KATZE_IS_NET (net), NULL); - g_return_val_if_fail (!widget || GTK_IS_WIDGET (widget), NULL); - g_return_val_if_fail (uri != NULL, NULL); - - pixbuf = NULL; - icon_uri = g_strdup (g_object_get_data (G_OBJECT (net), uri)); - g_object_set_data (G_OBJECT (net), uri, NULL); - if ((icon_uri && g_str_has_prefix (icon_uri, "http")) - || g_str_has_prefix (uri, "http")) - { - if (!icon_uri) - { - guint i = 8; - while (uri[i] != '\0' && uri[i] != '/') - i++; - if (uri[i] == '/') - { - icon_uri = g_strdup (uri); - icon_uri[i] = '\0'; - icon_uri = g_strdup_printf ("%s/favicon.ico", icon_uri); - } - else - icon_uri = g_strdup_printf ("%s/favicon.ico", uri); - } - - icon_file = katze_net_get_cached_path (net, icon_uri, "icons"); - - if (g_hash_table_lookup_extended (net->memory, - icon_file, NULL, (gpointer)&pixbuf)) - { - g_free (icon_file); - if (pixbuf) - g_object_ref (pixbuf); - } - else if ((pixbuf = gdk_pixbuf_new_from_file (icon_file, NULL))) - g_free (icon_file); - /* If the called doesn't provide an icon callback, - we assume there is no interest in loading an un-cached icon. */ - else if (icon_cb) - { - priv = g_new0 (KatzeNetIconPriv, 1); - priv->net = net; - priv->icon_file = icon_file; - priv->icon_cb = icon_cb; - priv->widget = widget ? g_object_ref (widget) : NULL; - priv->user_data = user_data; - - katze_net_load_uri (net, icon_uri, - (KatzeNetStatusCb)katze_net_icon_status_cb, - (KatzeNetTransferCb)katze_net_icon_transfer_cb, priv); - } - g_free (icon_uri); - } - - if (!pixbuf) - { - if (widget) - pixbuf = gtk_widget_render_icon (widget, - GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); - else - return NULL; - } - - if (widget) - settings = gtk_widget_get_settings (widget); - else - settings = gtk_settings_get_for_screen (gdk_screen_get_default ()); - - gtk_icon_size_lookup_for_settings (settings, 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); - - return pixbuf_scaled; -} diff --git a/katze/katze-net.h b/katze/katze-net.h index d57a74b0..f26a0ce1 100644 --- a/katze/katze-net.h +++ b/katze/katze-net.h @@ -74,15 +74,10 @@ katze_net_load_uri (KatzeNet* net, KatzeNetTransferCb transfer_cb, gpointer user_data); -typedef void (*KatzeNetIconCb) (GdkPixbuf* icon, - gpointer user_data); - -GdkPixbuf* -katze_net_load_icon (KatzeNet* net, +gchar* +katze_net_get_cached_path (KatzeNet* net, const gchar* uri, - KatzeNetIconCb icon_cb, - GtkWidget* widget, - gpointer user_data); + const gchar* subfolder); G_END_DECLS diff --git a/midori/midori-view.c b/midori/midori-view.c index 917ccb3a..b6883bcb 100644 --- a/midori/midori-view.c +++ b/midori/midori-view.c @@ -67,6 +67,7 @@ struct _MidoriView gchar* title; gchar* mime_type; GdkPixbuf* icon; + gchar* icon_uri; gdouble progress; MidoriLoadStatus load_status; gboolean minimized; @@ -103,6 +104,7 @@ struct _MidoriView gboolean back_forward_set; KatzeNet* net; + GHashTable* memory; }; struct _MidoriViewClass @@ -713,11 +715,184 @@ midori_view_icon_cb (GdkPixbuf* icon, midori_view_update_icon (view, icon); } +typedef void (*KatzeNetIconCb) (GdkPixbuf* icon, + MidoriView* view); + +typedef struct +{ + gchar* icon_file; + KatzeNetIconCb icon_cb; + MidoriView* view; + gpointer user_data; +} KatzeNetIconPriv; + +void +katze_net_icon_priv_free (KatzeNetIconPriv* priv) +{ + g_free (priv->icon_file); + g_free (priv); +} + +gboolean +katze_net_icon_status_cb (KatzeNetRequest* request, + KatzeNetIconPriv* priv) +{ + switch (request->status) + { + case KATZE_NET_VERIFIED: + if (request->mime_type && + !g_str_has_prefix (request->mime_type, "image/")) + { + katze_net_icon_priv_free (priv); + return FALSE; + } + break; + case KATZE_NET_MOVED: + break; + default: + katze_net_icon_priv_free (priv); + return FALSE; + } + + return TRUE; +} + +void +katze_net_icon_transfer_cb (KatzeNetRequest* request, + KatzeNetIconPriv* priv) +{ + GdkPixbuf* pixbuf; + FILE* fp; + GdkPixbuf* pixbuf_scaled; + gint icon_width, icon_height; + size_t ret; + GtkSettings* settings; + + if (request->status == KATZE_NET_MOVED) + return; + + pixbuf = NULL; + if (request->data) + { + if ((fp = fopen (priv->icon_file, "wb"))) + { + ret = fwrite (request->data, 1, request->length, fp); + fclose (fp); + if ((ret - request->length) != 0) + { + g_warning ("Error writing to file %s " + "in katze_net_icon_transfer_cb()", priv->icon_file); + } + pixbuf = gdk_pixbuf_new_from_file (priv->icon_file, NULL); + } + else + pixbuf = katze_pixbuf_new_from_buffer ((guchar*)request->data, + request->length, request->mime_type, NULL); + if (pixbuf) + g_object_ref (pixbuf); + g_hash_table_insert (priv->view->memory, + g_strdup (priv->icon_file), pixbuf); + } + + if (!priv->icon_cb) + { + katze_net_icon_priv_free (priv); + return; + } + + if (!pixbuf) + { + priv->icon_cb (NULL, priv->user_data); + katze_net_icon_priv_free (priv); + return; + } + + settings = gtk_widget_get_settings (priv->view->web_view); + gtk_icon_size_lookup_for_settings (settings, 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); + + priv->icon_cb (pixbuf_scaled, priv->user_data); + katze_net_icon_priv_free (priv); +} + + static void _midori_web_view_load_icon (MidoriView* view) { - GdkPixbuf* pixbuf = katze_net_load_icon (view->net, view->uri, - (KatzeNetIconCb)midori_view_icon_cb, NULL, view); + GdkPixbuf* pixbuf; + KatzeNetIconPriv* priv; + gchar* icon_uri; + gchar* icon_file; + gint icon_width, icon_height; + GdkPixbuf* pixbuf_scaled; + GtkSettings* settings; + + pixbuf = NULL; + icon_uri = g_strdup (view->icon_uri); + + if ((icon_uri && g_str_has_prefix (icon_uri, "http")) + || g_str_has_prefix (view->uri, "http")) + { + if (!icon_uri) + { + guint i = 8; + while (view->uri[i] != '\0' && view->uri[i] != '/') + i++; + if (view->uri[i] == '/') + { + icon_uri = g_strdup (view->uri); + icon_uri[i] = '\0'; + icon_uri = g_strdup_printf ("%s/favicon.ico", icon_uri); + } + else + icon_uri = g_strdup_printf ("%s/favicon.ico", view->uri); + } + + icon_file = katze_net_get_cached_path (view->net, icon_uri, "icons"); + if (g_hash_table_lookup_extended (view->memory, + icon_file, NULL, (gpointer)&pixbuf)) + { + g_free (icon_file); + if (pixbuf) + { + g_object_ref (pixbuf); + katze_assign (view->icon_uri, icon_uri); + } + } + else if ((pixbuf = gdk_pixbuf_new_from_file (icon_file, NULL))) + { + g_free (icon_file); + katze_assign (view->icon_uri, icon_uri); + } + /* If the called doesn't provide an icon callback, + we assume there is no interest in loading an un-cached icon. */ + else + { + priv = g_new0 (KatzeNetIconPriv, 1); + priv->icon_file = icon_file; + priv->icon_cb = (KatzeNetIconCb)midori_view_icon_cb; + priv->view = view; + + katze_net_load_uri (view->net, icon_uri, + (KatzeNetStatusCb)katze_net_icon_status_cb, + (KatzeNetTransferCb)katze_net_icon_transfer_cb, priv); + g_free (icon_uri); + } + } + + if (pixbuf) + { + settings = gtk_widget_get_settings (view->web_view); + gtk_icon_size_lookup_for_settings (settings, 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); + pixbuf = pixbuf_scaled; + } midori_view_update_icon (view, pixbuf); } @@ -785,6 +960,7 @@ webkit_web_view_load_committed_cb (WebKitWebView* web_view, uri = webkit_web_frame_get_uri (web_frame); g_return_if_fail (uri != NULL); katze_assign (view->uri, sokoke_format_uri_for_display (uri)); + katze_assign (view->icon_uri, NULL); if (view->item) { #if 0 @@ -1100,8 +1276,7 @@ webkit_web_view_load_finished_cb (WebKitWebView* web_view, default_uri = g_strdup (parts[0]); } else - g_object_set_data_full (G_OBJECT (view->net), view->uri, - g_strdup (*parts), (GDestroyNotify)g_free); + katze_assign (view->icon_uri, g_strdup (*parts)); g_strfreev (parts); i++; @@ -2557,6 +2732,13 @@ midori_view_notify_vadjustment_cb (MidoriView* view, g_object_unref (vadjustment); } +void +katze_net_object_maybe_unref (gpointer object) +{ + if (object) + g_object_unref (object); +} + static void midori_view_init (MidoriView* view) { @@ -2564,6 +2746,9 @@ midori_view_init (MidoriView* view) view->title = NULL; view->mime_type = g_strdup (""); view->icon = NULL; + view->icon_uri = NULL; + view->memory = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, katze_net_object_maybe_unref); view->progress = 0.0; view->load_status = MIDORI_LOAD_FINISHED; view->minimized = FALSE; @@ -2611,6 +2796,8 @@ midori_view_finalize (GObject* object) katze_assign (view->uri, NULL); katze_assign (view->title, NULL); katze_object_assign (view->icon, NULL); + katze_assign (view->icon_uri, NULL); + g_hash_table_destroy (view->memory); katze_assign (view->statusbar_text, NULL); katze_assign (view->link_uri, NULL); katze_assign (view->selected_text, NULL); @@ -3401,11 +3588,13 @@ midori_view_is_blank (MidoriView* view) * midori_view_get_icon: * @view: a #MidoriView * - * Retrieves the icon of the view. + * Retrieves the icon of the view, or a default icon. See + * midori_view_get_icon_uri() if you need to distinguish + * the origin of an icon. * * The returned icon is owned by the @view and must not be modified. * - * Return value: a #GdkPixbuf + * Return value: a #GdkPixbuf, or %NULL **/ GdkPixbuf* midori_view_get_icon (MidoriView* view) @@ -3415,6 +3604,31 @@ midori_view_get_icon (MidoriView* view) return view->icon; } +/** + * midori_view_get_icon_uri: + * @view: a #MidoriView + * + * Retrieves the address of the icon of the view + * if the loaded website has an icon, otherwise + * %NULL. + * Note that if there is no icon uri, midori_view_get_icon() + * will still return a default icon. + * + * The returned string is owned by the @view and must not be freed. + * + * Return value: a string, or %NULL + * + * Since: 0.2.5 + **/ +const gchar* +midori_view_get_icon_uri (MidoriView* view) +{ + g_return_val_if_fail (MIDORI_IS_VIEW (view), NULL); + + return view->icon_uri; +} + + /** * midori_view_get_display_uri: * @view: a #MidoriView diff --git a/midori/midori-view.h b/midori/midori-view.h index d3fa0894..ca083b48 100644 --- a/midori/midori-view.h +++ b/midori/midori-view.h @@ -92,6 +92,9 @@ midori_view_get_display_title (MidoriView* view); GdkPixbuf* midori_view_get_icon (MidoriView* view); +const gchar* +midori_view_get_icon_uri (MidoriView* view); + const gchar* midori_view_get_link_uri (MidoriView* view);