r13899 chris_y - /trunk/netsurf/amiga/gui.c
by netsurf@semichrome.net
Author: chris_y
Date: Sun Apr 29 11:13:53 2012
New Revision: 13899
URL: http://source.netsurf-browser.org?rev=13899&view=rev
Log:
Only struct gui_window_2 should use variable name 'gwin'. gui_window is
always 'g'.
Modified:
trunk/netsurf/amiga/gui.c
Modified: trunk/netsurf/amiga/gui.c
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/gui.c?rev=13899&r1=...
==============================================================================
--- trunk/netsurf/amiga/gui.c (original)
+++ trunk/netsurf/amiga/gui.c Sun Apr 29 11:13:53 2012
@@ -2468,7 +2468,7 @@
struct gui_window *gui_create_browser_window(struct browser_window *bw,
struct browser_window *clone, bool new_tab)
{
- struct gui_window *gwin = NULL;
+ struct gui_window *g = NULL;
bool closegadg=TRUE;
struct Node *node;
ULONG curx=nsoption_int(window_x),cury=nsoption_int(window_y),curw=nsoption_int(window_width),curh=nsoption_int(window_height);
@@ -2498,38 +2498,38 @@
}
}
- gwin = AllocVec(sizeof(struct gui_window),MEMF_PRIVATE | MEMF_CLEAR);
-
- if(!gwin)
+ g = AllocVec(sizeof(struct gui_window),MEMF_PRIVATE | MEMF_CLEAR);
+
+ if(!g)
{
warn_user("NoMemory","");
return NULL;
}
- NewList(&gwin->dllist);
+ NewList(&g->dllist);
if(new_tab && clone)
{
- gwin->shared = clone->window->shared;
- gwin->tab = gwin->shared->next_tab;
-
- if(gwin->shared->tabs == 1)
- ami_toggletabbar(gwin->shared, true);
-
- SetGadgetAttrs((struct Gadget *)gwin->shared->objects[GID_TABS],
- gwin->shared->win, NULL,
+ g->shared = clone->window->shared;
+ g->tab = g->shared->next_tab;
+
+ if(g->shared->tabs == 1)
+ ami_toggletabbar(g->shared, true);
+
+ SetGadgetAttrs((struct Gadget *)g->shared->objects[GID_TABS],
+ g->shared->win, NULL,
CLICKTAB_Labels, ~0,
TAG_DONE);
- gwin->tab_node = AllocClickTabNode(TNA_Text,messages_get("NetSurf"),
- TNA_Number,gwin->tab,
+ g->tab_node = AllocClickTabNode(TNA_Text,messages_get("NetSurf"),
+ TNA_Number,g->tab,
TNA_UserData,bw,
TNA_CloseGadget, TRUE,
TAG_DONE);
if(nsoption_bool(new_tab_last))
{
- AddTail(&gwin->shared->tab_list, gwin->tab_node);
+ AddTail(&g->shared->tab_list, g->tab_node);
}
else
{
@@ -2537,54 +2537,54 @@
if(clone->window->last_new_tab)
insert_after = clone->window->last_new_tab;
- Insert(&gwin->shared->tab_list, gwin->tab_node, insert_after);
- clone->window->last_new_tab = gwin->tab_node;
- }
-
- RefreshSetGadgetAttrs((struct Gadget *)gwin->shared->objects[GID_TABS],
- gwin->shared->win, NULL,
- CLICKTAB_Labels, &gwin->shared->tab_list,
+ Insert(&g->shared->tab_list, g->tab_node, insert_after);
+ clone->window->last_new_tab = g->tab_node;
+ }
+
+ RefreshSetGadgetAttrs((struct Gadget *)g->shared->objects[GID_TABS],
+ g->shared->win, NULL,
+ CLICKTAB_Labels, &g->shared->tab_list,
TAG_DONE);
if(nsoption_bool(new_tab_active))
{
- RefreshSetGadgetAttrs((struct Gadget *)gwin->shared->objects[GID_TABS],gwin->shared->win,NULL,
- CLICKTAB_Current,gwin->tab,
+ RefreshSetGadgetAttrs((struct Gadget *)g->shared->objects[GID_TABS],g->shared->win,NULL,
+ CLICKTAB_Current,g->tab,
TAG_DONE);
}
if(ClickTabBase->lib_Version < 53)
- RethinkLayout((struct Gadget *)gwin->shared->objects[GID_TABLAYOUT],gwin->shared->win,NULL,TRUE);
-
- gwin->shared->tabs++;
- gwin->shared->next_tab++;
-
- if(nsoption_bool(new_tab_active)) ami_switch_tab(gwin->shared,false);
-
- ami_update_buttons(gwin->shared);
-
- return gwin;
- }
-
- gwin->shared = AllocVec(sizeof(struct gui_window_2),MEMF_PRIVATE | MEMF_CLEAR);
-
- if(!gwin->shared)
+ RethinkLayout((struct Gadget *)g->shared->objects[GID_TABLAYOUT],g->shared->win,NULL,TRUE);
+
+ g->shared->tabs++;
+ g->shared->next_tab++;
+
+ if(nsoption_bool(new_tab_active)) ami_switch_tab(g->shared,false);
+
+ ami_update_buttons(g->shared);
+
+ return g;
+ }
+
+ g->shared = AllocVec(sizeof(struct gui_window_2),MEMF_PRIVATE | MEMF_CLEAR);
+
+ if(!g->shared)
{
warn_user("NoMemory","");
return NULL;
}
- gwin->shared->scrollerhook.h_Entry = (void *)ami_scroller_hook;
- gwin->shared->scrollerhook.h_Data = gwin->shared;
-
- gwin->shared->search_ico_hook.h_Entry = (void *)ami_set_search_ico_render_hook;
- gwin->shared->search_ico_hook.h_Data = gwin->shared;
-
- gwin->shared->favicon_hook.h_Entry = (void *)ami_set_favicon_render_hook;
- gwin->shared->favicon_hook.h_Data = gwin->shared;
-
- gwin->shared->throbber_hook.h_Entry = (void *)ami_set_throbber_render_hook;
- gwin->shared->throbber_hook.h_Data = gwin->shared;
+ g->shared->scrollerhook.h_Entry = (void *)ami_scroller_hook;
+ g->shared->scrollerhook.h_Data = g->shared;
+
+ g->shared->search_ico_hook.h_Entry = (void *)ami_set_search_ico_render_hook;
+ g->shared->search_ico_hook.h_Data = g->shared;
+
+ g->shared->favicon_hook.h_Entry = (void *)ami_set_favicon_render_hook;
+ g->shared->favicon_hook.h_Data = g->shared;
+
+ g->shared->throbber_hook.h_Entry = (void *)ami_set_throbber_render_hook;
+ g->shared->throbber_hook.h_Data = g->shared;
newprefs_hook.h_Entry = (void *)ami_gui_newprefs_hook;
newprefs_hook.h_Data = 0;
@@ -2604,36 +2604,36 @@
(locked_screen == TRUE) &&
(strcmp(nsoption_charp(use_pubscreen), "Workbench") == 0))
iconifygadget = TRUE;
- ami_create_menu(gwin->shared);
-
- NewList(&gwin->shared->tab_list);
- gwin->tab_node = AllocClickTabNode(TNA_Text,messages_get("NetSurf"),
+ ami_create_menu(g->shared);
+
+ NewList(&g->shared->tab_list);
+ g->tab_node = AllocClickTabNode(TNA_Text,messages_get("NetSurf"),
TNA_Number, 0,
TNA_UserData, bw,
TNA_CloseGadget, TRUE,
TAG_DONE);
- AddTail(&gwin->shared->tab_list,gwin->tab_node);
-
- gwin->shared->tabs=1;
- gwin->shared->next_tab=1;
-
- gwin->shared->svbuffer = AllocVec(2000, MEMF_CLEAR);
-
- gwin->shared->helphints[GID_BACK] =
+ AddTail(&g->shared->tab_list,g->tab_node);
+
+ g->shared->tabs=1;
+ g->shared->next_tab=1;
+
+ g->shared->svbuffer = AllocVec(2000, MEMF_CLEAR);
+
+ g->shared->helphints[GID_BACK] =
remove_escape_chars(messages_get("HelpToolbar0"), true);
- gwin->shared->helphints[GID_FORWARD] =
+ g->shared->helphints[GID_FORWARD] =
remove_escape_chars(messages_get("HelpToolbar1"), true);
- gwin->shared->helphints[GID_STOP] =
+ g->shared->helphints[GID_STOP] =
remove_escape_chars(messages_get("HelpToolbar2"), true);
- gwin->shared->helphints[GID_RELOAD] =
+ g->shared->helphints[GID_RELOAD] =
remove_escape_chars(messages_get("HelpToolbar3"), true);
- gwin->shared->helphints[GID_HOME] =
+ g->shared->helphints[GID_HOME] =
remove_escape_chars(messages_get("HelpToolbar4"), true);
- gwin->shared->helphints[GID_URL] =
+ g->shared->helphints[GID_URL] =
remove_escape_chars(messages_get("HelpToolbar14"), true);
- gwin->shared->helphints[GID_SEARCHSTRING] =
+ g->shared->helphints[GID_SEARCHSTRING] =
remove_escape_chars(messages_get("HelpWebSearch"), true);
- gwin->shared->helphints[GID_ADDTAB] =
+ g->shared->helphints[GID_ADDTAB] =
remove_escape_chars(messages_get("HelpAddTab"), true);
ami_get_theme_filename(nav_west,"theme_nav_west",false);
@@ -2659,7 +2659,7 @@
ami_get_theme_filename(addtab_g,"theme_addtab_g",false);
ami_get_theme_filename(tabthrobber,"theme_tab_loading",false);
- gwin->shared->objects[GID_ADDTAB_BM] = BitMapObject,
+ g->shared->objects[GID_ADDTAB_BM] = BitMapObject,
BITMAP_SourceFile, addtab,
BITMAP_SelectSourceFile, addtab_s,
BITMAP_DisabledSourceFile, addtab_g,
@@ -2667,7 +2667,7 @@
BITMAP_Masking, TRUE,
BitMapEnd;
- gwin->shared->objects[GID_CLOSETAB_BM] = BitMapObject,
+ g->shared->objects[GID_CLOSETAB_BM] = BitMapObject,
BITMAP_SourceFile, closetab,
BITMAP_SelectSourceFile, closetab_s,
BITMAP_DisabledSourceFile, closetab_g,
@@ -2678,37 +2678,37 @@
if(ClickTabBase->lib_Version < 53)
{
addtabclosegadget = LAYOUT_AddChild;
- gwin->shared->objects[GID_CLOSETAB] = ButtonObject,
+ g->shared->objects[GID_CLOSETAB] = ButtonObject,
GA_ID, GID_CLOSETAB,
GA_RelVerify, TRUE,
- BUTTON_RenderImage, gwin->shared->objects[GID_CLOSETAB_BM],
+ BUTTON_RenderImage, g->shared->objects[GID_CLOSETAB_BM],
ButtonEnd;
- gwin->shared->objects[GID_TABS] = ClickTabObject,
+ g->shared->objects[GID_TABS] = ClickTabObject,
GA_ID,GID_TABS,
GA_RelVerify,TRUE,
GA_Underscore,13, // disable kb shortcuts
- CLICKTAB_Labels,&gwin->shared->tab_list,
+ CLICKTAB_Labels,&g->shared->tab_list,
CLICKTAB_LabelTruncate,TRUE,
ClickTabEnd;
- gwin->shared->objects[GID_ADDTAB] = ButtonObject,
+ g->shared->objects[GID_ADDTAB] = ButtonObject,
GA_ID, GID_ADDTAB,
GA_RelVerify, TRUE,
GA_Text, "+",
- BUTTON_RenderImage, gwin->shared->objects[GID_ADDTAB_BM],
+ BUTTON_RenderImage, g->shared->objects[GID_ADDTAB_BM],
ButtonEnd;
}
else
{
- gwin->shared->objects[GID_TABS_FLAG] = BitMapObject,
+ g->shared->objects[GID_TABS_FLAG] = BitMapObject,
BITMAP_SourceFile, tabthrobber,
BITMAP_Screen,scrn,
BITMAP_Masking,TRUE,
BitMapEnd;
}
- gwin->shared->objects[OID_MAIN] = WindowObject,
+ g->shared->objects[OID_MAIN] = WindowObject,
WA_ScreenTitle,nsscreentitle,
WA_Activate, TRUE,
WA_DepthGadget, TRUE,
@@ -2730,26 +2730,26 @@
IDCMP_REFRESHWINDOW |
IDCMP_ACTIVEWINDOW | IDCMP_EXTENDEDMOUSE,
WINDOW_IconifyGadget, iconifygadget,
- WINDOW_NewMenu, gwin->shared->menu,
+ WINDOW_NewMenu, g->shared->menu,
WINDOW_MenuUserData, WGUD_HOOK,
WINDOW_VertProp, 1,
WINDOW_NewPrefsHook, &newprefs_hook,
- WINDOW_IDCMPHook, &gwin->shared->scrollerhook,
+ WINDOW_IDCMPHook, &g->shared->scrollerhook,
WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE | IDCMP_REFRESHWINDOW |
IDCMP_EXTENDEDMOUSE | IDCMP_SIZEVERIFY,
WINDOW_SharedPort, sport,
WINDOW_BuiltInScroll, TRUE,
WINDOW_GadgetHelp, TRUE,
- WINDOW_UserData, gwin->shared,
- WINDOW_ParentGroup, gwin->shared->objects[GID_MAIN] = VGroupObject,
+ WINDOW_UserData, g->shared,
+ WINDOW_ParentGroup, g->shared->objects[GID_MAIN] = VGroupObject,
LAYOUT_SpaceOuter, TRUE,
- LAYOUT_AddChild, gwin->shared->objects[GID_TOOLBARLAYOUT] = HGroupObject,
+ LAYOUT_AddChild, g->shared->objects[GID_TOOLBARLAYOUT] = HGroupObject,
LAYOUT_VertAlignment, LALIGN_CENTER,
- LAYOUT_AddChild, gwin->shared->objects[GID_BACK] = ButtonObject,
+ LAYOUT_AddChild, g->shared->objects[GID_BACK] = ButtonObject,
GA_ID,GID_BACK,
GA_RelVerify,TRUE,
GA_Disabled,TRUE,
- GA_HintInfo, gwin->shared->helphints[GID_BACK],
+ GA_HintInfo, g->shared->helphints[GID_BACK],
BUTTON_RenderImage,BitMapObject,
BITMAP_SourceFile,nav_west,
BITMAP_SelectSourceFile,nav_west_s,
@@ -2760,11 +2760,11 @@
ButtonEnd,
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
- LAYOUT_AddChild, gwin->shared->objects[GID_FORWARD] = ButtonObject,
+ LAYOUT_AddChild, g->shared->objects[GID_FORWARD] = ButtonObject,
GA_ID,GID_FORWARD,
GA_RelVerify,TRUE,
GA_Disabled,TRUE,
- GA_HintInfo, gwin->shared->helphints[GID_FORWARD],
+ GA_HintInfo, g->shared->helphints[GID_FORWARD],
BUTTON_RenderImage,BitMapObject,
BITMAP_SourceFile,nav_east,
BITMAP_SelectSourceFile,nav_east_s,
@@ -2775,10 +2775,10 @@
ButtonEnd,
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
- LAYOUT_AddChild, gwin->shared->objects[GID_STOP] = ButtonObject,
+ LAYOUT_AddChild, g->shared->objects[GID_STOP] = ButtonObject,
GA_ID,GID_STOP,
GA_RelVerify,TRUE,
- GA_HintInfo, gwin->shared->helphints[GID_STOP],
+ GA_HintInfo, g->shared->helphints[GID_STOP],
BUTTON_RenderImage,BitMapObject,
BITMAP_SourceFile,stop,
BITMAP_SelectSourceFile,stop_s,
@@ -2789,10 +2789,10 @@
ButtonEnd,
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
- LAYOUT_AddChild, gwin->shared->objects[GID_RELOAD] = ButtonObject,
+ LAYOUT_AddChild, g->shared->objects[GID_RELOAD] = ButtonObject,
GA_ID,GID_RELOAD,
GA_RelVerify,TRUE,
- GA_HintInfo, gwin->shared->helphints[GID_RELOAD],
+ GA_HintInfo, g->shared->helphints[GID_RELOAD],
BUTTON_RenderImage,BitMapObject,
BITMAP_SourceFile,reload,
BITMAP_SelectSourceFile,reload_s,
@@ -2803,10 +2803,10 @@
ButtonEnd,
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
- LAYOUT_AddChild, gwin->shared->objects[GID_HOME] = ButtonObject,
+ LAYOUT_AddChild, g->shared->objects[GID_HOME] = ButtonObject,
GA_ID,GID_HOME,
GA_RelVerify,TRUE,
- GA_HintInfo, gwin->shared->helphints[GID_HOME],
+ GA_HintInfo, g->shared->helphints[GID_HOME],
BUTTON_RenderImage,BitMapObject,
BITMAP_SourceFile,home,
BITMAP_SelectSourceFile,home_s,
@@ -2817,23 +2817,23 @@
ButtonEnd,
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
- LAYOUT_AddChild, gwin->shared->objects[GID_ICON] = SpaceObject,
+ LAYOUT_AddChild, g->shared->objects[GID_ICON] = SpaceObject,
GA_ID, GID_ICON,
SPACE_MinWidth, 16,
SPACE_MinHeight, 16,
SPACE_Transparent, TRUE,
- // SPACE_RenderHook, &gwin->shared->favicon_hook,
+ // SPACE_RenderHook, &g->shared->favicon_hook,
SpaceEnd,
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
- LAYOUT_AddChild, gwin->shared->objects[GID_URL] =
+ LAYOUT_AddChild, g->shared->objects[GID_URL] =
NewObject(urlStringClass, NULL,
STRINGA_MaxChars, 2000,
GA_ID, GID_URL,
GA_RelVerify, TRUE,
- GA_HintInfo, gwin->shared->helphints[GID_URL],
+ GA_HintInfo, g->shared->helphints[GID_URL],
GA_TabCycle, TRUE,
- STRINGA_Buffer, gwin->shared->svbuffer,
+ STRINGA_Buffer, g->shared->svbuffer,
STRINGVIEW_Header, URLHistory_GetList(),
StringEnd,
@@ -2843,29 +2843,29 @@
LAYOUT_WeightBar, TRUE,
LAYOUT_AddChild, HGroupObject,
LAYOUT_VertAlignment, LALIGN_CENTER,
- LAYOUT_AddChild, gwin->shared->objects[GID_SEARCH_ICON] = SpaceObject,
+ LAYOUT_AddChild, g->shared->objects[GID_SEARCH_ICON] = SpaceObject,
GA_ID, GID_SEARCH_ICON,
SPACE_MinWidth, 16,
SPACE_MinHeight, 16,
SPACE_Transparent, TRUE,
- SPACE_RenderHook, &gwin->shared->search_ico_hook,
+ SPACE_RenderHook, &g->shared->search_ico_hook,
SpaceEnd,
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
- LAYOUT_AddChild, gwin->shared->objects[GID_SEARCHSTRING] =StringObject,
+ LAYOUT_AddChild, g->shared->objects[GID_SEARCHSTRING] =StringObject,
GA_ID,GID_SEARCHSTRING,
STRINGA_TextVal, NULL,
GA_RelVerify,TRUE,
- GA_HintInfo, gwin->shared->helphints[GID_SEARCHSTRING],
+ GA_HintInfo, g->shared->helphints[GID_SEARCHSTRING],
StringEnd,
LayoutEnd,
CHILD_WeightedWidth, 0,
- LAYOUT_AddChild, gwin->shared->objects[GID_THROBBER] = SpaceObject,
+ LAYOUT_AddChild, g->shared->objects[GID_THROBBER] = SpaceObject,
GA_ID,GID_THROBBER,
SPACE_MinWidth,throbber_width,
SPACE_MinHeight,throbber_height,
SPACE_Transparent,TRUE,
- // SPACE_RenderHook, &gwin->shared->throbber_hook,
+ // SPACE_RenderHook, &g->shared->throbber_hook,
SpaceEnd,
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
@@ -2875,21 +2875,21 @@
BEVEL_Style, BVS_SBAR_VERT,
BevelEnd,
CHILD_WeightedHeight, 0,
- LAYOUT_AddChild, gwin->shared->objects[GID_TABLAYOUT] = HGroupObject,
+ LAYOUT_AddChild, g->shared->objects[GID_TABLAYOUT] = HGroupObject,
LAYOUT_SpaceInner,FALSE,
- addtabclosegadget, gwin->shared->objects[GID_CLOSETAB],
+ addtabclosegadget, g->shared->objects[GID_CLOSETAB],
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
- addtabclosegadget, gwin->shared->objects[GID_TABS],
+ addtabclosegadget, g->shared->objects[GID_TABS],
CHILD_CacheDomain,FALSE,
- addtabclosegadget, gwin->shared->objects[GID_ADDTAB],
+ addtabclosegadget, g->shared->objects[GID_ADDTAB],
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
LayoutEnd,
CHILD_WeightedHeight,0,
- LAYOUT_AddChild, gwin->shared->objects[GID_BROWSER] = SpaceObject,
+ LAYOUT_AddChild, g->shared->objects[GID_BROWSER] = SpaceObject,
GA_ID,GID_BROWSER,
SPACE_Transparent,TRUE,
SpaceEnd,
@@ -2899,11 +2899,11 @@
else
{
/* borderless kiosk mode window */
- gwin->tab = 0;
- gwin->shared->tabs = 0;
- gwin->tab_node = NULL;
-
- gwin->shared->objects[OID_MAIN] = WindowObject,
+ g->tab = 0;
+ g->shared->tabs = 0;
+ g->tab_node = NULL;
+
+ g->shared->objects[OID_MAIN] = WindowObject,
WA_ScreenTitle,nsscreentitle,
WA_Activate, TRUE,
WA_DepthGadget, FALSE,
@@ -2926,15 +2926,15 @@
IDCMP_EXTENDEDMOUSE,
WINDOW_HorizProp,1,
WINDOW_VertProp,1,
- WINDOW_IDCMPHook,&gwin->shared->scrollerhook,
+ WINDOW_IDCMPHook,&g->shared->scrollerhook,
WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE |
IDCMP_EXTENDEDMOUSE | IDCMP_REFRESHWINDOW,
WINDOW_SharedPort,sport,
- WINDOW_UserData,gwin->shared,
+ WINDOW_UserData,g->shared,
WINDOW_BuiltInScroll,TRUE,
- WINDOW_ParentGroup, gwin->shared->objects[GID_MAIN] = VGroupObject,
+ WINDOW_ParentGroup, g->shared->objects[GID_MAIN] = VGroupObject,
LAYOUT_SpaceOuter, TRUE,
- LAYOUT_AddChild, gwin->shared->objects[GID_BROWSER] = SpaceObject,
+ LAYOUT_AddChild, g->shared->objects[GID_BROWSER] = SpaceObject,
GA_ID,GID_BROWSER,
SPACE_Transparent,TRUE,
SpaceEnd,
@@ -2942,21 +2942,21 @@
EndWindow;
}
- gwin->shared->win = (struct Window *)RA_OpenWindow(gwin->shared->objects[OID_MAIN]);
-
- if(!gwin->shared->win)
+ g->shared->win = (struct Window *)RA_OpenWindow(g->shared->objects[OID_MAIN]);
+
+ if(!g->shared->win)
{
warn_user("NoMemory","");
- FreeVec(gwin->shared);
- FreeVec(gwin);
+ FreeVec(g->shared);
+ FreeVec(g);
return NULL;
}
- GetAttr(WINDOW_VertObject, gwin->shared->objects[OID_MAIN],
- (ULONG *)&gwin->shared->objects[OID_VSCROLL]);
-
- RefreshSetGadgetAttrs((struct Gadget *)(APTR)gwin->shared->objects[OID_VSCROLL],
- gwin->shared->win, NULL,
+ GetAttr(WINDOW_VertObject, g->shared->objects[OID_MAIN],
+ (ULONG *)&g->shared->objects[OID_VSCROLL]);
+
+ RefreshSetGadgetAttrs((struct Gadget *)(APTR)g->shared->objects[OID_VSCROLL],
+ g->shared->win, NULL,
GA_ID, OID_VSCROLL,
ICA_TARGET, ICTARGET_IDCMP,
TAG_DONE);
@@ -2965,10 +2965,10 @@
{
ULONG sz, size1, size2;
- sz = ami_get_border_gadget_balance(gwin->shared,
+ sz = ami_get_border_gadget_balance(g->shared,
(ULONG *)&size1, (ULONG *)&size2);
- gwin->shared->objects[GID_HSCROLL] = NewObject(
+ g->shared->objects[GID_HSCROLL] = NewObject(
NULL,
"scrollergclass",
GA_ID, GID_HSCROLL,
@@ -2981,10 +2981,10 @@
GA_DrawInfo, dri,
TAG_DONE);
- GetAttr(GA_Height, (Object *)gwin->shared->objects[GID_HSCROLL],
+ GetAttr(GA_Height, (Object *)g->shared->objects[GID_HSCROLL],
(ULONG *)&sz);
- gwin->shared->objects[GID_STATUS] = NewObject(
+ g->shared->objects[GID_STATUS] = NewObject(
NULL,
"frbuttonclass",
GA_ID, GID_STATUS,
@@ -3005,50 +3005,50 @@
IA_Screen, scrn,
GAUGEIA_Level, 0,
TAG_DONE),
- GA_Next, gwin->shared->objects[GID_HSCROLL],
+ GA_Next, g->shared->objects[GID_HSCROLL],
TAG_DONE);
- AddGList(gwin->shared->win, (struct Gadget *)gwin->shared->objects[GID_STATUS],
+ AddGList(g->shared->win, (struct Gadget *)g->shared->objects[GID_STATUS],
(UWORD)~0, -1, NULL);
/* Apparently you can't set GA_Width on creation time for frbuttonclass */
- SetGadgetAttrs((struct Gadget *)gwin->shared->objects[GID_STATUS],
- gwin->shared->win, NULL,
+ SetGadgetAttrs((struct Gadget *)g->shared->objects[GID_STATUS],
+ g->shared->win, NULL,
GA_Width, size1,
TAG_DONE);
- RefreshGadgets((APTR)gwin->shared->objects[GID_STATUS],
- gwin->shared->win, NULL);
+ RefreshGadgets((APTR)g->shared->objects[GID_STATUS],
+ g->shared->win, NULL);
}
else
{
- GetAttr(WINDOW_HorizObject, gwin->shared->objects[OID_MAIN],
- (ULONG *)&gwin->shared->objects[OID_HSCROLL]);
-
- RefreshSetGadgetAttrs((struct Gadget *)(APTR)gwin->shared->objects[OID_HSCROLL],
- gwin->shared->win, NULL,
+ GetAttr(WINDOW_HorizObject, g->shared->objects[OID_MAIN],
+ (ULONG *)&g->shared->objects[OID_HSCROLL]);
+
+ RefreshSetGadgetAttrs((struct Gadget *)(APTR)g->shared->objects[OID_HSCROLL],
+ g->shared->win, NULL,
GA_ID, OID_HSCROLL,
ICA_TARGET, ICTARGET_IDCMP,
TAG_DONE);
}
- gwin->shared->rmbtrapped = FALSE;
- gwin->shared->bw = bw;
+ g->shared->rmbtrapped = FALSE;
+ g->shared->bw = bw;
curbw = bw;
- gwin->shared->appwin = AddAppWindowA((ULONG)gwin->shared->objects[OID_MAIN],
- (ULONG)gwin->shared, gwin->shared->win, appport, NULL);
-
- gwin->shared->node = AddObject(window_list,AMINS_WINDOW);
- gwin->shared->node->objstruct = gwin->shared;
+ g->shared->appwin = AddAppWindowA((ULONG)g->shared->objects[OID_MAIN],
+ (ULONG)g->shared, g->shared->win, appport, NULL);
+
+ g->shared->node = AddObject(window_list,AMINS_WINDOW);
+ g->shared->node->objstruct = g->shared;
glob = &browserglob;
if(locked_screen) UnlockPubScreen(NULL,scrn);
search_web_retrieve_ico(false);
- return gwin;
+ return g;
}
ULONG ami_set_border_gadget_balance(struct gui_window_2 *gwin)
11 years, 4 months
r13898 chris_y - in /trunk/netsurf/amiga: gui.c gui.h menu.c menu.h
by netsurf@semichrome.net
Author: chris_y
Date: Sun Apr 29 10:59:37 2012
New Revision: 13898
URL: http://source.netsurf-browser.org?rev=13898&view=rev
Log:
Change menus so menu functions are called internally by window.class
(RA_HandleInput). This makes menu selection more reliable and stops us
missing menu events which appeared to be getting lost within the
HANDLEINPUT method.
Modified:
trunk/netsurf/amiga/gui.c
trunk/netsurf/amiga/gui.h
trunk/netsurf/amiga/menu.c
trunk/netsurf/amiga/menu.h
Modified: trunk/netsurf/amiga/gui.c
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/gui.c?rev=13898&r1=...
==============================================================================
--- trunk/netsurf/amiga/gui.c (original)
+++ trunk/netsurf/amiga/gui.c Sun Apr 29 10:59:37 2012
@@ -15,9 +15,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-/* define this to use simple (as opposed to smart) refresh windows */
-// #define AMI_SIMPLEREFRESH 1
/* NetSurf core includes */
#include "content/urldb.h"
@@ -154,6 +151,8 @@
struct MsgPort *applibport = NULL;
ULONG applibsig = 0;
BOOL refresh_search_ico = FALSE;
+BOOL refresh_favicon = FALSE;
+BOOL refresh_throbber = FALSE;
struct Hook newprefs_hook;
static char *current_user;
@@ -179,6 +178,10 @@
Object *ami_gui_splash_open(void);
void ami_gui_splash_close(Object *win_obj);
static uint32 ami_set_search_ico_render_hook(struct Hook *hook, APTR space,
+ struct gpRender *msg);
+static uint32 ami_set_favicon_render_hook(struct Hook *hook, APTR space,
+ struct gpRender *msg);
+static uint32 ami_set_throbber_render_hook(struct Hook *hook, APTR space,
struct gpRender *msg);
bool ami_gui_map_filename(char **remapped, const char *path, const char *file,
const char *map);
@@ -1334,7 +1337,7 @@
while((result = RA_HandleInput(gwin->objects[OID_MAIN],&code)) != WMHI_LASTMSG)
{
-//printf("class %ld\n",class);
+//printf("%ld: %ld (switch)\n",code, result & WMHI_CLASSMASK);
switch(result & WMHI_CLASSMASK) // class
{
case WMHI_MOUSEMOVE:
@@ -1626,16 +1629,6 @@
default:
// printf("GADGET: %ld\n",(result & WMHI_GADGETMASK));
break;
- }
- break;
-
- case WMHI_MENUPICK:
- item = ItemAddress(gwin->win->MenuStrip,code);
- while (code != MENUNULL)
- {
- ami_menupick(code,gwin,item);
- if(win_destroyed) break;
- code = item->NextSelect;
}
break;
@@ -1918,6 +1911,18 @@
gui_window_set_search_ico(NULL);
refresh_search_ico = FALSE;
}
+
+ if(refresh_favicon)
+ {
+ gui_window_set_icon(gwin->bw->window, gwin->bw->window->favicon);
+ refresh_favicon = FALSE;
+ }
+
+ if(refresh_throbber)
+ {
+ ami_update_throbber(gwin, true);
+ refresh_throbber = FALSE;
+ }
}
void ami_gui_appicon_remove(struct gui_window_2 *gwin)
@@ -2574,6 +2579,12 @@
gwin->shared->search_ico_hook.h_Entry = (void *)ami_set_search_ico_render_hook;
gwin->shared->search_ico_hook.h_Data = gwin->shared;
+
+ gwin->shared->favicon_hook.h_Entry = (void *)ami_set_favicon_render_hook;
+ gwin->shared->favicon_hook.h_Data = gwin->shared;
+
+ gwin->shared->throbber_hook.h_Entry = (void *)ami_set_throbber_render_hook;
+ gwin->shared->throbber_hook.h_Data = gwin->shared;
newprefs_hook.h_Entry = (void *)ami_gui_newprefs_hook;
newprefs_hook.h_Data = 0;
@@ -2712,7 +2723,7 @@
WA_ReportMouse,TRUE,
refresh_mode, TRUE,
WA_SizeBBottom, TRUE,
- WA_IDCMP,IDCMP_MENUPICK | IDCMP_MOUSEMOVE |
+ WA_IDCMP, IDCMP_MENUPICK | IDCMP_MOUSEMOVE |
IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE |
IDCMP_RAWKEY | IDCMP_SIZEVERIFY |
IDCMP_GADGETUP | IDCMP_IDCMPUPDATE |
@@ -2720,15 +2731,16 @@
IDCMP_ACTIVEWINDOW | IDCMP_EXTENDEDMOUSE,
WINDOW_IconifyGadget, iconifygadget,
WINDOW_NewMenu, gwin->shared->menu,
- WINDOW_VertProp,1,
- WINDOW_NewPrefsHook,&newprefs_hook,
- WINDOW_IDCMPHook,&gwin->shared->scrollerhook,
+ WINDOW_MenuUserData, WGUD_HOOK,
+ WINDOW_VertProp, 1,
+ WINDOW_NewPrefsHook, &newprefs_hook,
+ WINDOW_IDCMPHook, &gwin->shared->scrollerhook,
WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE | IDCMP_REFRESHWINDOW |
IDCMP_EXTENDEDMOUSE | IDCMP_SIZEVERIFY,
- WINDOW_SharedPort,sport,
- WINDOW_BuiltInScroll,TRUE,
+ WINDOW_SharedPort, sport,
+ WINDOW_BuiltInScroll, TRUE,
WINDOW_GadgetHelp, TRUE,
- WINDOW_UserData,gwin->shared,
+ WINDOW_UserData, gwin->shared,
WINDOW_ParentGroup, gwin->shared->objects[GID_MAIN] = VGroupObject,
LAYOUT_SpaceOuter, TRUE,
LAYOUT_AddChild, gwin->shared->objects[GID_TOOLBARLAYOUT] = HGroupObject,
@@ -2810,6 +2822,7 @@
SPACE_MinWidth, 16,
SPACE_MinHeight, 16,
SPACE_Transparent, TRUE,
+ // SPACE_RenderHook, &gwin->shared->favicon_hook,
SpaceEnd,
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
@@ -2852,6 +2865,7 @@
SPACE_MinWidth,throbber_width,
SPACE_MinHeight,throbber_height,
SPACE_Transparent,TRUE,
+ // SPACE_RenderHook, &gwin->shared->throbber_hook,
SpaceEnd,
CHILD_WeightedWidth,0,
CHILD_WeightedHeight,0,
@@ -3832,6 +3846,13 @@
g->favicon = icon;
}
+static uint32 ami_set_favicon_render_hook(struct Hook *hook, APTR space,
+ struct gpRender *msg)
+{
+ refresh_favicon = TRUE;
+ return 0;
+}
+
/**
* set gui display of a retrieved favicon representing the search
* provider
@@ -3898,6 +3919,13 @@
struct gpRender *msg)
{
refresh_search_ico = TRUE;
+ return 0;
+}
+
+static uint32 ami_set_throbber_render_hook(struct Hook *hook, APTR space,
+ struct gpRender *msg)
+{
+ refresh_throbber = TRUE;
return 0;
}
Modified: trunk/netsurf/amiga/gui.h
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/gui.h?rev=13898&r1=...
==============================================================================
--- trunk/netsurf/amiga/gui.h (original)
+++ trunk/netsurf/amiga/gui.h Sun Apr 29 10:59:37 2012
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2010 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008-2012 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -94,6 +94,7 @@
bool new_content;
char *menulab[AMI_MENU_AREXX_MAX + 1];
char menukey[AMI_MENU_AREXX_MAX + 1];
+ struct Hook menu_hook[AMI_MENU_AREXX_MAX + 1];
UBYTE *menutype;
struct NewMenu *menu;
ULONG hotlist_items;
@@ -106,6 +107,8 @@
struct AppIcon *appicon; /* iconify appicon */
struct DiskObject *dobj; /* iconify appicon */
struct Hook search_ico_hook;
+ struct Hook favicon_hook;
+ struct Hook throbber_hook;
gui_drag_type drag_op;
struct IBox *ptr_lock;
struct AppWindow *appwin;
Modified: trunk/netsurf/amiga/menu.c
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/menu.c?rev=13898&r1...
==============================================================================
--- trunk/netsurf/amiga/menu.c (original)
+++ trunk/netsurf/amiga/menu.c Sun Apr 29 10:59:37 2012
@@ -85,6 +85,38 @@
ULONG *item, bool count, struct gui_window_2 *gwin);
void ami_menu_arexx_scan(struct gui_window_2 *gwin);
+/* Functions for menu selections */
+static void ami_menu_item_project_newwin(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_project_newtab(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_project_open(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_project_save(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_project_closetab(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_project_closewin(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_project_print(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_project_about(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_project_quit(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_edit_cut(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_edit_copy(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_edit_paste(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_edit_selectall(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_edit_clearsel(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_browser_find(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_browser_localhistory(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_browser_globalhistory(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_browser_cookies(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_browser_scale_decrease(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_browser_scale_normal(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_browser_scale_increase(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_browser_redraw(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_hotlist_add(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_hotlist_show(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_hotlist_entries(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_settings_edit(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_settings_snapshot(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_settings_save(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_arexx_execute(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+static void ami_menu_item_arexx_entries(struct Hook *hook, APTR window, struct IntuiMessage *msg);
+
void ami_free_menulabs(struct gui_window_2 *gwin)
{
@@ -102,6 +134,11 @@
{
ami_utf8_free(gwin->menulab[i]);
}
+
+ if(i >= AMI_MENU_AREXX)
+ {
+ if(gwin->menu_hook[i].h_Data) free(gwin->menu_hook[i].h_Data);
+ }
}
gwin->menulab[i] = NULL;
@@ -129,126 +166,211 @@
gwin->menutype[0] = NM_TITLE;
gwin->menulab[0] = ami_utf8_easy((char *)messages_get("Project"));
+
gwin->menutype[1] = NM_ITEM;
gwin->menulab[1] = ami_utf8_easy((char *)messages_get("NewWindowNS"));
gwin->menukey[1] = 'N';
+ gwin->menu_hook[1].h_Entry = (HOOKFUNC)ami_menu_item_project_newwin;
+
gwin->menutype[2] = NM_ITEM;
gwin->menulab[2] = ami_utf8_easy((char *)messages_get("NewTab"));
gwin->menukey[2] = 'T';
+ gwin->menu_hook[2].h_Entry = (HOOKFUNC)ami_menu_item_project_newtab;
+
gwin->menutype[3] = NM_ITEM;
gwin->menulab[3] = NM_BARLABEL;
+
gwin->menutype[4] = NM_ITEM;
gwin->menulab[4] = ami_utf8_easy((char *)messages_get("OpenFile"));
gwin->menukey[4] = 'O';
+ gwin->menu_hook[4].h_Entry = (HOOKFUNC)ami_menu_item_project_open;
+
gwin->menutype[5] = NM_ITEM;
gwin->menulab[5] = ami_utf8_easy((char *)messages_get("SaveAsNS"));
+
gwin->menutype[6] = NM_SUB;
gwin->menulab[6] = ami_utf8_easy((char *)messages_get("Source"));
gwin->menukey[6] = 'S';
+ gwin->menu_hook[6].h_Entry = (HOOKFUNC)ami_menu_item_project_save;
+ gwin->menu_hook[6].h_Data = AMINS_SAVE_SOURCE;
+
gwin->menutype[7] = NM_SUB;
gwin->menulab[7] = ami_utf8_easy((char *)messages_get("TextNS"));
+ gwin->menu_hook[7].h_Entry = (HOOKFUNC)ami_menu_item_project_save;
+ gwin->menu_hook[7].h_Data = (void *)AMINS_SAVE_TEXT;
+
gwin->menutype[8] = NM_SUB;
gwin->menulab[8] = ami_utf8_easy((char *)messages_get("SaveCompNS"));
+ gwin->menu_hook[8].h_Entry = (HOOKFUNC)ami_menu_item_project_save;
+ gwin->menu_hook[8].h_Data = (void *)AMINS_SAVE_COMPLETE;
+
gwin->menutype[9] = NM_SUB;
gwin->menulab[9] = ami_utf8_easy((char *)messages_get("PDFNS"));
+ gwin->menu_hook[9].h_Entry = (HOOKFUNC)ami_menu_item_project_save;
+ gwin->menu_hook[9].h_Data = (void *)AMINS_SAVE_PDF;
+
gwin->menutype[10] = NM_SUB;
gwin->menulab[10] = ami_utf8_easy((char *)messages_get("IFF"));
+ gwin->menu_hook[10].h_Entry = (HOOKFUNC)ami_menu_item_project_save;
+ gwin->menu_hook[10].h_Data = (void *)AMINS_SAVE_IFF;
+
gwin->menutype[11] = NM_ITEM;
gwin->menulab[11] = NM_BARLABEL;
+
gwin->menutype[12] = NM_ITEM;
gwin->menulab[12] = ami_utf8_easy((char *)messages_get("CloseTab"));
gwin->menukey[12] = 'K';
+ gwin->menu_hook[12].h_Entry = (HOOKFUNC)ami_menu_item_project_closetab;
+
gwin->menutype[13] = NM_ITEM;
gwin->menulab[13] = ami_utf8_easy((char *)messages_get("CloseWindow"));
+ gwin->menu_hook[13].h_Entry = (HOOKFUNC)ami_menu_item_project_closewin;
+
gwin->menutype[14] = NM_ITEM;
gwin->menulab[14] = NM_BARLABEL;
+
gwin->menutype[15] = NM_ITEM;
gwin->menulab[15] = ami_utf8_easy((char *)messages_get("PrintNS"));
gwin->menukey[15] = 'P';
+ gwin->menu_hook[15].h_Entry = (HOOKFUNC)ami_menu_item_project_print;
+
gwin->menutype[16] = NM_ITEM;
gwin->menulab[16] = NM_BARLABEL;
+
gwin->menutype[17] = NM_ITEM;
gwin->menulab[17] = ami_utf8_easy((char *)messages_get("About"));
gwin->menukey[17] = '?';
+ gwin->menu_hook[17].h_Entry = (HOOKFUNC)ami_menu_item_project_about;
+
gwin->menutype[18] = NM_ITEM;
gwin->menulab[18] = ami_utf8_easy((char *)messages_get("Quit"));
gwin->menukey[18] = 'Q';
+ gwin->menu_hook[18].h_Entry = (HOOKFUNC)ami_menu_item_project_quit;
+
gwin->menutype[19] = NM_TITLE;
gwin->menulab[19] = ami_utf8_easy((char *)messages_get("Edit"));
+
gwin->menutype[20] = NM_ITEM;
gwin->menulab[20] = ami_utf8_easy((char *)messages_get("CutNS"));
gwin->menukey[20] = 'X';
+ gwin->menu_hook[20].h_Entry = (HOOKFUNC)ami_menu_item_edit_cut;
+
gwin->menutype[21] = NM_ITEM;
gwin->menulab[21] = ami_utf8_easy((char *)messages_get("CopyNS"));
gwin->menukey[21] = 'C';
+ gwin->menu_hook[21].h_Entry = (HOOKFUNC)ami_menu_item_edit_copy;
+
gwin->menutype[22] = NM_ITEM;
gwin->menulab[22] = ami_utf8_easy((char *)messages_get("PasteNS"));
gwin->menukey[22] = 'V';
+ gwin->menu_hook[22].h_Entry = (HOOKFUNC)ami_menu_item_edit_paste;
+
gwin->menutype[23] = NM_ITEM;
gwin->menulab[23] = NM_BARLABEL;
+
gwin->menutype[24] = NM_ITEM;
gwin->menulab[24] = ami_utf8_easy((char *)messages_get("SelectAllNS"));
gwin->menukey[24] = 'A';
+ gwin->menu_hook[24].h_Entry = (HOOKFUNC)ami_menu_item_edit_selectall;
+
gwin->menutype[25] = NM_ITEM;
gwin->menulab[25] = ami_utf8_easy((char *)messages_get("ClearNS"));
gwin->menukey[25] = 'Z';
+ gwin->menu_hook[25].h_Entry = (HOOKFUNC)ami_menu_item_edit_clearsel;
+
gwin->menutype[26] = NM_TITLE;
gwin->menulab[26] = ami_utf8_easy((char *)messages_get("Browser"));
+
gwin->menutype[27] = NM_ITEM;
gwin->menulab[27] = ami_utf8_easy((char *)messages_get("FindTextNS"));
gwin->menukey[27] = 'F';
+ gwin->menu_hook[27].h_Entry = (HOOKFUNC)ami_menu_item_browser_find;
+
gwin->menutype[28] = NM_ITEM;
gwin->menulab[28] = NM_BARLABEL;
+
gwin->menutype[29] = NM_ITEM;
gwin->menulab[29] = ami_utf8_easy((char *)messages_get("HistLocalNS"));
+ gwin->menu_hook[29].h_Entry = (HOOKFUNC)ami_menu_item_browser_localhistory;
+
gwin->menutype[30] = NM_ITEM;
gwin->menulab[30] = ami_utf8_easy((char *)messages_get("HistGlobalNS"));
+ gwin->menu_hook[30].h_Entry = (HOOKFUNC)ami_menu_item_browser_globalhistory;
+
gwin->menutype[31] = NM_ITEM;
gwin->menulab[31] = NM_BARLABEL;
+
gwin->menutype[32] = NM_ITEM;
gwin->menulab[32] = ami_utf8_easy((char *)messages_get("ShowCookies"));
+ gwin->menu_hook[32].h_Entry = (HOOKFUNC)ami_menu_item_browser_cookies;
+
gwin->menutype[33] = NM_ITEM;
gwin->menulab[33] = NM_BARLABEL;
+
gwin->menutype[34] = NM_ITEM;
gwin->menulab[34] = ami_utf8_easy((char *)messages_get("ScaleNS"));
+
gwin->menutype[35] = NM_SUB;
gwin->menulab[35] = ami_utf8_easy((char *)messages_get("ScaleDec"));
gwin->menukey[35] = '-';
+ gwin->menu_hook[35].h_Entry = (HOOKFUNC)ami_menu_item_browser_scale_decrease;
+
gwin->menutype[36] = NM_SUB;
gwin->menulab[36] = ami_utf8_easy((char *)messages_get("ScaleNorm"));
gwin->menukey[36] = '=';
+ gwin->menu_hook[36].h_Entry = (HOOKFUNC)ami_menu_item_browser_scale_normal;
+
gwin->menutype[37] = NM_SUB;
gwin->menulab[37] = ami_utf8_easy((char *)messages_get("ScaleInc"));
gwin->menukey[37] = '+';
+ gwin->menu_hook[37].h_Entry = (HOOKFUNC)ami_menu_item_browser_scale_increase;
+
gwin->menutype[38] = NM_ITEM;
gwin->menulab[38] = ami_utf8_easy((char *)messages_get("Redraw"));
+ gwin->menu_hook[38].h_Entry = (HOOKFUNC)ami_menu_item_browser_redraw;
+
gwin->menutype[39] = NM_TITLE;
gwin->menulab[39] = ami_utf8_easy((char *)messages_get("Hotlist"));
- gwin->menukey[39] = 'H';
+
gwin->menutype[40] = NM_ITEM;
gwin->menulab[40] = ami_utf8_easy((char *)messages_get("HotlistAdd"));
gwin->menukey[40] = 'B';
+ gwin->menu_hook[40].h_Entry = (HOOKFUNC)ami_menu_item_hotlist_add;
+
gwin->menutype[41] = NM_ITEM;
gwin->menulab[41] = ami_utf8_easy((char *)messages_get("HotlistShowNS"));
gwin->menukey[41] = 'H';
+ gwin->menu_hook[41].h_Entry = (HOOKFUNC)ami_menu_item_hotlist_show;
+
gwin->menutype[42] = NM_ITEM;
gwin->menulab[42] = NM_BARLABEL;
gwin->menutype[AMI_MENU_HOTLIST_MAX + 1] = NM_TITLE;
gwin->menulab[AMI_MENU_HOTLIST_MAX + 1] = ami_utf8_easy((char *)messages_get("Settings"));
+
gwin->menutype[AMI_MENU_HOTLIST_MAX + 2] = NM_ITEM;
gwin->menulab[AMI_MENU_HOTLIST_MAX + 2] = ami_utf8_easy((char *)messages_get("SettingsEdit"));
+ gwin->menu_hook[AMI_MENU_HOTLIST_MAX + 2].h_Entry = (HOOKFUNC)ami_menu_item_settings_edit;
+
gwin->menutype[AMI_MENU_HOTLIST_MAX + 3] = NM_ITEM;
gwin->menulab[AMI_MENU_HOTLIST_MAX + 3] = NM_BARLABEL;
+
gwin->menutype[AMI_MENU_HOTLIST_MAX + 4] = NM_ITEM;
gwin->menulab[AMI_MENU_HOTLIST_MAX + 4] = ami_utf8_easy((char *)messages_get("SnapshotWindow"));
+ gwin->menu_hook[AMI_MENU_HOTLIST_MAX + 4].h_Entry = (HOOKFUNC)ami_menu_item_settings_snapshot;
+
gwin->menutype[AMI_MENU_HOTLIST_MAX + 5] = NM_ITEM;
gwin->menulab[AMI_MENU_HOTLIST_MAX + 5] = ami_utf8_easy((char *)messages_get("SettingsSave"));
+ gwin->menu_hook[AMI_MENU_HOTLIST_MAX + 5].h_Entry = (HOOKFUNC)ami_menu_item_settings_save;
+
gwin->menutype[AMI_MENU_HOTLIST_MAX + 6] = NM_TITLE;
gwin->menulab[AMI_MENU_HOTLIST_MAX + 6] = ami_utf8_easy((char *)messages_get("ARexx"));
+
gwin->menutype[AMI_MENU_HOTLIST_MAX + 7] = NM_ITEM;
gwin->menulab[AMI_MENU_HOTLIST_MAX + 7] = ami_utf8_easy((char *)messages_get("ARexxExecute"));
gwin->menukey[AMI_MENU_HOTLIST_MAX + 7] = 'E';
+ gwin->menu_hook[AMI_MENU_HOTLIST_MAX + 7].h_Entry = (HOOKFUNC)ami_menu_item_arexx_execute;
+
gwin->menutype[AMI_MENU_HOTLIST_MAX + 8] = NM_ITEM;
gwin->menulab[AMI_MENU_HOTLIST_MAX + 8] = NM_BARLABEL;
@@ -283,6 +405,7 @@
gwin->menu[i].nm_Label = gwin->menulab[i];
if(gwin->menukey[i]) gwin->menu[i].nm_CommKey = &gwin->menukey[i];
gwin->menu[i].nm_Flags = 0;
+ if(gwin->menu_hook[i].h_Entry) gwin->menu[i].nm_UserData = &gwin->menu_hook[i];
}
gwin->menu[1].nm_Flags = 0;
@@ -351,7 +474,9 @@
}
gwin->menu[item].nm_Label = gwin->menulab[item];
- gwin->menu[item].nm_UserData = (char *)strdup(ead->ed_Name);
+ gwin->menu_hook[item].h_Entry = (HOOKFUNC)ami_menu_item_arexx_entries;
+ gwin->menu_hook[item].h_Data = (char *)strdup(ead->ed_Name);
+ gwin->menu[item].nm_UserData = (HOOKFUNC)&gwin->menu_hook[item];
item++;
}
@@ -422,8 +547,9 @@
}
gwin->menu[*item].nm_Label = gwin->menulab[*item];
-
- gwin->menu[*item].nm_UserData = (void *)tree_url_node_get_url(node);
+ gwin->menu_hook[*item].h_Entry = (HOOKFUNC)ami_menu_item_hotlist_entries;
+ gwin->menu_hook[*item].h_Data = (void *)tree_url_node_get_url(node);
+ gwin->menu[*item].nm_UserData = (HOOKFUNC)&gwin->menu_hook[*item];
if(tree_node_is_folder(node) && (!tree_node_get_child(node)))
gwin->menu[*item].nm_Flags = NM_ITEMDISABLED;
}
@@ -438,297 +564,6 @@
}
*gen = *gen - 1;
-}
-
-void ami_menupick(ULONG code,struct gui_window_2 *gwin,struct MenuItem *item)
-{
- struct browser_window *bw;
- ULONG menunum=0,itemnum=0,subnum=0;
- menunum = MENUNUM(code);
- itemnum = ITEMNUM(code);
- subnum = SUBNUM(code);
- char *temp, *temp2;
- int sel = 0;
- struct bitmap *bm = NULL;
-
- switch(menunum)
- {
- case 0: // project
- switch(itemnum)
- {
- case 0: // new window
- bw = browser_window_create(nsoption_charp(homepage_url), NULL, 0, true, false);
- break;
-
- case 1: // new tab
- bw = browser_window_create(nsoption_charp(homepage_url), gwin->bw, 0, true, true);
- break;
-
- case 3: // open local file
- ami_file_open(gwin);
- break;
-
- case 4: // save
- switch(subnum)
- {
- case 0:
- ami_file_save_req(AMINS_SAVE_SOURCE, gwin,
- gwin->bw->current_content, NULL);
- break;
-
- case 1:
- ami_file_save_req(AMINS_SAVE_TEXT, gwin,
- gwin->bw->current_content, NULL);
- break;
-
- case 2:
- ami_file_save_req(AMINS_SAVE_COMPLETE, gwin,
- gwin->bw->current_content, NULL);
- break;
-
- case 3:
- ami_file_save_req(AMINS_SAVE_PDF, gwin,
- gwin->bw->current_content, NULL);
- break;
-
- case 4: // iff
- ami_file_save_req(AMINS_SAVE_IFF, gwin,
- gwin->bw->current_content, NULL);
- break;
- }
- break;
-
- case 6: // close tab
- browser_window_destroy(gwin->bw);
- break;
-
- case 7: // close window
- ami_close_all_tabs(gwin);
- break;
-
- case 9: // print
- ami_update_pointer(gwin->win,GUI_POINTER_WAIT);
- ami_print_ui(gwin->bw->current_content);
- ami_update_pointer(gwin->win,GUI_POINTER_DEFAULT);
- break;
-
- case 11: // about
- ami_update_pointer(gwin->win,GUI_POINTER_WAIT);
-
- temp = ASPrintf("%s|%s|%s", messages_get("OK"),
- messages_get("HelpCredits"),
- messages_get("HelpLicence"));
-
- temp2 = ami_utf8_easy(temp);
- FreeVec(temp);
-
- sel = TimedDosRequesterTags(
- TDR_ImageType,TDRIMAGE_INFO,
- TDR_TitleString, messages_get("NetSurf"),
- TDR_Window, gwin->win,
- TDR_GadgetString, temp2,
-#ifndef NDEBUG
- TDR_FormatString,"NetSurf %s\n%s\n%s (%s)\n\nhttp://www.netsurf-browser.org",
-#else
- TDR_FormatString,"NetSurf %s\n%s\n\nhttp://www.netsurf-browser.org",
-#endif
- TDR_Arg1,netsurf_version,
-#ifdef NS_AMIGA_CAIRO
- TDR_Arg2,"Cairo (OS4.1+) SObjs build",
-#else
- TDR_Arg2,"graphics.library static build",
-#endif
- TDR_Arg3,versvn,
- TDR_Arg4,verdate,
- TAG_DONE);
-
- free(temp2);
-
- if(sel == 2)
- browser_window_create("about:credits", NULL, 0, true, false);
- else if(sel == 0)
- browser_window_create("about:licence", NULL, 0, true, false);
-
- ami_update_pointer(gwin->win,GUI_POINTER_DEFAULT);
- break;
-
- case 12: // quit
- ami_quit_netsurf();
- break;
- }
- break;
-
- case 1: // edit
- switch(itemnum)
- {
- case 0: // cut
- browser_window_key_press(gwin->bw, KEY_CUT_SELECTION);
- break;
-
- case 1: // copy
- if(content_get_type(gwin->bw->current_content) <= CONTENT_CSS)
- {
- browser_window_key_press(gwin->bw, KEY_COPY_SELECTION);
- browser_window_key_press(gwin->bw, KEY_CLEAR_SELECTION);
- }
- else if(bm = content_get_bitmap(gwin->bw->current_content))
- {
- bm->url = (char *)nsurl_access(hlcache_handle_get_url(gwin->bw->current_content));
- bm->title = (char *)content_get_title(gwin->bw->current_content);
- ami_easy_clipboard_bitmap(bm);
- }
-#ifdef WITH_NS_SVG
- else if(ami_mime_compare(gwin->bw->current_content, "svg") == true)
- {
- ami_easy_clipboard_svg(gwin->bw->current_content);
- }
-#endif
- break;
-
- case 2: // paste
- browser_window_key_press(gwin->bw, KEY_PASTE);
- break;
-
- case 4: // select all
- browser_window_key_press(gwin->bw, KEY_SELECT_ALL);
- gui_start_selection(gwin->bw->window);
- break;
-
- case 5: // clear selection
- browser_window_key_press(gwin->bw, KEY_CLEAR_SELECTION);
- break;
- }
- break;
-
- case 2:
- switch(itemnum)
- {
- case 0: // search
- ami_search_open(gwin->bw->window);
- break;
-
- case 2: // local history
- if(gwin->bw && gwin->bw->history)
- ami_history_open(gwin->bw, gwin->bw->history);
- break;
-
- case 3: // global history
- ami_tree_open(global_history_window,AMI_TREE_HISTORY);
- break;
-
- case 5: // cookies tree
- ami_tree_open(cookies_window,AMI_TREE_COOKIES);
- break;
-
- case 7: // size
- switch(subnum)
- {
- case 0: // decrease */
- if(gwin->bw->scale > 0.1)
- browser_window_set_scale(gwin->bw,
- gwin->bw->scale - 0.1, false);
- break;
-
- case 1: // normal */
- browser_window_set_scale(gwin->bw, 1.0, false);
- break;
-
- case 2: // increase */
- browser_window_set_scale(gwin->bw,
- gwin->bw->scale + 0.1, false);
- break;
- }
- break;
-
- case 8: // redraw
- gwin->redraw_required = true;
- gwin->new_content = true;
- break;
- }
- break;
-
- case 3: // hotlist
- switch(itemnum)
- {
- case 0: // add
- bw = gwin->bw;
-
- if (bw == NULL ||
- bw->current_content == NULL ||
- nsurl_access(hlcache_handle_get_url(bw->current_content)) == NULL)
- break;
-
- hotlist_add_page(nsurl_access(hlcache_handle_get_url(bw->current_content)));
- break;
-
- case 1: // show
- ami_tree_open(hotlist_window, AMI_TREE_HOTLIST);
- break;
-
- default: // bookmarks
- if(GTMENUITEM_USERDATA(item))
- browser_window_go(gwin->bw,GTMENUITEM_USERDATA(item),NULL, true);
- break;
- }
- break;
-
- case 4: // settings
- switch(itemnum)
- {
- case 0: // edit prefs
- ami_gui_opts_open();
- break;
-
- case 2: // snapshot
- nsoption_set_int(window_x, gwin->win->LeftEdge);
- nsoption_set_int(window_y, gwin->win->TopEdge);
- nsoption_set_int(window_width, gwin->win->Width);
- nsoption_set_int(window_height, gwin->win->Height);
- break;
-
- case 3: // save settings
- nsoption_write(current_user_options);
- break;
- }
- break;
-
- case 5: // arexx
- switch(itemnum)
- {
- case 0: // execute arexx
- if(AslRequestTags(filereq,
- ASLFR_TitleText,messages_get("NetSurf"),
- ASLFR_Screen,scrn,
- ASLFR_DoSaveMode,FALSE,
- ASLFR_InitialDrawer,nsoption_charp(arexx_dir),
- ASLFR_InitialPattern,"#?.nsrx",
- TAG_DONE))
- {
- if(temp = AllocVec(1024,MEMF_PRIVATE | MEMF_CLEAR))
- {
- strlcpy(temp,filereq->fr_Drawer,1024);
- AddPart(temp,filereq->fr_File,1024);
- ami_arexx_execute(temp);
- FreeVec(temp);
- }
- }
- break;
-
- default: // arexx menu items
- if(GTMENUITEM_USERDATA(item))
- {
- if(temp = AllocVec(1024,MEMF_PRIVATE | MEMF_CLEAR))
- {
- strcpy(temp,nsoption_charp(arexx_dir));
- AddPart(temp,GTMENUITEM_USERDATA(item),1024);
- ami_arexx_execute(temp);
- FreeVec(temp);
- }
- }
- break;
- }
- break;
- }
}
void ami_menu_update_disabled(struct gui_window *g, hlcache_handle *c)
@@ -790,3 +625,330 @@
}
}
}
+
+/*
+ * The below functions are called automatically by window.class when menu items are selected.
+ */
+
+static void ami_menu_item_project_newwin(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct browser_window *bw;
+
+ bw = browser_window_create(nsoption_charp(homepage_url), NULL, 0, true, false);
+}
+
+static void ami_menu_item_project_newtab(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct browser_window *bw;
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ bw = browser_window_create(nsoption_charp(homepage_url), gwin->bw, 0, true, true);
+}
+
+static void ami_menu_item_project_open(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ ami_file_open(gwin);
+}
+
+static void ami_menu_item_project_save(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ ULONG type = (ULONG)hook->h_Data;
+
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ ami_file_save_req(type, gwin, gwin->bw->current_content, NULL);
+}
+
+static void ami_menu_item_project_closetab(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ browser_window_destroy(gwin->bw);
+}
+
+static void ami_menu_item_project_closewin(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ ami_close_all_tabs(gwin);
+}
+
+static void ami_menu_item_project_print(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ ami_update_pointer(gwin->win,GUI_POINTER_WAIT);
+ ami_print_ui(gwin->bw->current_content);
+ ami_update_pointer(gwin->win,GUI_POINTER_DEFAULT);
+}
+
+static void ami_menu_item_project_about(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ char *temp, *temp2;
+ int sel;
+
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ ami_update_pointer(gwin->win,GUI_POINTER_WAIT);
+
+ temp = ASPrintf("%s|%s|%s", messages_get("OK"),
+ messages_get("HelpCredits"),
+ messages_get("HelpLicence"));
+
+ temp2 = ami_utf8_easy(temp);
+ FreeVec(temp);
+
+ sel = TimedDosRequesterTags(TDR_ImageType,TDRIMAGE_INFO,
+ TDR_TitleString, messages_get("NetSurf"),
+ TDR_Window, gwin->win,
+ TDR_GadgetString, temp2,
+#ifndef NDEBUG
+ TDR_FormatString,"NetSurf %s\n%s\n%s (%s)\n\nhttp://www.netsurf-browser.org",
+#else
+ TDR_FormatString,"NetSurf %s\n%s\n\nhttp://www.netsurf-browser.org",
+#endif
+ TDR_Arg1,netsurf_version,
+#ifdef NS_AMIGA_CAIRO
+ TDR_Arg2,"Cairo (OS4.1+) SObjs build",
+#else
+ TDR_Arg2,"graphics.library static build",
+#endif
+ TDR_Arg3,versvn,
+ TDR_Arg4,verdate,
+ TAG_DONE);
+
+ free(temp2);
+
+ if(sel == 2)
+ browser_window_create("about:credits", NULL, 0, true, false);
+ else if(sel == 0)
+ browser_window_create("about:licence", NULL, 0, true, false);
+
+ ami_update_pointer(gwin->win,GUI_POINTER_DEFAULT);
+}
+
+static void ami_menu_item_project_quit(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ ami_quit_netsurf();
+}
+
+static void ami_menu_item_edit_cut(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ browser_window_key_press(gwin->bw, KEY_CUT_SELECTION);
+}
+
+static void ami_menu_item_edit_copy(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct bitmap *bm;
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ if(content_get_type(gwin->bw->current_content) <= CONTENT_CSS)
+ {
+ browser_window_key_press(gwin->bw, KEY_COPY_SELECTION);
+ browser_window_key_press(gwin->bw, KEY_CLEAR_SELECTION);
+ }
+ else if(bm = content_get_bitmap(gwin->bw->current_content))
+ {
+ bm->url = (char *)nsurl_access(hlcache_handle_get_url(gwin->bw->current_content));
+ bm->title = (char *)content_get_title(gwin->bw->current_content);
+ ami_easy_clipboard_bitmap(bm);
+ }
+#ifdef WITH_NS_SVG
+ else if(ami_mime_compare(gwin->bw->current_content, "svg") == true)
+ {
+ ami_easy_clipboard_svg(gwin->bw->current_content);
+ }
+#endif
+}
+
+static void ami_menu_item_edit_paste(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ browser_window_key_press(gwin->bw, KEY_PASTE);
+}
+
+static void ami_menu_item_edit_selectall(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ browser_window_key_press(gwin->bw, KEY_SELECT_ALL);
+ gui_start_selection(gwin->bw->window);
+}
+
+static void ami_menu_item_edit_clearsel(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ browser_window_key_press(gwin->bw, KEY_CLEAR_SELECTION);
+}
+
+static void ami_menu_item_browser_find(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ ami_search_open(gwin->bw->window);
+}
+
+static void ami_menu_item_browser_localhistory(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ if(gwin->bw && gwin->bw->history)
+ ami_history_open(gwin->bw, gwin->bw->history);
+}
+
+static void ami_menu_item_browser_globalhistory(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ ami_tree_open(global_history_window,AMI_TREE_HISTORY);
+}
+
+static void ami_menu_item_browser_cookies(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ ami_tree_open(cookies_window,AMI_TREE_COOKIES);
+}
+
+static void ami_menu_item_browser_scale_decrease(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ if(browser_window_get_scale(gwin->bw) > 0.1)
+ browser_window_set_scale(gwin->bw, browser_window_get_scale(gwin->bw) - 0.1, false);
+}
+
+static void ami_menu_item_browser_scale_normal(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ browser_window_set_scale(gwin->bw, 1.0, false);
+}
+
+static void ami_menu_item_browser_scale_increase(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ browser_window_set_scale(gwin->bw, browser_window_get_scale(gwin->bw) + 0.1, false);
+}
+
+static void ami_menu_item_browser_redraw(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ gwin->redraw_required = true;
+ gwin->new_content = true;
+}
+
+static void ami_menu_item_hotlist_add(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct browser_window *bw;
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ bw = gwin->bw;
+
+ if (bw == NULL || bw->current_content == NULL ||
+ nsurl_access(hlcache_handle_get_url(bw->current_content)) == NULL)
+ return;
+
+ hotlist_add_page(nsurl_access(hlcache_handle_get_url(bw->current_content)));
+}
+
+static void ami_menu_item_hotlist_show(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ ami_tree_open(hotlist_window, AMI_TREE_HOTLIST);
+}
+
+static void ami_menu_item_hotlist_entries(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ char *url = hook->h_Data;
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ if(url) browser_window_go(gwin->bw, url, NULL, true);
+}
+
+static void ami_menu_item_settings_edit(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ ami_gui_opts_open();
+}
+
+static void ami_menu_item_settings_snapshot(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ nsoption_set_int(window_x, gwin->win->LeftEdge);
+ nsoption_set_int(window_y, gwin->win->TopEdge);
+ nsoption_set_int(window_width, gwin->win->Width);
+ nsoption_set_int(window_height, gwin->win->Height);
+}
+
+static void ami_menu_item_settings_save(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ nsoption_write(current_user_options);
+}
+
+static void ami_menu_item_arexx_execute(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ char *temp;
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ if(AslRequestTags(filereq,
+ ASLFR_TitleText, messages_get("NetSurf"),
+ ASLFR_Screen, scrn,
+ ASLFR_DoSaveMode, FALSE,
+ ASLFR_InitialDrawer, nsoption_charp(arexx_dir),
+ ASLFR_InitialPattern, "#?.nsrx",
+ TAG_DONE))
+ {
+ if(temp = AllocVec(1024,MEMF_PRIVATE | MEMF_CLEAR))
+ {
+ strlcpy(temp, filereq->fr_Drawer, 1024);
+ AddPart(temp, filereq->fr_File, 1024);
+ ami_arexx_execute(temp);
+ FreeVec(temp);
+ }
+ }
+}
+
+static void ami_menu_item_arexx_entries(struct Hook *hook, APTR window, struct IntuiMessage *msg)
+{
+ char *script = hook->h_Data;
+ char *temp;
+ struct gui_window_2 *gwin;
+ GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+
+ if(script)
+ {
+ if(temp = AllocVec(1024, MEMF_PRIVATE | MEMF_CLEAR))
+ {
+ strcpy(temp, nsoption_charp(arexx_dir));
+ AddPart(temp, script, 1024);
+ ami_arexx_execute(temp);
+ FreeVec(temp);
+ }
+ }
+}
Modified: trunk/netsurf/amiga/menu.h
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/menu.h?rev=13898&r1...
==============================================================================
--- trunk/netsurf/amiga/menu.h (original)
+++ trunk/netsurf/amiga/menu.h Sun Apr 29 10:59:37 2012
@@ -69,6 +69,5 @@
void ami_free_menulabs(struct gui_window_2 *gwin);
struct NewMenu *ami_create_menu(struct gui_window_2 *gwin);
void ami_menu_refresh(struct gui_window_2 *gwin);
-void ami_menupick(ULONG code,struct gui_window_2 *gwin,struct MenuItem *item);
void ami_menu_update_disabled(struct gui_window *g, hlcache_handle *c);
#endif
11 years, 4 months
r13897 tlsa - in /trunk/netsurfweb/projects: hubbub/index.en libcss/index.en libwapcaplet/index.en
by netsurf@semichrome.net
Author: tlsa
Date: Sun Apr 29 06:52:13 2012
New Revision: 13897
URL: http://source.netsurf-browser.org?rev=13897&view=rev
Log:
Update project pages with new releases.
Modified:
trunk/netsurfweb/projects/hubbub/index.en
trunk/netsurfweb/projects/libcss/index.en
trunk/netsurfweb/projects/libwapcaplet/index.en
Modified: trunk/netsurfweb/projects/hubbub/index.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/projects/hubbub/index....
==============================================================================
--- trunk/netsurfweb/projects/hubbub/index.en (original)
+++ trunk/netsurfweb/projects/hubbub/index.en Sun Apr 29 06:52:13 2012
@@ -69,6 +69,7 @@
<h2>Releases</h2>
<ul>
+<li><a href="../releases/hubbub-0.1.2-src.tar.gz">Hubbub 0.1.2 tarball</a></li>
<li><a href="../releases/hubbub-0.1.1-src.tar.gz">Hubbub 0.1.1 tarball</a></li>
<li><a href="../releases/hubbub-0.1.0-src.tar.gz">Hubbub 0.1.0 tarball</a></li>
<li><a href="../releases/hubbub-0.0.2-src.tar.gz">Hubbub 0.0.2 tarball</a></li>
Modified: trunk/netsurfweb/projects/libcss/index.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/projects/libcss/index....
==============================================================================
--- trunk/netsurfweb/projects/libcss/index.en (original)
+++ trunk/netsurfweb/projects/libcss/index.en Sun Apr 29 06:52:13 2012
@@ -65,6 +65,8 @@
<p>Most recent first:</p>
<dl class="releases">
+<dt>LibCSS 0.1.2</dt>
+<dd><a href="../releases/libcss-0.1.2-src.tar.gz">Tarball</a> – <a href="#changes-0.1.2">Changes</a></dd>
<dt>LibCSS 0.1.1</dt>
<dd><a href="../releases/libcss-0.1.1-src.tar.gz">Tarball</a> – <a href="#changes-0.1.1">Changes</a></dd>
<dt>LibCSS 0.1.0</dt>
@@ -78,6 +80,15 @@
<h2>Changes</h2>
<dl class="changes">
+<dt id="changes-0.1.2">LibCSS 0.1.2</dt>
+<dd><ul>
+<li>Avoided interning standard strings for every stylesheet, style tag and style attribute.</li>
+<li>Made significant optimisations to style selection.</li>
+<li>Fixed case where font-family is unspecified in input CSS.</li>
+<li>Added some support for @font-face.</li>
+<li>Fixed !important on opacity property.</li>
+<li>Added support for parsing CSS3 Multi-column layout properties.</li>
+</ul></dd>
<dt id="changes-0.1.1">LibCSS 0.1.1</dt>
<dd><ul>
<li>Improved build tree cleaning.</li>
Modified: trunk/netsurfweb/projects/libwapcaplet/index.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/projects/libwapcaplet/...
==============================================================================
--- trunk/netsurfweb/projects/libwapcaplet/index.en (original)
+++ trunk/netsurfweb/projects/libwapcaplet/index.en Sun Apr 29 06:52:13 2012
@@ -46,6 +46,7 @@
<h2>Releases</h2>
<ul>
+<li><a href="../releases/libwapcaplet-0.1.1-src.tar.gz">LibWapcaplet 0.1.1 tarball</a></li>
<li><a href="../releases/libwapcaplet-0.1.0-src.tar.gz">LibWapcaplet 0.1.0 tarball</a></li>
<li><a href="../releases/libwapcaplet-0.0.2-src.tar.gz">LibWapcaplet 0.0.2 tarball</a></li>
</ul>
11 years, 4 months
r13896 chris_y - in /trunk/netsurf/amiga: gui.c options.h
by netsurf@semichrome.net
Author: chris_y
Date: Sat Apr 28 18:23:29 2012
New Revision: 13896
URL: http://source.netsurf-browser.org?rev=13896&view=rev
Log:
Make simple refresh a configurable option
Modified:
trunk/netsurf/amiga/gui.c
trunk/netsurf/amiga/options.h
Modified: trunk/netsurf/amiga/gui.c
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/gui.c?rev=13896&r1=...
==============================================================================
--- trunk/netsurf/amiga/gui.c (original)
+++ trunk/netsurf/amiga/gui.c Sat Apr 28 18:23:29 2012
@@ -2475,6 +2475,7 @@
char closetab[100],closetab_s[100],closetab_g[100];
char addtab[100],addtab_s[100],addtab_g[100];
char tabthrobber[100];
+ ULONG refresh_mode = WA_SmartRefresh;
if (!scrn) ami_openscreenfirst();
@@ -2576,6 +2577,12 @@
newprefs_hook.h_Entry = (void *)ami_gui_newprefs_hook;
newprefs_hook.h_Data = 0;
+
+ if(nsoption_bool(window_simple_refresh) == true) {
+ refresh_mode = WA_SimpleRefresh;
+ } else {
+ refresh_mode = WA_SmartRefresh;
+ }
if(!nsoption_bool(kiosk_mode))
{
@@ -2703,29 +2710,20 @@
WA_Height,curh,
WA_CustomScreen,scrn,
WA_ReportMouse,TRUE,
-#ifdef AMI_SIMPLEREFRESH
- WA_SimpleRefresh,TRUE,
-#else
- WA_SmartRefresh,TRUE,
-#endif
+ refresh_mode, TRUE,
WA_SizeBBottom, TRUE,
WA_IDCMP,IDCMP_MENUPICK | IDCMP_MOUSEMOVE |
IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE |
IDCMP_RAWKEY | IDCMP_SIZEVERIFY |
IDCMP_GADGETUP | IDCMP_IDCMPUPDATE |
-#ifdef AMI_SIMPLEREFRESH
IDCMP_REFRESHWINDOW |
-#endif
IDCMP_ACTIVEWINDOW | IDCMP_EXTENDEDMOUSE,
WINDOW_IconifyGadget, iconifygadget,
WINDOW_NewMenu, gwin->shared->menu,
WINDOW_VertProp,1,
WINDOW_NewPrefsHook,&newprefs_hook,
WINDOW_IDCMPHook,&gwin->shared->scrollerhook,
- WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE |
-#ifdef AMI_SIMPLEREFRESH
- IDCMP_REFRESHWINDOW |
-#endif
+ WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE | IDCMP_REFRESHWINDOW |
IDCMP_EXTENDEDMOUSE | IDCMP_SIZEVERIFY,
WINDOW_SharedPort,sport,
WINDOW_BuiltInScroll,TRUE,
@@ -2904,17 +2902,19 @@
WA_Width, scrn->Width,
WA_Height, scrn->Height,
WA_SizeGadget, FALSE,
- WA_CustomScreen,scrn,
- WA_ReportMouse,TRUE,
- WA_IDCMP,IDCMP_MENUPICK | IDCMP_MOUSEMOVE |
+ WA_CustomScreen, scrn,
+ WA_ReportMouse, TRUE,
+ refresh_mode, TRUE,
+ WA_IDCMP, IDCMP_MENUPICK | IDCMP_MOUSEMOVE |
IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE |
- IDCMP_RAWKEY | // IDCMP_INTUITICKS |
+ IDCMP_RAWKEY | IDCMP_REFRESHWINDOW |
IDCMP_GADGETUP | IDCMP_IDCMPUPDATE |
IDCMP_EXTENDEDMOUSE,
WINDOW_HorizProp,1,
WINDOW_VertProp,1,
WINDOW_IDCMPHook,&gwin->shared->scrollerhook,
- WINDOW_IDCMPHookBits,IDCMP_IDCMPUPDATE | IDCMP_EXTENDEDMOUSE,
+ WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE |
+ IDCMP_EXTENDEDMOUSE | IDCMP_REFRESHWINDOW,
WINDOW_SharedPort,sport,
WINDOW_UserData,gwin->shared,
WINDOW_BuiltInScroll,TRUE,
@@ -3527,11 +3527,10 @@
g->new_content = false;
}
-#if AMI_SIMPLEREFRESH
-// simplerefresh only
-
void ami_refresh_window(struct gui_window_2 *gwin)
{
+ /* simplerefresh only */
+
struct IBox *bbox;
int x0, x1, y0, y1, sx, sy;
struct RegionRectangle *regrect, *nregrect;
@@ -3572,22 +3571,8 @@
ami_do_redraw_limits(gwin->bw->window, gwin->bw, x0, y0, x1, y1);
}
-/* quick refresh - scuppered by shared offscreen bitmap
- BltBitMapTags(BLITA_SrcType, BLITT_BITMAP,
- BLITA_Source, browserglob.bm,
- BLITA_SrcX, 0,
- BLITA_SrcY, 0,
- BLITA_DestType, BLITT_RASTPORT,
- BLITA_Dest, gwin->win->RPort,
- BLITA_DestX, bbox->Left,
- BLITA_DestY, bbox->Top,
- BLITA_Width, bbox->Width,
- BLITA_Height, bbox->Height,
- TAG_DONE);
-*/
EndRefresh(gwin->win, TRUE);
}
-#endif
void ami_get_hscroll_pos(struct gui_window_2 *gwin, ULONG *xs)
{
@@ -4051,16 +4036,13 @@
case IDCMP_SIZEVERIFY:
break;
-#ifdef AMI_SIMPLEREFRESH
case IDCMP_REFRESHWINDOW:
-//printf("refreshing\n");
ami_refresh_window(gwin);
break;
default:
printf("UNHANDLED EVENT %ld\n",msg->Class);
break;
-#endif
}
// ReplyMsg((struct Message *)msg);
}
Modified: trunk/netsurf/amiga/options.h
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/options.h?rev=13896...
==============================================================================
--- trunk/netsurf/amiga/options.h (original)
+++ trunk/netsurf/amiga/options.h Sat Apr 28 18:23:29 2012
@@ -70,6 +70,7 @@
int cookies_window_ysize; \
int cairo_renderer; \
bool direct_render; \
+ bool window_simple_refresh; \
int redraw_tile_size_x; \
int redraw_tile_size_y; \
int monitor_aspect_x; \
@@ -125,6 +126,7 @@
.cookies_window_ysize = 0, \
.cairo_renderer = 1, \
.direct_render = false, \
+ .window_simple_refresh = false, \
.redraw_tile_size_x = 400, \
.redraw_tile_size_y = 150, \
.monitor_aspect_x = 0, \
@@ -179,6 +181,7 @@
{ "cookies_window_ysize", OPTION_INTEGER, &nsoptions.cookies_window_ysize}, \
{ "cairo_renderer", OPTION_INTEGER, &nsoptions.cairo_renderer}, \
{ "direct_render", OPTION_BOOL, &nsoptions.direct_render}, \
+{ "window_simple_refresh", OPTION_BOOL, &nsoptions.window_simple_refresh}, \
{ "redraw_tile_size_x", OPTION_INTEGER, &nsoptions.redraw_tile_size_x}, \
{ "redraw_tile_size_y", OPTION_INTEGER, &nsoptions.redraw_tile_size_y}, \
{ "monitor_aspect_x", OPTION_INTEGER, &nsoptions.monitor_aspect_x}, \
11 years, 4 months
r13895 chris_y - /trunk/netsurf/amiga/gui.c
by netsurf@semichrome.net
Author: chris_y
Date: Sat Apr 28 17:53:50 2012
New Revision: 13895
URL: http://source.netsurf-browser.org?rev=13895&view=rev
Log:
Fix simplerefresh. When dragging windows back on-screen, damaged areas are
still not repaired fully. Overlapping windows have no such problem.
Menu events seem to be getting lost in simple refresh mode (this may be
related to event triggered for redrawing the area under the menu when it is
closed)
Modified:
trunk/netsurf/amiga/gui.c
Modified: trunk/netsurf/amiga/gui.c
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/gui.c?rev=13895&r1=...
==============================================================================
--- trunk/netsurf/amiga/gui.c (original)
+++ trunk/netsurf/amiga/gui.c Sat Apr 28 17:53:50 2012
@@ -3533,18 +3533,24 @@
void ami_refresh_window(struct gui_window_2 *gwin)
{
struct IBox *bbox;
- int x0, x1, y0, y1;
+ int x0, x1, y0, y1, sx, sy;
struct RegionRectangle *regrect, *nregrect;
+ sx = gwin->bw->window->scrollx;
+ sy = gwin->bw->window->scrolly;
+
GetAttr(SPACE_AreaBox, (Object *)gwin->objects[GID_BROWSER], (ULONG *)&bbox);
BeginRefresh(gwin->win);
-// probably need to trawl through struct Region *DamageList
- x0 = gwin->win->RPort->Layer->DamageList->bounds.MinX;
- x1 = gwin->win->RPort->Layer->DamageList->bounds.MaxX;
- y0 = gwin->win->RPort->Layer->DamageList->bounds.MinY;
- y1 = gwin->win->RPort->Layer->DamageList->bounds.MaxY;
+ x0 = ((gwin->win->RPort->Layer->DamageList->bounds.MinX - bbox->Left) /
+ browser_window_get_scale(gwin->bw)) + sx;
+ x1 = ((gwin->win->RPort->Layer->DamageList->bounds.MaxX - bbox->Left) /
+ browser_window_get_scale(gwin->bw)) + sx;
+ y0 = ((gwin->win->RPort->Layer->DamageList->bounds.MinY - bbox->Top) /
+ browser_window_get_scale(gwin->bw)) + sy;
+ y1 = ((gwin->win->RPort->Layer->DamageList->bounds.MaxY - bbox->Top) /
+ browser_window_get_scale(gwin->bw)) + sy;
regrect = gwin->win->RPort->Layer->DamageList->RegionRectangle;
@@ -3552,10 +3558,14 @@
while(regrect)
{
- x0 = regrect->bounds.MinX;
- x1 = regrect->bounds.MaxX;
- y0 = regrect->bounds.MinY;
- y1 = regrect->bounds.MaxY;
+ x0 = ((regrect->bounds.MinX - bbox->Left) /
+ browser_window_get_scale(gwin->bw)) + sx;
+ x1 = ((regrect->bounds.MaxX - bbox->Left) /
+ browser_window_get_scale(gwin->bw)) + sx;
+ y0 = ((regrect->bounds.MinY - bbox->Top) /
+ browser_window_get_scale(gwin->bw)) + sy;
+ y1 = ((regrect->bounds.MaxY - bbox->Top) /
+ browser_window_get_scale(gwin->bw)) + sy;
regrect = regrect->Next;
11 years, 4 months
r13894 chris_y - in /trunk/netsurf/amiga: context_menu.c font.c gui.c gui.h
by netsurf@semichrome.net
Author: chris_y
Date: Sat Apr 28 14:43:46 2012
New Revision: 13894
URL: http://source.netsurf-browser.org?rev=13894&view=rev
Log:
Add AppWindow ourself rather than letting window.class create it. Initial
tests indicate we are no longer losing icon drop events although there is
still an "event leak" somewhere.
Fix warnings.
Modified:
trunk/netsurf/amiga/context_menu.c
trunk/netsurf/amiga/font.c
trunk/netsurf/amiga/gui.c
trunk/netsurf/amiga/gui.h
Modified: trunk/netsurf/amiga/context_menu.c
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/context_menu.c?rev=...
==============================================================================
--- trunk/netsurf/amiga/context_menu.c (original)
+++ trunk/netsurf/amiga/context_menu.c Sat Apr 28 14:43:46 2012
@@ -47,6 +47,7 @@
#include "desktop/tree_url_node.h"
#include "render/box.h"
#include "render/form.h"
+#include "render/html.h"
#include "utils/utf8.h"
#include "utils/messages.h"
#include "utils/utils.h"
Modified: trunk/netsurf/amiga/font.c
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/font.c?rev=13894&r1...
==============================================================================
--- trunk/netsurf/amiga/font.c (original)
+++ trunk/netsurf/amiga/font.c Sat Apr 28 14:43:46 2012
@@ -583,7 +583,7 @@
OT_WidthList, &gwlist,
TAG_END) == 0)
{
- gwnode = GetHead((struct MinList *)gwlist);
+ gwnode = (struct GlyphWidthEntry *)GetHead((struct List *)gwlist);
if(gwnode) char1w = gwnode->gwe_Width;
kern = 0;
Modified: trunk/netsurf/amiga/gui.c
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/gui.c?rev=13894&r1=...
==============================================================================
--- trunk/netsurf/amiga/gui.c (original)
+++ trunk/netsurf/amiga/gui.c Sat Apr 28 14:43:46 2012
@@ -17,7 +17,7 @@
*/
/* define this to use simple (as opposed to smart) refresh windows */
-//#define AMI_SIMPLEREFRESH 1
+// #define AMI_SIMPLEREFRESH 1
/* NetSurf core includes */
#include "content/urldb.h"
@@ -1334,7 +1334,6 @@
while((result = RA_HandleInput(gwin->objects[OID_MAIN],&code)) != WMHI_LASTMSG)
{
-
//printf("class %ld\n",class);
switch(result & WMHI_CLASSMASK) // class
{
@@ -1849,9 +1848,9 @@
amiga_icon_superimpose_favicon_internal(gwin->bw->window->favicon,
gwin->dobj);
HideWindow(gwin->win);
- gwin->appicon = AddAppIcon((ULONG)gwin->objects[OID_MAIN], 0,
- gwin->win->Title, appport, 0,
- gwin->dobj, NULL);
+ gwin->appicon = AddAppIcon((ULONG)gwin->objects[OID_MAIN],
+ (ULONG)gwin, gwin->win->Title, appport,
+ 0, gwin->dobj, NULL);
curbw = NULL;
}
@@ -1943,7 +1942,7 @@
while(appmsg=(struct AppMessage *)GetMsg(appport))
{
- GetAttr(WINDOW_UserData, (Object *)appmsg->am_ID, (ULONG *)&gwin);
+ gwin = (struct gui_window_2 *)appmsg->am_UserData;
if(appmsg->am_Type == AMTYPE_APPICON)
{
@@ -2092,7 +2091,9 @@
ULONG signalmask = winsignal | appsig | schedulesig | rxsig | printsig | applibsig;
signal = Wait(signalmask);
-
+/*
+printf("sig recvd %ld (%ld %ld %ld %ld %ld %ld)\n", signal, winsignal , appsig , schedulesig , rxsig , printsig , applibsig);
+*/
if(signal & winsignal)
ami_handle_msg();
@@ -2726,8 +2727,6 @@
IDCMP_REFRESHWINDOW |
#endif
IDCMP_EXTENDEDMOUSE | IDCMP_SIZEVERIFY,
- WINDOW_AppPort, appport,
- WINDOW_AppWindow,TRUE,
WINDOW_SharedPort,sport,
WINDOW_BuiltInScroll,TRUE,
WINDOW_GadgetHelp, TRUE,
@@ -2916,8 +2915,6 @@
WINDOW_VertProp,1,
WINDOW_IDCMPHook,&gwin->shared->scrollerhook,
WINDOW_IDCMPHookBits,IDCMP_IDCMPUPDATE | IDCMP_EXTENDEDMOUSE,
- WINDOW_AppPort, appport,
- WINDOW_AppWindow,TRUE,
WINDOW_SharedPort,sport,
WINDOW_UserData,gwin->shared,
WINDOW_BuiltInScroll,TRUE,
@@ -3026,6 +3023,9 @@
gwin->shared->bw = bw;
curbw = bw;
+ gwin->shared->appwin = AddAppWindowA((ULONG)gwin->shared->objects[OID_MAIN],
+ (ULONG)gwin->shared, gwin->shared->win, appport, NULL);
+
gwin->shared->node = AddObject(window_list,AMINS_WINDOW);
gwin->shared->node->objstruct = gwin->shared;
@@ -3170,6 +3170,7 @@
DisposeObject(g->shared->objects[OID_MAIN]);
ami_gui_appicon_remove(g->shared);
+ if(g->shared->appwin) RemoveAppWindow(g->shared->appwin);
/* These aren't freed by the above.
* TODO: nav_west etc need freeing too */
Modified: trunk/netsurf/amiga/gui.h
URL: http://source.netsurf-browser.org/trunk/netsurf/amiga/gui.h?rev=13894&r1=...
==============================================================================
--- trunk/netsurf/amiga/gui.h (original)
+++ trunk/netsurf/amiga/gui.h Sat Apr 28 14:43:46 2012
@@ -108,6 +108,7 @@
struct Hook search_ico_hook;
gui_drag_type drag_op;
struct IBox *ptr_lock;
+ struct AppWindow *appwin;
};
struct gui_window
11 years, 4 months
r13893 vince - /trunk/netsurf/content/llcache.c
by netsurf@semichrome.net
Author: vince
Date: Sat Apr 28 08:24:09 2012
New Revision: 13893
URL: http://source.netsurf-browser.org?rev=13893&view=rev
Log:
cleanup and reorganise low level cache source ready for extending with disc cache
Modified:
trunk/netsurf/content/llcache.c
Modified: trunk/netsurf/content/llcache.c
URL: http://source.netsurf-browser.org/trunk/netsurf/content/llcache.c?rev=138...
==============================================================================
--- trunk/netsurf/content/llcache.c (original)
+++ trunk/netsurf/content/llcache.c Sat Apr 28 08:24:09 2012
@@ -144,6 +144,7 @@
struct llcache_s {
/** Handler for fetch-related queries */
llcache_query_callback query_cb;
+
/** Data for fetch-related query handler */
void *query_cb_pw;
@@ -164,428 +165,9 @@
static lwc_string *llcache_about_lwc;
static lwc_string *llcache_resource_lwc;
-
-static nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
- llcache_object_user **user);
-static nserror llcache_object_user_destroy(llcache_object_user *user);
-
-static nserror llcache_object_retrieve(nsurl *url, uint32_t flags,
- nsurl *referer, const llcache_post_data *post,
- uint32_t redirect_count, llcache_object **result);
-static nserror llcache_object_retrieve_from_cache(nsurl *url,
- uint32_t flags, nsurl *referer,
- const llcache_post_data *post, uint32_t redirect_count,
- llcache_object **result);
-static bool llcache_object_is_fresh(const llcache_object *object);
-static nserror llcache_object_cache_update(llcache_object *object);
-static nserror llcache_object_clone_cache_data(llcache_object *source,
- llcache_object *destination, bool deep);
-static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
- nsurl *referer, const llcache_post_data *post,
- uint32_t redirect_count);
-static nserror llcache_object_refetch(llcache_object *object);
-
-static nserror llcache_object_new(nsurl *url, llcache_object **result);
-static nserror llcache_object_destroy(llcache_object *object);
-static nserror llcache_object_add_user(llcache_object *object,
- llcache_object_user *user);
-static nserror llcache_object_remove_user(llcache_object *object,
- llcache_object_user *user);
-static llcache_object_user *llcache_object_find_user(
- const llcache_handle *handle);
-
-static nserror llcache_object_add_to_list(llcache_object *object,
- llcache_object **list);
-static nserror llcache_object_remove_from_list(llcache_object *object,
- llcache_object **list);
-static bool llcache_object_in_list(const llcache_object *object,
- const llcache_object *list);
-
-static nserror llcache_object_notify_users(llcache_object *object);
-
-static nserror llcache_object_snapshot(llcache_object *object,
- llcache_object **snapshot);
-
-static nserror llcache_post_data_clone(const llcache_post_data *orig,
- llcache_post_data **clone);
-
-static nserror llcache_query_handle_response(bool proceed, void *cbpw);
-
+/* forward referenced callback function */
static void llcache_fetch_callback(const fetch_msg *msg, void *p);
-static nserror llcache_fetch_redirect(llcache_object *object,
- const char *target, llcache_object **replacement);
-static nserror llcache_fetch_notmodified(llcache_object *object,
- llcache_object **replacement);
-static nserror llcache_fetch_split_header(const uint8_t *data, size_t len,
- char **name, char **value);
-static nserror llcache_fetch_parse_header(llcache_object *object,
- const uint8_t *data, size_t len, char **name, char **value);
-static nserror llcache_fetch_process_header(llcache_object *object,
- const uint8_t *data, size_t len);
-static nserror llcache_fetch_process_data(llcache_object *object,
- const uint8_t *data, size_t len);
-static nserror llcache_fetch_auth(llcache_object *object,
- const char *realm);
-static nserror llcache_fetch_cert_error(llcache_object *object,
- const struct ssl_cert_info *certs, size_t num);
-
-/* Destroy headers */
-static inline void llcache_destroy_headers(llcache_object *object)
-{
- while (object->num_headers > 0) {
- object->num_headers--;
-
- free(object->headers[object->num_headers].name);
- free(object->headers[object->num_headers].value);
- }
- free(object->headers);
- object->headers = NULL;
-}
-
-/* Invalidate cache control data */
-static inline void llcache_invalidate_cache_control_data(llcache_object *object)
-{
- free(object->cache.etag);
- memset(&(object->cache), 0, sizeof(llcache_cache_control));
-
- object->cache.age = INVALID_AGE;
- object->cache.max_age = INVALID_AGE;
-}
-
-
-/******************************************************************************
- * Public API *
- ******************************************************************************/
-
-/* See llcache.h for documentation */
-nserror
-llcache_initialise(llcache_query_callback cb, void *pw, uint32_t llcache_limit)
-{
- llcache = calloc(1, sizeof(struct llcache_s));
- if (llcache == NULL) {
- return NSERROR_NOMEM;
- }
-
- llcache->query_cb = cb;
- llcache->query_cb_pw = pw;
- llcache->limit = llcache_limit;
-
- /* Create static scheme strings */
- if (lwc_intern_string("file", SLEN("file"),
- &llcache_file_lwc) != lwc_error_ok)
- return NSERROR_NOMEM;
-
- if (lwc_intern_string("about", SLEN("about"),
- &llcache_about_lwc) != lwc_error_ok)
- return NSERROR_NOMEM;
-
- if (lwc_intern_string("resource", SLEN("resource"),
- &llcache_resource_lwc) != lwc_error_ok)
- return NSERROR_NOMEM;
-
- LOG(("llcache initialised with a limit of %d bytes", llcache_limit));
-
- return NSERROR_OK;
-}
-
-/* See llcache.h for documentation */
-void llcache_finalise(void)
-{
- llcache_object *object, *next;
-
- /* Clean uncached objects */
- for (object = llcache->uncached_objects; object != NULL; object = next) {
- llcache_object_user *user, *next_user;
-
- next = object->next;
-
- for (user = object->users; user != NULL; user = next_user) {
- next_user = user->next;
-
- if (user->handle != NULL)
- free(user->handle);
-
- free(user);
- }
-
- /* Fetch system has already been destroyed */
- object->fetch.fetch = NULL;
-
- llcache_object_destroy(object);
- }
-
- /* Clean cached objects */
- for (object = llcache->cached_objects; object != NULL; object = next) {
- llcache_object_user *user, *next_user;
-
- next = object->next;
-
- for (user = object->users; user != NULL; user = next_user) {
- next_user = user->next;
-
- if (user->handle != NULL)
- free(user->handle);
-
- free(user);
- }
-
- /* Fetch system has already been destroyed */
- object->fetch.fetch = NULL;
-
- llcache_object_destroy(object);
- }
-
- /* Unref static scheme lwc strings */
- lwc_string_unref(llcache_file_lwc);
- lwc_string_unref(llcache_about_lwc);
- lwc_string_unref(llcache_resource_lwc);
-
- free(llcache);
- llcache = NULL;
-}
-
-/* See llcache.h for documentation */
-nserror llcache_poll(void)
-{
- llcache_object *object;
-
- fetch_poll();
-
- /* Catch new users up with state of objects */
- for (object = llcache->cached_objects; object != NULL;
- object = object->next) {
- llcache_object_notify_users(object);
- }
-
- for (object = llcache->uncached_objects; object != NULL;
- object = object->next) {
- llcache_object_notify_users(object);
- }
-
- return NSERROR_OK;
-}
-
-/* See llcache.h for documentation */
-nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
- nsurl *referer, const llcache_post_data *post,
- llcache_handle_callback cb, void *pw,
- llcache_handle **result)
-{
- nserror error;
- llcache_object_user *user;
- llcache_object *object;
-
- /* Can we fetch this URL at all? */
- if (fetch_can_fetch(url) == false)
- return NSERROR_NO_FETCH_HANDLER;
-
- /* Create a new object user */
- error = llcache_object_user_new(cb, pw, &user);
- if (error != NSERROR_OK)
- return error;
-
- /* Retrieve a suitable object from the cache,
- * creating a new one if needed. */
- error = llcache_object_retrieve(url, flags, referer, post, 0, &object);
- if (error != NSERROR_OK) {
- llcache_object_user_destroy(user);
- return error;
- }
-
- /* Add user to object */
- llcache_object_add_user(object, user);
-
- *result = user->handle;
-
- return NSERROR_OK;
-}
-
-/* See llcache.h for documentation */
-nserror llcache_handle_change_callback(llcache_handle *handle,
- llcache_handle_callback cb, void *pw)
-{
- handle->cb = cb;
- handle->pw = pw;
-
- return NSERROR_OK;
-}
-
-/* See llcache.h for documentation */
-nserror llcache_handle_release(llcache_handle *handle)
-{
- nserror error = NSERROR_OK;
- llcache_object *object = handle->object;
- llcache_object_user *user = llcache_object_find_user(handle);
-
- assert(user != NULL);
-
- if (user->iterator_target) {
- /* Can't remove / delete user object if it's
- * the target of an iterator */
- user->queued_for_delete = true;
- } else {
- /* Remove the user from the object and destroy it */
- error = llcache_object_remove_user(object, user);
- if (error == NSERROR_OK) {
- error = llcache_object_user_destroy(user);
- }
- }
-
- return error;
-}
-
-/* See llcache.h for documentation */
-nserror llcache_handle_clone(llcache_handle *handle, llcache_handle **result)
-{
- nserror error;
- llcache_object_user *newuser;
-
- error = llcache_object_user_new(handle->cb, handle->pw, &newuser);
- if (error == NSERROR_OK) {
- llcache_object_add_user(handle->object, newuser);
- newuser->handle->state = handle->state;
- *result = newuser->handle;
- }
-
- return error;
-}
-
-/* See llcache.h for documentation */
-nserror llcache_handle_abort(llcache_handle *handle)
-{
- llcache_object_user *user = llcache_object_find_user(handle);
- llcache_object *object = handle->object, *newobject;
- nserror error = NSERROR_OK;
- bool all_alone = true;
-
- /* Determine if we are the only user */
- if (user->prev != NULL)
- all_alone = false;
- if (user->next != NULL)
- all_alone = false;
-
- if (all_alone == false) {
- /* We must snapshot this object */
- error = llcache_object_snapshot(object, &newobject);
- if (error != NSERROR_OK)
- return error;
-
- /* Move across to the new object */
- if (user->iterator_target) {
- /* User is current iterator target, clone it */
- llcache_object_user *newuser =
- calloc(1, sizeof(llcache_object_user));
- if (newuser == NULL) {
- llcache_object_destroy(newobject);
- return NSERROR_NOMEM;
- }
-
- /* Move handle across to clone */
- newuser->handle = user->handle;
- user->handle = NULL;
-
- /* Mark user as needing deletion */
- user->queued_for_delete = true;
-
- llcache_object_add_user(newobject, newuser);
- } else {
- llcache_object_remove_user(object, user);
- llcache_object_add_user(newobject, user);
- }
-
- /* Add new object to uncached list */
- llcache_object_add_to_list(newobject,
- &llcache->uncached_objects);
- } else {
- /* We're the only user, so abort any fetch in progress */
- if (object->fetch.fetch != NULL) {
- fetch_abort(object->fetch.fetch);
- object->fetch.fetch = NULL;
- }
-
- object->fetch.state = LLCACHE_FETCH_COMPLETE;
-
- /* Invalidate cache control data */
- llcache_invalidate_cache_control_data(object);
- }
-
- return error;
-}
-
-/* See llcache.h for documentation */
-nserror llcache_handle_force_stream(llcache_handle *handle)
-{
- llcache_object_user *user = llcache_object_find_user(handle);
- llcache_object *object = handle->object;
-
- /* Cannot stream if there are multiple users */
- if (user->prev != NULL || user->next != NULL)
- return NSERROR_OK;
-
- /* Forcibly uncache this object */
- if (llcache_object_in_list(object, llcache->cached_objects)) {
- llcache_object_remove_from_list(object,
- &llcache->cached_objects);
- llcache_object_add_to_list(object, &llcache->uncached_objects);
- }
-
- object->fetch.flags |= LLCACHE_RETRIEVE_STREAM_DATA;
-
- return NSERROR_OK;
-}
-
-/* See llcache.h for documentation */
-nserror llcache_handle_invalidate_cache_data(llcache_handle *handle)
-{
- if (handle->object != NULL && handle->object->fetch.fetch == NULL &&
- handle->object->cache.no_cache ==
- LLCACHE_VALIDATE_FRESH) {
- handle->object->cache.no_cache = LLCACHE_VALIDATE_ONCE;
- }
-
- return NSERROR_OK;
-}
-
-/* See llcache.h for documentation */
-nsurl *llcache_handle_get_url(const llcache_handle *handle)
-{
- return handle->object != NULL ? handle->object->url : NULL;
-}
-
-/* See llcache.h for documentation */
-const uint8_t *llcache_handle_get_source_data(const llcache_handle *handle,
- size_t *size)
-{
- *size = handle->object != NULL ? handle->object->source_len : 0;
-
- return handle->object != NULL ? handle->object->source_data : NULL;
-}
-
-/* See llcache.h for documentation */
-const char *llcache_handle_get_header(const llcache_handle *handle,
- const char *key)
-{
- const llcache_object *object = handle->object;
- size_t i;
-
- if (object == NULL)
- return NULL;
-
- /* About as trivial as possible */
- for (i = 0; i < object->num_headers; i++) {
- if (strcasecmp(key, object->headers[i].name) == 0)
- return object->headers[i].value;
- }
-
- return NULL;
-}
-
-/* See llcache.h for documentation */
-bool llcache_handle_references_same_object(const llcache_handle *a,
- const llcache_handle *b)
-{
- return a->object == b->object;
-}
+
/******************************************************************************
* Low-level cache internals *
@@ -599,7 +181,7 @@
* \param user Pointer to location to receive result
* \return NSERROR_OK on success, appropriate error otherwise
*/
-nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
+static nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
llcache_object_user **user)
{
llcache_handle *h;
@@ -637,7 +219,7 @@
*
* \pre User is not attached to an object
*/
-nserror llcache_object_user_destroy(llcache_object_user *user)
+static nserror llcache_object_user_destroy(llcache_object_user *user)
{
#ifdef LLCACHE_TRACE
LOG(("Destroyed user %p", user));
@@ -655,6 +237,39 @@
}
/**
+ * Remove a user from a low-level cache object
+ *
+ * \param object Object to remove user from
+ * \param user User to remove
+ * \return NSERROR_OK.
+ */
+static nserror llcache_object_remove_user(llcache_object *object,
+ llcache_object_user *user)
+{
+ assert(user != NULL);
+ assert(object != NULL);
+ assert(object->users != NULL);
+ assert(user->handle == NULL || user->handle->object == object);
+ assert((user->prev != NULL) || (object->users == user));
+
+ if (user == object->users)
+ object->users = user->next;
+ else
+ user->prev->next = user->next;
+
+ if (user->next != NULL)
+ user->next->prev = user->prev;
+
+ user->next = user->prev = NULL;
+
+#ifdef LLCACHE_TRACE
+ LOG(("Removing user %p from %p", user, object));
+#endif
+
+ return NSERROR_OK;
+}
+
+/**
* Iterate the users of an object, calling their callbacks.
*
* \param object The object to iterate
@@ -693,193 +308,536 @@
}
/**
- * Retrieve an object from the cache, fetching it if necessary.
- *
- * \param url URL of object to retrieve
+ * Create a new low-level cache object
+ *
+ * \param url URL of object to create
+ * \param result Pointer to location to receive result
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_object_new(nsurl *url, llcache_object **result)
+{
+ llcache_object *obj = calloc(1, sizeof(llcache_object));
+ if (obj == NULL)
+ return NSERROR_NOMEM;
+
+#ifdef LLCACHE_TRACE
+ LOG(("Created object %p (%s)", obj, nsurl_access(url)));
+#endif
+
+ obj->url = nsurl_ref(url);
+
+ *result = obj;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Clone a POST data object
+ *
+ * \param orig Object to clone
+ * \param clone Pointer to location to receive clone
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_post_data_clone(const llcache_post_data *orig,
+ llcache_post_data **clone)
+{
+ llcache_post_data *post_clone;
+
+ post_clone = calloc(1, sizeof(llcache_post_data));
+ if (post_clone == NULL)
+ return NSERROR_NOMEM;
+
+ post_clone->type = orig->type;
+
+ /* Deep-copy the type-specific data */
+ if (orig->type == LLCACHE_POST_URL_ENCODED) {
+ post_clone->data.urlenc = strdup(orig->data.urlenc);
+ if (post_clone->data.urlenc == NULL) {
+ free(post_clone);
+
+ return NSERROR_NOMEM;
+ }
+ } else {
+ post_clone->data.multipart = fetch_multipart_data_clone(
+ orig->data.multipart);
+ if (post_clone->data.multipart == NULL) {
+ free(post_clone);
+
+ return NSERROR_NOMEM;
+ }
+ }
+
+ *clone = post_clone;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Split a fetch header into name and value
+ *
+ * \param data Header string
+ * \param len Byte length of header
+ * \param name Pointer to location to receive header name
+ * \param value Pointer to location to receive header value
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_fetch_split_header(const uint8_t *data, size_t len,
+ char **name, char **value)
+{
+ char *n, *v;
+ const uint8_t *colon;
+
+ /* Find colon */
+ colon = (const uint8_t *) strchr((const char *) data, ':');
+ if (colon == NULL) {
+ /* Failed, assume a key with no value */
+ n = strdup((const char *) data);
+ if (n == NULL)
+ return NSERROR_NOMEM;
+
+ v = strdup("");
+ if (v == NULL) {
+ free(n);
+ return NSERROR_NOMEM;
+ }
+ } else {
+ /* Split header into name & value */
+
+ /* Strip leading whitespace from name */
+ while (data[0] == ' ' || data[0] == '\t' ||
+ data[0] == '\r' || data[0] == '\n') {
+ data++;
+ }
+
+ /* Strip trailing whitespace from name */
+ while (colon > data && (colon[-1] == ' ' ||
+ colon[-1] == '\t' || colon[-1] == '\r' ||
+ colon[-1] == '\n'))
+ colon--;
+
+ n = strndup((const char *) data, colon - data);
+ if (n == NULL)
+ return NSERROR_NOMEM;
+
+ /* Find colon again */
+ while (*colon != ':') {
+ colon++;
+ }
+
+ /* Skip over colon and any subsequent whitespace */
+ do {
+ colon++;
+ } while (*colon == ' ' || *colon == '\t' ||
+ *colon == '\r' || *colon == '\n');
+
+ /* Strip trailing whitespace from value */
+ while (len > 0 && (data[len - 1] == ' ' ||
+ data[len - 1] == '\t' ||
+ data[len - 1] == '\r' ||
+ data[len - 1] == '\n')) {
+ len--;
+ }
+
+ v = strndup((const char *) colon, len - (colon - data));
+ if (v == NULL) {
+ free(n);
+ return NSERROR_NOMEM;
+ }
+ }
+
+ *name = n;
+ *value = v;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Parse a fetch header
+ *
+ * \param object Object to parse header for
+ * \param data Header string
+ * \param len Byte length of header
+ * \param name Pointer to location to receive header name
+ * \param value Pointer to location to receive header value
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \note This function also has the side-effect of updating
+ * the cache control data for the object if an interesting
+ * header is encountered
+ */
+static nserror llcache_fetch_parse_header(llcache_object *object,
+ const uint8_t *data, size_t len, char **name, char **value)
+{
+ nserror error;
+
+ /* Set fetch response time if not already set */
+ if (object->cache.res_time == 0)
+ object->cache.res_time = time(NULL);
+
+ /* Decompose header into name-value pair */
+ error = llcache_fetch_split_header(data, len, name, value);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Parse cache headers to populate cache control data */
+#define SKIP_ST(p) while (*p != '\0' && (*p == ' ' || *p == '\t')) p++
+
+ if (5 < len && strcasecmp(*name, "Date") == 0) {
+ /* extract Date header */
+ object->cache.date = curl_getdate(*value, NULL);
+ } else if (4 < len && strcasecmp(*name, "Age") == 0) {
+ /* extract Age header */
+ if ('0' <= **value && **value <= '9')
+ object->cache.age = atoi(*value);
+ } else if (8 < len && strcasecmp(*name, "Expires") == 0) {
+ /* extract Expires header */
+ object->cache.expires = curl_getdate(*value, NULL);
+ } else if (14 < len && strcasecmp(*name, "Cache-Control") == 0) {
+ /* extract and parse Cache-Control header */
+ const char *start = *value;
+ const char *comma = *value;
+
+ while (*comma != '\0') {
+ while (*comma != '\0' && *comma != ',')
+ comma++;
+
+ if (8 < comma - start && (strncasecmp(start,
+ "no-cache", 8) == 0 ||
+ strncasecmp(start, "no-store", 8) == 0))
+ /* When we get a disk cache we should
+ * distinguish between these two */
+ object->cache.no_cache = LLCACHE_VALIDATE_ALWAYS;
+ else if (7 < comma - start &&
+ strncasecmp(start, "max-age", 7) == 0) {
+ /* Find '=' */
+ while (start < comma && *start != '=')
+ start++;
+
+ /* Skip over it */
+ start++;
+
+ /* Skip whitespace */
+ SKIP_ST(start);
+
+ if (start < comma)
+ object->cache.max_age = atoi(start);
+ }
+
+ if (*comma != '\0') {
+ /* Skip past comma */
+ comma++;
+ /* Skip whitespace */
+ SKIP_ST(comma);
+ }
+
+ /* Set start for next token */
+ start = comma;
+ }
+ } else if (5 < len && strcasecmp(*name, "ETag") == 0) {
+ /* extract ETag header */
+ free(object->cache.etag);
+ object->cache.etag = strdup(*value);
+ if (object->cache.etag == NULL)
+ return NSERROR_NOMEM;
+ } else if (14 < len && strcasecmp(*name, "Last-Modified") == 0) {
+ /* extract Last-Modified header */
+ object->cache.last_modified = curl_getdate(*value, NULL);
+ }
+
+#undef SKIP_ST
+
+ return NSERROR_OK;
+}
+
+/* Destroy headers */
+static inline void llcache_destroy_headers(llcache_object *object)
+{
+ while (object->num_headers > 0) {
+ object->num_headers--;
+
+ free(object->headers[object->num_headers].name);
+ free(object->headers[object->num_headers].value);
+ }
+ free(object->headers);
+ object->headers = NULL;
+}
+
+/* Invalidate cache control data */
+static inline void llcache_invalidate_cache_control_data(llcache_object *object)
+{
+ free(object->cache.etag);
+ memset(&(object->cache), 0, sizeof(llcache_cache_control));
+
+ object->cache.age = INVALID_AGE;
+ object->cache.max_age = INVALID_AGE;
+}
+
+/**
+ * Process a fetch header
+ *
+ * \param object Object being fetched
+ * \param data Header string
+ * \param len Byte length of header
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_fetch_process_header(llcache_object *object,
+ const uint8_t *data, size_t len)
+{
+ nserror error;
+ char *name, *value;
+ llcache_header *temp;
+
+ /* The headers for multiple HTTP responses may be delivered to us if
+ * the fetch layer receives a 401 response for which it has
+ * authentication credentials. This will result in a silent re-request
+ * after which we'll receive the actual response headers for the
+ * object we want to fetch (assuming that the credentials were correct
+ * of course)
+ *
+ * Therefore, if the header is an HTTP response start marker, then we
+ * must discard any headers we've read so far, reset the cache data
+ * that we might have computed, and start again.
+ */
+ /** \todo Properly parse the response line */
+ if (strncmp((const char *) data, "HTTP/", SLEN("HTTP/")) == 0) {
+ time_t req_time = object->cache.req_time;
+
+ llcache_invalidate_cache_control_data(object);
+
+ /* Restore request time, so we compute object's age correctly */
+ object->cache.req_time = req_time;
+
+ llcache_destroy_headers(object);
+ }
+
+ error = llcache_fetch_parse_header(object, data, len, &name, &value);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Append header data to the object's headers array */
+ temp = realloc(object->headers, (object->num_headers + 1) *
+ sizeof(llcache_header));
+ if (temp == NULL) {
+ free(name);
+ free(value);
+ return NSERROR_NOMEM;
+ }
+
+ object->headers = temp;
+
+ object->headers[object->num_headers].name = name;
+ object->headers[object->num_headers].value = value;
+
+ object->num_headers++;
+
+ return NSERROR_OK;
+}
+
+/**
+ * (Re)fetch an object
+ *
+ * \param object Object to refetch
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \pre The fetch parameters in object->fetch must be populated
+ */
+static nserror llcache_object_refetch(llcache_object *object)
+{
+ const char *urlenc = NULL;
+ struct fetch_multipart_data *multipart = NULL;
+ char **headers = NULL;
+ int header_idx = 0;
+
+ if (object->fetch.post != NULL) {
+ if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED)
+ urlenc = object->fetch.post->data.urlenc;
+ else
+ multipart = object->fetch.post->data.multipart;
+ }
+
+ /* Generate cache-control headers */
+ headers = malloc(3 * sizeof(char *));
+ if (headers == NULL)
+ return NSERROR_NOMEM;
+
+ if (object->cache.etag != NULL) {
+ const size_t len = SLEN("If-None-Match: ") +
+ strlen(object->cache.etag) + 1;
+
+ headers[header_idx] = malloc(len);
+ if (headers[header_idx] == NULL) {
+ free(headers);
+ return NSERROR_NOMEM;
+ }
+
+ snprintf(headers[header_idx], len, "If-None-Match: %s",
+ object->cache.etag);
+
+ header_idx++;
+ }
+ if (object->cache.date != 0) {
+ /* Maximum length of an RFC 1123 date is 29 bytes */
+ const size_t len = SLEN("If-Modified-Since: ") + 29 + 1;
+
+ headers[header_idx] = malloc(len);
+ if (headers[header_idx] == NULL) {
+ while (--header_idx >= 0)
+ free(headers[header_idx]);
+ free(headers);
+ return NSERROR_NOMEM;
+ }
+
+ snprintf(headers[header_idx], len, "If-Modified-Since: %s",
+ rfc1123_date(object->cache.date));
+
+ header_idx++;
+ }
+ headers[header_idx] = NULL;
+
+ /* Reset cache control data */
+ llcache_invalidate_cache_control_data(object);
+ object->cache.req_time = time(NULL);
+
+ /* Reset fetch state */
+ object->fetch.state = LLCACHE_FETCH_INIT;
+
+#ifdef LLCACHE_TRACE
+ LOG(("Refetching %p", object));
+#endif
+
+ /* Kick off fetch */
+ object->fetch.fetch = fetch_start(object->url, object->fetch.referer,
+ llcache_fetch_callback, object,
+ object->fetch.flags & LLCACHE_RETRIEVE_NO_ERROR_PAGES,
+ urlenc, multipart,
+ object->fetch.flags & LLCACHE_RETRIEVE_VERIFIABLE,
+ (const char **) headers);
+
+ /* Clean up cache-control headers */
+ while (--header_idx >= 0)
+ free(headers[header_idx]);
+ free(headers);
+
+ /* Did we succeed in creating a fetch? */
+ if (object->fetch.fetch == NULL)
+ return NSERROR_NOMEM;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Kick-off a fetch for an object
+ *
+ * \param object Object to fetch
* \param flags Fetch flags
- * \param referer Referring URL, or NULL if none
- * \param post POST data, or NULL for a GET request
+ * \param referer Referring URL, or NULL for none
+ * \param post POST data, or NULL for GET
* \param redirect_count Number of redirects followed so far
- * \param result Pointer to location to recieve retrieved object
* \return NSERROR_OK on success, appropriate error otherwise
- */
-nserror llcache_object_retrieve(nsurl *url, uint32_t flags,
+ *
+ * \pre object::url must contain the URL to fetch
+ * \pre If there is a freshness validation candidate,
+ * object::candidate and object::cache must be filled in
+ * \pre There must not be a fetch in progress for \a object
+ */
+static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
nsurl *referer, const llcache_post_data *post,
- uint32_t redirect_count, llcache_object **result)
+ uint32_t redirect_count)
{
nserror error;
- llcache_object *obj;
- bool has_query;
- nsurl *defragmented_url;
+ nsurl *referer_clone = NULL;
+ llcache_post_data *post_clone = NULL;
#ifdef LLCACHE_TRACE
- LOG(("Retrieve %s (%x, %s, %p)", url, flags, referer, post));
+ LOG(("Starting fetch for %p", object));
#endif
- /**
- * Caching Rules:
- *
- * 1) Forced fetches are never cached
- * 2) POST requests are never cached
- */
-
- /* Look for a query segment */
- has_query = nsurl_has_component(url, NSURL_QUERY);
-
- /* Get rid of any url fragment */
- if (nsurl_has_component(url, NSURL_FRAGMENT)) {
- error = nsurl_defragment(url, &defragmented_url);
+ if (post != NULL) {
+ error = llcache_post_data_clone(post, &post_clone);
if (error != NSERROR_OK)
return error;
- } else {
- defragmented_url = nsurl_ref(url);
- }
-
- if (flags & LLCACHE_RETRIEVE_FORCE_FETCH || post != NULL) {
- /* Create new object */
- error = llcache_object_new(defragmented_url, &obj);
- if (error != NSERROR_OK) {
- nsurl_unref(defragmented_url);
- return error;
- }
-
- /* Attempt to kick-off fetch */
- error = llcache_object_fetch(obj, flags, referer, post,
- redirect_count);
- if (error != NSERROR_OK) {
- llcache_object_destroy(obj);
- nsurl_unref(defragmented_url);
- return error;
- }
-
- /* Add new object to uncached list */
- llcache_object_add_to_list(obj, &llcache->uncached_objects);
- } else {
- error = llcache_object_retrieve_from_cache(defragmented_url,
- flags, referer, post, redirect_count, &obj);
- if (error != NSERROR_OK) {
- nsurl_unref(defragmented_url);
- return error;
- }
-
- /* Returned object is already in the cached list */
- }
-
- obj->has_query = has_query;
+ }
+
+ if (referer != NULL)
+ referer_clone = nsurl_ref(referer);
+
+ object->fetch.flags = flags;
+ object->fetch.referer = referer_clone;
+ object->fetch.post = post_clone;
+ object->fetch.redirect_count = redirect_count;
+
+ return llcache_object_refetch(object);
+}
+
+/**
+ * Destroy a low-level cache object
+ *
+ * \param object Object to destroy
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \pre Object is detached from cache list
+ * \pre Object has no users
+ * \pre Object is not a candidate (i.e. object::candidate_count == 0)
+ */
+static nserror llcache_object_destroy(llcache_object *object)
+{
+ size_t i;
#ifdef LLCACHE_TRACE
- LOG(("Retrieved %p", obj));
+ LOG(("Destroying object %p", object));
#endif
-
- *result = obj;
-
- nsurl_unref(defragmented_url);
-
+
+ nsurl_unref(object->url);
+ free(object->source_data);
+
+ if (object->fetch.fetch != NULL) {
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+ }
+
+ if (object->fetch.referer != NULL)
+ nsurl_unref(object->fetch.referer);
+
+ if (object->fetch.post != NULL) {
+ if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED) {
+ free(object->fetch.post->data.urlenc);
+ } else {
+ fetch_multipart_data_destroy(
+ object->fetch.post->data.multipart);
+ }
+
+ free(object->fetch.post);
+ }
+
+ free(object->cache.etag);
+
+ for (i = 0; i < object->num_headers; i++) {
+ free(object->headers[i].name);
+ free(object->headers[i].value);
+ }
+ free(object->headers);
+
+ free(object);
+
return NSERROR_OK;
}
/**
- * Retrieve a potentially cached object
- *
- * \param url URL of object to retrieve
- * \param flags Fetch flags
- * \param referer Referring URL, or NULL if none
- * \param post POST data, or NULL for a GET request
- * \param redirect_count Number of redirects followed so far
- * \param result Pointer to location to recieve retrieved object
- * \return NSERROR_OK on success, appropriate error otherwise
- */
-nserror llcache_object_retrieve_from_cache(nsurl *url, uint32_t flags,
- nsurl *referer, const llcache_post_data *post,
- uint32_t redirect_count, llcache_object **result)
-{
- nserror error;
- llcache_object *obj, *newest = NULL;
-
-#ifdef LLCACHE_TRACE
- LOG(("Searching cache for %s (%x %s %p)", url, flags, referer, post));
-#endif
-
- /* Search for the most recently fetched matching object */
- for (obj = llcache->cached_objects; obj != NULL; obj = obj->next) {
-
- if ((newest == NULL ||
- obj->cache.req_time > newest->cache.req_time) &&
- nsurl_compare(obj->url, url,
- NSURL_COMPLETE) == true) {
- newest = obj;
- }
- }
-
- if (newest != NULL && llcache_object_is_fresh(newest)) {
- /* Found a suitable object, and it's still fresh, so use it */
- obj = newest;
-
-#ifdef LLCACHE_TRACE
- LOG(("Found fresh %p", obj));
-#endif
-
- /* The client needs to catch up with the object's state.
- * This will occur the next time that llcache_poll is called.
- */
- } else if (newest != NULL) {
- /* Found a candidate object but it needs freshness validation */
-
- /* Create a new object */
- error = llcache_object_new(url, &obj);
- if (error != NSERROR_OK)
- return error;
-
-#ifdef LLCACHE_TRACE
- LOG(("Found candidate %p (%p)", obj, newest));
-#endif
-
- /* Clone candidate's cache data */
- error = llcache_object_clone_cache_data(newest, obj, true);
- if (error != NSERROR_OK) {
- llcache_object_destroy(obj);
- return error;
- }
-
- /* Record candidate, so we can fall back if it is still fresh */
- newest->candidate_count++;
- obj->candidate = newest;
-
- /* Attempt to kick-off fetch */
- error = llcache_object_fetch(obj, flags, referer, post,
- redirect_count);
- if (error != NSERROR_OK) {
- newest->candidate_count--;
- llcache_object_destroy(obj);
- return error;
- }
-
- /* Add new object to cache */
- llcache_object_add_to_list(obj, &llcache->cached_objects);
- } else {
- /* No object found; create a new one */
- /* Create new object */
- error = llcache_object_new(url, &obj);
- if (error != NSERROR_OK)
- return error;
-
-#ifdef LLCACHE_TRACE
- LOG(("Not found %p", obj));
-#endif
-
- /* Attempt to kick-off fetch */
- error = llcache_object_fetch(obj, flags, referer, post,
- redirect_count);
- if (error != NSERROR_OK) {
- llcache_object_destroy(obj);
- return error;
- }
-
- /* Add new object to cache */
- llcache_object_add_to_list(obj, &llcache->cached_objects);
- }
-
- *result = obj;
+ * Add a low-level cache object to a cache list
+ *
+ * \param object Object to add
+ * \param list List to add to
+ * \return NSERROR_OK
+ */
+static nserror llcache_object_add_to_list(llcache_object *object,
+ llcache_object **list)
+{
+ object->prev = NULL;
+ object->next = *list;
+
+ if (*list != NULL)
+ (*list)->prev = object;
+ *list = object;
return NSERROR_OK;
}
@@ -890,7 +848,7 @@
* \param object Object to consider
* \return True if object is still fresh, false otherwise
*/
-bool llcache_object_is_fresh(const llcache_object *object)
+static bool llcache_object_is_fresh(const llcache_object *object)
{
const llcache_cache_control *cd = &object->cache;
int current_age, freshness_lifetime;
@@ -933,20 +891,6 @@
}
/**
- * Update an object's cache state
- *
- * \param object Object to update cache for
- * \return NSERROR_OK.
- */
-nserror llcache_object_cache_update(llcache_object *object)
-{
- if (object->cache.date == 0)
- object->cache.date = time(NULL);
-
- return NSERROR_OK;
-}
-
-/**
* Clone an object's cache data
*
* \param source Source object containing cache data to clone
@@ -956,7 +900,7 @@
*
* \post If \a deep is false, then any pointers in \a source will be set to NULL
*/
-nserror llcache_object_clone_cache_data(llcache_object *source,
+static nserror llcache_object_clone_cache_data(llcache_object *source,
llcache_object *destination, bool deep)
{
/* ETag must be first, as it can fail when deep cloning */
@@ -1004,215 +948,194 @@
}
/**
- * Kick-off a fetch for an object
- *
- * \param object Object to fetch
+ * Retrieve a potentially cached object
+ *
+ * \param url URL of object to retrieve
* \param flags Fetch flags
- * \param referer Referring URL, or NULL for none
- * \param post POST data, or NULL for GET
+ * \param referer Referring URL, or NULL if none
+ * \param post POST data, or NULL for a GET request
* \param redirect_count Number of redirects followed so far
+ * \param result Pointer to location to recieve retrieved object
* \return NSERROR_OK on success, appropriate error otherwise
- *
- * \pre object::url must contain the URL to fetch
- * \pre If there is a freshness validation candidate,
- * object::candidate and object::cache must be filled in
- * \pre There must not be a fetch in progress for \a object
- */
-nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
+ */
+static nserror llcache_object_retrieve_from_cache(nsurl *url, uint32_t flags,
nsurl *referer, const llcache_post_data *post,
- uint32_t redirect_count)
+ uint32_t redirect_count, llcache_object **result)
{
nserror error;
- nsurl *referer_clone = NULL;
- llcache_post_data *post_clone = NULL;
+ llcache_object *obj, *newest = NULL;
#ifdef LLCACHE_TRACE
- LOG(("Starting fetch for %p", object));
+ LOG(("Searching cache for %s (%x %s %p)", url, flags, referer, post));
#endif
- if (post != NULL) {
- error = llcache_post_data_clone(post, &post_clone);
+ /* Search for the most recently fetched matching object */
+ for (obj = llcache->cached_objects; obj != NULL; obj = obj->next) {
+
+ if ((newest == NULL ||
+ obj->cache.req_time > newest->cache.req_time) &&
+ nsurl_compare(obj->url, url,
+ NSURL_COMPLETE) == true) {
+ newest = obj;
+ }
+ }
+
+ if (newest != NULL && llcache_object_is_fresh(newest)) {
+ /* Found a suitable object, and it's still fresh, so use it */
+ obj = newest;
+
+#ifdef LLCACHE_TRACE
+ LOG(("Found fresh %p", obj));
+#endif
+
+ /* The client needs to catch up with the object's state.
+ * This will occur the next time that llcache_poll is called.
+ */
+ } else if (newest != NULL) {
+ /* Found a candidate object but it needs freshness validation */
+
+ /* Create a new object */
+ error = llcache_object_new(url, &obj);
if (error != NSERROR_OK)
return error;
- }
-
- if (referer != NULL)
- referer_clone = nsurl_ref(referer);
-
- object->fetch.flags = flags;
- object->fetch.referer = referer_clone;
- object->fetch.post = post_clone;
- object->fetch.redirect_count = redirect_count;
-
- return llcache_object_refetch(object);
-}
-
-/**
- * (Re)fetch an object
- *
- * \param object Object to refetch
+
+#ifdef LLCACHE_TRACE
+ LOG(("Found candidate %p (%p)", obj, newest));
+#endif
+
+ /* Clone candidate's cache data */
+ error = llcache_object_clone_cache_data(newest, obj, true);
+ if (error != NSERROR_OK) {
+ llcache_object_destroy(obj);
+ return error;
+ }
+
+ /* Record candidate, so we can fall back if it is still fresh */
+ newest->candidate_count++;
+ obj->candidate = newest;
+
+ /* Attempt to kick-off fetch */
+ error = llcache_object_fetch(obj, flags, referer, post,
+ redirect_count);
+ if (error != NSERROR_OK) {
+ newest->candidate_count--;
+ llcache_object_destroy(obj);
+ return error;
+ }
+
+ /* Add new object to cache */
+ llcache_object_add_to_list(obj, &llcache->cached_objects);
+ } else {
+ /* No object found; create a new one */
+ /* Create new object */
+ error = llcache_object_new(url, &obj);
+ if (error != NSERROR_OK)
+ return error;
+
+#ifdef LLCACHE_TRACE
+ LOG(("Not found %p", obj));
+#endif
+
+ /* Attempt to kick-off fetch */
+ error = llcache_object_fetch(obj, flags, referer, post,
+ redirect_count);
+ if (error != NSERROR_OK) {
+ llcache_object_destroy(obj);
+ return error;
+ }
+
+ /* Add new object to cache */
+ llcache_object_add_to_list(obj, &llcache->cached_objects);
+ }
+
+ *result = obj;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Retrieve an object from the cache, fetching it if necessary.
+ *
+ * \param url URL of object to retrieve
+ * \param flags Fetch flags
+ * \param referer Referring URL, or NULL if none
+ * \param post POST data, or NULL for a GET request
+ * \param redirect_count Number of redirects followed so far
+ * \param result Pointer to location to recieve retrieved object
* \return NSERROR_OK on success, appropriate error otherwise
- *
- * \pre The fetch parameters in object->fetch must be populated
- */
-nserror llcache_object_refetch(llcache_object *object)
-{
- const char *urlenc = NULL;
- struct fetch_multipart_data *multipart = NULL;
- char **headers = NULL;
- int header_idx = 0;
-
- if (object->fetch.post != NULL) {
- if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED)
- urlenc = object->fetch.post->data.urlenc;
- else
- multipart = object->fetch.post->data.multipart;
- }
-
- /* Generate cache-control headers */
- headers = malloc(3 * sizeof(char *));
- if (headers == NULL)
- return NSERROR_NOMEM;
-
- if (object->cache.etag != NULL) {
- const size_t len = SLEN("If-None-Match: ") +
- strlen(object->cache.etag) + 1;
-
- headers[header_idx] = malloc(len);
- if (headers[header_idx] == NULL) {
- free(headers);
- return NSERROR_NOMEM;
- }
-
- snprintf(headers[header_idx], len, "If-None-Match: %s",
- object->cache.etag);
-
- header_idx++;
- }
- if (object->cache.date != 0) {
- /* Maximum length of an RFC 1123 date is 29 bytes */
- const size_t len = SLEN("If-Modified-Since: ") + 29 + 1;
-
- headers[header_idx] = malloc(len);
- if (headers[header_idx] == NULL) {
- while (--header_idx >= 0)
- free(headers[header_idx]);
- free(headers);
- return NSERROR_NOMEM;
- }
-
- snprintf(headers[header_idx], len, "If-Modified-Since: %s",
- rfc1123_date(object->cache.date));
-
- header_idx++;
- }
- headers[header_idx] = NULL;
-
- /* Reset cache control data */
- llcache_invalidate_cache_control_data(object);
- object->cache.req_time = time(NULL);
-
- /* Reset fetch state */
- object->fetch.state = LLCACHE_FETCH_INIT;
+ */
+static nserror llcache_object_retrieve(nsurl *url, uint32_t flags,
+ nsurl *referer, const llcache_post_data *post,
+ uint32_t redirect_count, llcache_object **result)
+{
+ nserror error;
+ llcache_object *obj;
+ bool has_query;
+ nsurl *defragmented_url;
#ifdef LLCACHE_TRACE
- LOG(("Refetching %p", object));
+ LOG(("Retrieve %s (%x, %s, %p)", url, flags, referer, post));
#endif
- /* Kick off fetch */
- object->fetch.fetch = fetch_start(object->url, object->fetch.referer,
- llcache_fetch_callback, object,
- object->fetch.flags & LLCACHE_RETRIEVE_NO_ERROR_PAGES,
- urlenc, multipart,
- object->fetch.flags & LLCACHE_RETRIEVE_VERIFIABLE,
- (const char **) headers);
-
- /* Clean up cache-control headers */
- while (--header_idx >= 0)
- free(headers[header_idx]);
- free(headers);
-
- /* Did we succeed in creating a fetch? */
- if (object->fetch.fetch == NULL)
- return NSERROR_NOMEM;
-
- return NSERROR_OK;
-}
-
-/**
- * Create a new low-level cache object
- *
- * \param url URL of object to create
- * \param result Pointer to location to receive result
- * \return NSERROR_OK on success, appropriate error otherwise
- */
-nserror llcache_object_new(nsurl *url, llcache_object **result)
-{
- llcache_object *obj = calloc(1, sizeof(llcache_object));
- if (obj == NULL)
- return NSERROR_NOMEM;
+ /**
+ * Caching Rules:
+ *
+ * 1) Forced fetches are never cached
+ * 2) POST requests are never cached
+ */
+
+ /* Look for a query segment */
+ has_query = nsurl_has_component(url, NSURL_QUERY);
+
+ /* Get rid of any url fragment */
+ if (nsurl_has_component(url, NSURL_FRAGMENT)) {
+ error = nsurl_defragment(url, &defragmented_url);
+ if (error != NSERROR_OK)
+ return error;
+ } else {
+ defragmented_url = nsurl_ref(url);
+ }
+
+ if (flags & LLCACHE_RETRIEVE_FORCE_FETCH || post != NULL) {
+ /* Create new object */
+ error = llcache_object_new(defragmented_url, &obj);
+ if (error != NSERROR_OK) {
+ nsurl_unref(defragmented_url);
+ return error;
+ }
+
+ /* Attempt to kick-off fetch */
+ error = llcache_object_fetch(obj, flags, referer, post,
+ redirect_count);
+ if (error != NSERROR_OK) {
+ llcache_object_destroy(obj);
+ nsurl_unref(defragmented_url);
+ return error;
+ }
+
+ /* Add new object to uncached list */
+ llcache_object_add_to_list(obj, &llcache->uncached_objects);
+ } else {
+ error = llcache_object_retrieve_from_cache(defragmented_url,
+ flags, referer, post, redirect_count, &obj);
+ if (error != NSERROR_OK) {
+ nsurl_unref(defragmented_url);
+ return error;
+ }
+
+ /* Returned object is already in the cached list */
+ }
+
+ obj->has_query = has_query;
#ifdef LLCACHE_TRACE
- LOG(("Created object %p (%s)", obj, nsurl_access(url)));
+ LOG(("Retrieved %p", obj));
#endif
-
- obj->url = nsurl_ref(url);
-
+
*result = obj;
-
- return NSERROR_OK;
-}
-
-/**
- * Destroy a low-level cache object
- *
- * \param object Object to destroy
- * \return NSERROR_OK on success, appropriate error otherwise
- *
- * \pre Object is detached from cache list
- * \pre Object has no users
- * \pre Object is not a candidate (i.e. object::candidate_count == 0)
- */
-nserror llcache_object_destroy(llcache_object *object)
-{
- size_t i;
-
-#ifdef LLCACHE_TRACE
- LOG(("Destroying object %p", object));
-#endif
-
- nsurl_unref(object->url);
- free(object->source_data);
-
- if (object->fetch.fetch != NULL) {
- fetch_abort(object->fetch.fetch);
- object->fetch.fetch = NULL;
- }
-
- if (object->fetch.referer != NULL)
- nsurl_unref(object->fetch.referer);
-
- if (object->fetch.post != NULL) {
- if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED) {
- free(object->fetch.post->data.urlenc);
- } else {
- fetch_multipart_data_destroy(
- object->fetch.post->data.multipart);
- }
-
- free(object->fetch.post);
- }
-
- free(object->cache.etag);
-
- for (i = 0; i < object->num_headers; i++) {
- free(object->headers[i].name);
- free(object->headers[i].value);
- }
- free(object->headers);
-
- free(object);
-
+
+ nsurl_unref(defragmented_url);
+
return NSERROR_OK;
}
@@ -1223,7 +1146,7 @@
* \param user User to add
* \return NSERROR_OK.
*/
-nserror llcache_object_add_user(llcache_object *object,
+static nserror llcache_object_add_user(llcache_object *object,
llcache_object_user *user)
{
assert(user->next == NULL);
@@ -1246,36 +1169,557 @@
}
/**
- * Remove a user from a low-level cache object
- *
- * \param object Object to remove user from
- * \param user User to remove
+ * Handle FETCH_REDIRECT event
+ *
+ * \param object Object being redirected
+ * \param target Target of redirect (may be relative)
+ * \param replacement Pointer to location to receive replacement object
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_fetch_redirect(llcache_object *object, const char *target,
+ llcache_object **replacement)
+{
+ nserror error;
+ llcache_object *dest;
+ llcache_object_user *user, *next;
+ const llcache_post_data *post = object->fetch.post;
+ nsurl *url;
+ lwc_string *scheme;
+ lwc_string *object_scheme;
+ bool match;
+ /* Extract HTTP response code from the fetch object */
+ long http_code = fetch_http_code(object->fetch.fetch);
+
+ /* Abort fetch for this object */
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+
+ /* Invalidate the cache control data */
+ llcache_invalidate_cache_control_data(object);
+
+ /* And mark it complete */
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+
+ /* Forcibly stop redirecting if we've followed too many redirects */
+#define REDIRECT_LIMIT 10
+ if (object->fetch.redirect_count > REDIRECT_LIMIT) {
+ llcache_event event;
+
+ LOG(("Too many nested redirects"));
+
+ event.type = LLCACHE_EVENT_ERROR;
+ event.data.msg = messages_get("BadRedirect");
+
+ return llcache_send_event_to_users(object, &event);
+ }
+#undef REDIRECT_LIMIT
+
+ /* Make target absolute */
+ error = nsurl_join(object->url, target, &url);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Reject attempts to redirect from unvalidated to validated schemes
+ * A "validated" scheme is one over which we have some guarantee that
+ * the source is trustworthy. */
+ object_scheme = nsurl_get_component(object->url, NSURL_SCHEME);
+ scheme = nsurl_get_component(url, NSURL_SCHEME);
+
+ /* resource: and about: are allowed to redirect anywhere */
+ if ((lwc_string_isequal(object_scheme, llcache_resource_lwc,
+ &match) == lwc_error_ok && match == false) &&
+ (lwc_string_isequal(object_scheme, llcache_about_lwc,
+ &match) == lwc_error_ok && match == false)) {
+ /* file, about and resource are not valid redirect targets */
+ if ((lwc_string_isequal(object_scheme, llcache_file_lwc,
+ &match) == lwc_error_ok && match == true) ||
+ (lwc_string_isequal(object_scheme, llcache_about_lwc,
+ &match) == lwc_error_ok && match == true) ||
+ (lwc_string_isequal(object_scheme, llcache_resource_lwc,
+ &match) == lwc_error_ok && match == true)) {
+ lwc_string_unref(object_scheme);
+ lwc_string_unref(scheme);
+ nsurl_unref(url);
+ return NSERROR_OK;
+ }
+ }
+
+ lwc_string_unref(scheme);
+ lwc_string_unref(object_scheme);
+
+ /* Bail out if we've no way of handling this URL */
+ if (fetch_can_fetch(url) == false) {
+ nsurl_unref(url);
+ return NSERROR_OK;
+ }
+
+ if (http_code == 301 || http_code == 302 || http_code == 303) {
+ /* 301, 302, 303 redirects are all unconditional GET requests */
+ post = NULL;
+ } else if (http_code != 307 || post != NULL) {
+ /** \todo 300, 305, 307 with POST */
+ nsurl_unref(url);
+ return NSERROR_OK;
+ }
+
+ /* Attempt to fetch target URL */
+ error = llcache_object_retrieve(url, object->fetch.flags,
+ object->fetch.referer, post,
+ object->fetch.redirect_count + 1, &dest);
+
+ /* No longer require url */
+ nsurl_unref(url);
+
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Move user(s) to replacement object */
+ for (user = object->users; user != NULL; user = next) {
+ next = user->next;
+
+ llcache_object_remove_user(object, user);
+ llcache_object_add_user(dest, user);
+ }
+
+ /* Dest is now our object */
+ *replacement = dest;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Update an object's cache state
+ *
+ * \param object Object to update cache for
* \return NSERROR_OK.
*/
-nserror llcache_object_remove_user(llcache_object *object,
- llcache_object_user *user)
-{
- assert(user != NULL);
- assert(object != NULL);
- assert(object->users != NULL);
- assert(user->handle == NULL || user->handle->object == object);
- assert((user->prev != NULL) || (object->users == user));
-
- if (user == object->users)
- object->users = user->next;
- else
- user->prev->next = user->next;
-
- if (user->next != NULL)
- user->next->prev = user->prev;
-
- user->next = user->prev = NULL;
-
+static nserror llcache_object_cache_update(llcache_object *object)
+{
+ if (object->cache.date == 0)
+ object->cache.date = time(NULL);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Handle FETCH_NOTMODIFIED event
+ *
+ * \param object Object to process
+ * \param replacement Pointer to location to receive replacement object
+ * \return NSERROR_OK.
+ */
+static nserror llcache_fetch_notmodified(llcache_object *object,
+ llcache_object **replacement)
+{
+ /* There may be no candidate if the server erroneously responded
+ * to an unconditional request with a 304 Not Modified response.
+ * In this case, we simply retain the initial object, having
+ * invalidated it and marked it as complete.
+ */
+ if (object->candidate != NULL) {
+ llcache_object_user *user, *next;
+
+ /* Move user(s) to candidate content */
+ for (user = object->users; user != NULL; user = next) {
+ next = user->next;
+
+ llcache_object_remove_user(object, user);
+ llcache_object_add_user(object->candidate, user);
+ }
+
+ /* Candidate is no longer a candidate for us */
+ object->candidate->candidate_count--;
+
+ /* Clone our cache control data into the candidate */
+ llcache_object_clone_cache_data(object, object->candidate,
+ false);
+ /* Bring candidate's cache data up to date */
+ llcache_object_cache_update(object->candidate);
+ /* Revert no-cache to normal, if required */
+ if (object->candidate->cache.no_cache ==
+ LLCACHE_VALIDATE_ONCE) {
+ object->candidate->cache.no_cache =
+ LLCACHE_VALIDATE_FRESH;
+ }
+
+ /* Candidate is now our object */
+ *replacement = object->candidate;
+ object->candidate = NULL;
+ } else {
+ /* There was no candidate: retain object */
+ *replacement = object;
+ }
+
+ /* Ensure fetch has stopped */
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+
+ /* Invalidate our cache-control data */
+ llcache_invalidate_cache_control_data(object);
+
+ /* Mark it complete */
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+
+ /* Old object will be flushed from the cache on the next poll */
+
+ return NSERROR_OK;
+}
+
+/**
+ * Process a chunk of fetched data
+ *
+ * \param object Object being fetched
+ * \param data Data to process
+ * \param len Byte length of data
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+static nserror llcache_fetch_process_data(llcache_object *object, const uint8_t *data,
+ size_t len)
+{
+ /* Resize source buffer if it's too small */
+ if (object->source_len + len >= object->source_alloc) {
+ const size_t new_len = object->source_len + len + 64 * 1024;
+ uint8_t *temp = realloc(object->source_data, new_len);
+ if (temp == NULL)
+ return NSERROR_NOMEM;
+
+ object->source_data = temp;
+ object->source_alloc = new_len;
+ }
+
+ /* Append this data chunk to source buffer */
+ memcpy(object->source_data + object->source_len, data, len);
+ object->source_len += len;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Handle a query response
+ *
+ * \param proceed Whether to proceed with fetch
+ * \param cbpw Our context for query
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_query_handle_response(bool proceed, void *cbpw)
+{
+ llcache_event event;
+ llcache_object *object = cbpw;
+
+ object->fetch.outstanding_query = false;
+
+ /* Refetch, using existing fetch parameters, if client allows us to */
+ if (proceed)
+ return llcache_object_refetch(object);
+
+ /* Invalidate cache-control data */
+ llcache_invalidate_cache_control_data(object);
+
+ /* Mark it complete */
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+
+ /* Inform client(s) that object fetch failed */
+ event.type = LLCACHE_EVENT_ERROR;
+ /** \todo More appropriate error message */
+ event.data.msg = messages_get("FetchFailed");
+
+ return llcache_send_event_to_users(object, &event);
+}
+
+/**
+ * Handle an authentication request
+ *
+ * \param object Object being fetched
+ * \param realm Authentication realm
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+static nserror llcache_fetch_auth(llcache_object *object, const char *realm)
+{
+ const char *auth;
+ nserror error = NSERROR_OK;
+
+ /* Abort fetch for this object */
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+
+ /* Invalidate cache-control data */
+ llcache_invalidate_cache_control_data(object);
+
+ /* Destroy headers */
+ llcache_destroy_headers(object);
+
+ /* If there was no realm, then default to the URL */
+ /** \todo If there was no WWW-Authenticate header, use response body */
+ if (realm == NULL)
+ realm = nsurl_access(object->url);
+
+ auth = urldb_get_auth_details(nsurl_access(object->url), realm);
+
+ if (auth == NULL || object->fetch.tried_with_auth == true) {
+ /* No authentication details, or tried what we had, so ask */
+ object->fetch.tried_with_auth = false;
+
+ if (llcache->query_cb != NULL) {
+ llcache_query query;
+
+ /* Emit query for authentication details */
+ query.type = LLCACHE_QUERY_AUTH;
+ query.url = object->url;
+ query.data.auth.realm = realm;
+
+ object->fetch.outstanding_query = true;
+
+ error = llcache->query_cb(&query, llcache->query_cb_pw,
+ llcache_query_handle_response, object);
+ } else {
+ llcache_event event;
+
+ /* Mark object complete */
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+
+ /* Inform client(s) that object fetch failed */
+ event.type = LLCACHE_EVENT_ERROR;
+ /** \todo More appropriate error message */
+ event.data.msg = messages_get("FetchFailed");
+
+ error = llcache_send_event_to_users(object, &event);
+ }
+ } else {
+ /* Flag that we've tried to refetch with credentials, so
+ * that if the fetch fails again, we ask the user again */
+ object->fetch.tried_with_auth = true;
+ error = llcache_object_refetch(object);
+ }
+
+ return error;
+}
+
+/**
+ * Handle a TLS certificate verification failure
+ *
+ * \param object Object being fetched
+ * \param certs Certificate chain
+ * \param num Number of certificates in chain
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_fetch_cert_error(llcache_object *object,
+ const struct ssl_cert_info *certs, size_t num)
+{
+ nserror error = NSERROR_OK;
+
+ /* Fetch has been stopped, and destroyed. Invalidate object's pointer */
+ object->fetch.fetch = NULL;
+
+ /* Invalidate cache-control data */
+ llcache_invalidate_cache_control_data(object);
+
+ if (llcache->query_cb != NULL) {
+ llcache_query query;
+
+ /* Emit query for TLS */
+ query.type = LLCACHE_QUERY_SSL;
+ query.url = object->url;
+ query.data.ssl.certs = certs;
+ query.data.ssl.num = num;
+
+ object->fetch.outstanding_query = true;
+
+ error = llcache->query_cb(&query, llcache->query_cb_pw,
+ llcache_query_handle_response, object);
+ } else {
+ llcache_event event;
+
+ /* Mark object complete */
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+
+ /* Inform client(s) that object fetch failed */
+ event.type = LLCACHE_EVENT_ERROR;
+ /** \todo More appropriate error message */
+ event.data.msg = messages_get("FetchFailed");
+
+ error = llcache_send_event_to_users(object, &event);
+ }
+
+ return error;
+}
+
+/**
+ * Handler for fetch events
+ *
+ * \param msg Fetch event
+ * \param p Our private data
+ */
+static void llcache_fetch_callback(const fetch_msg *msg, void *p)
+{
+ nserror error = NSERROR_OK;
+ llcache_object *object = p;
+ llcache_event event;
+
#ifdef LLCACHE_TRACE
- LOG(("Removing user %p from %p", user, object));
+ LOG(("Fetch event %d for %p", msg->type, object));
#endif
- return NSERROR_OK;
+ switch (msg->type) {
+ case FETCH_HEADER:
+ /* Received a fetch header */
+ object->fetch.state = LLCACHE_FETCH_HEADERS;
+
+ error = llcache_fetch_process_header(object,
+ msg->data.header_or_data.buf,
+ msg->data.header_or_data.len);
+ break;
+
+ /* 3xx responses */
+ case FETCH_REDIRECT:
+ /* Request resulted in a redirect */
+
+ /* Release candidate, if any */
+ if (object->candidate != NULL) {
+ object->candidate->candidate_count--;
+ object->candidate = NULL;
+ }
+
+ error = llcache_fetch_redirect(object,
+ msg->data.redirect, &object);
+ break;
+ case FETCH_NOTMODIFIED:
+ /* Conditional request determined that cached object is fresh */
+ error = llcache_fetch_notmodified(object, &object);
+ break;
+
+ /* Normal 2xx state machine */
+ case FETCH_DATA:
+ /* Received some data */
+ if (object->fetch.state != LLCACHE_FETCH_DATA) {
+ /* On entry into this state, check if we need to
+ * invalidate the cache control data. We are guaranteed
+ * to have received all response headers.
+ *
+ * There are two cases in which we want to suppress
+ * cacheing of an object:
+ *
+ * 1) The HTTP response code is not 200 or 203
+ * 2) The request URI had a query string and the
+ * response headers did not provide an explicit
+ * object expiration time.
+ */
+ long http_code = fetch_http_code(object->fetch.fetch);
+
+ if ((http_code != 200 && http_code != 203) ||
+ (object->has_query &&
+ (object->cache.max_age == INVALID_AGE &&
+ object->cache.expires == 0))) {
+ /* Invalidate cache control data */
+ llcache_invalidate_cache_control_data(object);
+ }
+
+ /* Release candidate, if any */
+ if (object->candidate != NULL) {
+ object->candidate->candidate_count--;
+ object->candidate = NULL;
+ }
+ }
+
+ object->fetch.state = LLCACHE_FETCH_DATA;
+
+ error = llcache_fetch_process_data(object,
+ msg->data.header_or_data.buf,
+ msg->data.header_or_data.len);
+ break;
+ case FETCH_FINISHED:
+ /* Finished fetching */
+ {
+ uint8_t *temp;
+
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+ object->fetch.fetch = NULL;
+
+ /* Shrink source buffer to required size */
+ temp = realloc(object->source_data,
+ object->source_len);
+ /* If source_len is 0, then temp may be NULL */
+ if (temp != NULL || object->source_len == 0) {
+ object->source_data = temp;
+ object->source_alloc = object->source_len;
+ }
+
+ llcache_object_cache_update(object);
+ }
+ break;
+
+ /* Out-of-band information */
+ case FETCH_ERROR:
+ /* An error occurred while fetching */
+ /* The fetch has has already been cleaned up by the fetcher */
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+ object->fetch.fetch = NULL;
+
+ /* Release candidate, if any */
+ if (object->candidate != NULL) {
+ object->candidate->candidate_count--;
+ object->candidate = NULL;
+ }
+
+ /* Invalidate cache control data */
+ llcache_invalidate_cache_control_data(object);
+
+ /** \todo Consider using errorcode for something */
+
+ event.type = LLCACHE_EVENT_ERROR;
+ event.data.msg = msg->data.error;
+
+ error = llcache_send_event_to_users(object, &event);
+
+ break;
+ case FETCH_PROGRESS:
+ /* Progress update */
+ event.type = LLCACHE_EVENT_PROGRESS;
+ event.data.msg = msg->data.progress;
+
+ error = llcache_send_event_to_users(object, &event);
+
+ break;
+
+ /* Events requiring action */
+ case FETCH_AUTH:
+ /* Need Authentication */
+
+ /* Release candidate, if any */
+ if (object->candidate != NULL) {
+ object->candidate->candidate_count--;
+ object->candidate = NULL;
+ }
+
+ error = llcache_fetch_auth(object, msg->data.auth.realm);
+ break;
+ case FETCH_CERT_ERR:
+ /* Something went wrong when validating TLS certificates */
+
+ /* Release candidate, if any */
+ if (object->candidate != NULL) {
+ object->candidate->candidate_count--;
+ object->candidate = NULL;
+ }
+
+ error = llcache_fetch_cert_error(object,
+ msg->data.cert_err.certs,
+ msg->data.cert_err.num_certs);
+ break;
+ }
+
+ /* Deal with any errors reported by event handlers */
+ if (error != NSERROR_OK) {
+ if (object->fetch.fetch != NULL) {
+ fetch_abort(object->fetch.fetch);
+ object->fetch.fetch = NULL;
+
+ /* Invalidate cache control data */
+ llcache_invalidate_cache_control_data(object);
+
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+ }
+ return;
+ }
}
/**
@@ -1284,7 +1728,7 @@
* \param handle External cache handle to search for
* \return Pointer to corresponding user, or NULL if not found
*/
-llcache_object_user *llcache_object_find_user(const llcache_handle *handle)
+static llcache_object_user *llcache_object_find_user(const llcache_handle *handle)
{
llcache_object_user *user;
@@ -1299,33 +1743,13 @@
}
/**
- * Add a low-level cache object to a cache list
- *
- * \param object Object to add
- * \param list List to add to
- * \return NSERROR_OK
- */
-nserror llcache_object_add_to_list(llcache_object *object,
- llcache_object **list)
-{
- object->prev = NULL;
- object->next = *list;
-
- if (*list != NULL)
- (*list)->prev = object;
- *list = object;
-
- return NSERROR_OK;
-}
-
-/**
* Remove a low-level cache object from a cache list
*
* \param object Object to remove
* \param list List to remove from
* \return NSERROR_OK
*/
-nserror llcache_object_remove_from_list(llcache_object *object,
+static nserror llcache_object_remove_from_list(llcache_object *object,
llcache_object **list)
{
if (object == *list)
@@ -1346,7 +1770,7 @@
* \param list List to search in
* \return True if object resides in list, false otherwise
*/
-bool llcache_object_in_list(const llcache_object *object,
+static bool llcache_object_in_list(const llcache_object *object,
const llcache_object *list)
{
while (list != NULL) {
@@ -1365,7 +1789,7 @@
* \param object Object to notify users about
* \return NSERROR_OK on success, appropriate error otherwise
*/
-nserror llcache_object_notify_users(llcache_object *object)
+static nserror llcache_object_notify_users(llcache_object *object)
{
nserror error;
llcache_object_user *user, *next_user;
@@ -1595,7 +2019,7 @@
* \param snapshot Pointer to receive snapshot of \a object
* \return NSERROR_OK on success, appropriate error otherwise
*/
-nserror llcache_object_snapshot(llcache_object *object,
+static nserror llcache_object_snapshot(llcache_object *object,
llcache_object **snapshot)
{
llcache_object *newobj;
@@ -1649,9 +2073,15 @@
return NSERROR_OK;
}
+
+/******************************************************************************
+ * Public API *
+ ******************************************************************************/
+
/**
* Attempt to clean the cache
*/
+/* Exported interface documented in llcache.h */
void llcache_clean(void)
{
llcache_object *object, *next;
@@ -1673,9 +2103,10 @@
next = object->next;
/* The candidate count of uncacheable objects is always 0 */
- if (object->users == NULL && object->candidate_count == 0 &&
- object->fetch.fetch == NULL &&
- object->fetch.outstanding_query == false) {
+ if ((object->users == NULL) &&
+ (object->candidate_count == 0) &&
+ (object->fetch.fetch == NULL) &&
+ (object->fetch.outstanding_query == false)) {
#ifdef LLCACHE_TRACE
LOG(("Found victim %p", object));
#endif
@@ -1691,10 +2122,11 @@
for (object = llcache->cached_objects; object != NULL; object = next) {
next = object->next;
- if (object->users == NULL && object->candidate_count == 0 &&
- llcache_object_is_fresh(object) == false &&
- object->fetch.fetch == NULL &&
- object->fetch.outstanding_query == false) {
+ if ((object->users == NULL) &&
+ (object->candidate_count == 0) &&
+ (llcache_object_is_fresh(object) == false) &&
+ (object->fetch.fetch == NULL) &&
+ (object->fetch.outstanding_query == false)) {
#ifdef LLCACHE_TRACE
LOG(("Found victim %p", object));
#endif
@@ -1706,9 +2138,10 @@
}
}
+ /* 3) Fresh cacheable objects with no users or pending
+ * fetches, only if the cache exceeds the configured size.
+ */
if (llcache->limit < llcache_size) {
- /* 3) Fresh cacheable objects with
- * no users or pending fetches */
for (object = llcache->cached_objects; object != NULL;
object = next) {
next = object->next;
@@ -1737,822 +2170,333 @@
}
-/**
- * Clone a POST data object
- *
- * \param orig Object to clone
- * \param clone Pointer to location to receive clone
- * \return NSERROR_OK on success, appropriate error otherwise
- */
-nserror llcache_post_data_clone(const llcache_post_data *orig,
- llcache_post_data **clone)
-{
- llcache_post_data *post_clone;
-
- post_clone = calloc(1, sizeof(llcache_post_data));
- if (post_clone == NULL)
+/* See llcache.h for documentation */
+nserror
+llcache_initialise(llcache_query_callback cb, void *pw, uint32_t llcache_limit)
+{
+ llcache = calloc(1, sizeof(struct llcache_s));
+ if (llcache == NULL) {
return NSERROR_NOMEM;
-
- post_clone->type = orig->type;
-
- /* Deep-copy the type-specific data */
- if (orig->type == LLCACHE_POST_URL_ENCODED) {
- post_clone->data.urlenc = strdup(orig->data.urlenc);
- if (post_clone->data.urlenc == NULL) {
- free(post_clone);
-
- return NSERROR_NOMEM;
- }
+ }
+
+ llcache->query_cb = cb;
+ llcache->query_cb_pw = pw;
+ llcache->limit = llcache_limit;
+
+ /* Create static scheme strings */
+ if (lwc_intern_string("file", SLEN("file"),
+ &llcache_file_lwc) != lwc_error_ok)
+ return NSERROR_NOMEM;
+
+ if (lwc_intern_string("about", SLEN("about"),
+ &llcache_about_lwc) != lwc_error_ok)
+ return NSERROR_NOMEM;
+
+ if (lwc_intern_string("resource", SLEN("resource"),
+ &llcache_resource_lwc) != lwc_error_ok)
+ return NSERROR_NOMEM;
+
+ LOG(("llcache initialised with a limit of %d bytes", llcache_limit));
+
+ return NSERROR_OK;
+}
+
+/* See llcache.h for documentation */
+void llcache_finalise(void)
+{
+ llcache_object *object, *next;
+
+ /* Clean uncached objects */
+ for (object = llcache->uncached_objects; object != NULL; object = next) {
+ llcache_object_user *user, *next_user;
+
+ next = object->next;
+
+ for (user = object->users; user != NULL; user = next_user) {
+ next_user = user->next;
+
+ if (user->handle != NULL)
+ free(user->handle);
+
+ free(user);
+ }
+
+ /* Fetch system has already been destroyed */
+ object->fetch.fetch = NULL;
+
+ llcache_object_destroy(object);
+ }
+
+ /* Clean cached objects */
+ for (object = llcache->cached_objects; object != NULL; object = next) {
+ llcache_object_user *user, *next_user;
+
+ next = object->next;
+
+ for (user = object->users; user != NULL; user = next_user) {
+ next_user = user->next;
+
+ if (user->handle != NULL)
+ free(user->handle);
+
+ free(user);
+ }
+
+ /* Fetch system has already been destroyed */
+ object->fetch.fetch = NULL;
+
+ llcache_object_destroy(object);
+ }
+
+ /* Unref static scheme lwc strings */
+ lwc_string_unref(llcache_file_lwc);
+ lwc_string_unref(llcache_about_lwc);
+ lwc_string_unref(llcache_resource_lwc);
+
+ free(llcache);
+ llcache = NULL;
+}
+
+/* See llcache.h for documentation */
+nserror llcache_poll(void)
+{
+ llcache_object *object;
+
+ fetch_poll();
+
+ /* Catch new users up with state of objects */
+ for (object = llcache->cached_objects; object != NULL;
+ object = object->next) {
+ llcache_object_notify_users(object);
+ }
+
+ for (object = llcache->uncached_objects; object != NULL;
+ object = object->next) {
+ llcache_object_notify_users(object);
+ }
+
+ return NSERROR_OK;
+}
+
+/* See llcache.h for documentation */
+nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
+ nsurl *referer, const llcache_post_data *post,
+ llcache_handle_callback cb, void *pw,
+ llcache_handle **result)
+{
+ nserror error;
+ llcache_object_user *user;
+ llcache_object *object;
+
+ /* Can we fetch this URL at all? */
+ if (fetch_can_fetch(url) == false)
+ return NSERROR_NO_FETCH_HANDLER;
+
+ /* Create a new object user */
+ error = llcache_object_user_new(cb, pw, &user);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Retrieve a suitable object from the cache,
+ * creating a new one if needed. */
+ error = llcache_object_retrieve(url, flags, referer, post, 0, &object);
+ if (error != NSERROR_OK) {
+ llcache_object_user_destroy(user);
+ return error;
+ }
+
+ /* Add user to object */
+ llcache_object_add_user(object, user);
+
+ *result = user->handle;
+
+ return NSERROR_OK;
+}
+
+/* See llcache.h for documentation */
+nserror llcache_handle_change_callback(llcache_handle *handle,
+ llcache_handle_callback cb, void *pw)
+{
+ handle->cb = cb;
+ handle->pw = pw;
+
+ return NSERROR_OK;
+}
+
+/* See llcache.h for documentation */
+nserror llcache_handle_release(llcache_handle *handle)
+{
+ nserror error = NSERROR_OK;
+ llcache_object *object = handle->object;
+ llcache_object_user *user = llcache_object_find_user(handle);
+
+ assert(user != NULL);
+
+ if (user->iterator_target) {
+ /* Can't remove / delete user object if it's
+ * the target of an iterator */
+ user->queued_for_delete = true;
} else {
- post_clone->data.multipart = fetch_multipart_data_clone(
- orig->data.multipart);
- if (post_clone->data.multipart == NULL) {
- free(post_clone);
-
- return NSERROR_NOMEM;
- }
- }
-
- *clone = post_clone;
-
- return NSERROR_OK;
-}
-
-/**
- * Handle a query response
- *
- * \param proceed Whether to proceed with fetch
- * \param cbpw Our context for query
- * \return NSERROR_OK on success, appropriate error otherwise
- */
-nserror llcache_query_handle_response(bool proceed, void *cbpw)
-{
- llcache_event event;
- llcache_object *object = cbpw;
-
- object->fetch.outstanding_query = false;
-
- /* Refetch, using existing fetch parameters, if client allows us to */
- if (proceed)
- return llcache_object_refetch(object);
-
- /* Invalidate cache-control data */
- llcache_invalidate_cache_control_data(object);
-
- /* Mark it complete */
- object->fetch.state = LLCACHE_FETCH_COMPLETE;
-
- /* Inform client(s) that object fetch failed */
- event.type = LLCACHE_EVENT_ERROR;
- /** \todo More appropriate error message */
- event.data.msg = messages_get("FetchFailed");
-
- return llcache_send_event_to_users(object, &event);
-}
-
-/**
- * Handler for fetch events
- *
- * \param msg Fetch event
- * \param p Our private data
- */
-void llcache_fetch_callback(const fetch_msg *msg, void *p)
-{
+ /* Remove the user from the object and destroy it */
+ error = llcache_object_remove_user(object, user);
+ if (error == NSERROR_OK) {
+ error = llcache_object_user_destroy(user);
+ }
+ }
+
+ return error;
+}
+
+/* See llcache.h for documentation */
+nserror llcache_handle_clone(llcache_handle *handle, llcache_handle **result)
+{
+ nserror error;
+ llcache_object_user *newuser;
+
+ error = llcache_object_user_new(handle->cb, handle->pw, &newuser);
+ if (error == NSERROR_OK) {
+ llcache_object_add_user(handle->object, newuser);
+ newuser->handle->state = handle->state;
+ *result = newuser->handle;
+ }
+
+ return error;
+}
+
+/* See llcache.h for documentation */
+nserror llcache_handle_abort(llcache_handle *handle)
+{
+ llcache_object_user *user = llcache_object_find_user(handle);
+ llcache_object *object = handle->object, *newobject;
nserror error = NSERROR_OK;
- llcache_object *object = p;
- llcache_event event;
-
-#ifdef LLCACHE_TRACE
- LOG(("Fetch event %d for %p", msg->type, object));
-#endif
-
- switch (msg->type) {
- case FETCH_HEADER:
- /* Received a fetch header */
- object->fetch.state = LLCACHE_FETCH_HEADERS;
-
- error = llcache_fetch_process_header(object,
- msg->data.header_or_data.buf,
- msg->data.header_or_data.len);
- break;
-
- /* 3xx responses */
- case FETCH_REDIRECT:
- /* Request resulted in a redirect */
-
- /* Release candidate, if any */
- if (object->candidate != NULL) {
- object->candidate->candidate_count--;
- object->candidate = NULL;
- }
-
- error = llcache_fetch_redirect(object,
- msg->data.redirect, &object);
- break;
- case FETCH_NOTMODIFIED:
- /* Conditional request determined that cached object is fresh */
- error = llcache_fetch_notmodified(object, &object);
- break;
-
- /* Normal 2xx state machine */
- case FETCH_DATA:
- /* Received some data */
- if (object->fetch.state != LLCACHE_FETCH_DATA) {
- /* On entry into this state, check if we need to
- * invalidate the cache control data. We are guaranteed
- * to have received all response headers.
- *
- * There are two cases in which we want to suppress
- * cacheing of an object:
- *
- * 1) The HTTP response code is not 200 or 203
- * 2) The request URI had a query string and the
- * response headers did not provide an explicit
- * object expiration time.
- */
- long http_code = fetch_http_code(object->fetch.fetch);
-
- if ((http_code != 200 && http_code != 203) ||
- (object->has_query &&
- (object->cache.max_age == INVALID_AGE &&
- object->cache.expires == 0))) {
- /* Invalidate cache control data */
- llcache_invalidate_cache_control_data(object);
+ bool all_alone = true;
+
+ /* Determine if we are the only user */
+ if (user->prev != NULL)
+ all_alone = false;
+ if (user->next != NULL)
+ all_alone = false;
+
+ if (all_alone == false) {
+ /* We must snapshot this object */
+ error = llcache_object_snapshot(object, &newobject);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* Move across to the new object */
+ if (user->iterator_target) {
+ /* User is current iterator target, clone it */
+ llcache_object_user *newuser =
+ calloc(1, sizeof(llcache_object_user));
+ if (newuser == NULL) {
+ llcache_object_destroy(newobject);
+ return NSERROR_NOMEM;
}
- /* Release candidate, if any */
- if (object->candidate != NULL) {
- object->candidate->candidate_count--;
- object->candidate = NULL;
- }
- }
-
- object->fetch.state = LLCACHE_FETCH_DATA;
-
- error = llcache_fetch_process_data(object,
- msg->data.header_or_data.buf,
- msg->data.header_or_data.len);
- break;
- case FETCH_FINISHED:
- /* Finished fetching */
- {
- uint8_t *temp;
-
- object->fetch.state = LLCACHE_FETCH_COMPLETE;
- object->fetch.fetch = NULL;
-
- /* Shrink source buffer to required size */
- temp = realloc(object->source_data,
- object->source_len);
- /* If source_len is 0, then temp may be NULL */
- if (temp != NULL || object->source_len == 0) {
- object->source_data = temp;
- object->source_alloc = object->source_len;
- }
-
- llcache_object_cache_update(object);
- }
- break;
-
- /* Out-of-band information */
- case FETCH_ERROR:
- /* An error occurred while fetching */
- /* The fetch has has already been cleaned up by the fetcher */
- object->fetch.state = LLCACHE_FETCH_COMPLETE;
- object->fetch.fetch = NULL;
-
- /* Release candidate, if any */
- if (object->candidate != NULL) {
- object->candidate->candidate_count--;
- object->candidate = NULL;
- }
-
- /* Invalidate cache control data */
- llcache_invalidate_cache_control_data(object);
-
- /** \todo Consider using errorcode for something */
-
- event.type = LLCACHE_EVENT_ERROR;
- event.data.msg = msg->data.error;
+ /* Move handle across to clone */
+ newuser->handle = user->handle;
+ user->handle = NULL;
+
+ /* Mark user as needing deletion */
+ user->queued_for_delete = true;
+
+ llcache_object_add_user(newobject, newuser);
+ } else {
+ llcache_object_remove_user(object, user);
+ llcache_object_add_user(newobject, user);
+ }
- error = llcache_send_event_to_users(object, &event);
-
- break;
- case FETCH_PROGRESS:
- /* Progress update */
- event.type = LLCACHE_EVENT_PROGRESS;
- event.data.msg = msg->data.progress;
-
- error = llcache_send_event_to_users(object, &event);
-
- break;
-
- /* Events requiring action */
- case FETCH_AUTH:
- /* Need Authentication */
-
- /* Release candidate, if any */
- if (object->candidate != NULL) {
- object->candidate->candidate_count--;
- object->candidate = NULL;
- }
-
- error = llcache_fetch_auth(object, msg->data.auth.realm);
- break;
- case FETCH_CERT_ERR:
- /* Something went wrong when validating TLS certificates */
-
- /* Release candidate, if any */
- if (object->candidate != NULL) {
- object->candidate->candidate_count--;
- object->candidate = NULL;
- }
-
- error = llcache_fetch_cert_error(object,
- msg->data.cert_err.certs,
- msg->data.cert_err.num_certs);
- break;
- }
-
- /* Deal with any errors reported by event handlers */
- if (error != NSERROR_OK) {
+ /* Add new object to uncached list */
+ llcache_object_add_to_list(newobject,
+ &llcache->uncached_objects);
+ } else {
+ /* We're the only user, so abort any fetch in progress */
if (object->fetch.fetch != NULL) {
fetch_abort(object->fetch.fetch);
object->fetch.fetch = NULL;
-
- /* Invalidate cache control data */
- llcache_invalidate_cache_control_data(object);
-
- object->fetch.state = LLCACHE_FETCH_COMPLETE;
- }
- return;
- }
-}
-
-/**
- * Handle FETCH_REDIRECT event
- *
- * \param object Object being redirected
- * \param target Target of redirect (may be relative)
- * \param replacement Pointer to location to receive replacement object
- * \return NSERROR_OK on success, appropriate error otherwise
- */
-nserror llcache_fetch_redirect(llcache_object *object, const char *target,
- llcache_object **replacement)
-{
- nserror error;
- llcache_object *dest;
- llcache_object_user *user, *next;
- const llcache_post_data *post = object->fetch.post;
- nsurl *url;
- lwc_string *scheme;
- lwc_string *object_scheme;
- bool match;
- /* Extract HTTP response code from the fetch object */
- long http_code = fetch_http_code(object->fetch.fetch);
-
- /* Abort fetch for this object */
- fetch_abort(object->fetch.fetch);
- object->fetch.fetch = NULL;
-
- /* Invalidate the cache control data */
- llcache_invalidate_cache_control_data(object);
-
- /* And mark it complete */
- object->fetch.state = LLCACHE_FETCH_COMPLETE;
-
- /* Forcibly stop redirecting if we've followed too many redirects */
-#define REDIRECT_LIMIT 10
- if (object->fetch.redirect_count > REDIRECT_LIMIT) {
- llcache_event event;
-
- LOG(("Too many nested redirects"));
-
- event.type = LLCACHE_EVENT_ERROR;
- event.data.msg = messages_get("BadRedirect");
+ }
- return llcache_send_event_to_users(object, &event);
- }
-#undef REDIRECT_LIMIT
-
- /* Make target absolute */
- error = nsurl_join(object->url, target, &url);
- if (error != NSERROR_OK)
- return error;
-
- /* Reject attempts to redirect from unvalidated to validated schemes
- * A "validated" scheme is one over which we have some guarantee that
- * the source is trustworthy. */
- object_scheme = nsurl_get_component(object->url, NSURL_SCHEME);
- scheme = nsurl_get_component(url, NSURL_SCHEME);
-
- /* resource: and about: are allowed to redirect anywhere */
- if ((lwc_string_isequal(object_scheme, llcache_resource_lwc,
- &match) == lwc_error_ok && match == false) &&
- (lwc_string_isequal(object_scheme, llcache_about_lwc,
- &match) == lwc_error_ok && match == false)) {
- /* file, about and resource are not valid redirect targets */
- if ((lwc_string_isequal(object_scheme, llcache_file_lwc,
- &match) == lwc_error_ok && match == true) ||
- (lwc_string_isequal(object_scheme, llcache_about_lwc,
- &match) == lwc_error_ok && match == true) ||
- (lwc_string_isequal(object_scheme, llcache_resource_lwc,
- &match) == lwc_error_ok && match == true)) {
- lwc_string_unref(object_scheme);
- lwc_string_unref(scheme);
- nsurl_unref(url);
- return NSERROR_OK;
- }
- }
-
- lwc_string_unref(scheme);
- lwc_string_unref(object_scheme);
-
- /* Bail out if we've no way of handling this URL */
- if (fetch_can_fetch(url) == false) {
- nsurl_unref(url);
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+
+ /* Invalidate cache control data */
+ llcache_invalidate_cache_control_data(object);
+ }
+
+ return error;
+}
+
+/* See llcache.h for documentation */
+nserror llcache_handle_force_stream(llcache_handle *handle)
+{
+ llcache_object_user *user = llcache_object_find_user(handle);
+ llcache_object *object = handle->object;
+
+ /* Cannot stream if there are multiple users */
+ if (user->prev != NULL || user->next != NULL)
return NSERROR_OK;
- }
-
- if (http_code == 301 || http_code == 302 || http_code == 303) {
- /* 301, 302, 303 redirects are all unconditional GET requests */
- post = NULL;
- } else if (http_code != 307 || post != NULL) {
- /** \todo 300, 305, 307 with POST */
- nsurl_unref(url);
- return NSERROR_OK;
- }
-
- /* Attempt to fetch target URL */
- error = llcache_object_retrieve(url, object->fetch.flags,
- object->fetch.referer, post,
- object->fetch.redirect_count + 1, &dest);
-
- /* No longer require url */
- nsurl_unref(url);
-
- if (error != NSERROR_OK)
- return error;
-
- /* Move user(s) to replacement object */
- for (user = object->users; user != NULL; user = next) {
- next = user->next;
-
- llcache_object_remove_user(object, user);
- llcache_object_add_user(dest, user);
- }
-
- /* Dest is now our object */
- *replacement = dest;
-
- return NSERROR_OK;
-}
-
-/**
- * Handle FETCH_NOTMODIFIED event
- *
- * \param object Object to process
- * \param replacement Pointer to location to receive replacement object
- * \return NSERROR_OK.
- */
-nserror llcache_fetch_notmodified(llcache_object *object,
- llcache_object **replacement)
-{
- /* There may be no candidate if the server erroneously responded
- * to an unconditional request with a 304 Not Modified response.
- * In this case, we simply retain the initial object, having
- * invalidated it and marked it as complete.
- */
- if (object->candidate != NULL) {
- llcache_object_user *user, *next;
-
- /* Move user(s) to candidate content */
- for (user = object->users; user != NULL; user = next) {
- next = user->next;
-
- llcache_object_remove_user(object, user);
- llcache_object_add_user(object->candidate, user);
- }
-
- /* Candidate is no longer a candidate for us */
- object->candidate->candidate_count--;
-
- /* Clone our cache control data into the candidate */
- llcache_object_clone_cache_data(object, object->candidate,
- false);
- /* Bring candidate's cache data up to date */
- llcache_object_cache_update(object->candidate);
- /* Revert no-cache to normal, if required */
- if (object->candidate->cache.no_cache ==
- LLCACHE_VALIDATE_ONCE) {
- object->candidate->cache.no_cache =
- LLCACHE_VALIDATE_FRESH;
- }
-
- /* Candidate is now our object */
- *replacement = object->candidate;
- object->candidate = NULL;
- } else {
- /* There was no candidate: retain object */
- *replacement = object;
- }
-
- /* Ensure fetch has stopped */
- fetch_abort(object->fetch.fetch);
- object->fetch.fetch = NULL;
-
- /* Invalidate our cache-control data */
- llcache_invalidate_cache_control_data(object);
-
- /* Mark it complete */
- object->fetch.state = LLCACHE_FETCH_COMPLETE;
-
- /* Old object will be flushed from the cache on the next poll */
+
+ /* Forcibly uncache this object */
+ if (llcache_object_in_list(object, llcache->cached_objects)) {
+ llcache_object_remove_from_list(object,
+ &llcache->cached_objects);
+ llcache_object_add_to_list(object, &llcache->uncached_objects);
+ }
+
+ object->fetch.flags |= LLCACHE_RETRIEVE_STREAM_DATA;
return NSERROR_OK;
}
-/**
- * Split a fetch header into name and value
- *
- * \param data Header string
- * \param len Byte length of header
- * \param name Pointer to location to receive header name
- * \param value Pointer to location to receive header value
- * \return NSERROR_OK on success, appropriate error otherwise
- */
-nserror llcache_fetch_split_header(const uint8_t *data, size_t len,
- char **name, char **value)
-{
- char *n, *v;
- const uint8_t *colon;
-
- /* Find colon */
- colon = (const uint8_t *) strchr((const char *) data, ':');
- if (colon == NULL) {
- /* Failed, assume a key with no value */
- n = strdup((const char *) data);
- if (n == NULL)
- return NSERROR_NOMEM;
-
- v = strdup("");
- if (v == NULL) {
- free(n);
- return NSERROR_NOMEM;
- }
- } else {
- /* Split header into name & value */
-
- /* Strip leading whitespace from name */
- while (data[0] == ' ' || data[0] == '\t' ||
- data[0] == '\r' || data[0] == '\n') {
- data++;
- }
-
- /* Strip trailing whitespace from name */
- while (colon > data && (colon[-1] == ' ' ||
- colon[-1] == '\t' || colon[-1] == '\r' ||
- colon[-1] == '\n'))
- colon--;
-
- n = strndup((const char *) data, colon - data);
- if (n == NULL)
- return NSERROR_NOMEM;
-
- /* Find colon again */
- while (*colon != ':') {
- colon++;
- }
-
- /* Skip over colon and any subsequent whitespace */
- do {
- colon++;
- } while (*colon == ' ' || *colon == '\t' ||
- *colon == '\r' || *colon == '\n');
-
- /* Strip trailing whitespace from value */
- while (len > 0 && (data[len - 1] == ' ' ||
- data[len - 1] == '\t' ||
- data[len - 1] == '\r' ||
- data[len - 1] == '\n')) {
- len--;
- }
-
- v = strndup((const char *) colon, len - (colon - data));
- if (v == NULL) {
- free(n);
- return NSERROR_NOMEM;
- }
- }
-
- *name = n;
- *value = v;
+/* See llcache.h for documentation */
+nserror llcache_handle_invalidate_cache_data(llcache_handle *handle)
+{
+ if (handle->object != NULL && handle->object->fetch.fetch == NULL &&
+ handle->object->cache.no_cache ==
+ LLCACHE_VALIDATE_FRESH) {
+ handle->object->cache.no_cache = LLCACHE_VALIDATE_ONCE;
+ }
return NSERROR_OK;
}
-/**
- * Parse a fetch header
- *
- * \param object Object to parse header for
- * \param data Header string
- * \param len Byte length of header
- * \param name Pointer to location to receive header name
- * \param value Pointer to location to receive header value
- * \return NSERROR_OK on success, appropriate error otherwise
- *
- * \note This function also has the side-effect of updating
- * the cache control data for the object if an interesting
- * header is encountered
- */
-nserror llcache_fetch_parse_header(llcache_object *object,
- const uint8_t *data, size_t len, char **name, char **value)
-{
- nserror error;
-
- /* Set fetch response time if not already set */
- if (object->cache.res_time == 0)
- object->cache.res_time = time(NULL);
-
- /* Decompose header into name-value pair */
- error = llcache_fetch_split_header(data, len, name, value);
- if (error != NSERROR_OK)
- return error;
-
- /* Parse cache headers to populate cache control data */
-#define SKIP_ST(p) while (*p != '\0' && (*p == ' ' || *p == '\t')) p++
-
- if (5 < len && strcasecmp(*name, "Date") == 0) {
- /* extract Date header */
- object->cache.date = curl_getdate(*value, NULL);
- } else if (4 < len && strcasecmp(*name, "Age") == 0) {
- /* extract Age header */
- if ('0' <= **value && **value <= '9')
- object->cache.age = atoi(*value);
- } else if (8 < len && strcasecmp(*name, "Expires") == 0) {
- /* extract Expires header */
- object->cache.expires = curl_getdate(*value, NULL);
- } else if (14 < len && strcasecmp(*name, "Cache-Control") == 0) {
- /* extract and parse Cache-Control header */
- const char *start = *value;
- const char *comma = *value;
-
- while (*comma != '\0') {
- while (*comma != '\0' && *comma != ',')
- comma++;
-
- if (8 < comma - start && (strncasecmp(start,
- "no-cache", 8) == 0 ||
- strncasecmp(start, "no-store", 8) == 0))
- /* When we get a disk cache we should
- * distinguish between these two */
- object->cache.no_cache = LLCACHE_VALIDATE_ALWAYS;
- else if (7 < comma - start &&
- strncasecmp(start, "max-age", 7) == 0) {
- /* Find '=' */
- while (start < comma && *start != '=')
- start++;
-
- /* Skip over it */
- start++;
-
- /* Skip whitespace */
- SKIP_ST(start);
-
- if (start < comma)
- object->cache.max_age = atoi(start);
- }
-
- if (*comma != '\0') {
- /* Skip past comma */
- comma++;
- /* Skip whitespace */
- SKIP_ST(comma);
- }
-
- /* Set start for next token */
- start = comma;
- }
- } else if (5 < len && strcasecmp(*name, "ETag") == 0) {
- /* extract ETag header */
- free(object->cache.etag);
- object->cache.etag = strdup(*value);
- if (object->cache.etag == NULL)
- return NSERROR_NOMEM;
- } else if (14 < len && strcasecmp(*name, "Last-Modified") == 0) {
- /* extract Last-Modified header */
- object->cache.last_modified = curl_getdate(*value, NULL);
- }
-
-#undef SKIP_ST
-
- return NSERROR_OK;
-}
-
-/**
- * Process a fetch header
- *
- * \param object Object being fetched
- * \param data Header string
- * \param len Byte length of header
- * \return NSERROR_OK on success, appropriate error otherwise
- */
-nserror llcache_fetch_process_header(llcache_object *object,
- const uint8_t *data, size_t len)
-{
- nserror error;
- char *name, *value;
- llcache_header *temp;
-
- /* The headers for multiple HTTP responses may be delivered to us if
- * the fetch layer receives a 401 response for which it has
- * authentication credentials. This will result in a silent re-request
- * after which we'll receive the actual response headers for the
- * object we want to fetch (assuming that the credentials were correct
- * of course)
- *
- * Therefore, if the header is an HTTP response start marker, then we
- * must discard any headers we've read so far, reset the cache data
- * that we might have computed, and start again.
- */
- /** \todo Properly parse the response line */
- if (strncmp((const char *) data, "HTTP/", SLEN("HTTP/")) == 0) {
- time_t req_time = object->cache.req_time;
-
- llcache_invalidate_cache_control_data(object);
-
- /* Restore request time, so we compute object's age correctly */
- object->cache.req_time = req_time;
-
- llcache_destroy_headers(object);
- }
-
- error = llcache_fetch_parse_header(object, data, len, &name, &value);
- if (error != NSERROR_OK)
- return error;
-
- /* Append header data to the object's headers array */
- temp = realloc(object->headers, (object->num_headers + 1) *
- sizeof(llcache_header));
- if (temp == NULL) {
- free(name);
- free(value);
- return NSERROR_NOMEM;
- }
-
- object->headers = temp;
-
- object->headers[object->num_headers].name = name;
- object->headers[object->num_headers].value = value;
-
- object->num_headers++;
-
- return NSERROR_OK;
-}
-
-/**
- * Process a chunk of fetched data
- *
- * \param object Object being fetched
- * \param data Data to process
- * \param len Byte length of data
- * \return NSERROR_OK on success, appropriate error otherwise.
- */
-nserror llcache_fetch_process_data(llcache_object *object, const uint8_t *data,
- size_t len)
-{
- /* Resize source buffer if it's too small */
- if (object->source_len + len >= object->source_alloc) {
- const size_t new_len = object->source_len + len + 64 * 1024;
- uint8_t *temp = realloc(object->source_data, new_len);
- if (temp == NULL)
- return NSERROR_NOMEM;
-
- object->source_data = temp;
- object->source_alloc = new_len;
- }
-
- /* Append this data chunk to source buffer */
- memcpy(object->source_data + object->source_len, data, len);
- object->source_len += len;
-
- return NSERROR_OK;
-}
-
-/**
- * Handle an authentication request
- *
- * \param object Object being fetched
- * \param realm Authentication realm
- * \return NSERROR_OK on success, appropriate error otherwise.
- */
-nserror llcache_fetch_auth(llcache_object *object, const char *realm)
-{
- const char *auth;
- nserror error = NSERROR_OK;
-
- /* Abort fetch for this object */
- fetch_abort(object->fetch.fetch);
- object->fetch.fetch = NULL;
-
- /* Invalidate cache-control data */
- llcache_invalidate_cache_control_data(object);
-
- /* Destroy headers */
- llcache_destroy_headers(object);
-
- /* If there was no realm, then default to the URL */
- /** \todo If there was no WWW-Authenticate header, use response body */
- if (realm == NULL)
- realm = nsurl_access(object->url);
-
- auth = urldb_get_auth_details(nsurl_access(object->url), realm);
-
- if (auth == NULL || object->fetch.tried_with_auth == true) {
- /* No authentication details, or tried what we had, so ask */
- object->fetch.tried_with_auth = false;
-
- if (llcache->query_cb != NULL) {
- llcache_query query;
-
- /* Emit query for authentication details */
- query.type = LLCACHE_QUERY_AUTH;
- query.url = object->url;
- query.data.auth.realm = realm;
-
- object->fetch.outstanding_query = true;
-
- error = llcache->query_cb(&query, llcache->query_cb_pw,
- llcache_query_handle_response, object);
- } else {
- llcache_event event;
-
- /* Mark object complete */
- object->fetch.state = LLCACHE_FETCH_COMPLETE;
-
- /* Inform client(s) that object fetch failed */
- event.type = LLCACHE_EVENT_ERROR;
- /** \todo More appropriate error message */
- event.data.msg = messages_get("FetchFailed");
-
- error = llcache_send_event_to_users(object, &event);
- }
- } else {
- /* Flag that we've tried to refetch with credentials, so
- * that if the fetch fails again, we ask the user again */
- object->fetch.tried_with_auth = true;
- error = llcache_object_refetch(object);
- }
-
- return error;
-}
-
-/**
- * Handle a TLS certificate verification failure
- *
- * \param object Object being fetched
- * \param certs Certificate chain
- * \param num Number of certificates in chain
- * \return NSERROR_OK on success, appropriate error otherwise
- */
-nserror llcache_fetch_cert_error(llcache_object *object,
- const struct ssl_cert_info *certs, size_t num)
-{
- nserror error = NSERROR_OK;
-
- /* Fetch has been stopped, and destroyed. Invalidate object's pointer */
- object->fetch.fetch = NULL;
-
- /* Invalidate cache-control data */
- llcache_invalidate_cache_control_data(object);
-
- if (llcache->query_cb != NULL) {
- llcache_query query;
-
- /* Emit query for TLS */
- query.type = LLCACHE_QUERY_SSL;
- query.url = object->url;
- query.data.ssl.certs = certs;
- query.data.ssl.num = num;
-
- object->fetch.outstanding_query = true;
-
- error = llcache->query_cb(&query, llcache->query_cb_pw,
- llcache_query_handle_response, object);
- } else {
- llcache_event event;
-
- /* Mark object complete */
- object->fetch.state = LLCACHE_FETCH_COMPLETE;
-
- /* Inform client(s) that object fetch failed */
- event.type = LLCACHE_EVENT_ERROR;
- /** \todo More appropriate error message */
- event.data.msg = messages_get("FetchFailed");
-
- error = llcache_send_event_to_users(object, &event);
- }
-
- return error;
-}
-
+/* See llcache.h for documentation */
+nsurl *llcache_handle_get_url(const llcache_handle *handle)
+{
+ return handle->object != NULL ? handle->object->url : NULL;
+}
+
+/* See llcache.h for documentation */
+const uint8_t *llcache_handle_get_source_data(const llcache_handle *handle,
+ size_t *size)
+{
+ *size = handle->object != NULL ? handle->object->source_len : 0;
+
+ return handle->object != NULL ? handle->object->source_data : NULL;
+}
+
+/* See llcache.h for documentation */
+const char *llcache_handle_get_header(const llcache_handle *handle,
+ const char *key)
+{
+ const llcache_object *object = handle->object;
+ size_t i;
+
+ if (object == NULL)
+ return NULL;
+
+ /* About as trivial as possible */
+ for (i = 0; i < object->num_headers; i++) {
+ if (strcasecmp(key, object->headers[i].name) == 0)
+ return object->headers[i].value;
+ }
+
+ return NULL;
+}
+
+/* See llcache.h for documentation */
+bool llcache_handle_references_same_object(const llcache_handle *a,
+ const llcache_handle *b)
+{
+ return a->object == b->object;
+}
+
11 years, 4 months
r13892 tlsa - in /trunk/netsurfweb: about/index.en about/news.en downloads/amiga/index.en downloads/atari/ downloads/atari/index.en downloads/gtk/index.en downloads/index.en downloads/riscos/index.en index.en
by netsurf@semichrome.net
Author: tlsa
Date: Fri Apr 27 09:00:48 2012
New Revision: 13892
URL: http://source.netsurf-browser.org?rev=13892&view=rev
Log:
NetSurf 2.9 update.
Added:
trunk/netsurfweb/downloads/atari/
trunk/netsurfweb/downloads/atari/index.en
Modified:
trunk/netsurfweb/about/index.en
trunk/netsurfweb/about/news.en
trunk/netsurfweb/downloads/amiga/index.en
trunk/netsurfweb/downloads/gtk/index.en
trunk/netsurfweb/downloads/index.en
trunk/netsurfweb/downloads/riscos/index.en
trunk/netsurfweb/index.en
Modified: trunk/netsurfweb/about/index.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/about/index.en?rev=138...
==============================================================================
--- trunk/netsurfweb/about/index.en (original)
+++ trunk/netsurfweb/about/index.en Fri Apr 27 09:00:48 2012
@@ -123,6 +123,8 @@
<tr><th>Apr 2011</th><td>NetSurf 2.7 released</td></tr>
<tr><th>Sep 2011</th><td>Frames and iframes in NetSurf core</td></tr>
<tr><th>Sep 2011</th><td>NetSurf 2.8 released</td></tr>
+<tr><th>Mar 2012</th><td>LibDOM used in NetSurf builds</td></tr>
+<tr><th>Apr 2012</th><td>NetSurf 2.9 released</td></tr>
</table>
<div class="frontscreen"><p class="frontscreen"><a href="screenshots/images/riscos-wikipedia.png"><img src="screenshots/images/riscosthumb-wikipedia.png" alt="GTK NetSurf screenshot."></a> <span>A more recent NetSurf showing <em>Wikipedia</em>.</span></p></div>
@@ -190,7 +192,7 @@
<div class="footer">
-<p>Copyright 2003 - 2011 The NetSurf Developers</p>
+<p>Copyright 2003 - 2012 The NetSurf Developers</p>
</div>
</div>
Modified: trunk/netsurfweb/about/news.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/about/news.en?rev=1389...
==============================================================================
--- trunk/netsurfweb/about/news.en (original)
+++ trunk/netsurfweb/about/news.en Fri Apr 27 09:00:48 2012
@@ -56,6 +56,10 @@
<h1>News</h1>
<dl class="news">
+<dt><a href="/downloads/">NetSurf 2.9 released</a> <span>28 Apr 2012</span></dt>
+<dd>NetSurf 2.9 contains many improvements over the previous release. The most significant changes are new multi-tasking behaviour, optimised URL handling, fetcher optimisations, cache optimisations, and faster CSS selection. Full details in the change log. We recommend all users upgrade.</dd>
+<dt><a href="http://vincentsanders.blogspot.co.uk/2012/03/netsurf-developer-workshop.html">LibDOM progress</a> <span>26 Mar 2012</span></dt>
+<dd>The NetSurf Developers held a <a href="http://vincentsanders.blogspot.co.uk/2012/03/netsurf-developer-workshop.html">developer workshop</a> over the weekend, during which much progress was made on <a href="/projects/libdom/">LibDOM</a> which sits at the heart of our <a href="http://wiki.netsurf-browser.org/Development_Plan">NetSurf 3.0 plans</a>. NetSurf trunk is now using the LibDOM library in place of LibXML2, and we hope to extract several benefits from this change over the coming months. Thanks to <a href="http://www.collabora.com/">Collabora</a> who kindly hosted the workshop.</dd>
<dt><a href="/projects/ttf2f/">New home for TTF2f</a> <span>07 Dec 2011</span></dt>
<dd>The RISC OS font conversion utility TTF2f has a new web page here, on the NetSurf site. It is capable of converting TrueType, OpenType and other formats to the native RISC OS format. It supports conversion of large fonts with wide Unicode coverage. Anyone wishing to develop TTF2f further should get in touch!</dd>
<dt><a href="/downloads/">NetSurf 2.8 released</a> <span>21 Sep 2011</span></dt>
@@ -134,7 +138,7 @@
<div class="footer">
-<p>Copyright 2003 - 2010 The NetSurf Developers</p>
+<p>Copyright 2003 - 2012 The NetSurf Developers</p>
</div>
</div>
Modified: trunk/netsurfweb/downloads/amiga/index.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/downloads/amiga/index....
==============================================================================
--- trunk/netsurfweb/downloads/amiga/index.en (original)
+++ trunk/netsurfweb/downloads/amiga/index.en Fri Apr 27 09:00:48 2012
@@ -61,7 +61,7 @@
<div class="downloadlatestouter">
<div class="downloadlatest">
<div class="downloadlatestbox">
-<p class="downloadmain downloadfirst"><a href="netsurf-2.8.lha"><span>NetSurf 2.8 for AmigaOS</span> <span>(7.9MB)</span> <span class="downloaddate">21 Sep 2011</span></a></p>
+<p class="downloadmain downloadfirst"><a href="netsurf-2.9.lha"><span>NetSurf 2.9 for AmigaOS</span> <span>(5.9MB)</span> <span class="downloaddate">27 Mar 2012</span></a></p>
<!--<p class="downloadinstructions"><a href="/documentation/roinfo#GettingStartedInstallation">Installation instructions</a></p>-->
<p class="preul">Requires:</p>
<ul>
@@ -70,7 +70,7 @@
</div>
<div class="downloadlatestbox downloadlast">
-<p class="downloadmain"><a href="/downloads/releases/netsurf-2.8-src.tar.gz"><span>NetSurf 2.8 source code</span> <span>(2.3MB)</span> <span class="downloaddate">21 Sep 2011</span></a></p>
+<p class="downloadmain"><a href="/downloads/releases/netsurf-2.9-src.tar.gz"><span>NetSurf 2.9 source code</span> <span>(2.5MB)</span> <span class="downloaddate">27 Mar 2012</span></a></p>
<p class="downloadinstructions"><a href="/downloads/source/#BuildInstructions">Build instructions</a></p>
<p class="preul">Build NetSurf for:</p>
<ul>
@@ -88,6 +88,13 @@
<h2>Previous releases</h2>
<dl>
+<dt>NetSurf 2.8</dt>
+<dd>
+<ul>
+<li><a href="netsurf-2.8.lha">NetSurf 2.8 browser for AmigaOS 4</a> (21 Sep 2011)</li>
+<li><a href="/downloads/releases/netsurf-2.8-src.tar.gz">NetSurf 2.8 source code</a> (21 Sep 2011)</li>
+</ul>
+</dd>
<dt>NetSurf 2.7</dt>
<dd>
<ul>
@@ -131,7 +138,7 @@
<div class="footer">
-<p>Copyright 2003 - 2011 The NetSurf Developers</p>
+<p>Copyright 2003 - 2012 The NetSurf Developers</p>
</div>
</div>
Added: trunk/netsurfweb/downloads/atari/index.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/downloads/atari/index....
==============================================================================
--- trunk/netsurfweb/downloads/atari/index.en (added)
+++ trunk/netsurfweb/downloads/atari/index.en Fri Apr 27 09:00:48 2012
@@ -1,0 +1,121 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>NetSurf | Atari Downloads</title>
+<link rel="stylesheet" type="text/css" href="/netsurf.css">
+<link rel="icon" type="image/png" href="/webimages/favicon.png">
+</head>
+
+<body>
+<p class="banner"><a href="/"><img src="/netsurf.png" alt="NetSurf"></a></p>
+
+<div class="navigation">
+<div class="navsection">
+<ul>
+<li><a href="/about/">About NetSurf</a></li>
+<li><a href="/downloads/">Downloads</a>
+<ul>
+<li><a href="/downloads/source/">Source</a></li>
+<li><a href="/downloads/extras">Extras</a></li>
+</ul>
+</li>
+<li><a href="/documentation/">Documentation</a></li>
+<li><a href="/developers/">Development area</a></li>
+<li><a href="/webmasters/">Webmaster area</a></li>
+<li><a href="/contact/">Contact</a></li>
+</ul>
+</div>
+
+<div class="navsection">
+<ul class="languages">
+<!--<li><a href="index.de">Deutsch</a></li>-->
+<li>English</li>
+<!--<li><a href="index.fr">Français</a></li>-->
+<!--<li><a href="index.nl">Nederlands</a></li>-->
+</ul>
+</div>
+
+<div class="navsection">
+<ul class="sitelinks">
+<li><a href="http://wiki.netsurf-browser.org/">Development wiki</a></li>
+<li><a href="http://source.netsurf-browser.org/">SVN repository viewer</a></li>
+</ul>
+</div>
+
+</div>
+
+<div class="content">
+
+<p class="breadcrumbs"><a href="/">Home</a> » <a href="/">Downloads</a> » Atari</p>
+
+<h1>Atari NetSurf Downloads</h1>
+
+<div class="bignote">
+<dl>
+<dt><a href="http://freeshell.de/~monokrom/geeklog/index.php?topic=20110219230358215">Test build</a> (off site)</dt>
+<dd>Development builds may be available for those that want to try the latest experimental features.</dd>
+</dl>
+</div>
+
+<div class="downloadlatestouter">
+<div class="downloadlatest">
+<div class="downloadlatestbox">
+<p class="downloadmain downloadfirst"><a href="netsurf-2.9.zip"><span>NetSurf 2.9 for Atari</span> <span>(10.0MB)</span> <span class="downloaddate">27 Mar 2012</span></a></p>
+<!--<p class="downloadinstructions"><a href="/documentation/roinfo#GettingStartedInstallation">Installation instructions</a></p>-->
+<p class="preul">Requires:</p>
+<ul>
+<li>Atari OS version?</li>
+</ul>
+</div>
+
+<div class="downloadlatestbox downloadlast">
+<p class="downloadmain"><a href="/downloads/releases/netsurf-2.9-src.tar.gz"><span>NetSurf 2.9 source code</span> <span>(2.3MB)</span> <span class="downloaddate">27 Mar 2012</span></a></p>
+<p class="downloadinstructions"><a href="/downloads/source/#BuildInstructions">Build instructions</a></p>
+<p class="preul">Build NetSurf for:</p>
+<ul>
+<li>Atari</li>
+<li>Linux</li>
+<li>Free/NetBSD</li>
+<li>And more</li>
+</ul>
+</div>
+</div>
+<div class="arrow"></div>
+</div>
+
+<p>Check out the <a href="/downloads/releases/ChangeLog.txt">change log</a> to see what's changed since the last release.</p>
+
+<!--h2>Previous releases</h2>
+<dl>
+<dt>NetSurf 2.9</dt>
+<dd>
+<ul>
+<li><a href="netsurf-2.9.zip">NetSurf 2.9 browser for Atari</a> (27 Mar 2012)</li>
+<li><a href="/downloads/releases/netsurf-2.9-src.tar.gz">NetSurf 2.9 source code</a> (27 Mar 2012)</li>
+</ul>
+</dd>
+</dl-->
+
+<h2>Latest Source</h2>
+
+<p>Alternatively, you can obtain the <a href="/downloads/source/">latest source</a>, if you want to play with the AmigaOS port.</p>
+
+
+<div class="footer">
+<p>Copyright 2003 - 2012 The NetSurf Developers</p>
+</div>
+
+</div>
+
+
+<form method="get" action="http://www.google.co.uk/search">
+<div class="searchbox">
+<input type="hidden" name="q" value="site:netsurf-browser.org">
+<input type="text" name="q" maxlength="255"><br>
+<input type="submit" value="Search" name="btnG">
+</div>
+</form>
+
+</body>
+</html>
Modified: trunk/netsurfweb/downloads/gtk/index.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/downloads/gtk/index.en...
==============================================================================
--- trunk/netsurfweb/downloads/gtk/index.en (original)
+++ trunk/netsurfweb/downloads/gtk/index.en Fri Apr 27 09:00:48 2012
@@ -63,7 +63,7 @@
<div class="downloadlatestouter">
<div class="downloadlatest">
<div class="downloadlatestbox downloadlast">
-<p class="downloadmain downloadfirst"><a href="/downloads/releases/netsurf-2.8-src.tar.gz"><span>NetSurf 2.8 source code</span> <span>(2.3MB)</span> <span class="downloaddate">21 Sep 2011</span></a></p>
+<p class="downloadmain downloadfirst"><a href="/downloads/releases/netsurf-2.9-src.tar.gz"><span>NetSurf 2.9 source code</span> <span>(2.5MB)</span> <span class="downloaddate">27 Mar 2012</span></a></p>
<p class="downloadinstructions"><a href="/downloads/source/#BuildInstructions">Build instructions</a></p>
<p class="preul">Build NetSurf for:</p>
<ul>
@@ -122,6 +122,12 @@
<h2>Previous releases</h2>
<dl>
+<dt>NetSurf 2.8</dt>
+<dd>
+<ul>
+<li><a href="/downloads/releases/netsurf-2.8-src.tar.gz">NetSurf 2.8 source code</a> (21 Sep 2011)</li>
+</ul>
+</dd>
<dt>NetSurf 2.7</dt>
<dd>
<ul>
@@ -180,7 +186,7 @@
<div class="footer">
-<p>Copyright 2003 - 2011 The NetSurf Developers</p>
+<p>Copyright 2003 - 2012 The NetSurf Developers</p>
</div>
</div>
Modified: trunk/netsurfweb/downloads/index.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/downloads/index.en?rev...
==============================================================================
--- trunk/netsurfweb/downloads/index.en (original)
+++ trunk/netsurfweb/downloads/index.en Fri Apr 27 09:00:48 2012
@@ -59,7 +59,7 @@
<li class="beos"><a href="beos/">Haiku & BeOS</a></li>
<li class="amiga"><a href="amiga/">AmigaOS</a></li>
<!--li class="windows"><a href="windows/">Windows</a></li-->
-<!--li class="atari"><a href="atari/">Atari</a></li-->
+<li class="atari"><a href="atari/">Atari</a></li>
<li class="macosx"><a href="macosx/">Mac OS X</a></li>
</ul>
Modified: trunk/netsurfweb/downloads/riscos/index.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/downloads/riscos/index...
==============================================================================
--- trunk/netsurfweb/downloads/riscos/index.en (original)
+++ trunk/netsurfweb/downloads/riscos/index.en Fri Apr 27 09:00:48 2012
@@ -62,7 +62,7 @@
<div class="downloadlatestouter">
<div class="downloadlatest">
<div class="downloadlatestbox">
-<p class="downloadmain downloadfirst"><a href="/downloads/releases/netsurf-2.8.zip"><span>NetSurf 2.8 for RISC OS</span> <span>(2.8MB)</span> <span class="downloaddate">21 Sep 2011</span></a></p>
+<p class="downloadmain downloadfirst"><a href="/downloads/releases/netsurf-2.9.zip"><span>NetSurf 2.9 for RISC OS</span> <span>(2.8MB)</span> <span class="downloaddate">27 Mar 2012</span></a></p>
<p class="downloadinstructions"><a href="/documentation/roinfo#GettingStartedInstallation">Installation instructions</a></p>
<p class="preul">Binary download includes:</p>
<ul>
@@ -80,7 +80,7 @@
</div>
<div class="downloadlatestbox downloadlast">
-<p class="downloadmain"><a href="/downloads/releases/netsurf-2.8-src.tar.gz"><span>NetSurf 2.8 source code</span> <span>(2.3MB)</span> <span class="downloaddate">21 Sep 2011</span></a></p>
+<p class="downloadmain"><a href="/downloads/releases/netsurf-2.9-src.tar.gz"><span>NetSurf 2.9 source code</span> <span>(2.5MB)</span> <span class="downloaddate">27 Mar 2012</span></a></p>
<p class="downloadinstructions"><a href="/downloads/source/#BuildInstructions">Build instructions</a></p>
<p class="preul">Build NetSurf for:</p>
<ul>
@@ -99,6 +99,13 @@
<h2>Previous releases</h2>
<dl>
+<dt>NetSurf 2.8</dt>
+<dd>
+<ul>
+<li><a href="/downloads/releases/netsurf-2.8.zip">NetSurf 2.8 browser for RISC OS</a> (21 Sep 2011)</li>
+<li><a href="/downloads/releases/netsurf-2.8-src.tar.gz">NetSurf 2.8 source code</a> (21 Sep 2011)</li>
+</ul>
+</dd>
<dt>NetSurf 2.7</dt>
<dd>
<ul>
@@ -159,7 +166,7 @@
<div class="footer">
-<p>Copyright 2003 - 2011 The NetSurf Developers</p>
+<p>Copyright 2003 - 2012 The NetSurf Developers</p>
</div>
</div>
Modified: trunk/netsurfweb/index.en
URL: http://source.netsurf-browser.org/trunk/netsurfweb/index.en?rev=13892&r1=...
==============================================================================
--- trunk/netsurfweb/index.en (original)
+++ trunk/netsurfweb/index.en Fri Apr 27 09:00:48 2012
@@ -126,7 +126,7 @@
<div class="downloadbox">
<div class="downloadcontainer">
<div class="downloadcontent">
-<h2 id="downloadrelease"><a href="/downloads/">Download NetSurf 2.8</a></h2>
+<h2 id="downloadrelease"><a href="/downloads/">Download NetSurf 2.9</a></h2>
<ul>
<li><a href="/downloads/riscos/">For RISC OS</a></li>
<li><a href="/downloads/gtk/">For Linux</a></li>
@@ -145,18 +145,18 @@
<h2 id="news">Latest news</h2>
<dl class="frontnews">
+<dt><a href="/downloads/">NetSurf 2.9 released</a> <span>28 Apr 2012</span></dt>
+<dd>NetSurf 2.9 contains many improvements over the previous release. The most significant changes are new multi-tasking behaviour, optimised URL handling, fetcher optimisations, cache optimisations, and faster CSS selection. Full details in the change log. We recommend all users upgrade.</dd>
+<dt><a href="http://vincentsanders.blogspot.co.uk/2012/03/netsurf-developer-workshop.html">LibDOM progress</a> <span>26 Mar 2012</span></dt>
+<dd>The NetSurf Developers held a <a href="http://vincentsanders.blogspot.co.uk/2012/03/netsurf-developer-workshop.html">developer workshop</a> over the weekend, during which much progress was made on <a href="/projects/libdom/">LibDOM</a> which sits at the heart of our <a href="http://wiki.netsurf-browser.org/Development_Plan">NetSurf 3.0 plans</a>. NetSurf trunk is now using the LibDOM library in place of LibXML2, and we hope to extract several benefits from this change over the coming months. Thanks to <a href="http://www.collabora.com/">Collabora</a> who kindly hosted the workshop.</dd>
<dt><a href="/projects/ttf2f/">New home for TTF2f</a> <span>07 Dec 2011</span></dt>
<dd>The RISC OS font conversion utility TTF2f has a new web page here, on the NetSurf site. It is capable of converting TrueType, OpenType and other formats to the native RISC OS format. It supports conversion of large fonts with wide Unicode coverage. Anyone wishing to develop TTF2f further should get in touch!</dd>
-<dt><a href="/downloads/">NetSurf 2.8 released</a> <span>21 Sep 2011</span></dt>
-<dd>NetSurf 2.8 adds support for frames and iframes on all platforms, MIME type sniffing, and a new image cache. Image decoding can now be deferred until images are required for more optimal resource use and faster page load times. The release also incorporates many other new features, optimisations, improvements and bug fixes. Full details in the change log. We recommend all users upgrade.</dd>
-<dt><a href="/downloads/">NetSurf 2.7 released</a> <span>16 Apr 2011</span></dt>
-<dd>NetSurf 2.7 contains many improvements over the previous release. The most significant change is the addition of core global history, bookmarks and cookie management features. Full details in the change log. We recommend all users upgrade.</dd>
</dl>
<p class="more"><a href="/about/news" class="seemore">See more news</a></p>
-<h2 id="features">NetSurf 2.8 features</h2>
-
-<p>NetSurf 2.8 is available for: RISC OS; Linux and other UNIX-like systems; Mac OS X; and AmigaOS 4.</p>
+<h2 id="features">NetSurf 2.9 features</h2>
+
+<p>NetSurf 2.9 is available for: RISC OS; Linux and other UNIX-like systems; Mac OS X; and AmigaOS 4.</p>
<dl>
<dt>General</dt>
@@ -199,7 +199,7 @@
</div>
<div class="footer">
-<p>Copyright 2003 - 2011 The NetSurf Developers</p>
+<p>Copyright 2003 - 2012 The NetSurf Developers</p>
</div>
</div>
11 years, 4 months
r13891 mono - /trunk/netsurf/atari/bitmap.c
by netsurf@semichrome.net
Author: mono
Date: Thu Apr 26 17:21:02 2012
New Revision: 13891
URL: http://source.netsurf-browser.org?rev=13891&view=rev
Log:
Only check transparent pixels when transparency is enabled.
Modified:
trunk/netsurf/atari/bitmap.c
Modified: trunk/netsurf/atari/bitmap.c
URL: http://source.netsurf-browser.org/trunk/netsurf/atari/bitmap.c?rev=13891&...
==============================================================================
--- trunk/netsurf/atari/bitmap.c (original)
+++ trunk/netsurf/atari/bitmap.c Thu Apr 26 17:21:02 2012
@@ -102,25 +102,23 @@
return( NULL );
}
- if( bitmap->pixdata == NULL ) {
- assert( 1 == 0 );
- /* add some buffer for bad code */
- bitmap->pixdata = malloc( newsize + 128 );
- bitmap->opaque = false;
- } else {
- int oldsize = bitmap->rowstride * bitmap->height;
- bool doalloc = (state & BITMAP_GROW) ? (newsize > oldsize) : (newsize != oldsize);
- if( newsize > oldsize )
- assert( doalloc == true );
- if( doalloc ) {
- bitmap->pixdata = realloc( bitmap->pixdata, newsize + 128 );
- if( bitmap->pixdata == NULL )
- return( NULL );
- }
- }
+ assert( bitmap->pixdata != NULL );
+ int oldsize = bitmap->rowstride * bitmap->height;
+ bool doalloc = (state & BITMAP_GROW) ? (newsize > oldsize) : (newsize != oldsize);
+ if( newsize > oldsize )
+ assert( doalloc == true );
+ if( doalloc ) {
+ // TODO: set red band to a specific value and check the red band
+ // on bitmap_destroy()
+ bitmap->pixdata = realloc( bitmap->pixdata, newsize + 128 );
+ if( bitmap->pixdata == NULL )
+ return( NULL );
+ }
+
if( state & BITMAP_CLEAR ){
memset( bitmap->pixdata, 0x00, newsize + 128 );
}
+
bitmap->width = w;
bitmap->height = h;
bitmap->bpp = bpp;
@@ -329,6 +327,10 @@
LOG(("NULL bitmap!"));
return false;
}
+
+ if( nsoption_int(atari_transparency) == 0 ){
+ return( true );
+ }
tst = bm->width * bm->height;
11 years, 4 months
r13890 mono - /trunk/netsurf/atari/gui.c
by netsurf@semichrome.net
Author: mono
Date: Wed Apr 25 16:33:01 2012
New Revision: 13890
URL: http://source.netsurf-browser.org?rev=13890&view=rev
Log:
set rendering flag within throbber_stop / start functions, update toolbar buttons on throbber stop.
Modified:
trunk/netsurf/atari/gui.c
Modified: trunk/netsurf/atari/gui.c
URL: http://source.netsurf-browser.org/trunk/netsurf/atari/gui.c?rev=13890&r1=...
==============================================================================
--- trunk/netsurf/atari/gui.c (original)
+++ trunk/netsurf/atari/gui.c Wed Apr 25 16:33:01 2012
@@ -115,7 +115,7 @@
evnt.timer = 0;
flags |= MU_TIMER;
EvntWindom( flags );
- next_poll = clock() + (CLOCKS_PER_SEC>>2);
+ next_poll = clock() + (CLOCKS_PER_SEC>>3);
}
} else {
if( input_window != NULL ){
@@ -270,23 +270,7 @@
* set the status bar message
*/
void gui_window_set_status(struct gui_window *w, const char *text)
-{
- static char * msg_loading = NULL;
- static char * msg_fetch = NULL;
-
- if( msg_loading == NULL ){
- msg_loading = messages_get("Loading");
- msg_fetch = messages_get("Fetch");
- }
-
- if( (strncmp(msg_loading, text, 4) == 0)
- ||
- (strncmp(msg_fetch, text, 4)) == 0 ) {
- rendering = true;
- } else {
- rendering = false;
- }
-
+{
if (w == NULL || text == NULL )
return;
window_set_stauts( w , (char*)text );
@@ -505,6 +489,8 @@
schedule(100, throbber_advance, w );
ApplWrite( _AESapid, WM_REDRAW, w->root->handle->handle,
work.g_x, work.g_y, work.g_w, work.g_h );
+
+ rendering = true;
}
void gui_window_stop_throbber(struct gui_window *w)
@@ -517,11 +503,17 @@
schedule_remove(throbber_advance, w);
+ /* refresh toolbar buttons: */
+ tb_update_buttons( w, -1 );
+
+ /* redraw throbber: */
mt_CompGetLGrect(&app, w->root->toolbar->throbber.comp,
WF_WORKXYWH, &work);
- w->root->toolbar->throbber.running = false;
+ w->root->toolbar->throbber.running = false;
ApplWrite( _AESapid, WM_REDRAW, w->root->handle->handle,
work.g_x, work.g_y, work.g_w, work.g_h );
+
+ rendering = false;
}
/* Place caret in window */
11 years, 5 months