Precis: This is the first issued review of Mark Benjamin's branch which implements favicon support for the browser core and the GTK frontend.
Added files Index: render/favicon.c =================================================================== --- /dev/null 2008-11-24 10:09:14.252162000 +0000 +++ render/favicon.c 2009-04-28 16:01:49.412080078 +0100 @@ -0,0 +1,370 @@ +/* + * Copyright 2007 James Bursa <[email protected]> + * Copyright 2009 Mark Benjamin <[email protected]> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include "content/fetch.h" +#include "content/fetchcache.h" +#include "render/favicon.h" +#include "render/html.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/talloc.h" +#include "utils/url.h" +#include "utils/utils.h" + +static char *html_get_icon_ref(struct content *c, xmlNode *html); +static void html_favicon_callback(content_msg msg, struct content *icon, + intptr_t p1, intptr_t p2, union content_msg_data data); +static unsigned long hash(char *str); + +unsigned long hash(char *str) +{ + if (str == NULL) + return 0; + unsigned long hash = 5381; + int c; + while ((c = (unsigned char) *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + return hash; +} + +/** + * retrieve 1 url reference to 1 favicon + * \param html xml node of html element + * \return pointer to url; NULL for no icon + */ +char *html_get_icon_ref(struct content *c, xmlNode *html) +{ + xmlNode *node; + char *rel, *type, *href, *url, *suf, *url2; + url2 = NULL; + url_func_result res; + int score, hiscore; + hiscore = 0; + /* hashed values - saves calculating them afresh every time */ + #define HHICON 0x7c98572e + /* icon */ + #define HHSHORTCUTICON 0xfcbccdca + /* shortcut icon */ + #define HHAPPLETOUCHICON 0x024c6ddd + /* apple-touch-icon */ + #define HHIMAGEPNG 0x7382417c + /* image/png */ + #define HHIMAGEGIF 0x73821a8d + /* image/gif */ + #define HHIMAGEVNDMICROSOFTICON 0xdae02bba + /* image.vnd.microsoft.icon */ + #define HHIMAGEJPEG 0xe3c72f5d + /* image/jpeg */ + #define HHIMAGEJPG 0x73822838 + /* image/jpg */ + #define HHIMAGEICO 0x73822252 + /* image/ico */ + #define HHIMAGEICON 0xe3c66d00 + /* image/icon */ + #define HHIMAGEXICON 0x0e3e78e5 + /* image/x-icon */ + #define HHTEXTICO 0x17e966a2 + /* text/icon */ + #define HHAPPLICATIONICO 0x087b6fb4 + /*application/icon*/ + #define HHSUFICO 0x0b887ec0 + /* ico */ + #define HHSUFPNG 0x0b889dea + /* png */ + #define HHSUFGIF 0x0b8876fb + /* gif */ + #define HHSUFJPG 0x0b888486 + /* jpg */ + #define HHSUFJPEG 0x7c99198b + /* jpeg */ + + union content_msg_data msg_data; + + node = html; + while (node) { + score = 0; + suf = NULL; + if (node->children) { /* children */ + node = node->children; + } else if (node->next) { /* siblings */ + node = node->next; + } else { /* ancestor siblings */ + while (node && !node->next) + node = node->parent; + if (!node) + break; + node = node->next; + } + assert(node); + + if (node->type != XML_ELEMENT_NODE) + continue; + + if (strcmp((const char *) node->name, "link") == 0) { + /* rel=<space separated list, including 'icon'> */ + if ((rel = (char *) xmlGetProp(node, + (const xmlChar *) "rel")) == NULL) + continue; + if (strcasestr(rel, "icon") == 0) { + xmlFree(rel); + continue; + } + LOG(("icon node found")); + switch(hash(rel)) { + case HHICON: + LOG(("icon")); + score = 3; + break; + case HHSHORTCUTICON: + LOG(("shortcut icon")); + score = 5; + break; + case HHAPPLETOUCHICON: + LOG(("apple-touch-icon")); + score = 1; + break; + } + xmlFree(rel); + /* current implementation scores candidates according + * to how closely they seem to adhere to standards, + * scoring system may be modified in the future */ + if ((type = (char *) xmlGetProp(node, + (const xmlChar *) "type")) != NULL) { + switch(hash(type)) { + case HHIMAGEPNG: + score += 5; + break; + case HHIMAGEGIF: + score += 5; + break; + case HHIMAGEVNDMICROSOFTICON: + score += 5; + break; + case HHIMAGEJPEG: + score += 5; + break; + case HHIMAGEJPG: + score += 5; + break; + case HHIMAGEICO: + score += 5; + break; + case HHIMAGEICON: + score += 5; + break; + case HHIMAGEXICON: + score += 5; + break; + case HHTEXTICO: + score += 2; + break; + case HHAPPLICATIONICO: + score += 1; + break; + } + xmlFree(type); + } + if ((href = (char *) xmlGetProp(node, + (const xmlChar *) "href")) == NULL) + continue; + suf = strrchr(href, '.'); + if (suf != NULL) { + suf ++; + switch(hash(suf)) { + case HHSUFICO: + score += 10; + break; + case HHSUFPNG: + score += 10; + break; + case HHSUFGIF: + score += 10; + break; + case HHSUFJPG: + score += 7; + break; + case HHSUFJPEG: + score += 7; + break; + } + } + if (score > hiscore) { + res = url_join(href, c->data.html.base_url, + &url); + xmlFree(href); + if (res != URL_FUNC_OK) + continue; + + LOG(("best favicon so far '%s'", url)); + res = url_normalize(url, &url2); + if (res != URL_FUNC_OK) { + url2 = NULL; + if (res == URL_FUNC_NOMEM) + goto no_memory; + continue; + } + hiscore = score; + free(url); + } + } + } + if (url2 == NULL) { + struct url_components comp; + if (url_get_components(c->data.html.base_url, &comp) != + URL_FUNC_OK) + return NULL; + if (url_normalize(comp.authority, + &url) != URL_FUNC_OK) + return NULL; + url_destroy_components(&comp); + if (url_join("/favicon.ico", url, &url2) != URL_FUNC_OK) + return NULL; + free(url); + } + LOG(("Best favicon %s", url2)); + return url2; +no_memory: + msg_data.error = messages_get("NoMemory"); + /* content_broadcast(c, CONTENT_MSG_ERROR, msg_data); */ + return false; +} + +/** + * retrieve 1 favicon + * \param c content structure + * \param html xml node of html element + * \return true for success, false for error + */ + +bool html_get_icon(struct content *c, xmlNode *html) +{ + union content_msg_data msg_data; + char *url = html_get_icon_ref(c, html); + struct content *favcontent = NULL; + if (url != NULL) + favcontent = fetchcache(url, html_favicon_callback, + (intptr_t) c, 0, c->width, c->height, true, 0, + 0, false, false); + free(url); + if (favcontent == NULL) + return false; + + c->data.html.favicon = favcontent; + + fetchcache_go(favcontent, c->url, html_favicon_callback, + (intptr_t) c, 0, c->width, c->height, + 0, 0, false, c->url); + + if (!c->data.html.favicon) { + msg_data.error = "Favicon failed to load"; + return false; + } + return true; +} + +/** + * Callback for fetchcache() for linked favicon + */ + +void html_favicon_callback(content_msg msg, struct content *icon, + intptr_t p1, intptr_t p2, union content_msg_data data) +{ + struct content *c = (struct content *) p1; + unsigned int i = p2; + + switch (msg) { + case CONTENT_MSG_LOADING: + /* check that the favicon is really a correct image + * type */ + + if ((icon->type == CONTENT_ICO) || + (icon->type == CONTENT_PNG) || + (icon->type == CONTENT_GIF)) { + + /* may need call to content_open() */ + + } else { + c->data.html.favicon = 0; + LOG(("%s is not a favicon", icon->url)); + content_add_error(c, "NotFavIco", 0); + html_set_status(c, messages_get("NotFavIco")); + content_broadcast(c, CONTENT_MSG_STATUS, data); + content_remove_user(icon, + html_favicon_callback, + (intptr_t) c, i); + if (!icon->user_list->next) { + /* we were the only user and we + * don't want this content, so + * stop it fetching and mark it + * as having an error so it gets + * removed from the cache next time + * content_clean() gets called */ + fetch_abort(icon->fetch); + icon->fetch = 0; + icon->status = CONTENT_STATUS_ERROR; + } + } + break; + + case CONTENT_MSG_READY: + break; + + case CONTENT_MSG_DONE: + LOG(("got favicon '%s'", icon->url)); + break; + + case CONTENT_MSG_LAUNCH: + /* Fall through */ + case CONTENT_MSG_ERROR: + LOG(("favicon %s failed: %s", icon->url, data.error)); + /* The favicon we were fetching may have been + * redirected, in that case, the object pointers + * will differ, so ensure that the object that's + * in error is still in use by us before invalidating + * the pointer */ + if (c->data.html.favicon == icon) { + c->data.html.favicon = 0; + content_add_error(c, "?", 0); + } + break; + + case CONTENT_MSG_STATUS: + html_set_status(c, icon->status_message); + content_broadcast(c, CONTENT_MSG_STATUS, data); + break; + + case CONTENT_MSG_NEWPTR: + c->data.html.favicon = icon; + break; + + case CONTENT_MSG_AUTH: + c->data.html.favicon = 0; + content_add_error(c, "?", 0); + break; + + case CONTENT_MSG_SSL: + c->data.html.favicon = 0; + content_add_error(c, "?", 0); + break; + + default: + assert(0); + } +} Index: render/favicon.h =================================================================== --- /dev/null 2008-11-24 10:09:14.252162000 +0000 +++ render/favicon.h 2009-04-28 16:01:49.412080078 +0100 @@ -0,0 +1,25 @@ +/* + * Copyright 2007 James Bursa <[email protected]> + * Copyright 2009 Mark Benjamin <[email protected]> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __NETSURF_RENDER_FAVICON_H__ +#define __NETSURF_RENDER_FAVICON_H__ + +bool html_get_icon(struct content *c, xmlNode *html); + +#endif Changed files !NetSurf/Resources/en/Messages | 1 Makefile.sources | 2 amiga/gui.c | 4 + beos/beos_scaffolding.cpp | 4 + desktop/browser.c | 17 ++++++ desktop/gui.h | 1 desktop/print.c | 2 framebuffer/fb_gui.c | 4 + gtk/dialogs/gtk_options.c | 41 +++++++++----- gtk/dialogs/gtk_source.c | 36 +++++++++++++ gtk/gtk_bitmap.c | 7 +- gtk/gtk_scaffolding.c | 99 ++++++++++++++++++++++++++++++++++- gtk/gtk_scaffolding.h | 44 +-------------- gtk/gtk_tabs.c | 2 gtk/options.h | 7 +- gtk/res/netsurf.glade | 113 ++++++++++++++++++++++++----------------- gtk/res/options.glade | 60 +++++++++++++++++++++ image/ico.c | 9 +++ image/ico.h | 2 render/html.c | 60 +++++++++++++-------- render/html.h | 3 + riscos/window.c | 3 + 22 files changed, 386 insertions(+), 135 deletions(-) Index: render/html.c =================================================================== --- render/html.c (revision 7353) +++ render/html.c (working copy) @@ -36,7 +36,11 @@ #include "desktop/gui.h" #include "desktop/options.h" #include "image/bitmap.h" +#include "image/png.h" +#include "image/gif.h" +#include "image/ico.h" #include "render/box.h" +#include "render/favicon.h" #include "render/font.h" #include "render/form.h" #include "render/html.h" @@ -73,7 +77,6 @@ static bool html_object_type_permitted(c static void html_object_refresh(void *p); static void html_destroy_frameset(struct content_html_frames *frameset); static void html_destroy_iframe(struct content_html_iframe *iframe); -static void html_set_status(struct content *c, const char *extra); #if ALWAYS_DUMP_FRAMESET static void html_dump_frameset(struct content_html_frames *frame, unsigned int depth); @@ -161,7 +164,7 @@ bool html_create(struct content *c, cons error: if (error == BINDING_BADENCODING) { - LOG(("Bad encoding: %s", html->encoding ? html->encoding : "")); + LOG(("Bad encoding: %s", html->encoding ? html->encoding :"")); msg_data.error = messages_get("ParsingFail"); } else msg_data.error = messages_get("NoMemory"); @@ -283,6 +286,7 @@ encoding_change: * * - parsing to an XML tree is completed * - stylesheets are fetched + * - favicon is retrieved * - the XML tree is converted to a box tree and object fetches are started * - the box tree is laid out * @@ -399,6 +403,9 @@ bool html_convert(struct content *c, int if (!html_find_stylesheets(c, html)) return false; + /* get icon */ + html_get_icon(c, html); + /* Retrieve forms from parser */ c->data.html.forms = binding_get_forms(c->data.html.parser_binding); for (f = c->data.html.forms; f != NULL; f = f->prev) { @@ -534,17 +541,20 @@ bool html_head(struct content *c, xmlNod } xmlFree(href); } - /* don't use the central values to ease freeing later on */ - if ((s = xmlGetProp(node, (const xmlChar *) "target"))) { - if ((!strcasecmp((const char *) s, "_blank")) || - (!strcasecmp((const char *) s, - "_top")) || - (!strcasecmp((const char *) s, - "_parent")) || - (!strcasecmp((const char *) s, - "_self")) || + /* don't use the central values to ease freeing later + * on */ + if ((s = xmlGetProp(node, (const xmlChar *) + "target"))) { + if ((!strcasecmp((const char *) s, "_blank")) + ||(!strcasecmp((const char *) + s, "_top")) || (!strcasecmp( + (const char *) s, "_parent")) + || (!strcasecmp((const char *) + s, "_self")) || ('a' <= s[0] && s[0] <= 'z') || - ('A' <= s[0] && s[0] <= 'Z')) { /* [6.16] */ + ('A' <= s[0] && s[0] <= 'Z') + ) { + /* [6.16] */ c->data.html.base_target = talloc_strdup(c, (const char *) s); @@ -615,7 +625,8 @@ bool html_meta_refresh(struct content *c end = (char *) content + strlen((const char *) content); - /* content := *LWS intpart fracpart? *LWS [';' *LWS *1url *LWS] + /* content := *LWS intpart fracpart? *LWS [';' *LWS *1url + * *LWS] * intpart := 1*DIGIT * fracpart := 1*('.' | DIGIT) * url := "url" *LWS '=' *LWS (url-nq | url-sq | url-dq) @@ -758,14 +769,13 @@ bool html_meta_refresh(struct content *c return true; } - /** * Process inline stylesheets and fetch linked stylesheets. * * Uses STYLE and LINK elements inside and outside HEAD * * \param c content structure - * \param head xml node of html element + * \param html xml node of html element * \return true on success, false if an error occurred */ @@ -844,7 +854,7 @@ bool html_find_stylesheets(struct conten if (strcmp((const char *) node->name, "link") == 0) { - /* rel=<space separated list, including 'stylesheet'> */ + /* rel=<space separated list, including 'stylesheet'>*/ if ((rel = (char *) xmlGetProp(node, (const xmlChar *) "rel")) == NULL) continue; @@ -872,7 +882,8 @@ bool html_find_stylesheets(struct conten if ((media = (char *) xmlGetProp(node, (const xmlChar *) "media")) != NULL) { if (strcasestr(media, "screen") == 0 && - strcasestr(media, "all") == 0) { + strcasestr(media, "all") + == 0) { xmlFree(media); continue; } @@ -947,7 +958,8 @@ bool html_find_stylesheets(struct conten html_convert_css_callback, (intptr_t) c, STYLESHEET_STYLE)) { /* no memory */ - c->data.html.stylesheet_content[STYLESHEET_STYLE] = 0; + c->data.html.stylesheet_content[ + STYLESHEET_STYLE] = 0; goto no_memory; } } else { @@ -1127,7 +1139,8 @@ void html_convert_css_callback(content_m case CONTENT_MSG_LAUNCH: /* Fall through */ case CONTENT_MSG_ERROR: - LOG(("stylesheet %s failed: %s", css->url, data.error)); + LOG(("stylesheet %s failed: %s", css->url, + data.error)); /* The stylesheet we were fetching may have been * redirected, in that case, the object pointers * will differ, so ensure that the object that's @@ -1672,7 +1685,8 @@ void html_stop(struct content *c) (intptr_t) c, i); else { content_remove_user(c->data.html.object[i].content, - html_object_callback, (intptr_t) c, i); + html_object_callback, (intptr_t) c, + i); c->data.html.object[i].content = 0; } } @@ -1778,8 +1792,10 @@ void html_destroy(struct content *c) LOG(("object %i %p", i, c->data.html.object[i].content)); if (c->data.html.object[i].content) { content_remove_user(c->data.html.object[i].content, - html_object_callback, (intptr_t) c, i); - if (c->data.html.object[i].content->type == CONTENT_HTML) + html_object_callback, (intptr_t) c, + i); + if (c->data.html.object[i].content->type == + CONTENT_HTML) schedule_remove(html_object_refresh, c->data.html.object[i].content); } Index: render/html.h =================================================================== --- render/html.h (revision 7353) +++ render/html.h (working copy) @@ -128,6 +128,8 @@ struct content_html_data { colour background_colour; /**< Document background colour. */ const struct font_functions *font_func; + struct content *favicon; + /** Number of entries in stylesheet_content. */ unsigned int stylesheet_count; /** Stylesheets. Each may be 0. */ @@ -184,6 +186,7 @@ void html_open(struct content *c, struct struct content *page, unsigned int index, struct box *box, struct object_params *params); void html_close(struct content *c); +void html_set_status(struct content *c, const char *extra); /* in render/html_redraw.c */ bool html_redraw(struct content *c, int x, int y, Index: image/ico.c =================================================================== --- image/ico.c (revision 7353) +++ image/ico.c (working copy) @@ -114,6 +114,15 @@ bool nsico_redraw(struct content *c, int background_colour, c); } +bool nsico_set_bitmap_from_size(struct content *c, int width, int height) +{ + struct bmp_image *bmp = ico_find(c->data.ico.ico, width, height); + if (!bmp->decoded) + if (bmp_decode(bmp) != BMP_OK) + return false; + c->bitmap = bmp->bitmap; + return true; +} bool nsico_redraw_tiled(struct content *c, int x, int y, int width, int height, Index: image/ico.h =================================================================== --- image/ico.h (revision 7353) +++ image/ico.h (working copy) @@ -47,7 +47,7 @@ bool nsico_redraw_tiled(struct content * int clip_x0, int clip_y0, int clip_x1, int clip_y1, float scale, colour background_colour, bool repeat_x, bool repeat_y); - +bool nsico_set_bitmap_from_size(struct content *c, int width, int height); #endif /* WITH_BMP */ #endif Index: framebuffer/fb_gui.c =================================================================== --- framebuffer/fb_gui.c (revision 7353) +++ framebuffer/fb_gui.c (working copy) @@ -1000,6 +1000,10 @@ void gui_window_stop_throbber(struct gui } +void gui_window_set_icon(struct gui_window *g, struct content *icon) +{ +} + void gui_window_place_caret(struct gui_window *g, int x, int y, int height) { } Index: gtk/options.h =================================================================== --- gtk/options.h (revision 7353) +++ gtk/options.h (working copy) @@ -34,6 +34,7 @@ extern int option_history_age; extern bool option_hover_urls; extern bool option_focus_new; extern bool option_new_blank; +extern bool option_source_tab; #define EXTRA_OPTION_DEFINE \ bool option_render_resample = false; \ @@ -48,7 +49,8 @@ bool option_disable_plugins = false; \ int option_history_age = 0; \ bool option_hover_urls = false; \ bool option_focus_new = false; \ -bool option_new_blank = false; +bool option_new_blank = false; \ +bool option_source_tab = false; #define EXTRA_OPTION_TABLE \ { "render_resample", OPTION_BOOL, &option_render_resample }, \ @@ -63,6 +65,7 @@ bool option_new_blank = false; { "history_age", OPTION_INTEGER, &option_history_age}, \ { "hover_urls", OPTION_BOOL, &option_hover_urls}, \ { "focus_new", OPTION_BOOL, &option_focus_new}, \ -{ "new_blank", OPTION_BOOL, &option_new_blank} +{ "new_blank", OPTION_BOOL, &option_new_blank}, \ +{ "source_tab", OPTION_BOOL, &option_source_tab} #endif Index: gtk/gtk_bitmap.c =================================================================== --- gtk/gtk_bitmap.c (revision 7353) +++ gtk/gtk_bitmap.c (working copy) @@ -34,6 +34,9 @@ #include "utils/log.h" +#define MIN_PRETILE_WIDTH 256 +#define MIN_PRETILE_HEIGHT 256 + struct bitmap { GdkPixbuf *primary; GdkPixbuf *pretile_x; @@ -41,10 +44,6 @@ struct bitmap { GdkPixbuf *pretile_xy; }; -#define MIN_PRETILE_WIDTH 256 -#define MIN_PRETILE_HEIGHT 256 - - /** * Create a bitmap. * Index: gtk/gtk_scaffolding.c =================================================================== --- gtk/gtk_scaffolding.c (revision 7353) +++ gtk/gtk_scaffolding.c (working copy) @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> #include <gtk/gtk.h> +#include <gdk-pixbuf/gdk-pixbuf.h> #include <libxml/debugXML.h> #include "content/content.h" #include "desktop/browser.h" @@ -37,6 +38,7 @@ #endif #include "desktop/selection.h" #include "desktop/textinput.h" +#include "gtk/gtk_bitmap.h" #include "gtk/gtk_completion.h" #include "gtk/dialogs/gtk_options.h" #include "gtk/dialogs/gtk_about.h" @@ -52,6 +54,7 @@ #include "gtk/gtk_throbber.h" #include "gtk/gtk_window.h" #include "gtk/options.h" +#include "image/ico.h" #include "render/box.h" #include "render/font.h" #include "render/form.h" @@ -77,6 +80,44 @@ struct menu_events { GCallback handler; }; +struct gtk_scaffolding { + GtkWindow *window; + GtkNotebook *notebook; + GtkEntry *url_bar; + GtkEntryCompletion *url_bar_completion; + GtkStatusbar *status_bar; + GtkMenuItem *edit_menu; + GtkMenuItem *tabs_menu; + GtkToolbar *tool_bar; + GtkToolButton *back_button; + GtkToolButton *history_button; + GtkToolButton *forward_button; + GtkToolButton *stop_button; + GtkToolButton *reload_button; + GtkToolItem *toolFav; + GtkMenuBar *menu_bar; + GtkMenuItem *back_menu; + GtkMenuItem *forward_menu; + GtkMenuItem *stop_menu; + GtkMenuItem *reload_menu; + GtkImage *throbber; + GtkPaned *status_pane; + + GladeXML *xml; + + GladeXML *popup_xml; + GtkMenu *popup_menu; + + struct gtk_history_window *history_window; + GtkDialog *preferences_dialog; + + int throb_frame; + struct gui_window *top_level; + int being_destroyed; + + bool fullscreen; +}; + static int open_windows = 0; /**< current number of open browsers */ static struct gtk_scaffolding *current_model; /**< current window for model dialogue use */ @@ -1238,6 +1279,7 @@ nsgtk_scaffolding *nsgtk_new_scaffolding g->forward_menu = GTK_MENU_ITEM(GET_WIDGET("forward")); g->stop_menu = GTK_MENU_ITEM(GET_WIDGET("stop")); g->reload_menu = GTK_MENU_ITEM(GET_WIDGET("reload")); + g->toolFav = GTK_TOOL_ITEM(GET_WIDGET("toolFav")); g->throbber = GTK_IMAGE(GET_WIDGET("throbber")); g->preferences_dialog = NULL; @@ -1378,8 +1420,10 @@ nsgtk_scaffolding *nsgtk_new_scaffolding /* connect history window signals to their handlers */ CONNECT(g->history_window->drawing_area, "expose_event", nsgtk_history_expose_event, g->history_window); -// CONNECT(g->history_window->drawing_area, "motion_notify_event", -// nsgtk_history_motion_notify_event, g->history_window); + /* + CONNECT(g->history_window->drawing_area, "motion_notify_event", + nsgtk_history_motion_notify_event, g->history_window); + */ CONNECT(g->history_window->drawing_area, "button_press_event", nsgtk_history_button_press_event, g->history_window); CONNECT(g->history_window->window, "delete_event", @@ -1546,6 +1590,40 @@ void gui_window_stop_throbber(struct gui gtk_image_set_from_pixbuf(g->throbber, nsgtk_throbber->framedata[0]); } +/** + * set favicon + */ +void gui_window_set_icon(struct gui_window *_g, struct content *icon) +{ + struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); + GtkWidget *currenticon = gtk_bin_get_child(GTK_BIN(g->toolFav)); + GtkImage *iconImage = NULL; + if (currenticon != NULL) { + gtk_container_remove(GTK_CONTAINER(g->toolFav), + currenticon); + } + if ((icon != NULL) && (icon->type == CONTENT_ICO)) { + nsico_set_bitmap_from_size(icon, 20, 20); + } + if ((icon != NULL) && (icon->bitmap != NULL)) { + GdkPixbuf *pb = gtk_bitmap_get_primary(icon->bitmap); + if ((pb != NULL) && (gdk_pixbuf_get_width(pb) > 0) && + (gdk_pixbuf_get_height(pb) > 0)) { + pb = gdk_pixbuf_scale_simple(pb, 20, 20, + GDK_INTERP_HYPER); + iconImage = GTK_IMAGE( + gtk_image_new_from_pixbuf(pb)); + } else { + iconImage = NULL; + } + } + if (iconImage == NULL) + iconImage = GTK_IMAGE(gtk_image_new_from_file(g_strconcat( + res_dir_location, "netsurf-16x16.xpm", NULL))); + gtk_container_add(GTK_CONTAINER(g->toolFav), GTK_WIDGET( + iconImage)); + gtk_widget_show_all(GTK_WIDGET(g->toolFav)); +} gboolean nsgtk_scaffolding_is_busy(struct gtk_scaffolding *scaffold) { @@ -1563,14 +1641,24 @@ GtkNotebook* nsgtk_scaffolding_get_noteb return g->scaffold->notebook; } +GtkEntry *nsgtk_scaffolding_get_urlbar(struct gui_window *g) +{ + return g->scaffold->url_bar; +} + +GtkToolbar *nsgtk_scaffolding_get_toolbar(struct gui_window *g) +{ + return g->scaffold->tool_bar; +} + + void nsgtk_scaffolding_set_top_level (struct gui_window *gw) { gw->scaffold->top_level = gw; - /* Synchronise the history (will also update the URL bar) */ nsgtk_window_update_back_forward(gw->scaffold); - /* Ensure the window's title bar is updated */ + /* Ensure the window's title bar as well as favicon are updated */ if (gw->bw != NULL && gw->bw->current_content != NULL) { if (gw->bw->current_content->title != NULL) { gui_window_set_title(gw, @@ -1578,6 +1666,9 @@ void nsgtk_scaffolding_set_top_level (st } else { gui_window_set_title(gw, gw->bw->current_content->url); } + if (gw->bw->current_content->type == CONTENT_HTML) + gui_window_set_icon(gw, gw->bw->current_content-> + data.html.favicon); } } Index: gtk/gtk_scaffolding.h =================================================================== --- gtk/gtk_scaffolding.h (revision 7353) +++ gtk/gtk_scaffolding.h (working copy) @@ -26,52 +26,16 @@ typedef struct gtk_scaffolding nsgtk_scaffolding; -struct gtk_scaffolding { - GtkWindow *window; - GtkNotebook *notebook; - GtkEntry *url_bar; - GtkEntryCompletion *url_bar_completion; - GtkStatusbar *status_bar; - GtkMenuItem *edit_menu; - GtkMenuItem *tabs_menu; - GtkToolbar *tool_bar; - GtkToolButton *back_button; - GtkToolButton *history_button; - GtkToolButton *forward_button; - GtkToolButton *stop_button; - GtkToolButton *reload_button; - GtkMenuBar *menu_bar; - GtkMenuItem *back_menu; - GtkMenuItem *forward_menu; - GtkMenuItem *stop_menu; - GtkMenuItem *reload_menu; - GtkImage *throbber; - GtkPaned *status_pane; - - GladeXML *xml; - - GladeXML *popup_xml; - GtkMenu *popup_menu; - - struct gtk_history_window *history_window; - GtkDialog *preferences_dialog; - - int throb_frame; - struct gui_window *top_level; - int being_destroyed; - - bool fullscreen; -}; - GtkWindow *nsgtk_get_window_for_scaffold(struct gtk_scaffolding *g); nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel); gboolean nsgtk_scaffolding_is_busy(nsgtk_scaffolding *scaffold); -GtkWindow* nsgtk_scaffolding_get_window (struct gui_window *g); - -GtkNotebook* nsgtk_scaffolding_get_notebook (struct gui_window *g); +GtkWindow *nsgtk_scaffolding_get_window (struct gui_window *g); +GtkNotebook *nsgtk_scaffolding_get_notebook (struct gui_window *g); +GtkEntry *nsgtk_scaffolding_get_urlbar(struct gui_window *g); +GtkToolbar *nsgtk_scaffolding_get_toolbar(struct gui_window *g); void nsgtk_scaffolding_set_top_level (struct gui_window *gw); Index: gtk/gtk_tabs.c =================================================================== --- gtk/gtk_tabs.c (revision 7353) +++ gtk/gtk_tabs.c (working copy) @@ -81,7 +81,7 @@ void nsgtk_tab_add(struct gui_window *wi } if (background) gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), remember); - gtk_widget_grab_focus(GTK_WIDGET(window->scaffold->url_bar)); + gtk_widget_grab_focus(GTK_WIDGET(nsgtk_scaffolding_get_urlbar(window))); } void nsgtk_tab_visibility_update(GtkNotebook *notebook, GtkWidget *child, Index: gtk/dialogs/gtk_options.c =================================================================== --- gtk/dialogs/gtk_options.c (revision 7353) +++ gtk/dialogs/gtk_options.c (working copy) @@ -97,6 +97,8 @@ DECLARE(checkRequestOverwrite); DECLARE(fileChooserDownloads); DECLARE(checkFocusNew); DECLARE(checkNewBlank); +DECLARE(sourceButtonTab); +static GtkWidget *sourceButtonWindow; DECLARE(spinMarginTop); DECLARE(spinMarginBottom); @@ -133,6 +135,12 @@ GtkDialog* nsgtk_options_init(struct bro "dlgPreferences")); gtk_window_set_transient_for (GTK_WINDOW(wndPreferences), parent); + FIND_WIDGET(sourceButtonTab); + FIND_WIDGET(sourceButtonWindow); + GSList *group = gtk_radio_button_get_group(GTK_RADIO_BUTTON( + sourceButtonWindow)); + gtk_radio_button_set_group(GTK_RADIO_BUTTON(sourceButtonTab), group); + /* set the widgets to reflect the current options */ nsgtk_options_load(); @@ -187,6 +195,7 @@ GtkDialog* nsgtk_options_init(struct bro CONNECT(checkFocusNew, "toggled"); CONNECT(checkNewBlank, "toggled"); + CONNECT(sourceButtonTab, "toggled"); CONNECT(spinMarginTop, "value-changed"); CONNECT(spinMarginBottom, "value-changed"); @@ -388,6 +397,7 @@ void nsgtk_options_load(void) SET_CHECK(checkFocusNew, option_focus_new); SET_CHECK(checkNewBlank, option_new_blank); + SET_CHECK(sourceButtonTab, option_source_tab); SET_SPIN(spinMarginTop, option_margin_top); SET_SPIN(spinMarginBottom, option_margin_bottom); @@ -647,26 +657,26 @@ COMBO_CHANGED(comboButtonType, option_bu while (current) { switch(option_button_type) { case 1: - gtk_toolbar_set_style(GTK_TOOLBAR(current->scaffold->tool_bar), - GTK_TOOLBAR_ICONS); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(current->scaffold->tool_bar), - GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_toolbar_set_style(nsgtk_scaffolding_get_toolbar( + current), GTK_TOOLBAR_ICONS); + gtk_toolbar_set_icon_size(nsgtk_scaffolding_get_toolbar( + current), GTK_ICON_SIZE_SMALL_TOOLBAR); break; case 2: - gtk_toolbar_set_style(GTK_TOOLBAR(current->scaffold->tool_bar), - GTK_TOOLBAR_ICONS); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(current->scaffold->tool_bar), - GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_toolbar_set_style(nsgtk_scaffolding_get_toolbar( + current), GTK_TOOLBAR_ICONS); + gtk_toolbar_set_icon_size(nsgtk_scaffolding_get_toolbar( + current), GTK_ICON_SIZE_LARGE_TOOLBAR); break; case 3: - gtk_toolbar_set_style(GTK_TOOLBAR(current->scaffold->tool_bar), - GTK_TOOLBAR_BOTH); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(current->scaffold->tool_bar), - GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_toolbar_set_style(nsgtk_scaffolding_get_toolbar( + current), GTK_TOOLBAR_BOTH); + gtk_toolbar_set_icon_size(nsgtk_scaffolding_get_toolbar( + current), GTK_ICON_SIZE_LARGE_TOOLBAR); break; case 4: - gtk_toolbar_set_style(GTK_TOOLBAR(current->scaffold->tool_bar), - GTK_TOOLBAR_TEXT); + gtk_toolbar_set_style(nsgtk_scaffolding_get_toolbar( + current), GTK_TOOLBAR_TEXT); default: break; } @@ -696,6 +706,9 @@ END_HANDLER CHECK_CHANGED(checkNewBlank, option_new_blank) END_HANDLER +CHECK_CHANGED(sourceButtonTab, option_source_tab) +END_HANDLER + SPIN_CHANGED(spinMarginTop, option_margin_top) END_HANDLER Index: gtk/dialogs/gtk_source.c =================================================================== --- gtk/dialogs/gtk_source.c (revision 7353) +++ gtk/dialogs/gtk_source.c (working copy) @@ -28,8 +28,10 @@ #include "gtk/gtk_gui.h" #include "gtk/gtk_print.h" #include "gtk/gtk_selection.h" +#include "gtk/options.h" #include "desktop/netsurf.h" #include "desktop/print.h" +#include "desktop/options.h" #include "utils/messages.h" #include "utils/url.h" #include "utils/utils.h" @@ -61,6 +63,7 @@ static gchar *glade_Location; static struct nsgtk_source_window *nsgtk_source_list = 0; static char source_zoomlevel = 10; +void nsgtk_source_tab_init(GtkWindow *parent, struct browser_window *bw); static void nsgtk_attach_source_menu_handlers(GladeXML *xml, gpointer g); static gboolean nsgtk_source_delete_event(GtkWindow *window, gpointer g); static gboolean nsgtk_source_destroy_event(GtkWindow *window, gpointer g); @@ -103,6 +106,10 @@ MENUEVENT(source_about), void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw) { + if (option_source_tab) { + nsgtk_source_tab_init(parent, bw); + return; + } if (bw->current_content->type == CONTENT_HTML) { glade_Location = g_strconcat(res_dir_location, "source.glade", NULL); @@ -208,6 +215,35 @@ void nsgtk_source_dialog_init(GtkWindow } } +void nsgtk_source_tab_init(GtkWindow *parent, struct browser_window *bw) +{ + char *ndata = 0; + utf8_convert_ret r = utf8_from_enc( + bw->current_content->source_data, + bw->current_content->data.html.encoding, + bw->current_content->source_size, + &ndata); + if (r == UTF8_CONVERT_NOMEM) { + warn_user("NoMemory",0); + return; + } else if (r == UTF8_CONVERT_BADENC) { + warn_user("EncNotRec",0); + return; + } + gchar *filename; + gint handle = g_file_open_tmp("nsgtksourceXXXXXX", &filename, NULL); + close (handle); /* in case it was binary mode */ + FILE *f = fopen(filename, "w"); + fprintf(f, "%s", ndata); + fclose(f); + struct browser_window *newbw = browser_window_create(g_strconcat( + "file://", filename, NULL), bw, NULL, false, true); + if (newbw->current_content) + newbw->current_content->title = g_strconcat("source of ", + bw->current_content->url , NULL); +} + + void nsgtk_attach_source_menu_handlers(GladeXML *xml, gpointer g) { struct menu_events *event = source_menu_events; Index: gtk/res/netsurf.glade =================================================================== --- gtk/res/netsurf.glade (revision 7353) +++ gtk/res/netsurf.glade (working copy) @@ -790,7 +790,7 @@ <property name="stock_id">gtk-go-back</property> </widget> <packing> - <property name="homogeneous">True</property> + <property name="expand">False</property> </packing> </child> <child> @@ -802,7 +802,7 @@ <property name="icon">arrow_down_8x32.png</property> </widget> <packing> - <property name="homogeneous">True</property> + <property name="expand">False</property> </packing> </child> <child> @@ -811,7 +811,7 @@ <property name="stock_id">gtk-go-forward</property> </widget> <packing> - <property name="homogeneous">True</property> + <property name="expand">False</property> </packing> </child> <child> @@ -820,7 +820,7 @@ <property name="stock_id">gtk-stop</property> </widget> <packing> - <property name="homogeneous">True</property> + <property name="expand">False</property> </packing> </child> <child> @@ -829,7 +829,7 @@ <property name="stock_id">gtk-refresh</property> </widget> <packing> - <property name="homogeneous">True</property> + <property name="expand">False</property> </packing> </child> <child> @@ -838,7 +838,22 @@ <property name="stock_id">gtk-home</property> </widget> <packing> - <property name="homogeneous">True</property> + <property name="expand">False</property> + </packing> + </child> + <child> + <widget class="GtkToolItem" id="toolFav"> + <property name="visible">True</property> + <child> + <widget class="GtkImage" id="FavIcon"> + <property name="visible">True</property> + <property name="pixbuf">netsurf-16x16.xpm</property> + </widget> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> </packing> </child> <child> @@ -852,6 +867,10 @@ </widget> </child> </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> </child> <child> <widget class="GtkToolItem" id="toolthrobber"> @@ -864,6 +883,10 @@ </widget> </child> </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> </child> </widget> <packing> @@ -956,106 +979,106 @@ <property name="column_spacing">11</property> <property name="row_spacing">10</property> <child> - <widget class="GtkLabel" id="labelLoginHost"> + <widget class="GtkEntry" id="entryLoginUser"> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">moo.yoo.com</property> + <property name="can_focus">True</property> + <property name="has_focus">True</property> + <property name="text" translatable="yes">sesame</property> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="x_options"></property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label57"> + <widget class="GtkEntry" id="entryLoginPass"> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Password</property> + <property name="can_focus">True</property> + <property name="visibility">False</property> + <property name="activates_default">True</property> + <property name="text" translatable="yes">opensesame</property> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">3</property> <property name="bottom_attach">4</property> - <property name="x_options"></property> + <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label56"> + <widget class="GtkLabel" id="labelLoginRealm"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Username</property> + <property name="label" translatable="yes">my sekr3t area</property> </widget> <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="x_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label54"> + <widget class="GtkLabel" id="label55"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Host</property> + <property name="label" translatable="yes">Realm</property> </widget> <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="x_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label55"> + <widget class="GtkLabel" id="label54"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Realm</property> + <property name="label" translatable="yes">Host</property> </widget> <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> <property name="x_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="labelLoginRealm"> + <widget class="GtkLabel" id="label56"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">my sekr3t area</property> + <property name="label" translatable="yes">Username</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> <property name="x_options"></property> </packing> </child> <child> - <widget class="GtkEntry" id="entryLoginPass"> + <widget class="GtkLabel" id="label57"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="visibility">False</property> - <property name="activates_default">True</property> - <property name="text" translatable="yes">opensesame</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Password</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> <property name="top_attach">3</property> <property name="bottom_attach">4</property> - <property name="y_options"></property> + <property name="x_options"></property> </packing> </child> <child> - <widget class="GtkEntry" id="entryLoginUser"> + <widget class="GtkLabel" id="labelLoginHost"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="has_focus">True</property> - <property name="text" translatable="yes">sesame</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">moo.yoo.com</property> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"></property> + <property name="x_options"></property> </packing> </child> </widget> Index: gtk/res/options.glade =================================================================== --- gtk/res/options.glade (revision 7353) +++ gtk/res/options.glade (working copy) @@ -1742,6 +1742,66 @@ Text only</property> </packing> </child> <child> + <widget class="GtkFrame" id="frame9"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <child> + <widget class="GtkAlignment" id="alignment9"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <widget class="GtkHBox" id="hbox9"> + <property name="visible">True</property> + <child> + <widget class="GtkRadioButton" id="sourceButtonWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">in own window </property> + <property name="response_id">0</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + <child> + <widget class="GtkRadioButton" id="sourceButtonTab"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">in new tab</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label22"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>View Source</b></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> <placeholder/> </child> </widget> Index: !NetSurf/Resources/en/Messages =================================================================== --- !NetSurf/Resources/en/Messages (revision 7353) +++ !NetSurf/Resources/en/Messages (working copy) @@ -607,6 +607,7 @@ Done:Document done BadRedirect:Bad redirect URL FetchFailed:Unable to fetch document NotCSS:Warning: stylesheet is not CSS +NotFavIco:Favicon not supported BadObject:Warning: bad object type ObjError:Error loading object: %s ParsingFail:Parsing the document failed. Index: beos/beos_scaffolding.cpp =================================================================== --- beos/beos_scaffolding.cpp (revision 7353) +++ beos/beos_scaffolding.cpp (working copy) @@ -2312,6 +2312,10 @@ void gui_window_stop_throbber(struct gui g->top_view->UnlockLooper(); } +void gui_window_set_icon(struct gui_window *g, struct content *icon) +{ +} + #warning XXX #if 0 /* GTK */ gboolean nsbeos_scaffolding_is_busy(nsbeos_scaffolding *scaffold) Index: Makefile.sources =================================================================== --- Makefile.sources (revision 7353) +++ Makefile.sources (working copy) @@ -8,7 +8,7 @@ S_CONTENT := content.c fetch.c fetchcache.c urldb.c \ fetchers/fetch_curl.c fetchers/fetch_data.c S_CSS := css.c css_enum.c parser.c ruleset.c scanner.c -S_RENDER := box.c box_construct.c box_normalise.c directory.c \ +S_RENDER := box.c box_construct.c box_normalise.c directory.c favicon.c \ form.c html.c html_redraw.c hubbub_binding.c imagemap.c \ layout.c list.c loosen.c table.c textplain.c S_UTILS := base64.c filename.c hashtable.c locale.c messages.c talloc.c \ Index: riscos/window.c =================================================================== --- riscos/window.c (revision 7353) +++ riscos/window.c (working copy) @@ -1092,6 +1092,9 @@ void gui_window_stop_throbber(struct gui } } +void gui_window_set_icon(struct gui_window *g, struct content *icon) +{ +} /** * Place the caret in a browser window. Index: desktop/browser.c =================================================================== --- desktop/browser.c (revision 7353) +++ desktop/browser.c (working copy) @@ -85,6 +85,7 @@ static bool browser_window_check_throbbe static void browser_window_convert_to_download(struct browser_window *bw); static void browser_window_start_throbber(struct browser_window *bw); static void browser_window_stop_throbber(struct browser_window *bw); +static void browser_window_set_icon(struct browser_window *bw); static void browser_window_set_status(struct browser_window *bw, const char *text); static void browser_window_set_pointer(struct gui_window *g, @@ -491,6 +492,7 @@ void browser_window_callback(content_msg browser_window_update(bw, false); browser_window_set_status(bw, c->status_message); browser_window_stop_throbber(bw); + browser_window_set_icon(bw); history_update(bw->history, c); hotlist_visited(c); free(bw->referer); @@ -763,6 +765,21 @@ bool browser_window_check_throbber(struc return false; } +/** + * when ready, set icon at top level + * \param bw browser_window + * current implementation ignores lower-levels' link rels completely + */ +void browser_window_set_icon(struct browser_window *bw) +{ + while (bw->parent) + bw = bw->parent; + if ((bw->current_content != NULL) && (bw->current_content->type == CONTENT_HTML)) + gui_window_set_icon(bw->window, + bw->current_content->data.html.favicon); + else + gui_window_set_icon(bw->window, NULL); +} /** * Redraw browser window, set extent to content, and update title. Index: desktop/gui.h =================================================================== --- desktop/gui.h (revision 7353) +++ desktop/gui.h (working copy) @@ -88,6 +88,7 @@ void gui_window_hide_pointer(struct gui_ void gui_window_set_url(struct gui_window *g, const char *url); void gui_window_start_throbber(struct gui_window *g); void gui_window_stop_throbber(struct gui_window *g); +void gui_window_set_icon(struct gui_window *g, struct content *icon); void gui_window_place_caret(struct gui_window *g, int x, int y, int height); void gui_window_remove_caret(struct gui_window *g); void gui_window_new_content(struct gui_window *g); Index: desktop/print.c =================================================================== --- desktop/print.c (revision 7353) +++ desktop/print.c (working copy) @@ -197,7 +197,7 @@ struct content *print_init(struct conten } /** - * The content is resized to fit page width. In case it is to wide, it is + * The content is resized to fit page width. In case it is too wide, it is * loosened. * * \param content The content to be printed Index: amiga/gui.c =================================================================== --- amiga/gui.c (revision 7353) +++ amiga/gui.c (working copy) @@ -2658,6 +2658,10 @@ void gui_window_stop_throbber(struct gui g->shared->throbber_frame = 0; } +void gui_window_set_icon(struct gui_window *g, struct content *icon) +{ +} + void ami_update_throbber(struct gui_window_2 *g,bool redraw) { struct IBox *bbox; Conflicted files Removed files
