/* * Copyright 2008-2015 Chris Young * * This file is part of NetSurf, http://www.netsurf-browser.org/ * * NetSurf is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * NetSurf is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* Custom StringView class */ #include "amiga/stringview/stringview.h" #include "amiga/stringview/urlhistory.h" /* AmigaOS libraries */ #ifdef __amigaos4__ #include #endif #include #include #include #include #include #include #include #include #include #include #include /* Other OS includes */ #include #include #include #include #ifdef __amigaos4__ #include #include #include #include #endif #include #include #include #include /* ReAction libraries */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* newlib includes */ #include #include /* NetSurf core includes */ #include "utils/log.h" #include "utils/messages.h" #include "utils/nsoption.h" #include "utils/utf8.h" #include "utils/utils.h" #include "utils/nsurl.h" #include "utils/file.h" #include "content/fetchers.h" #include "content/fetchers/resource.h" #include "content/urldb.h" #include "image/ico.h" #include "desktop/browser_history.h" #include "desktop/browser.h" #include "desktop/hotlist.h" #include "desktop/mouse.h" #include "desktop/netsurf.h" #include "desktop/version.h" #include "desktop/save_complete.h" #include "desktop/scrollbar.h" #include "desktop/searchweb.h" #include "desktop/textinput.h" #include "desktop/tree.h" #include "desktop/gui_window.h" #include "desktop/gui_fetch.h" #include "desktop/gui_misc.h" /* NetSurf Amiga platform includes */ #include "amiga/gui.h" #include "amiga/arexx.h" #include "amiga/bitmap.h" #include "amiga/clipboard.h" #include "amiga/cookies.h" #include "amiga/ctxmenu.h" #include "amiga/datatypes.h" #include "amiga/download.h" #include "amiga/drag.h" #include "amiga/file.h" #include "amiga/filetype.h" #include "amiga/font.h" #include "amiga/fs_backing_store.h" #include "amiga/gui_options.h" #include "amiga/help.h" #include "amiga/history.h" #include "amiga/history_local.h" #include "amiga/hotlist.h" #include "amiga/icon.h" #include "amiga/launch.h" #include "amiga/libs.h" #include "amiga/login.h" #include "amiga/menu.h" #include "amiga/misc.h" #include "amiga/plotters.h" #include "amiga/plugin_hack.h" #include "amiga/print.h" #include "amiga/schedule.h" #include "amiga/search.h" #include "amiga/selectmenu.h" #include "amiga/theme.h" #include "amiga/tree.h" #include "amiga/utf8.h" #include "amiga/sslcert.h" #define AMINS_SCROLLERPEN NUMDRIPENS #define NSA_KBD_SCROLL_PX 10 /* Extra mouse button defines to match those in intuition/intuition.h */ #define SIDEDOWN (IECODE_4TH_BUTTON) #define SIDEUP (IECODE_4TH_BUTTON | IECODE_UP_PREFIX) #define EXTRADOWN (IECODE_5TH_BUTTON) #define EXTRAUP (IECODE_5TH_BUTTON | IECODE_UP_PREFIX) static bool ami_quit = false; extern struct gui_utf8_table *amiga_utf8_table; struct ami_gui_tb_userdata { struct List *sblist; struct gui_window_2 *gw; int items; }; static struct MsgPort *schedulermsgport = NULL; static struct MsgPort *appport; static Class *urlStringClass; static BOOL locked_screen = FALSE; static int screen_signal = -1; static ULONG sz_gad_width = 0; static ULONG sz_gad_height = 0; static bool win_destroyed; static STRPTR nsscreentitle; static struct MsgPort *applibport = NULL; static ULONG applibsig = 0; static uint32 ami_appid = 0; static struct Hook newprefs_hook; static STRPTR temp_homepage_url = NULL; static bool cli_force = false; #define USERS_DIR "PROGDIR:Users" static char *users_dir = NULL; static char *current_user = NULL; static char *current_user_dir; static char *current_user_faviconcache; static const __attribute__((used)) char *stack_cookie = "\0$STACK:131072\0"; const char * const versvn; const char * const verdate; void ami_switch_tab(struct gui_window_2 *gwin,bool redraw); void ami_change_tab(struct gui_window_2 *gwin, int direction); void ami_get_hscroll_pos(struct gui_window_2 *gwin, ULONG *xs); void ami_get_vscroll_pos(struct gui_window_2 *gwin, ULONG *ys); void ami_quit_netsurf_delayed(void); Object *ami_gui_splash_open(void); void ami_gui_splash_close(Object *win_obj); HOOKF(uint32, ami_set_favicon_render_hook, APTR, space, struct gpRender *); HOOKF(uint32, ami_set_throbber_render_hook, APTR, space, struct gpRender *); bool ami_gui_map_filename(char **remapped, const char *path, const char *file, const char *map); static void ami_gui_window_update_box_deferred(struct gui_window *g, bool draw); static void ami_do_redraw(struct gui_window_2 *g); static void ami_schedule_redraw_remove(struct gui_window_2 *gwin); static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy); static void gui_window_set_scroll(struct gui_window *g, int sx, int sy); static void gui_window_remove_caret(struct gui_window *g); static void gui_window_place_caret(struct gui_window *g, int x, int y, int height, const struct rect *clip); /* accessors for default options - user option is updated if it is set as per default */ #define nsoption_default_set_int(OPTION, VALUE) \ if (nsoptions_default[NSOPTION_##OPTION].value.i == nsoptions[NSOPTION_##OPTION].value.i) \ nsoptions[NSOPTION_##OPTION].value.i = VALUE; \ nsoptions_default[NSOPTION_##OPTION].value.i = VALUE STRPTR ami_locale_langs(void) { struct Locale *locale; STRPTR acceptlangs = NULL; char *remapped; if((locale = OpenLocale(NULL))) { for(int i = 0; i < 10; i++) { if(locale->loc_PrefLanguages[i]) { if(ami_gui_map_filename(&remapped, "PROGDIR:Resources", locale->loc_PrefLanguages[i], "LangNames")) { if(acceptlangs) { STRPTR acceptlangs2 = acceptlangs; acceptlangs = ASPrintf("%s, %s",acceptlangs2, remapped); FreeVec(acceptlangs2); acceptlangs2 = NULL; } else { acceptlangs = ASPrintf("%s", remapped); } } } else { continue; } } CloseLocale(locale); } return acceptlangs; } bool ami_gui_map_filename(char **remapped, const char *path, const char *file, const char *map) { BPTR fh = 0; char *mapfile = NULL; size_t mapfile_size = 0; char buffer[1024]; char *realfname; bool found = false; netsurf_mkpath(&mapfile, &mapfile_size, 2, path, map); if(mapfile == NULL) return false; fh = FOpen(mapfile, MODE_OLDFILE, 0); if(fh) { while(FGets(fh, buffer, 1024) != 0) { if((buffer[0] == '#') || (buffer[0] == '\n') || (buffer[0] == '\0')) continue; realfname = strchr(buffer, ':'); if(realfname) { if(strncmp(buffer, file, strlen(file)) == 0) { if(realfname[strlen(realfname)-1] == '\n') realfname[strlen(realfname)-1] = '\0'; *remapped = strdup(realfname + 1); found = true; break; } } } FClose(fh); } if(found == false) *remapped = strdup(file); else LOG("Remapped %s to %s in path %s using %s", file, *remapped, path, map); free(mapfile); return found; } static bool ami_gui_check_resource(char *fullpath, const char *file) { bool found = false; char *remapped; BPTR lock = 0; size_t fullpath_len = 1024; ami_gui_map_filename(&remapped, fullpath, file, "Resource.map"); netsurf_mkpath(&fullpath, &fullpath_len, 2, fullpath, remapped); LOG("Checking for %s", fullpath); lock = Lock(fullpath, ACCESS_READ); if(lock) { UnLock(lock); found = true; } if(found) LOG("Found %s", fullpath); free(remapped); return found; } bool ami_locate_resource(char *fullpath, const char *file) { struct Locale *locale; int i; bool found = false; char *remapped; size_t fullpath_len = 1024; /* Check NetSurf user data area first */ if(current_user_dir != NULL) { strcpy(fullpath, current_user_dir); found = ami_gui_check_resource(fullpath, file); if(found) return true; } /* Check current theme directory */ if(nsoption_charp(theme)) { strcpy(fullpath, nsoption_charp(theme)); found = ami_gui_check_resource(fullpath, file); if(found) return true; } /* If not found, start on the user's preferred languages */ locale = OpenLocale(NULL); for(i=0;i<10;i++) { strcpy(fullpath,"PROGDIR:Resources/"); if(locale->loc_PrefLanguages[i]) { ami_gui_map_filename(&remapped, "PROGDIR:Resources", locale->loc_PrefLanguages[i], "LangNames"); netsurf_mkpath(&fullpath, &fullpath_len, 2, fullpath, remapped); found = ami_gui_check_resource(fullpath, file); } else { continue; } if(found) break; } if(!found) { /* If not found yet, check in PROGDIR:Resources/en, * might not be in user's preferred languages */ strcpy(fullpath, "PROGDIR:Resources/en/"); found = ami_gui_check_resource(fullpath, file); } CloseLocale(locale); if(!found) { /* Lastly check directly in PROGDIR:Resources */ strcpy(fullpath, "PROGDIR:Resources/"); found = ami_gui_check_resource(fullpath, file); } return found; } static bool ami_open_resources(void) { urlStringClass = MakeStringClass(); if(!(appport = AllocSysObjectTags(ASOT_PORT, ASO_NoTrack, FALSE, TAG_DONE))) return false; if(!(sport = AllocSysObjectTags(ASOT_PORT, ASO_NoTrack, FALSE, TAG_DONE))) return false; if(!(schedulermsgport = AllocSysObjectTags(ASOT_PORT, ASO_NoTrack, FALSE, TAG_DONE))) return false; return true; } static UWORD ami_system_colour_scrollbar_fgpen(struct DrawInfo *drinfo) { LONG scrollerfillpen = FALSE; #ifdef __amigaos4__ GetGUIAttrs(NULL, drinfo, GUIA_PropKnobColor, &scrollerfillpen, TAG_DONE); if(scrollerfillpen) return FILLPEN; else return FOREGROUNDPEN; #else return FILLPEN; #endif } /** * set option from pen */ static nserror colour_option_from_pen(UWORD pen, enum nsoption_e option, struct Screen *screen, colour def_colour) { ULONG colr[3]; struct DrawInfo *drinfo; if((option < NSOPTION_SYS_COLOUR_START) || (option > NSOPTION_SYS_COLOUR_END) || (nsoptions[option].type != OPTION_COLOUR)) { return NSERROR_BAD_PARAMETER; } if(screen != NULL) { drinfo = GetScreenDrawInfo(screen); if(drinfo != NULL) { if(pen == AMINS_SCROLLERPEN) pen = ami_system_colour_scrollbar_fgpen(drinfo); /* Get the colour of the pen being used for "pen" */ GetRGB32(screen->ViewPort.ColorMap, drinfo->dri_Pens[pen], 1, (ULONG *)&colr); /* convert it to a color */ def_colour = ((colr[0] & 0xff000000) >> 24) | ((colr[1] & 0xff000000) >> 16) | ((colr[2] & 0xff000000) >> 8); FreeScreenDrawInfo(screen, drinfo); } } if (nsoptions_default[option].value.c == nsoptions[option].value.c) nsoptions[option].value.c = def_colour; nsoptions_default[option].value.c = def_colour; return NSERROR_OK; } /* exported interface documented in amiga/gui.h */ STRPTR ami_gui_get_screen_title(void) { if(nsscreentitle == NULL) { nsscreentitle = ASPrintf("NetSurf %s", netsurf_version); /* If this fails it will be NULL, which means we'll get the screen's * default titlebar text instead - so no need to check for error. */ } return nsscreentitle; } static void ami_set_screen_defaults(struct Screen *screen) { nsoption_default_set_int(window_x, 0); nsoption_default_set_int(window_y, screen->BarHeight + 1); nsoption_default_set_int(window_width, screen->Width); nsoption_default_set_int(window_height, screen->Height - screen->BarHeight - 1); nsoption_default_set_int(redraw_tile_size_x, screen->Width); nsoption_default_set_int(redraw_tile_size_y, screen->Height); #ifdef __amigaos4__ /* set system colours for amiga ui */ colour_option_from_pen(FILLPEN, NSOPTION_sys_colour_ActiveBorder, screen, 0x00000000); colour_option_from_pen(FILLPEN, NSOPTION_sys_colour_ActiveCaption, screen, 0x00dddddd); colour_option_from_pen(BACKGROUNDPEN, NSOPTION_sys_colour_AppWorkspace, screen, 0x00eeeeee); colour_option_from_pen(BACKGROUNDPEN, NSOPTION_sys_colour_Background, screen, 0x00aa0000); colour_option_from_pen(FOREGROUNDPEN, NSOPTION_sys_colour_ButtonFace, screen, 0x00aaaaaa); colour_option_from_pen(FORESHINEPEN, NSOPTION_sys_colour_ButtonHighlight, screen, 0x00cccccc); colour_option_from_pen(FORESHADOWPEN, NSOPTION_sys_colour_ButtonShadow, screen, 0x00bbbbbb); colour_option_from_pen(TEXTPEN, NSOPTION_sys_colour_ButtonText, screen, 0x00000000); colour_option_from_pen(FILLTEXTPEN, NSOPTION_sys_colour_CaptionText, screen, 0x00000000); colour_option_from_pen(DISABLEDTEXTPEN, NSOPTION_sys_colour_GrayText, screen, 0x00777777); colour_option_from_pen(SELECTPEN, NSOPTION_sys_colour_Highlight, screen, 0x00ee0000); colour_option_from_pen(SELECTTEXTPEN, NSOPTION_sys_colour_HighlightText, screen, 0x00000000); colour_option_from_pen(INACTIVEFILLPEN, NSOPTION_sys_colour_InactiveBorder, screen, 0x00000000); colour_option_from_pen(INACTIVEFILLPEN, NSOPTION_sys_colour_InactiveCaption, screen, 0x00ffffff); colour_option_from_pen(INACTIVEFILLTEXTPEN, NSOPTION_sys_colour_InactiveCaptionText, screen, 0x00cccccc); colour_option_from_pen(BACKGROUNDPEN, NSOPTION_sys_colour_InfoBackground, screen, 0x00aaaaaa);/* This is wrong, HelpHint backgrounds are pale yellow but doesn't seem to be a DrawInfo pen defined for it. */ colour_option_from_pen(TEXTPEN, NSOPTION_sys_colour_InfoText, screen, 0x00000000); colour_option_from_pen(MENUBACKGROUNDPEN, NSOPTION_sys_colour_Menu, screen, 0x00aaaaaa); colour_option_from_pen(MENUTEXTPEN, NSOPTION_sys_colour_MenuText, screen, 0x00000000); colour_option_from_pen(AMINS_SCROLLERPEN, NSOPTION_sys_colour_Scrollbar, screen, 0x00aaaaaa); colour_option_from_pen(FORESHADOWPEN, NSOPTION_sys_colour_ThreeDDarkShadow, screen, 0x00555555); colour_option_from_pen(FOREGROUNDPEN, NSOPTION_sys_colour_ThreeDFace, screen, 0x00dddddd); colour_option_from_pen(FORESHINEPEN, NSOPTION_sys_colour_ThreeDHighlight, screen, 0x00aaaaaa); colour_option_from_pen(HALFSHINEPEN, NSOPTION_sys_colour_ThreeDLightShadow, screen, 0x00999999); colour_option_from_pen(HALFSHADOWPEN, NSOPTION_sys_colour_ThreeDShadow, screen, 0x00777777); colour_option_from_pen(BACKGROUNDPEN, NSOPTION_sys_colour_Window, screen, 0x00aaaaaa); colour_option_from_pen(INACTIVEFILLPEN, NSOPTION_sys_colour_WindowFrame, screen, 0x00000000); colour_option_from_pen(TEXTPEN, NSOPTION_sys_colour_WindowText, screen, 0x00000000); #endif } /** * Set option defaults for amiga frontend * * @param defaults The option table to update. * @return error status. */ static nserror ami_set_options(struct nsoption_s *defaults) { STRPTR tempacceptlangs; char temp[1024]; /* The following line disables the popupmenu.class select menu. ** It's not recommended to use it! */ nsoption_set_bool(core_select_menu, true); if((!nsoption_charp(accept_language)) || (nsoption_charp(accept_language)[0] == '\0') || (nsoption_bool(accept_lang_locale) == true)) { if((tempacceptlangs = ami_locale_langs())) { nsoption_set_charp(accept_language, (char *)strdup(tempacceptlangs)); FreeVec(tempacceptlangs); } } sprintf(temp, "%s/Cookies", current_user_dir); nsoption_setnull_charp(cookie_file, (char *)strdup(temp)); sprintf(temp, "%s/Hotlist", current_user_dir); nsoption_setnull_charp(hotlist_file, (char *)strdup(temp)); sprintf(temp, "%s/URLdb", current_user_dir); nsoption_setnull_charp(url_file, (char *)strdup(temp)); sprintf(temp, "%s/FontGlyphCache", current_user_dir); nsoption_setnull_charp(font_unicode_file, (char *)strdup(temp)); nsoption_setnull_charp(ca_bundle, (char *)strdup("PROGDIR:Resources/ca-bundle")); /* font defaults */ #ifdef __amigaos4__ nsoption_setnull_charp(font_sans, (char *)strdup("DejaVu Sans")); nsoption_setnull_charp(font_serif, (char *)strdup("DejaVu Serif")); nsoption_setnull_charp(font_mono, (char *)strdup("DejaVu Sans Mono")); nsoption_setnull_charp(font_cursive, (char *)strdup("DejaVu Sans")); nsoption_setnull_charp(font_fantasy, (char *)strdup("DejaVu Serif")); #else nsoption_setnull_charp(font_sans, (char *)strdup("CGTriumvirate")); nsoption_setnull_charp(font_serif, (char *)strdup("CGTimes")); nsoption_setnull_charp(font_mono, (char *)strdup("LetterGothic")); nsoption_setnull_charp(font_cursive, (char *)strdup("CGTriumvirate")); nsoption_setnull_charp(font_fantasy, (char *)strdup("CGTimes")); #endif if (nsoption_charp(font_unicode) == NULL) { BPTR lock = 0; /* Search for some likely candidates */ if((lock = Lock("FONTS:Code2000.otag", ACCESS_READ))) { UnLock(lock); nsoption_set_charp(font_unicode, (char *)strdup("Code2000")); } else if((lock = Lock("FONTS:Bitstream Cyberbit.otag", ACCESS_READ))) { UnLock(lock); nsoption_set_charp(font_unicode, (char *)strdup("Bitstream Cyberbit")); } } if (nsoption_charp(font_surrogate) == NULL) { BPTR lock = 0; /* Search for some likely candidates - * Ideally we should pick a font during the scan process which announces it * contains UCR_SURROGATES, but nothing appears to have the tag. */ if((lock = Lock("FONTS:Symbola.otag", ACCESS_READ))) { UnLock(lock); nsoption_set_charp(font_surrogate, (char *)strdup("Symbola")); } } #ifndef __amigaos4__ nsoption_set_bool(download_notify, false); nsoption_set_bool(font_antialiasing, false); nsoption_set_bool(truecolour_mouse_pointers, false); #endif return NSERROR_OK; } static void ami_amiupdate(void) { /* Create AppPath location for AmiUpdate use */ BPTR lock = 0; if(((lock = Lock("ENVARC:AppPaths",SHARED_LOCK)) == 0)) { lock = CreateDir("ENVARC:AppPaths"); } UnLock(lock); if((lock = Lock("PROGDIR:", ACCESS_READ))) { char filename[1024]; BPTR amiupdatefh; DevNameFromLock(lock, (STRPTR)&filename, 1024L, DN_FULLPATH); if((amiupdatefh = FOpen("ENVARC:AppPaths/NetSurf", MODE_NEWFILE, 0))) { FPuts(amiupdatefh, (CONST_STRPTR)&filename); FClose(amiupdatefh); } UnLock(lock); } } static nsurl *gui_get_resource_url(const char *path) { char buf[1024]; char path2[1024]; nsurl *url = NULL; if(ami_locate_resource(buf, path) == false) { if((strncmp(path + strlen(path) - SLEN(".htm"), ".htm", SLEN(".htm")) == 0) || (strncmp(path + strlen(path) - SLEN(".html"), ".html", SLEN(".html")) == 0)) { /* Try with RISC OS HTML filetype, might work */ strcpy(path2, path); strcat(path2, ",faf"); if(ami_locate_resource(buf, path2) == false) { return NULL; } } else return NULL; } netsurf_path_to_nsurl(buf, &url); return url; } HOOKF(void, ami_gui_newprefs_hook, APTR, window, APTR) { ami_set_screen_defaults(scrn); } static void ami_openscreen(void) { ULONG id = 0; ULONG compositing; if (nsoption_int(screen_compositing) == -1) compositing = ~0UL; else compositing = nsoption_int(screen_compositing); if (nsoption_charp(pubscreen_name) == NULL) { if((nsoption_charp(screen_modeid)) && (strncmp(nsoption_charp(screen_modeid), "0x", 2) == 0)) { id = strtoul(nsoption_charp(screen_modeid), NULL, 0); } else { struct ScreenModeRequester *screenmodereq = NULL; if((screenmodereq = AllocAslRequest(ASL_ScreenModeRequest,NULL))) { if(AslRequestTags(screenmodereq, ASLSM_MinDepth, 0, ASLSM_MaxDepth, 32, TAG_DONE)) { char *modeid = malloc(20); id = screenmodereq->sm_DisplayID; sprintf(modeid, "0x%lx", id); nsoption_set_charp(screen_modeid, modeid); nsoption_write(current_user_options, NULL, NULL); } FreeAslRequest(screenmodereq); } } if(screen_signal == -1) screen_signal = AllocSignal(-1); LOG("Screen signal %d", screen_signal); scrn = OpenScreenTags(NULL, /**\todo specify screen depth */ SA_DisplayID, id, SA_Title, ami_gui_get_screen_title(), SA_Type, PUBLICSCREEN, SA_PubName, "NetSurf", SA_PubSig, screen_signal, SA_PubTask, FindTask(0), SA_LikeWorkbench, TRUE, SA_Compositing, compositing, TAG_DONE); if(scrn) { PubScreenStatus(scrn,0); } else { FreeSignal(screen_signal); screen_signal = -1; if((scrn = LockPubScreen("NetSurf"))) { locked_screen = TRUE; } else { nsoption_set_charp(pubscreen_name, strdup("Workbench")); } } } if (nsoption_charp(pubscreen_name) != NULL) { scrn = LockPubScreen(nsoption_charp(pubscreen_name)); if(scrn == NULL) { scrn = LockPubScreen("Workbench"); } locked_screen = TRUE; } ami_font_setdevicedpi(id); ami_set_screen_defaults(scrn); ami_help_new_screen(scrn); } static void ami_openscreenfirst(void) { ami_openscreen(); if(!browserglob.bm) ami_init_layers(&browserglob, 0, 0); ami_theme_throbber_setup(); } static struct RDArgs *ami_gui_commandline(int *argc, char **argv, int *nargc, char **nargv) { int new_argc = 1; struct RDArgs *args; CONST_STRPTR template = "-v/S,NSOPTS/M,URL/K,USERSDIR/K,FORCE/S"; long rarray[] = {0,0,0,0,0}; enum { A_VERBOSE, /* ignored */ A_NSOPTS, /* ignored */ A_URL, A_USERSDIR, A_FORCE }; if(*argc == 0) return NULL; // argc==0 is started from wb if((args = ReadArgs(template, rarray, NULL))) { if(rarray[A_URL]) { LOG("URL %s specified on command line", rarray[A_URL]); temp_homepage_url = ami_to_utf8_easy((char *)rarray[A_URL]); } if(rarray[A_USERSDIR]) { LOG("USERSDIR %s specified on command line", rarray[A_USERSDIR]); users_dir = ASPrintf("%s", rarray[A_USERSDIR]); } if(rarray[A_FORCE]) { LOG("FORCE specified on command line"); cli_force = true; } if(rarray[A_NSOPTS]) { /* The NSOPTS/M parameter specified in the ReadArgs template is * special. The /M means it collects all arguments that can't * be assigned to any other parameter, and stores them in an * array. We collect these and pass them as a fake argc/argv * to nsoption_commandline(). * This trickery is necessary because if ReadArgs() is called * first, nsoption_commandline() can no longer parse (fetch?) * the arguments. If nsoption_commandline() is called first, * then ReadArgs cannot fetch the arguments. */ char **p = (char **)rarray[A_NSOPTS]; do { LOG("Arg [%d] assigned to NSOPTS/M by ReadArgs: %s", new_argc, *p); new_argc++; p++; } while(*p != NULL); const char *new_argv = malloc(sizeof(char *) * new_argc); const char **new_argvp = &new_argv; p = (char **)rarray[A_NSOPTS]; do { *new_argvp = *p; new_argvp++; p++; } while(*p != NULL); *nargc = new_argc; *nargv = new_argv; } } else { LOG("ReadArgs failed to parse command line"); } return args; } static void ami_gui_read_tooltypes(struct WBArg *wbarg) { struct DiskObject *dobj; STRPTR *toolarray; char *s; if((*wbarg->wa_Name) && (dobj = GetDiskObject(wbarg->wa_Name))) { toolarray = (STRPTR *)dobj->do_ToolTypes; if((s = (char *)FindToolType(toolarray,"USERSDIR"))) users_dir = ASPrintf("%s", s); if((s = (char *)FindToolType(toolarray,"USER"))) current_user = ASPrintf("%s", s); FreeDiskObject(dobj); } } static void ami_gui_read_all_tooltypes(int argc, char **argv) { struct WBStartup *WBenchMsg; struct WBArg *wbarg; char i; LONG olddir = -1; if(argc == 0) { /* Started from WB */ WBenchMsg = (struct WBStartup *)argv; for(i = 0, wbarg = WBenchMsg->sm_ArgList; i < WBenchMsg->sm_NumArgs; i++,wbarg++) { olddir =-1; if((wbarg->wa_Lock) && (*wbarg->wa_Name)) olddir = SetCurrentDir(wbarg->wa_Lock); ami_gui_read_tooltypes(wbarg); if(olddir !=-1) SetCurrentDir(olddir); } } } static void gui_init2(int argc, char** argv) { struct Screen *screen; BOOL notalreadyrunning; nsurl *url; nserror error; struct browser_window *bw = NULL; notalreadyrunning = ami_arexx_init(); /* Treeview init code ends up calling a font function which needs this */ glob = &browserglob; /* ...and this ensures the treeview at least gets the WB colour palette to work with */ if(scrn == NULL) { if((screen = LockPubScreen("Workbench"))) { ami_set_screen_defaults(screen); UnlockPubScreen(NULL, screen); } } else { ami_set_screen_defaults(scrn); } /**/ ami_hotlist_initialise(nsoption_charp(hotlist_file)); ami_cookies_initialise(); ami_global_history_initialise(); search_web_select_provider(nsoption_int(search_provider)); if (notalreadyrunning && (nsoption_bool(startup_no_window) == false)) ami_openscreenfirst(); if(temp_homepage_url && notalreadyrunning) { error = nsurl_create(temp_homepage_url, &url); if (error == NSERROR_OK) { error = browser_window_create(BW_CREATE_HISTORY, url, NULL, NULL, &bw); nsurl_unref(url); } if (error != NSERROR_OK) { warn_user(messages_get_errorcode(error), 0); } free(temp_homepage_url); } if(cli_force == true) { notalreadyrunning = TRUE; } if(argc == 0) { // WB struct WBStartup *WBenchMsg = (struct WBStartup *)argv; struct WBArg *wbarg; int first=0,i=0; char fullpath[1024]; for(i=0,wbarg=WBenchMsg->sm_ArgList;ism_NumArgs;i++,wbarg++) { if(i==0) continue; if((wbarg->wa_Lock)&&(*wbarg->wa_Name)) { DevNameFromLock(wbarg->wa_Lock,fullpath,1024,DN_FULLPATH); AddPart(fullpath,wbarg->wa_Name,1024); if(!temp_homepage_url) { nsurl *temp_url; if (netsurf_path_to_nsurl(fullpath, &temp_url) == NSERROR_OK) { temp_homepage_url = strdup(nsurl_access(temp_url)); nsurl_unref(temp_url); } } if(notalreadyrunning) { error = nsurl_create(temp_homepage_url, &url); if (error == NSERROR_OK) { if(!first) { error = browser_window_create(BW_CREATE_HISTORY, url, NULL, NULL, &bw); first=1; } else { error = browser_window_create(BW_CREATE_CLONE | BW_CREATE_HISTORY, url, NULL, bw, &bw); } nsurl_unref(url); } if (error != NSERROR_OK) { warn_user(messages_get_errorcode(error), 0); } free(temp_homepage_url); temp_homepage_url = NULL; } } /* this should be where we read tooltypes, but it's too late for that now */ } } nsoption_setnull_charp(homepage_url, (char *)strdup(NETSURF_HOMEPAGE)); if(!notalreadyrunning) { STRPTR sendcmd = NULL; if(temp_homepage_url) { sendcmd = ASPrintf("OPEN \"%s\" NEW",temp_homepage_url); free(temp_homepage_url); } else { sendcmd = ASPrintf("OPEN \"%s\" NEW",nsoption_charp(homepage_url)); } IDoMethod(arexx_obj,AM_EXECUTE,sendcmd,"NETSURF",NULL,NULL,NULL,NULL); FreeVec(sendcmd); ami_quit=true; return; } #ifdef __amigaos4__ if(IApplication) { if(argc == 0) { ULONG noicon = TAG_IGNORE; if (nsoption_bool(hide_docky_icon)) noicon = REGAPP_NoIcon; ami_appid = RegisterApplication(messages_get("NetSurf"), REGAPP_URLIdentifier, "netsurf-browser.org", REGAPP_WBStartup, (struct WBStartup *)argv, noicon, TRUE, REGAPP_HasPrefsWindow, TRUE, REGAPP_CanCreateNewDocs, TRUE, REGAPP_UniqueApplication, TRUE, REGAPP_Description, messages_get("NetSurfDesc"), TAG_DONE); } else { /* TODO: Specify icon when run from Shell */ ami_appid = RegisterApplication(messages_get("NetSurf"), REGAPP_URLIdentifier, "netsurf-browser.org", REGAPP_FileName, argv[0], REGAPP_NoIcon, TRUE, REGAPP_HasPrefsWindow, TRUE, REGAPP_CanCreateNewDocs, TRUE, REGAPP_UniqueApplication, TRUE, REGAPP_Description, messages_get("NetSurfDesc"), TAG_DONE); } GetApplicationAttrs(ami_appid, APPATTR_Port, (ULONG)&applibport, TAG_DONE); if(applibport) applibsig = (1L << applibport->mp_SigBit); } #endif if(!bw && (nsoption_bool(startup_no_window) == false)) { error = nsurl_create(nsoption_charp(homepage_url), &url); if (error == NSERROR_OK) { error = browser_window_create(BW_CREATE_HISTORY, url, NULL, NULL, NULL); nsurl_unref(url); } if (error != NSERROR_OK) { warn_user(messages_get_errorcode(error), 0); } } } static void ami_update_buttons(struct gui_window_2 *gwin) { long back=FALSE,forward=TRUE,tabclose=FALSE,stop=FALSE,reload=FALSE; long storage = FALSE; if(!browser_window_back_available(gwin->gw->bw)) back=TRUE; if(browser_window_forward_available(gwin->gw->bw)) forward=FALSE; if(!browser_window_stop_available(gwin->gw->bw)) stop=TRUE; if(!browser_window_reload_available(gwin->gw->bw)) reload=TRUE; if(nsoption_bool(kiosk_mode) == false) { if(gwin->tabs <= 1) { tabclose=TRUE; OffMenu(gwin->win,AMI_MENU_CLOSETAB); } else { OnMenu(gwin->win,AMI_MENU_CLOSETAB); } } GetAttr(GA_Disabled, gwin->objects[GID_BACK], (uint32 *)&storage); if(storage != back) SetGadgetAttrs((struct Gadget *)gwin->objects[GID_BACK], gwin->win, NULL, GA_Disabled, back, TAG_DONE); GetAttr(GA_Disabled, gwin->objects[GID_FORWARD], (uint32 *)&storage); if(storage != forward) SetGadgetAttrs((struct Gadget *)gwin->objects[GID_FORWARD], gwin->win, NULL, GA_Disabled, forward, TAG_DONE); GetAttr(GA_Disabled, gwin->objects[GID_RELOAD], (uint32 *)&storage); if(storage != reload) SetGadgetAttrs((struct Gadget *)gwin->objects[GID_RELOAD], gwin->win, NULL, GA_Disabled, reload, TAG_DONE); GetAttr(GA_Disabled, gwin->objects[GID_STOP], (uint32 *)&storage); if(storage != stop) SetGadgetAttrs((struct Gadget *)gwin->objects[GID_STOP], gwin->win, NULL, GA_Disabled, stop, TAG_DONE); if((gwin->tabs) && (ClickTabBase->lib_Version < 53)) { GetAttr(GA_Disabled, gwin->objects[GID_CLOSETAB], (uint32 *)&storage); if(storage != tabclose) SetGadgetAttrs((struct Gadget *)gwin->objects[GID_CLOSETAB], gwin->win, NULL, GA_Disabled, tabclose, TAG_DONE); } /* Update the back/forward buttons history context menu */ ami_ctxmenu_history_create(AMI_CTXMENU_HISTORY_BACK, gwin); ami_ctxmenu_history_create(AMI_CTXMENU_HISTORY_FORWARD, gwin); } void ami_gui_history(struct gui_window_2 *gwin, bool back) { if(back == true) { if(browser_window_back_available(gwin->gw->bw)) browser_window_history_back(gwin->gw->bw, false); } else { if(browser_window_forward_available(gwin->gw->bw)) browser_window_history_forward(gwin->gw->bw, false); } ami_update_buttons(gwin); } int ami_key_to_nskey(ULONG keycode, struct InputEvent *ie) { int nskey = 0, chars; char buffer[20]; char *utf8 = NULL; if(keycode >= IECODE_UP_PREFIX) return 0; switch(keycode) { case RAWKEY_CRSRUP: if(ie->ie_Qualifier & IEQUALIFIER_RSHIFT) { nskey = NS_KEY_PAGE_UP; } else if(ie->ie_Qualifier & IEQUALIFIER_RALT) { nskey = NS_KEY_TEXT_START; } else nskey = NS_KEY_UP; break; case RAWKEY_CRSRDOWN: if(ie->ie_Qualifier & IEQUALIFIER_RSHIFT) { nskey = NS_KEY_PAGE_DOWN; } else if(ie->ie_Qualifier & IEQUALIFIER_RALT) { nskey = NS_KEY_TEXT_END; } else nskey = NS_KEY_DOWN; break; case RAWKEY_CRSRLEFT: if(ie->ie_Qualifier & IEQUALIFIER_RSHIFT) { nskey = NS_KEY_LINE_START; } else if(ie->ie_Qualifier & IEQUALIFIER_RALT) { nskey = NS_KEY_WORD_LEFT; } else nskey = NS_KEY_LEFT; break; case RAWKEY_CRSRRIGHT: if(ie->ie_Qualifier & IEQUALIFIER_RSHIFT) { nskey = NS_KEY_LINE_END; } else if(ie->ie_Qualifier & IEQUALIFIER_RALT) { nskey = NS_KEY_WORD_RIGHT; } else nskey = NS_KEY_RIGHT; break; case RAWKEY_ESC: nskey = NS_KEY_ESCAPE; break; case RAWKEY_PAGEUP: nskey = NS_KEY_PAGE_UP; break; case RAWKEY_PAGEDOWN: nskey = NS_KEY_PAGE_DOWN; break; case RAWKEY_HOME: nskey = NS_KEY_TEXT_START; break; case RAWKEY_END: nskey = NS_KEY_TEXT_END; break; case RAWKEY_BACKSPACE: if(ie->ie_Qualifier & IEQUALIFIER_RSHIFT) { nskey = NS_KEY_DELETE_LINE_START; } else nskey = NS_KEY_DELETE_LEFT; break; case RAWKEY_DEL: if(ie->ie_Qualifier & IEQUALIFIER_RSHIFT) { nskey = NS_KEY_DELETE_LINE_END; } else nskey = NS_KEY_DELETE_RIGHT; break; case RAWKEY_TAB: if(ie->ie_Qualifier & IEQUALIFIER_RSHIFT) { nskey = NS_KEY_SHIFT_TAB; } else nskey = NS_KEY_TAB; break; case RAWKEY_F5: case RAWKEY_F8: case RAWKEY_F9: case RAWKEY_F10: case RAWKEY_HELP: // don't translate nskey = keycode; break; default: if((chars = MapRawKey(ie,buffer,20,NULL)) > 0) { utf8_from_local_encoding(buffer, chars, &utf8); nskey = utf8_to_ucs4(utf8, utf8_char_byte_length(utf8)); if(ie->ie_Qualifier & IEQUALIFIER_RCOMMAND) { switch(nskey) { case 'a': nskey = NS_KEY_SELECT_ALL; break; case 'c': nskey = NS_KEY_COPY_SELECTION; break; case 'v': nskey = NS_KEY_PASTE; break; case 'x': nskey = NS_KEY_CUT_SELECTION; break; case 'y': nskey = NS_KEY_REDO; break; case 'z': nskey = NS_KEY_UNDO; break; } } } break; } return nskey; } static void ami_update_quals(struct gui_window_2 *gwin) { uint32 quals = 0; #ifdef __amigaos4__ GetAttr(WINDOW_Qualifier,gwin->objects[OID_MAIN],(uint32 *)&quals); #else #warning qualifier needs fixing for OS3 #endif gwin->key_state = 0; if((quals & IEQUALIFIER_LSHIFT) || (quals & IEQUALIFIER_RSHIFT)) { gwin->key_state |= BROWSER_MOUSE_MOD_1; } if(quals & IEQUALIFIER_CONTROL) { gwin->key_state |= BROWSER_MOUSE_MOD_2; } if((quals & IEQUALIFIER_LALT) || (quals & IEQUALIFIER_RALT)) { gwin->key_state |= BROWSER_MOUSE_MOD_3; } } /* exported interface documented in amiga/gui.h */ nserror ami_gui_get_space_box(Object *obj, struct IBox **bbox) { if(LIB_IS_AT_LEAST((struct Library *)SpaceBase, 53, 6)) { #ifdef __amigaos4__ *bbox = AllocVecTagList(sizeof(struct IBox), NULL); if(*bbox == NULL) return NSERROR_NOMEM; GetAttr(SPACE_RenderBox, obj, (ULONG *)*bbox); #endif } else { GetAttr(SPACE_AreaBox, obj, (ULONG *)bbox); } return NSERROR_OK; } /* exported interface documented in amiga/gui.h */ void ami_gui_free_space_box(struct IBox *bbox) { if(LIB_IS_AT_LEAST((struct Library *)SpaceBase, 53, 6)) { FreeVec(bbox); } } static bool ami_spacebox_to_ns_coords(struct gui_window_2 *gwin, int *x, int *y, int space_x, int space_y) { int ns_x = space_x; int ns_y = space_y; ns_x /= gwin->gw->scale; ns_y /= gwin->gw->scale; ns_x += gwin->gw->scrollx; ns_y += gwin->gw->scrolly; *x = ns_x; *y = ns_y; return true; } bool ami_mouse_to_ns_coords(struct gui_window_2 *gwin, int *x, int *y, int mouse_x, int mouse_y) { int ns_x, ns_y; struct IBox *bbox; if(mouse_x == -1) mouse_x = gwin->win->MouseX; if(mouse_y == -1) mouse_y = gwin->win->MouseY; if(ami_gui_get_space_box((Object *)gwin->objects[GID_BROWSER], &bbox) == NSERROR_OK) { ns_x = (ULONG)(mouse_x - bbox->Left); ns_y = (ULONG)(mouse_y - bbox->Top); if((ns_x < 0) || (ns_x > bbox->Width) || (ns_y < 0) || (ns_y > bbox->Height)) return false; ami_gui_free_space_box(bbox); } else { warn_user("NoMemory", ""); return false; } return ami_spacebox_to_ns_coords(gwin, x, y, ns_x, ns_y); } static void ami_gui_scroll_internal(struct gui_window_2 *gwin, int xs, int ys) { struct IBox *bbox; int x, y; if(ami_mouse_to_ns_coords(gwin, &x, &y, -1, -1) == true) { if(browser_window_scroll_at_point(gwin->gw->bw, x, y, xs, ys) == false) { int width, height; gui_window_get_scroll(gwin->gw, &gwin->gw->scrollx, &gwin->gw->scrolly); if(ami_gui_get_space_box((Object *)gwin->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } browser_window_get_extents(gwin->gw->bw, false, &width, &height); switch(xs) { case SCROLL_PAGE_UP: xs = gwin->gw->scrollx - bbox->Width; break; case SCROLL_PAGE_DOWN: xs = gwin->gw->scrollx + bbox->Width; break; case SCROLL_TOP: xs = 0; break; case SCROLL_BOTTOM: xs = width; break; default: xs += gwin->gw->scrollx; break; } switch(ys) { case SCROLL_PAGE_UP: ys = gwin->gw->scrolly - bbox->Height; break; case SCROLL_PAGE_DOWN: ys = gwin->gw->scrolly + bbox->Height; break; case SCROLL_TOP: ys = 0; break; case SCROLL_BOTTOM: ys = height; break; default: ys += gwin->gw->scrolly; break; } ami_gui_free_space_box(bbox); gui_window_set_scroll(gwin->gw, xs, ys); } } } static struct IBox *ami_ns_rect_to_ibox(struct gui_window_2 *gwin, const struct rect *rect) { struct IBox *bbox, *ibox; ibox = AllocVecTagList(sizeof(struct IBox), NULL); if(ibox == NULL) return NULL; if(ami_gui_get_space_box((Object *)gwin->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return NULL; } ibox->Left = gwin->win->MouseX + (rect->x0 * gwin->gw->scale); ibox->Top = gwin->win->MouseY + (rect->y0 * gwin->gw->scale); ibox->Width = (rect->x1 - rect->x0) * gwin->gw->scale; ibox->Height = (rect->y1 - rect->y0) * gwin->gw->scale; if(ibox->Left < bbox->Left) ibox->Left = bbox->Left; if(ibox->Top < bbox->Top) ibox->Top = bbox->Top; if((ibox->Left > (bbox->Left + bbox->Width)) || (ibox->Top > (bbox->Top + bbox->Height)) || (ibox->Width < 0) || (ibox->Height < 0)) { FreeVec(ibox); ami_gui_free_space_box(bbox); return NULL; } ami_gui_free_space_box(bbox); return ibox; } static void ami_gui_trap_mouse(struct gui_window_2 *gwin) { #ifdef __amigaos4__ switch(gwin->drag_op) { case GDRAGGING_NONE: case GDRAGGING_SCROLLBAR: case GDRAGGING_OTHER: break; default: if(gwin->ptr_lock) { SetWindowAttrs(gwin->win, WA_GrabFocus, 10, WA_MouseLimits, gwin->ptr_lock, TAG_DONE); } break; } #endif } static void ami_gui_menu_update_all(void) { struct nsObject *node; struct nsObject *nnode; struct gui_window_2 *gwin; if(IsMinListEmpty(window_list)) return; node = (struct nsObject *)GetHead((struct List *)window_list); do { nnode=(struct nsObject *)GetSucc((struct Node *)node); gwin = node->objstruct; if(node->Type == AMINS_WINDOW) { ami_menu_update_checked(gwin); } } while((node = nnode)); } static void gui_window_get_dimensions(struct gui_window *g, int *width, int *height, bool scaled) { struct IBox *bbox; if(!g) return; if(ami_gui_get_space_box((Object *)g->shared->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } *width = bbox->Width; *height = bbox->Height; ami_gui_free_space_box(bbox); if(scaled) { *width /= g->scale; *height /= g->scale; } } /* Add a horizontal scroller, if not already present * Returns true if changed, false otherwise */ static bool ami_gui_hscroll_add(struct gui_window_2 *gwin) { struct TagItem attrs[2]; if(gwin->objects[GID_HSCROLL] != NULL) return false; attrs[0].ti_Tag = CHILD_MinWidth; attrs[0].ti_Data = 0; attrs[1].ti_Tag = TAG_DONE; attrs[1].ti_Data = 0; gwin->objects[GID_HSCROLL] = ScrollerObj, GA_ID, GID_HSCROLL, GA_RelVerify, TRUE, SCROLLER_Orientation, SORIENT_HORIZ, ICA_TARGET, ICTARGET_IDCMP, ScrollerEnd; #ifdef __amigaos4__ IDoMethod(gwin->objects[GID_HSCROLLLAYOUT], LM_ADDCHILD, gwin->win, gwin->objects[GID_HSCROLL], attrs); #else SetAttrs(gwin->objects[GID_HSCROLLLAYOUT], LAYOUT_AddChild, gwin->objects[GID_HSCROLL], TAG_MORE, &attrs); #endif return true; } /* Remove the horizontal scroller, if present */ static bool ami_gui_hscroll_remove(struct gui_window_2 *gwin) { if(gwin->objects[GID_HSCROLL] == NULL) return false; #ifdef __amigaos4__ IDoMethod(gwin->objects[GID_HSCROLLLAYOUT], LM_REMOVECHILD, gwin->win, gwin->objects[GID_HSCROLL]); #else SetAttrs(gwin->objects[GID_HSCROLLLAYOUT], LAYOUT_RemoveChild, gwin->objects[GID_HSCROLL]); #endif gwin->objects[GID_HSCROLL] = NULL; return true; } /* Add a vertical scroller, if not already present * Returns true if changed, false otherwise */ static bool ami_gui_vscroll_add(struct gui_window_2 *gwin) { struct TagItem attrs[2]; if(gwin->objects[GID_VSCROLL] != NULL) return false; attrs[0].ti_Tag = CHILD_MinWidth; attrs[0].ti_Data = 0; attrs[1].ti_Tag = TAG_DONE; attrs[1].ti_Data = 0; gwin->objects[GID_VSCROLL] = ScrollerObj, GA_ID, GID_VSCROLL, GA_RelVerify, TRUE, ICA_TARGET, ICTARGET_IDCMP, ScrollerEnd; #ifdef __amigaos4__ IDoMethod(gwin->objects[GID_VSCROLLLAYOUT], LM_ADDCHILD, gwin->win, gwin->objects[GID_VSCROLL], attrs); #else SetAttrs(gwin->objects[GID_VSCROLLLAYOUT], LAYOUT_AddChild, gwin->objects[GID_VSCROLL], TAG_MORE, &attrs); #endif return true; } /* Remove the vertical scroller, if present */ static bool ami_gui_vscroll_remove(struct gui_window_2 *gwin) { if(gwin->objects[GID_VSCROLL] == NULL) return false; #ifdef __amigaos4__ IDoMethod(gwin->objects[GID_VSCROLLLAYOUT], LM_REMOVECHILD, gwin->win, gwin->objects[GID_VSCROLL]); #else SetAttrs(gwin->objects[GID_VSCROLLLAYOUT], LAYOUT_RemoveChild, gwin->objects[GID_VSCROLL]); #endif gwin->objects[GID_VSCROLL] = NULL; return true; } /** * Check the scroll bar requirements for a browser window, and add/remove * the vertical scroller as appropriate. This should be the main entry * point used to perform this task. * * \param gwin "Shared" GUI window to check the state of */ static void ami_gui_scroller_update(struct gui_window_2 *gwin) { int h = 1, w = 1, wh = 0, ww = 0; bool rethinkv = false; bool rethinkh = false; browser_scrolling hscroll = BW_SCROLLING_YES; browser_scrolling vscroll = BW_SCROLLING_YES; browser_window_get_scrollbar_type(gwin->gw->bw, &hscroll, &vscroll); if(browser_window_is_frameset(gwin->gw->bw) == true) { rethinkv = ami_gui_vscroll_remove(gwin); rethinkh = ami_gui_hscroll_remove(gwin); } else { if((browser_window_get_extents(gwin->gw->bw, false, &w, &h) == NSERROR_OK)) { gui_window_get_dimensions(gwin->gw, &ww, &wh, false); } if(vscroll == BW_SCROLLING_NO) { rethinkv = ami_gui_vscroll_remove(gwin); } else { if (h > wh) rethinkv = ami_gui_vscroll_add(gwin); else rethinkv = ami_gui_vscroll_remove(gwin); } if(hscroll == BW_SCROLLING_NO) { rethinkh = ami_gui_hscroll_remove(gwin); } else { if (w > ww) rethinkh = ami_gui_hscroll_add(gwin); else rethinkh = ami_gui_hscroll_remove(gwin); } } if(rethinkv || rethinkh) { FlushLayoutDomainCache((struct Gadget *)gwin->objects[GID_MAIN]); RethinkLayout((struct Gadget *)gwin->objects[GID_MAIN], gwin->win, NULL, TRUE); browser_window_schedule_reformat(gwin->gw->bw); } } /** * function to add retrieved favicon to gui */ static void gui_window_set_icon(struct gui_window *g, hlcache_handle *icon) { struct BitMap *bm = NULL; struct IBox *bbox; struct bitmap *icon_bitmap = NULL; if(nsoption_bool(kiosk_mode) == true) return; if(!g) return; if ((icon != NULL) && ((icon_bitmap = content_get_bitmap(icon)) != NULL)) { bm = ami_bitmap_get_native(icon_bitmap, 16, 16, g->shared->win->RPort->BitMap); } if(g == g->shared->gw) { RefreshGList((struct Gadget *)g->shared->objects[GID_ICON], g->shared->win, NULL, 1); if(bm) { ULONG tag, tag_data, minterm; if(ami_plot_screen_is_palettemapped() == false) { tag = BLITA_UseSrcAlpha; tag_data = !icon_bitmap->opaque; minterm = 0xc0; } else { tag = BLITA_MaskPlane; tag_data = (ULONG)ami_bitmap_get_mask(icon_bitmap, 16, 16, bm); minterm = MINTERM_SRCMASK; } if(ami_gui_get_space_box((Object *)g->shared->objects[GID_ICON], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } EraseRect(g->shared->win->RPort, bbox->Left, bbox->Top, bbox->Left + 16, bbox->Top + 16); #ifdef __amigaos4__ BltBitMapTags(BLITA_SrcX, 0, BLITA_SrcY, 0, BLITA_DestX, bbox->Left, BLITA_DestY, bbox->Top, BLITA_Width, 16, BLITA_Height, 16, BLITA_Source, bm, BLITA_Dest, g->shared->win->RPort, BLITA_SrcType, BLITT_BITMAP, BLITA_DestType, BLITT_RASTPORT, BLITA_Minterm, minterm, tag, tag_data, TAG_DONE); #else if(tag_data) { BltMaskBitMapRastPort(bm, 0, 0, g->shared->win->RPort, bbox->Left, bbox->Top, 16, 16, minterm, tag_data); } else { BltBitMapRastPort(bm, 0, 0, g->shared->win->RPort, bbox->Left, bbox->Top, 16, 16, 0xc0); } #endif ami_gui_free_space_box(bbox); } } g->favicon = icon; } static void ami_gui_refresh_favicon(void *p) { struct gui_window_2 *gwin = (struct gui_window_2 *)p; gui_window_set_icon(gwin->gw, gwin->gw->favicon); } /* Gets the size that border gadget 1 (status) needs to be. * Returns the width of the size gadget as a convenience. */ static ULONG ami_get_border_gadget_size(struct gui_window_2 *gwin, ULONG *width, ULONG *height) { ULONG available_width; #ifdef __amigaos4__ if((sz_gad_width == 0) || (sz_gad_height == 0)) { struct DrawInfo *dri = GetScreenDrawInfo(scrn); GetGUIAttrs(NULL, dri, GUIA_SizeGadgetWidth, &sz_gad_width, GUIA_SizeGadgetHeight, &sz_gad_height, TAG_DONE); FreeScreenDrawInfo(scrn, dri); } #endif available_width = gwin->win->Width - scrn->WBorLeft - sz_gad_width; *width = available_width; *height = sz_gad_height; return sz_gad_width; } static void ami_set_border_gadget_size(struct gui_window_2 *gwin) { /* Reset gadget widths according to new calculation */ ULONG size1, size2, sz; sz = ami_get_border_gadget_size(gwin, &size1, &size2); RefreshSetGadgetAttrs((struct Gadget *)(APTR)gwin->objects[GID_STATUS], gwin->win, NULL, GA_Width, size1, TAG_DONE); RefreshWindowFrame(gwin->win); } static void ami_handle_msg(void) { ULONG result,storage = 0,x,y,xs,ys,width=800,height=600; uint16 code; struct IBox *bbox; struct nsObject *node; struct nsObject *nnode; struct gui_window_2 *gwin = NULL; struct InputEvent *ie; struct Node *tabnode; int nskey; struct timeval curtime; static int drag_x_move = 0, drag_y_move = 0; char *utf8 = NULL; nsurl *url; if(IsMinListEmpty(window_list)) { /* no windows in list, so NetSurf should not be running */ ami_try_quit(); return; } node = (struct nsObject *)GetHead((struct List *)window_list); do { nnode=(struct nsObject *)GetSucc((struct Node *)node); gwin = node->objstruct; if(node->Type == AMINS_TVWINDOW) { if(ami_tree_event((struct treeview_window *)gwin)) { ami_try_quit(); break; } else { node = nnode; continue; } } else if(node->Type == AMINS_FINDWINDOW) { if(ami_search_event()) { ami_try_quit(); break; } else { node = nnode; continue; } } else if(node->Type == AMINS_HISTORYWINDOW) { if(ami_history_event((struct history_window *)gwin)) { ami_try_quit(); break; } else { node = nnode; continue; } } else if(node->Type == AMINS_PRINTWINDOW) { if(ami_print_event((struct ami_print_window *)gwin)) { ami_try_quit(); break; } else { node = nnode; continue; } } else if(node->Type == AMINS_GUIOPTSWINDOW) { if(ami_gui_opts_event()) { /* last window possibly closed, so exit with conditions ;) */ if(scrn) ami_try_quit(); break; } else { node = nnode; continue; } } else if(node->Type == AMINS_DLWINDOW) { if(ami_download_window_event((struct gui_download_window *)gwin)) { ami_try_quit(); break; } else { node = nnode; continue; } } else if(node->Type == AMINS_LOGINWINDOW) { if(ami_401login_event((struct gui_login_window *)gwin)) { ami_try_quit(); break; } else { node = nnode; continue; } } if((gwin == NULL) || (gwin->objects[OID_MAIN] == NULL)) continue; while((result = RA_HandleInput(gwin->objects[OID_MAIN], &code)) != WMHI_LASTMSG) { switch(result & WMHI_CLASSMASK) // class { case WMHI_MOUSEMOVE: ami_gui_trap_mouse(gwin); /* re-assert mouse area */ drag_x_move = 0; drag_y_move = 0; if(ami_gui_get_space_box((Object *)gwin->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); break; } x = (ULONG)((gwin->win->MouseX - bbox->Left) / gwin->gw->scale); y = (ULONG)((gwin->win->MouseY - bbox->Top) / gwin->gw->scale); ami_get_hscroll_pos(gwin, (ULONG *)&xs); ami_get_vscroll_pos(gwin, (ULONG *)&ys); x += xs; y += ys; width=bbox->Width; height=bbox->Height; if(gwin->mouse_state & BROWSER_MOUSE_DRAG_ON) { ami_drag_icon_move(); if(ami_autoscroll == TRUE) { if((gwin->win->MouseX < bbox->Left) && ((gwin->win->MouseX - bbox->Left) > -AMI_DRAG_THRESHOLD)) drag_x_move = gwin->win->MouseX - bbox->Left; if((gwin->win->MouseX > (bbox->Left + bbox->Width)) && ((gwin->win->MouseX - (bbox->Left + bbox->Width)) < AMI_DRAG_THRESHOLD)) drag_x_move = gwin->win->MouseX - (bbox->Left + bbox->Width); if((gwin->win->MouseY < bbox->Top) && ((gwin->win->MouseY - bbox->Top) > -AMI_DRAG_THRESHOLD)) drag_y_move = gwin->win->MouseY - bbox->Top; if((gwin->win->MouseY > (bbox->Top + bbox->Height)) && ((gwin->win->MouseY - (bbox->Top + bbox->Height)) < AMI_DRAG_THRESHOLD)) drag_y_move = gwin->win->MouseY - (bbox->Top + bbox->Height); } } ami_gui_free_space_box(bbox); if((x>=xs) && (y>=ys) && (xmouse_state & BROWSER_MOUSE_PRESS_1) { browser_window_mouse_track(gwin->gw->bw,BROWSER_MOUSE_DRAG_1 | gwin->key_state,x,y); gwin->mouse_state = BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_DRAG_ON; } else if(gwin->mouse_state & BROWSER_MOUSE_PRESS_2) { browser_window_mouse_track(gwin->gw->bw,BROWSER_MOUSE_DRAG_2 | gwin->key_state,x,y); gwin->mouse_state = BROWSER_MOUSE_HOLDING_2 | BROWSER_MOUSE_DRAG_ON; } else { browser_window_mouse_track(gwin->gw->bw,gwin->mouse_state | gwin->key_state,x,y); } } else { if(!gwin->mouse_state) ami_set_pointer(gwin, GUI_POINTER_DEFAULT, true); } break; case WMHI_MOUSEBUTTONS: if(ami_gui_get_space_box((Object *)gwin->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } x = (ULONG)((gwin->win->MouseX - bbox->Left) / gwin->gw->scale); y = (ULONG)((gwin->win->MouseY - bbox->Top) / gwin->gw->scale); ami_get_hscroll_pos(gwin, (ULONG *)&xs); ami_get_vscroll_pos(gwin, (ULONG *)&ys); x += xs; y += ys; width=bbox->Width; height=bbox->Height; ami_gui_free_space_box(bbox); ami_update_quals(gwin); if((x>=xs) && (y>=ys) && (x>16; switch(code) { case SELECTDOWN: browser_window_mouse_click(gwin->gw->bw,BROWSER_MOUSE_PRESS_1 | gwin->key_state,x,y); gwin->mouse_state=BROWSER_MOUSE_PRESS_1; break; case MIDDLEDOWN: browser_window_mouse_click(gwin->gw->bw,BROWSER_MOUSE_PRESS_2 | gwin->key_state,x,y); gwin->mouse_state=BROWSER_MOUSE_PRESS_2; break; } } if(x=width+xs) x=width+xs-1; if(y>=height+ys) y=height+ys-1; switch(code) { case SELECTUP: if(gwin->mouse_state & BROWSER_MOUSE_PRESS_1) { CurrentTime((ULONG *)&curtime.tv_sec, (ULONG *)&curtime.tv_usec); gwin->mouse_state = BROWSER_MOUSE_CLICK_1; if(gwin->lastclick.tv_sec) { if(DoubleClick(gwin->lastclick.tv_sec, gwin->lastclick.tv_usec, curtime.tv_sec, curtime.tv_usec)) { if(gwin->prev_mouse_state & BROWSER_MOUSE_DOUBLE_CLICK) { gwin->mouse_state |= BROWSER_MOUSE_TRIPLE_CLICK; } else { gwin->mouse_state |= BROWSER_MOUSE_DOUBLE_CLICK; } } } browser_window_mouse_click(gwin->gw->bw, gwin->mouse_state | gwin->key_state,x,y); if(gwin->mouse_state & BROWSER_MOUSE_TRIPLE_CLICK) { gwin->lastclick.tv_sec = 0; gwin->lastclick.tv_usec = 0; } else { gwin->lastclick.tv_sec = curtime.tv_sec; gwin->lastclick.tv_usec = curtime.tv_usec; } } else { browser_window_mouse_track(gwin->gw->bw, 0, x, y); } gwin->prev_mouse_state = gwin->mouse_state; gwin->mouse_state=0; break; case MIDDLEUP: if(gwin->mouse_state & BROWSER_MOUSE_PRESS_2) { CurrentTime((ULONG *)&curtime.tv_sec, (ULONG *)&curtime.tv_usec); gwin->mouse_state = BROWSER_MOUSE_CLICK_2; if(gwin->lastclick.tv_sec) { if(DoubleClick(gwin->lastclick.tv_sec, gwin->lastclick.tv_usec, curtime.tv_sec, curtime.tv_usec)) { if(gwin->prev_mouse_state & BROWSER_MOUSE_DOUBLE_CLICK) { gwin->mouse_state |= BROWSER_MOUSE_TRIPLE_CLICK; } else { gwin->mouse_state |= BROWSER_MOUSE_DOUBLE_CLICK; } } } browser_window_mouse_click(gwin->gw->bw, gwin->mouse_state | gwin->key_state,x,y); if(gwin->mouse_state & BROWSER_MOUSE_TRIPLE_CLICK) { gwin->lastclick.tv_sec = 0; gwin->lastclick.tv_usec = 0; } else { gwin->lastclick.tv_sec = curtime.tv_sec; gwin->lastclick.tv_usec = curtime.tv_usec; } } else { browser_window_mouse_track(gwin->gw->bw, 0, x, y); } gwin->prev_mouse_state = gwin->mouse_state; gwin->mouse_state=0; break; #ifdef __amigaos4__ case SIDEUP: ami_gui_history(gwin, true); break; case EXTRAUP: ami_gui_history(gwin, false); break; #endif } if(drag_save_data && !gwin->mouse_state) ami_drag_save(gwin->win); break; case WMHI_GADGETUP: switch(result & WMHI_GADGETMASK) { case GID_TABS: if(gwin->objects[GID_TABS] == NULL) break; GetAttrs(gwin->objects[GID_TABS], CLICKTAB_NodeClosed, &tabnode, TAG_DONE); if(tabnode) { struct gui_window *closedgw; GetClickTabNodeAttrs(tabnode, TNA_UserData, &closedgw, TAG_DONE); browser_window_destroy(closedgw->bw); } else { ami_switch_tab(gwin, true); } break; case GID_CLOSETAB: browser_window_destroy(gwin->gw->bw); break; case GID_ADDTAB: ami_gui_new_blank_tab(gwin); break; case GID_URL: { nserror ret; nsurl *url; GetAttr(STRINGA_TextVal, (Object *)gwin->objects[GID_URL], (ULONG *)&storage); utf8 = ami_to_utf8_easy((const char *)storage); ret = search_web_omni(utf8, SEARCH_WEB_OMNI_NONE, &url); ami_utf8_free(utf8); if (ret == NSERROR_OK) { browser_window_navigate(gwin->gw->bw, url, NULL, BW_NAVIGATE_HISTORY, NULL, NULL, NULL); nsurl_unref(url); } if (ret != NSERROR_OK) { warn_user(messages_get_errorcode(ret), 0); } } break; case GID_TOOLBARLAYOUT: /* Need fixing: never gets here */ search_web_select_provider(-1); break; case GID_SEARCH_ICON: GetAttr(CHOOSER_Selected, gwin->objects[GID_SEARCH_ICON], (ULONG *)&storage); search_web_select_provider(storage); break; case GID_SEARCHSTRING: { nserror ret; nsurl *url; GetAttr(STRINGA_TextVal, (Object *)gwin->objects[GID_SEARCHSTRING], (ULONG *)&storage); utf8 = ami_to_utf8_easy((const char *)storage); ret = search_web_omni(utf8, SEARCH_WEB_OMNI_SEARCHONLY, &url); ami_utf8_free(utf8); if (ret == NSERROR_OK) { browser_window_navigate(gwin->gw->bw, url, NULL, BW_NAVIGATE_HISTORY, NULL, NULL, NULL); nsurl_unref(url); } if (ret != NSERROR_OK) { warn_user(messages_get_errorcode(ret), 0); } } break; case GID_HOME: { if (nsurl_create(nsoption_charp(homepage_url), &url) != NSERROR_OK) { warn_user("NoMemory", 0); } else { browser_window_navigate(gwin->gw->bw, url, NULL, BW_NAVIGATE_HISTORY, NULL, NULL, NULL); nsurl_unref(url); } } break; case GID_STOP: if(browser_window_stop_available(gwin->gw->bw)) browser_window_stop(gwin->gw->bw); break; case GID_RELOAD: ami_update_quals(gwin); if(browser_window_reload_available(gwin->gw->bw)) { if(gwin->key_state & BROWSER_MOUSE_MOD_1) { browser_window_reload(gwin->gw->bw, true); } else { browser_window_reload(gwin->gw->bw, false); } } break; case GID_BACK: ami_gui_history(gwin, true); break; case GID_FORWARD: ami_gui_history(gwin, false); break; case GID_FAVE: GetAttr(STRINGA_TextVal, (Object *)gwin->objects[GID_URL], (ULONG *)&storage); if(nsurl_create((const char *)storage, &url) == NSERROR_OK) { if(hotlist_has_url(url)) { hotlist_remove_url(url); } else { hotlist_add_url(url); } nsurl_unref(url); } ami_gui_update_hotlist_button(gwin); break; case GID_HOTLIST: default: // printf("GADGET: %ld\n",(result & WMHI_GADGETMASK)); break; } break; case WMHI_RAWKEY: ami_update_quals(gwin); storage = result & WMHI_GADGETMASK; if(storage >= IECODE_UP_PREFIX) break; GetAttr(WINDOW_InputEvent,gwin->objects[OID_MAIN],(ULONG *)&ie); nskey = ami_key_to_nskey(storage, ie); if((ie->ie_Qualifier & IEQUALIFIER_RCOMMAND) && ((31 < nskey) && (nskey < 127))) { /* NB: Some keypresses are converted to generic keypresses above * rather than being "menu-emulated" here. */ switch(nskey) { /* The following aren't available from the menu at the moment */ case 'r': // reload if(browser_window_reload_available(gwin->gw->bw)) browser_window_reload(gwin->gw->bw, false); break; case 'u': // open url if((nsoption_bool(kiosk_mode) == false)) ActivateLayoutGadget((struct Gadget *)gwin->objects[GID_MAIN], gwin->win, NULL, (uint32)gwin->objects[GID_URL]); break; } } else { if(!browser_window_key_press(gwin->gw->bw, nskey)) { switch(nskey) { case NS_KEY_UP: ami_gui_scroll_internal(gwin, 0, -NSA_KBD_SCROLL_PX); break; case NS_KEY_DOWN: ami_gui_scroll_internal(gwin, 0, +NSA_KBD_SCROLL_PX); break; case NS_KEY_LEFT: ami_gui_scroll_internal(gwin, -NSA_KBD_SCROLL_PX, 0); break; case NS_KEY_RIGHT: ami_gui_scroll_internal(gwin, +NSA_KBD_SCROLL_PX, 0); break; case NS_KEY_PAGE_UP: ami_gui_scroll_internal(gwin, 0, SCROLL_PAGE_UP); break; case NS_KEY_PAGE_DOWN: case ' ': ami_gui_scroll_internal(gwin, 0, SCROLL_PAGE_DOWN); break; case NS_KEY_LINE_START: // page left ami_gui_scroll_internal(gwin, SCROLL_PAGE_UP, 0); break; case NS_KEY_LINE_END: // page right ami_gui_scroll_internal(gwin, SCROLL_PAGE_DOWN, 0); break; case NS_KEY_TEXT_START: // home ami_gui_scroll_internal(gwin, SCROLL_TOP, SCROLL_TOP); break; case NS_KEY_TEXT_END: // end ami_gui_scroll_internal(gwin, SCROLL_BOTTOM, SCROLL_BOTTOM); break; case NS_KEY_WORD_RIGHT: // alt+right ami_change_tab(gwin, 1); break; case NS_KEY_WORD_LEFT: // alt+left ami_change_tab(gwin, -1); break; case NS_KEY_DELETE_LEFT: // backspace ami_gui_history(gwin, true); break; /* RawKeys. NB: These are passthrus in ami_key_to_nskey() */ case RAWKEY_F5: // reload if(browser_window_reload_available(gwin->gw->bw)) browser_window_reload(gwin->gw->bw,false); break; case RAWKEY_F8: // scale 100% ami_gui_set_scale(gwin->gw, 1.0); break; case RAWKEY_F9: // decrease scale ami_gui_set_scale(gwin->gw, gwin->gw->scale - 0.1); break; case RAWKEY_F10: // increase scale ami_gui_set_scale(gwin->gw, gwin->gw->scale + 0.1); break; case RAWKEY_HELP: // help ami_help_open(AMI_HELP_GUI, scrn); break; } } else if(nskey == NS_KEY_COPY_SELECTION) { /* if we've copied a selection we need to clear it - style guide rules */ browser_window_key_press(gwin->gw->bw, NS_KEY_CLEAR_SELECTION); } } break; case WMHI_NEWSIZE: ami_set_border_gadget_size(gwin); ami_throbber_redraw_schedule(0, gwin->gw); ami_schedule(0, ami_gui_refresh_favicon, gwin); browser_window_schedule_reformat(gwin->gw->bw); break; case WMHI_CLOSEWINDOW: ami_close_all_tabs(gwin); break; #ifdef __amigaos4__ case WMHI_ICONIFY: { struct bitmap *bm; bm = urldb_get_thumbnail(browser_window_get_url(gwin->gw->bw)); if(!bm) bm = content_get_bitmap(browser_window_get_content(gwin->gw->bw)); gwin->dobj = amiga_icon_from_bitmap(bm); amiga_icon_superimpose_favicon_internal(gwin->gw->favicon, gwin->dobj); HideWindow(gwin->win); gwin->appicon = AddAppIcon((ULONG)gwin->objects[OID_MAIN], (ULONG)gwin, gwin->win->Title, appport, 0, gwin->dobj, NULL); cur_gw = NULL; } break; #endif case WMHI_INACTIVE: gwin->gw->c_h_temp = gwin->gw->c_h; gui_window_remove_caret(gwin->gw); break; case WMHI_ACTIVE: if(gwin->gw->bw) cur_gw = gwin->gw; if(gwin->gw->c_h_temp) gwin->gw->c_h = gwin->gw->c_h_temp; break; case WMHI_INTUITICK: break; default: //printf("class: %ld\n",(result & WMHI_CLASSMASK)); break; } if(win_destroyed) { /* we can't be sure what state our window_list is in, so let's jump out of the function and start again */ win_destroyed = false; return; } if(drag_x_move || drag_y_move) { gui_window_get_scroll(gwin->gw, &gwin->gw->scrollx, &gwin->gw->scrolly); gui_window_set_scroll(gwin->gw, gwin->gw->scrollx + drag_x_move, gwin->gw->scrolly + drag_y_move); } // ReplyMsg((struct Message *)message); } } while((node = nnode)); if(ami_menu_window_close) { if(ami_menu_window_close == (void *)AMI_MENU_WINDOW_CLOSE_ALL) ami_quit_netsurf(); else ami_close_all_tabs(ami_menu_window_close); ami_menu_window_close = NULL; } if(ami_menu_check_toggled) { ami_gui_menu_update_all(); ami_menu_check_toggled = false; } } static void ami_gui_appicon_remove(struct gui_window_2 *gwin) { if(gwin->appicon) { RemoveAppIcon(gwin->appicon); amiga_icon_free(gwin->dobj); gwin->appicon = NULL; } } static void ami_handle_appmsg(void) { struct AppMessage *appmsg; struct gui_window_2 *gwin; int x, y; struct WBArg *appwinargs; STRPTR filename; int i = 0; while((appmsg = (struct AppMessage *)GetMsg(appport))) { gwin = (struct gui_window_2 *)appmsg->am_UserData; if(appmsg->am_Type == AMTYPE_APPICON) { ami_gui_appicon_remove(gwin); ShowWindow(gwin->win, WINDOW_FRONTMOST); ActivateWindow(gwin->win); } else if(appmsg->am_Type == AMTYPE_APPWINDOW) { for(i = 0; i < appmsg->am_NumArgs; ++i) { if((appwinargs = &appmsg->am_ArgList[i])) { if((filename = AllocVecTagList(1024, NULL))) { if(appwinargs->wa_Lock) { NameFromLock(appwinargs->wa_Lock, filename, 1024); } AddPart(filename, appwinargs->wa_Name, 1024); if(ami_mouse_to_ns_coords(gwin, &x, &y, appmsg->am_MouseX, appmsg->am_MouseY) == false) { nsurl *url; if (netsurf_path_to_nsurl(filename, &url) != NSERROR_OK) { warn_user("NoMemory", 0); } else { if(i == 0) { browser_window_navigate(gwin->gw->bw, url, NULL, BW_NAVIGATE_HISTORY, NULL, NULL, NULL); ActivateWindow(gwin->win); } else { browser_window_create(BW_CREATE_CLONE | BW_CREATE_HISTORY | BW_CREATE_TAB, url, NULL, gwin->gw->bw, NULL); } nsurl_unref(url); } } else { if(browser_window_drop_file_at_point(gwin->gw->bw, x, y, filename) == false) { nsurl *url; if (netsurf_path_to_nsurl(filename, &url) != NSERROR_OK) { warn_user("NoMemory", 0); } else { if(i == 0) { browser_window_navigate(gwin->gw->bw, url, NULL, BW_NAVIGATE_HISTORY, NULL, NULL, NULL); ActivateWindow(gwin->win); } else { browser_window_create(BW_CREATE_CLONE | BW_CREATE_HISTORY | BW_CREATE_TAB, url, NULL, gwin->gw->bw, NULL); } nsurl_unref(url); } } } FreeVec(filename); } } } } ReplyMsg((struct Message *)appmsg); } } static void ami_handle_applib(void) { #ifdef __amigaos4__ struct ApplicationMsg *applibmsg; struct browser_window *bw; nsurl *url; nserror error; if(!applibport) return; while((applibmsg=(struct ApplicationMsg *)GetMsg(applibport))) { switch (applibmsg->type) { case APPLIBMT_NewBlankDoc: { error = nsurl_create(nsoption_charp(homepage_url), &url); if (error == NSERROR_OK) { error = browser_window_create(BW_CREATE_HISTORY, url, NULL, NULL, &bw); nsurl_unref(url); } if (error != NSERROR_OK) { warn_user(messages_get_errorcode(error), 0); } } break; case APPLIBMT_OpenDoc: { struct ApplicationOpenPrintDocMsg *applibopdmsg = (struct ApplicationOpenPrintDocMsg *)applibmsg; error = netsurf_path_to_nsurl(applibopdmsg->fileName, &url); if (error == NSERROR_OK) { error = browser_window_create(BW_CREATE_HISTORY, url, NULL, NULL, &bw); nsurl_unref(url); } if (error != NSERROR_OK) { warn_user(messages_get_errorcode(error), 0); } } break; case APPLIBMT_ToFront: if(cur_gw) { ScreenToFront(scrn); WindowToFront(cur_gw->shared->win); ActivateWindow(cur_gw->shared->win); } break; case APPLIBMT_OpenPrefs: ScreenToFront(scrn); ami_gui_opts_open(); break; case APPLIBMT_Quit: case APPLIBMT_ForceQuit: ami_quit_netsurf(); break; case APPLIBMT_CustomMsg: { struct ApplicationCustomMsg *applibcustmsg = (struct ApplicationCustomMsg *)applibmsg; LOG("Ringhio BackMsg received: %s", applibcustmsg->customMsg); OpenWorkbenchObjectA(applibcustmsg->customMsg, NULL); } break; } ReplyMsg((struct Message *)applibmsg); } #endif } void ami_get_msg(void) { ULONG winsignal = 1L << sport->mp_SigBit; ULONG appsig = 1L << appport->mp_SigBit; ULONG schedulesig = 1L << schedulermsgport->mp_SigBit; ULONG ctrlcsig = SIGBREAKF_CTRL_C; uint32 signal = 0; fd_set read_fd_set, write_fd_set, except_fd_set; int max_fd = -1; struct MsgPort *printmsgport = ami_print_get_msgport(); ULONG printsig = 0; ULONG helpsignal = ami_help_signal(); if(printmsgport) printsig = 1L << printmsgport->mp_SigBit; uint32 signalmask = winsignal | appsig | schedulesig | rxsig | printsig | applibsig | helpsignal; if ((fetcher_fdset(&read_fd_set, &write_fd_set, &except_fd_set, &max_fd) == NSERROR_OK) && (max_fd != -1)) { /* max_fd is the highest fd in use, but waitselect() needs to know how many * are in use, so we add 1. */ if (waitselect(max_fd + 1, &read_fd_set, &write_fd_set, &except_fd_set, NULL, (unsigned int *)&signalmask) != -1) { signal = signalmask; } else { LOG("waitselect() returned error"); /* \todo Fix Ctrl-C handling. * WaitSelect() from bsdsocket.library returns -1 if the task was * signalled with a Ctrl-C. waitselect() from newlib.library does not. * Adding the Ctrl-C signal to our user signal mask causes a Ctrl-C to * occur sporadically. Otherwise we never get a -1 except on error. * NetSurf still terminates at the Wait() when network activity is over. */ } } else { /* If fetcher_fdset fails or no network activity, do it the old fashioned way. */ signalmask |= ctrlcsig; signal = Wait(signalmask); } if(signal & winsignal) ami_handle_msg(); if(signal & appsig) ami_handle_appmsg(); if(signal & rxsig) ami_arexx_handle(); if(signal & applibsig) ami_handle_applib(); if(signal & printsig) { while(GetMsg(printmsgport)); //ReplyMsg ami_print_cont(); } if(signal & schedulesig) { ami_schedule_handle(schedulermsgport); } if(signal & helpsignal) ami_help_process(); if(signal & ctrlcsig) ami_quit_netsurf_delayed(); } void ami_change_tab(struct gui_window_2 *gwin, int direction) { struct Node *tab_node = gwin->gw->tab_node; struct Node *ptab = NULL; if(gwin->tabs <= 1) return; if(direction > 0) { ptab = GetSucc(tab_node); } else { ptab = GetPred(tab_node); } if(!ptab) return; RefreshSetGadgetAttrs((struct Gadget *)gwin->objects[GID_TABS], gwin->win, NULL, CLICKTAB_CurrentNode, ptab, TAG_DONE); ami_switch_tab(gwin, true); } void ami_switch_tab(struct gui_window_2 *gwin, bool redraw) { struct Node *tabnode; struct IBox *bbox; /* Clear the last new tab list */ gwin->gw->last_new_tab = NULL; if(gwin->tabs == 0) return; gui_window_get_scroll(gwin->gw, &gwin->gw->scrollx, &gwin->gw->scrolly); GetAttr(CLICKTAB_CurrentNode, (Object *)gwin->objects[GID_TABS], (ULONG *)&tabnode); GetClickTabNodeAttrs(tabnode, TNA_UserData, &gwin->gw, TAG_DONE); cur_gw = gwin->gw; if(ami_gui_get_space_box((Object *)gwin->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } if((gwin->gw->bw == NULL) || (browser_window_has_content(gwin->gw->bw)) == false) { RefreshSetGadgetAttrs((struct Gadget *)gwin->objects[GID_URL], gwin->win, NULL, STRINGA_TextVal, "", TAG_DONE); ami_plot_clear_bbox(gwin->win->RPort, bbox); ami_gui_free_space_box(bbox); return; } ami_plot_release_pens(&gwin->shared_pens); ami_update_buttons(gwin); ami_menu_update_disabled(gwin->gw, browser_window_get_content(gwin->gw->bw)); if(redraw) { ami_plot_clear_bbox(gwin->win->RPort, bbox); browser_window_update(gwin->gw->bw, false); gui_window_set_scroll(gwin->gw, gwin->gw->scrollx, gwin->gw->scrolly); gwin->redraw_scroll = false; browser_window_refresh_url_bar(gwin->gw->bw); ami_gui_update_hotlist_button(gwin); ami_gui_scroller_update(gwin); ami_throbber_redraw_schedule(0, gwin->gw); gui_window_set_icon(gwin->gw, gwin->gw->favicon); } ami_gui_free_space_box(bbox); } void ami_quit_netsurf(void) { struct nsObject *node; struct nsObject *nnode; struct gui_window_2 *gwin; if(!IsMinListEmpty(window_list)) { node = (struct nsObject *)GetHead((struct List *)window_list); do { nnode=(struct nsObject *)GetSucc((struct Node *)node); gwin = node->objstruct; switch(node->Type) { case AMINS_TVWINDOW: ami_tree_close((struct treeview_window *)gwin); break; case AMINS_WINDOW: /* This also closes windows that are attached to the * gui_window, such as local history and find. */ ShowWindow(gwin->win, WINDOW_BACKMOST); ami_close_all_tabs(gwin); break; case AMINS_GUIOPTSWINDOW: ami_gui_opts_close(); break; case AMINS_DLWINDOW: ami_download_window_abort((struct gui_download_window *)gwin); break; } } while((node = nnode)); win_destroyed = true; } if(IsMinListEmpty(window_list)) { /* last window closed, so exit */ ami_quit = true; } } void ami_quit_netsurf_delayed(void) { int res = -1; #ifdef __amigaos4__ char *utf8text = ami_utf8_easy(messages_get("TCPIPShutdown")); char *utf8gadgets = ami_utf8_easy(messages_get("AbortShutdown")); DisplayBeep(NULL); res = TimedDosRequesterTags(TDR_ImageType, TDRIMAGE_INFO, TDR_TitleString, messages_get("NetSurf"), TDR_FormatString, utf8text, TDR_GadgetString, utf8gadgets, TDR_Timeout, 5, TDR_Inactive, TRUE, TAG_DONE); free(utf8text); free(utf8gadgets); #endif if(res == -1) { /* Requester timed out */ nsoption_set_bool(tab_close_warn, false); ami_quit_netsurf(); } } static void ami_gui_close_screen(struct Screen *scrn, BOOL locked_screen, BOOL donotwait) { if(scrn == NULL) return; if(CloseScreen(scrn) == TRUE) { if(locked_screen == FALSE) { FreeSignal(screen_signal); screen_signal = -1; scrn = NULL; } return; } if(locked_screen == TRUE) return; if(donotwait == TRUE) return; /* If this is our own screen, wait for visitor windows to close */ if(screen_signal != -1) { ULONG scrnsig = 1 << screen_signal; LOG("Waiting for visitor windows to close... (signal)"); Wait(scrnsig); } while (CloseScreen(scrn) == FALSE) { LOG("Waiting for visitor windows to close... (polling)"); Delay(50); } FreeSignal(screen_signal); screen_signal = -1; scrn = NULL; } void ami_try_quit(void) { if(!IsMinListEmpty(window_list)) return; if(nsoption_bool(close_no_quit) == false) { ami_quit = true; return; } else { ami_gui_close_screen(scrn, locked_screen, TRUE); } } static void gui_quit(void) { ami_theme_throbber_free(); urldb_save(nsoption_charp(url_file)); urldb_save_cookies(nsoption_charp(cookie_file)); ami_hotlist_free(nsoption_charp(hotlist_file)); ami_cookies_free(); ami_global_history_free(); #ifdef __amigaos4__ if(IApplication && ami_appid) UnregisterApplication(ami_appid, NULL); #endif ami_arexx_cleanup(); ami_free_layers(&browserglob); ami_close_fonts(); ami_help_free(); LOG("Closing screen"); ami_gui_close_screen(scrn, locked_screen, FALSE); if(nsscreentitle) FreeVec(nsscreentitle); LOG("Freeing menu items"); ami_ctxmenu_free(); ami_menu_free_glyphs(); LOG("Freeing mouse pointers"); ami_mouse_pointers_free(); LOG("Freeing clipboard"); ami_clipboard_free(); LOG("Removing scheduler process"); ami_scheduler_process_delete(); FreeSysObject(ASOT_PORT, appport); FreeSysObject(ASOT_PORT, sport); FreeSysObject(ASOT_PORT, schedulermsgport); ami_file_req_free(); ami_openurl_close(); FreeStringClass(urlStringClass); FreeObjList(window_list); FreeVec(current_user_options); FreeVec(current_user_dir); FreeVec(current_user_faviconcache); FreeVec(current_user); ami_libs_close(); } char *ami_gui_get_cache_favicon_name(nsurl *url, bool only_if_avail) { STRPTR filename = NULL; BPTR lock = 0; if ((filename = ASPrintf("%s/%x", current_user_faviconcache, nsurl_hash(url)))) { LOG("favicon cache location: %s", filename); if (only_if_avail == true) { if((lock = Lock(filename, ACCESS_READ))) { UnLock(lock); return filename; } } else { return filename; } } return NULL; } static void ami_gui_cache_favicon(nsurl *url, struct bitmap *favicon) { STRPTR filename = NULL; if ((filename = ami_gui_get_cache_favicon_name(url, false))) { if(favicon) amiga_bitmap_save(favicon, filename, AMI_BITMAP_SCALE_ICON); FreeVec(filename); } } void ami_gui_update_hotlist_button(struct gui_window_2 *gwin) { char *url; nsurl *nsurl; GetAttr(STRINGA_TextVal, (Object *)gwin->objects[GID_URL], (ULONG *)&url); if(nsurl_create(url, &nsurl) == NSERROR_OK) { if(hotlist_has_url(nsurl)) { RefreshSetGadgetAttrs((struct Gadget *)gwin->objects[GID_FAVE], gwin->win, NULL, BUTTON_RenderImage, gwin->objects[GID_FAVE_RMV], TAG_DONE); if (gwin->gw->favicon) ami_gui_cache_favicon(nsurl, content_get_bitmap(gwin->gw->favicon)); } else { RefreshSetGadgetAttrs((struct Gadget *)gwin->objects[GID_FAVE], gwin->win, NULL, BUTTON_RenderImage, gwin->objects[GID_FAVE_ADD], TAG_DONE); } nsurl_unref(nsurl); } } static bool ami_gui_hotlist_add(void *userdata, int level, int item, const char *title, nsurl *url, bool is_folder) { struct ami_gui_tb_userdata *tb_userdata = (struct ami_gui_tb_userdata *)userdata; struct Node *speed_button_node; char menu_icon[1024]; if(level != 1) return false; if(item > AMI_GUI_TOOLBAR_MAX) return false; if(is_folder == true) return false; char *utf8title = ami_utf8_easy(title); if(utf8title == NULL) return false; char *iconname = ami_gui_get_cache_favicon_name(url, true); if (iconname == NULL) iconname = ASPrintf("icons/content.png"); ami_locate_resource(menu_icon, iconname); tb_userdata->gw->hotlist_toolbar_lab[item] = BitMapObj, IA_Scalable, TRUE, BITMAP_Screen, scrn, BITMAP_SourceFile, menu_icon, BITMAP_Masking, TRUE, BitMapEnd; /* \todo make this scale the bitmap to these dimensions */ SetAttrs(tb_userdata->gw->hotlist_toolbar_lab[item], BITMAP_Width, 16, BITMAP_Height, 16, TAG_DONE); Object *lab_item = LabelObj, // LABEL_DrawInfo, dri, LABEL_DisposeImage, TRUE, LABEL_Image, tb_userdata->gw->hotlist_toolbar_lab[item], LABEL_Text, " ", LABEL_Text, utf8title, LabelEnd; free(utf8title); speed_button_node = AllocSpeedButtonNode(item, SBNA_Image, lab_item, SBNA_UserData, (void *)url, TAG_DONE); AddTail(tb_userdata->sblist, speed_button_node); tb_userdata->items++; return true; } static int ami_gui_hotlist_scan(struct tree *tree, struct List *speed_button_list, struct gui_window_2 *gwin) { struct ami_gui_tb_userdata userdata; userdata.gw = gwin; userdata.sblist = speed_button_list; userdata.items = 0; ami_hotlist_scan((void *)&userdata, 0, messages_get("HotlistToolbar"), ami_gui_hotlist_add); return userdata.items; } static void ami_gui_hotlist_toolbar_add(struct gui_window_2 *gwin) { struct TagItem attrs[2]; attrs[0].ti_Tag = CHILD_MinWidth; attrs[0].ti_Data = 0; attrs[1].ti_Tag = TAG_DONE; attrs[1].ti_Data = 0; NewList(&gwin->hotlist_toolbar_list); if(ami_gui_hotlist_scan(ami_tree_get_tree(hotlist_window), &gwin->hotlist_toolbar_list, gwin) > 0) { gwin->objects[GID_HOTLIST] = SpeedBarObj, GA_ID, GID_HOTLIST, GA_RelVerify, TRUE, ICA_TARGET, ICTARGET_IDCMP, SPEEDBAR_BevelStyle, BVS_NONE, SPEEDBAR_Buttons, &gwin->hotlist_toolbar_list, SpeedBarEnd; gwin->objects[GID_HOTLISTSEPBAR] = BevelObj, BEVEL_Style, BVS_SBAR_VERT, BevelEnd; #ifdef __amigaos4__ IDoMethod(gwin->objects[GID_HOTLISTLAYOUT], LM_ADDCHILD, gwin->win, gwin->objects[GID_HOTLIST], attrs); IDoMethod(gwin->objects[GID_HOTLISTLAYOUT], LM_ADDIMAGE, gwin->win, gwin->objects[GID_HOTLISTSEPBAR], NULL); #else SetAttrs(gwin->objects[GID_HOTLISTLAYOUT], LAYOUT_AddChild, gwin->objects[GID_HOTLIST], TAG_MORE, &attrs); SetAttrs(gwin->objects[GID_HOTLISTLAYOUT], LAYOUT_AddChild, gwin->objects[GID_HOTLISTSEPBAR], TAG_DONE); #endif FlushLayoutDomainCache((struct Gadget *)gwin->objects[GID_MAIN]); RethinkLayout((struct Gadget *)gwin->objects[GID_MAIN], gwin->win, NULL, TRUE); ami_schedule_redraw(gwin, true); } } static void ami_gui_hotlist_toolbar_free(struct gui_window_2 *gwin, struct List *speed_button_list) { int i; struct Node *node; struct Node *nnode; if(nsoption_bool(kiosk_mode) == true) return; if(IsListEmpty(speed_button_list)) return; node = GetHead(speed_button_list); do { nnode = GetSucc(node); Remove(node); FreeSpeedButtonNode(node); } while((node = nnode)); for(i = 0; i < AMI_GUI_TOOLBAR_MAX; i++) { if(gwin->hotlist_toolbar_lab[i]) { DisposeObject(gwin->hotlist_toolbar_lab[i]); gwin->hotlist_toolbar_lab[i] = NULL; } } } static void ami_gui_hotlist_toolbar_remove(struct gui_window_2 *gwin) { #ifdef __amigaos4__ IDoMethod(gwin->objects[GID_HOTLISTLAYOUT], LM_REMOVECHILD, gwin->win, gwin->objects[GID_HOTLIST]); IDoMethod(gwin->objects[GID_HOTLISTLAYOUT], LM_REMOVECHILD, gwin->win, gwin->objects[GID_HOTLISTSEPBAR]); #else SetAttrs(gwin->objects[GID_HOTLISTLAYOUT], LAYOUT_RemoveChild, gwin->objects[GID_HOTLIST]); SetAttrs(gwin->objects[GID_HOTLISTLAYOUT], LAYOUT_RemoveChild, gwin->objects[GID_HOTLISTSEPBAR]); #endif FlushLayoutDomainCache((struct Gadget *)gwin->objects[GID_MAIN]); RethinkLayout((struct Gadget *)gwin->objects[GID_MAIN], gwin->win, NULL, TRUE); ami_schedule_redraw(gwin, true); } static void ami_gui_hotlist_toolbar_update(struct gui_window_2 *gwin) { if(IsListEmpty(&gwin->hotlist_toolbar_list)) { ami_gui_hotlist_toolbar_add(gwin); return; } /* Below should be SetAttr according to Autodocs */ SetGadgetAttrs((struct Gadget *)gwin->objects[GID_HOTLIST], gwin->win, NULL, SPEEDBAR_Buttons, ~0, TAG_DONE); ami_gui_hotlist_toolbar_free(gwin, &gwin->hotlist_toolbar_list); if(ami_gui_hotlist_scan(ami_tree_get_tree(hotlist_window), &gwin->hotlist_toolbar_list, gwin) > 0) { SetGadgetAttrs((struct Gadget *)gwin->objects[GID_HOTLIST], gwin->win, NULL, SPEEDBAR_Buttons, &gwin->hotlist_toolbar_list, TAG_DONE); } else { ami_gui_hotlist_toolbar_remove(gwin); } } /** * Update hotlist toolbar and recreate the menu for all windows */ void ami_gui_hotlist_update_all(void) { struct nsObject *node; struct nsObject *nnode; struct gui_window_2 *gwin; if(IsMinListEmpty(window_list)) return; node = (struct nsObject *)GetHead((struct List *)window_list); do { nnode=(struct nsObject *)GetSucc((struct Node *)node); gwin = node->objstruct; if(node->Type == AMINS_WINDOW) { ami_gui_hotlist_toolbar_update(gwin); ami_menu_refresh(gwin); } } while((node = nnode)); } static void ami_toggletabbar(struct gui_window_2 *gwin, bool show) { if(ClickTabBase->lib_Version < 53) return; if(show) { struct TagItem attrs[3]; attrs[0].ti_Tag = CHILD_WeightedWidth; attrs[0].ti_Data = 0; attrs[1].ti_Tag = CHILD_WeightedHeight; attrs[1].ti_Data = 0; attrs[2].ti_Tag = TAG_DONE; attrs[2].ti_Data = 0; gwin->objects[GID_TABS] = ClickTabObj, GA_ID, GID_TABS, GA_RelVerify, TRUE, GA_Underscore, 13, // disable kb shortcuts GA_ContextMenu, ami_ctxmenu_clicktab_create(gwin), CLICKTAB_Labels, &gwin->tab_list, CLICKTAB_LabelTruncate, TRUE, CLICKTAB_CloseImage, gwin->objects[GID_CLOSETAB_BM], CLICKTAB_FlagImage, gwin->objects[GID_TABS_FLAG], ClickTabEnd; gwin->objects[GID_ADDTAB] = ButtonObj, GA_ID, GID_ADDTAB, GA_RelVerify, TRUE, GA_HintInfo, gwin->helphints[GID_ADDTAB], GA_Text, "+", BUTTON_RenderImage, gwin->objects[GID_ADDTAB_BM], ButtonEnd; #ifdef __amigaos4__ IDoMethod(gwin->objects[GID_TABLAYOUT], LM_ADDCHILD, gwin->win, gwin->objects[GID_TABS], NULL); IDoMethod(gwin->objects[GID_TABLAYOUT], LM_ADDCHILD, gwin->win, gwin->objects[GID_ADDTAB], attrs); #else SetAttrs(gwin->objects[GID_TABLAYOUT], LAYOUT_AddChild, gwin->objects[GID_TABS], TAG_DONE); SetAttrs(gwin->objects[GID_TABLAYOUT], LAYOUT_AddChild, gwin->objects[GID_ADDTAB], TAG_MORE, &attrs); #endif } else { #ifdef __amigaos4__ IDoMethod(gwin->objects[GID_TABLAYOUT], LM_REMOVECHILD, gwin->win, gwin->objects[GID_TABS]); IDoMethod(gwin->objects[GID_TABLAYOUT], LM_REMOVECHILD, gwin->win, gwin->objects[GID_ADDTAB]); #else SetAttrs(gwin->objects[GID_TABLAYOUT], LAYOUT_RemoveChild, gwin->objects[GID_TABS], TAG_DONE); SetAttrs(gwin->objects[GID_TABLAYOUT], LAYOUT_RemoveChild, gwin->objects[GID_ADDTAB], TAG_DONE); #endif gwin->objects[GID_TABS] = NULL; gwin->objects[GID_ADDTAB] = NULL; } FlushLayoutDomainCache((struct Gadget *)gwin->objects[GID_MAIN]); RethinkLayout((struct Gadget *)gwin->objects[GID_MAIN], gwin->win, NULL, TRUE); if(gwin->gw && gwin->gw->bw) browser_window_update(gwin->gw->bw, false); } void ami_gui_tabs_toggle_all(void) { struct nsObject *node; struct nsObject *nnode; struct gui_window_2 *gwin; if(IsMinListEmpty(window_list)) return; node = (struct nsObject *)GetHead((struct List *)window_list); do { nnode=(struct nsObject *)GetSucc((struct Node *)node); gwin = node->objstruct; if(node->Type == AMINS_WINDOW) { if(gwin->tabs == 1) { if(nsoption_bool(tab_always_show) == true) { ami_toggletabbar(gwin, true); } else { ami_toggletabbar(gwin, false); } } } } while((node = nnode)); } static void ami_gui_search_ico_refresh(void *p) { search_web_select_provider(-1); } /** * Count windows, and optionally tabs. * * \param window window to count tabs of * \param tabs if window > 0, will be updated to contain the number of tabs * in that window, unchanged otherwise * \return number of windows currently open */ int ami_gui_count_windows(int window, int *tabs) { int windows = 0; struct nsObject *node, *nnode; struct gui_window_2 *gwin; if(!IsMinListEmpty(window_list)) { node = (struct nsObject *)GetHead((struct List *)window_list); do { nnode=(struct nsObject *)GetSucc((struct Node *)node); gwin = node->objstruct; if(node->Type == AMINS_WINDOW) { windows++; if(window == windows) *tabs = gwin->tabs; } } while((node = nnode)); } return windows; } /** * Set the scale of a gui window * * \param gw gui_window to set scale for * \param scale scale to set */ void ami_gui_set_scale(struct gui_window *gw, float scale) { if(scale <= 0.0) return; gw->scale = scale; browser_window_set_scale(gw->bw, scale, true); } nserror ami_gui_new_blank_tab(struct gui_window_2 *gwin) { nsurl *url; nserror error; struct browser_window *bw = NULL; error = nsurl_create(nsoption_charp(homepage_url), &url); if (error == NSERROR_OK) { error = browser_window_create(BW_CREATE_HISTORY | BW_CREATE_TAB, url, NULL, gwin->gw->bw, &bw); nsurl_unref(url); } if (error != NSERROR_OK) { warn_user(messages_get_errorcode(error), 0); return error; } return NSERROR_OK; } static void ami_do_redraw_tiled(struct gui_window_2 *gwin, bool busy, int left, int top, int width, int height, int sx, int sy, struct IBox *bbox, struct redraw_context *ctx) { int x, y; struct rect clip; int tile_size_x = glob->width; int tile_size_y = glob->height; int tile_x_scale = (int)(tile_size_x / gwin->gw->scale); int tile_y_scale = (int)(tile_size_y / gwin->gw->scale); browserglob.shared_pens = &gwin->shared_pens; /* do we need this?? */ if(top < 0) { height += top; top = 0; } if(left < 0) { width += left; left = 0; } if(top < sy) { height += (top - sy); top = sy; } if(left < sx) { width += (left - sx); left = sx; } if(((top - sy) + height) > bbox->Height) height = bbox->Height - (top - sy); if(((left - sx) + width) > bbox->Width) width = bbox->Width - (left - sx); if(width <= 0) return; if(height <= 0) return; if(busy) ami_set_pointer(gwin, GUI_POINTER_WAIT, false); for(y = top; y < (top + height); y += tile_y_scale) { clip.y0 = 0; clip.y1 = tile_size_y; if(clip.y1 > height) clip.y1 = height; if((((y - sy) * gwin->gw->scale) + clip.y1) > bbox->Height) clip.y1 = bbox->Height - ((y - sy) * gwin->gw->scale); for(x = left; x < (left + width); x += tile_x_scale) { clip.x0 = 0; clip.x1 = tile_size_x; if(clip.x1 > width) clip.x1 = width; if((((x - sx) * gwin->gw->scale) + clip.x1) > bbox->Width) clip.x1 = bbox->Width - ((x - sx) * gwin->gw->scale); if(browser_window_redraw(gwin->gw->bw, clip.x0 - (int)x, clip.y0 - (int)y, &clip, ctx)) { ami_clearclipreg(&browserglob); #ifdef __amigaos4__ 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 + (int)((x - sx) * gwin->gw->scale), BLITA_DestY, bbox->Top + (int)((y - sy) * gwin->gw->scale), BLITA_Width, (int)(clip.x1), BLITA_Height, (int)(clip.y1), TAG_DONE); #else BltBitMapRastPort(browserglob.bm, 0, 0, gwin->win->RPort, bbox->Left + (int)((x - sx) * gwin->gw->scale), bbox->Top + (int)((y - sy) * gwin->gw->scale), (int)(clip.x1), (int)(clip.y1), 0xC0); #endif } } } if(busy) ami_reset_pointer(gwin); } /** * Redraw an area of the browser window - Amiga-specific function * * \param g a struct gui_window * \param bw a struct browser_window * \param busy busy flag passed to tiled redraw. * \param x0 top-left co-ordinate (in document co-ordinates) * \param y0 top-left co-ordinate (in document co-ordinates) * \param x1 bottom-right co-ordinate (in document co-ordinates) * \param y1 bottom-right co-ordinate (in document co-ordinates) */ static void ami_do_redraw_limits(struct gui_window *g, struct browser_window *bw, bool busy, int x0, int y0, int x1, int y1) { struct IBox *bbox; ULONG sx, sy; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &amiplot }; if(!g) return; if(browser_window_redraw_ready(bw) == false) return; sx = g->scrollx; sy = g->scrolly; if(g != g->shared->gw) return; if(ami_gui_get_space_box((Object *)g->shared->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } ami_do_redraw_tiled(g->shared, busy, x0, y0, (x1 - x0) * g->scale, (y1 - y0) * g->scale, sx, sy, bbox, &ctx); ami_gui_free_space_box(bbox); return; } static void ami_refresh_window(struct gui_window_2 *gwin) { /* simplerefresh only */ struct IBox *bbox; int x0, x1, y0, y1, sx, sy; struct RegionRectangle *regrect; sx = gwin->gw->scrollx; sy = gwin->gw->scrolly; ami_set_pointer(gwin, GUI_POINTER_WAIT, false); if(ami_gui_get_space_box((Object *)gwin->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } BeginRefresh(gwin->win); x0 = ((gwin->win->RPort->Layer->DamageList->bounds.MinX - bbox->Left) / browser_window_get_scale(gwin->gw->bw)) + sx - 1; x1 = ((gwin->win->RPort->Layer->DamageList->bounds.MaxX - bbox->Left) / browser_window_get_scale(gwin->gw->bw)) + sx + 2; y0 = ((gwin->win->RPort->Layer->DamageList->bounds.MinY - bbox->Top) / browser_window_get_scale(gwin->gw->bw)) + sy - 1; y1 = ((gwin->win->RPort->Layer->DamageList->bounds.MaxY - bbox->Top) / browser_window_get_scale(gwin->gw->bw)) + sy + 2; regrect = gwin->win->RPort->Layer->DamageList->RegionRectangle; ami_do_redraw_limits(gwin->gw, gwin->gw->bw, false, x0, y0, x1, y1); while(regrect) { x0 = ((regrect->bounds.MinX - bbox->Left) / browser_window_get_scale(gwin->gw->bw)) + sx - 1; x1 = ((regrect->bounds.MaxX - bbox->Left) / browser_window_get_scale(gwin->gw->bw)) + sx + 2; y0 = ((regrect->bounds.MinY - bbox->Top) / browser_window_get_scale(gwin->gw->bw)) + sy - 1; y1 = ((regrect->bounds.MaxY - bbox->Top) / browser_window_get_scale(gwin->gw->bw)) + sy + 2; regrect = regrect->Next; ami_do_redraw_limits(gwin->gw, gwin->gw->bw, false, x0, y0, x1, y1); } EndRefresh(gwin->win, TRUE); ami_gui_free_space_box(bbox); ami_reset_pointer(gwin); } HOOKF(void, ami_scroller_hook, Object *, object, struct IntuiMessage *) { ULONG gid; struct gui_window_2 *gwin = hook->h_Data; struct IntuiWheelData *wheel; struct Node *node = NULL; nsurl *url; switch(msg->Class) { case IDCMP_IDCMPUPDATE: gid = GetTagData( GA_ID, 0, msg->IAddress ); switch( gid ) { case GID_HSCROLL: case GID_VSCROLL: if(nsoption_bool(faster_scroll) == true) gwin->redraw_scroll = true; else gwin->redraw_scroll = false; ami_schedule_redraw(gwin, true); break; case GID_HOTLIST: if((node = (struct Node *)GetTagData(SPEEDBAR_SelectedNode, 0, msg->IAddress))) { GetSpeedButtonNodeAttrs(node, SBNA_UserData, (ULONG *)&url, TAG_DONE); if(gwin->key_state & BROWSER_MOUSE_MOD_2) { browser_window_create(BW_CREATE_TAB, url, NULL, gwin->gw->bw, NULL); } else { browser_window_navigate(gwin->gw->bw, url, NULL, BW_NAVIGATE_HISTORY, NULL, NULL, NULL); } } break; } break; #ifdef __amigaos4__ case IDCMP_EXTENDEDMOUSE: if(msg->Code == IMSGCODE_INTUIWHEELDATA) { wheel = (struct IntuiWheelData *)msg->IAddress; ami_gui_scroll_internal(gwin, wheel->WheelX * 50, wheel->WheelY * 50); } break; #endif case IDCMP_SIZEVERIFY: break; case IDCMP_REFRESHWINDOW: ami_refresh_window(gwin); break; default: LOG("IDCMP hook unhandled event: %d\n", msg->Class); break; } // ReplyMsg((struct Message *)msg); } static struct gui_window * gui_window_create(struct browser_window *bw, struct gui_window *existing, gui_window_create_flags flags) { struct gui_window *g = NULL; ULONG offset = 0; ULONG curx = nsoption_int(window_x), cury = nsoption_int(window_y); ULONG curw = nsoption_int(window_width), curh = nsoption_int(window_height); char nav_west[100],nav_west_s[100],nav_west_g[100]; char nav_east[100],nav_east_s[100],nav_east_g[100]; char stop[100],stop_s[100],stop_g[100]; char reload[100],reload_s[100],reload_g[100]; char home[100],home_s[100],home_g[100]; char closetab[100],closetab_s[100],closetab_g[100]; char addtab[100],addtab_s[100],addtab_g[100]; char fave[100], unfave[100]; char tabthrobber[100]; ULONG refresh_mode = WA_SmartRefresh; ULONG defer_layout = TRUE; ULONG idcmp_sizeverify = IDCMP_SIZEVERIFY; if (!scrn) ami_openscreenfirst(); if (nsoption_bool(kiosk_mode)) flags &= ~GW_CREATE_TAB; if (nsoption_bool(resize_with_contents)) idcmp_sizeverify = 0; /* Offset the new window by titlebar + 1 as per AmigaOS style guide. * If we don't have a clone window we offset by all windows open. */ offset = scrn->WBorTop + scrn->Font->ta_YSize + 1; if(existing) { curx = existing->shared->win->LeftEdge; cury = existing->shared->win->TopEdge + offset; curw = existing->shared->win->Width; curh = existing->shared->win->Height; } else { if(nsoption_bool(kiosk_mode) == false) { cury += offset * ami_gui_count_windows(0, NULL); } } if(curh > (scrn->Height - cury)) curh = scrn->Height - cury; g = ami_misc_allocvec_clear(sizeof(struct gui_window), 0); if(!g) { warn_user("NoMemory",""); return NULL; } NewList(&g->dllist); g->deferred_rects = NewObjList(); g->bw = bw; g->scale = browser_window_get_scale(bw); if((flags & GW_CREATE_TAB) && existing) { g->shared = existing->shared; g->tab = g->shared->next_tab; g->shared->tabs++; /* do this early so functions know to update the tabs */ if((g->shared->tabs == 2) && (nsoption_bool(tab_always_show) == false)) { ami_toggletabbar(g->shared, true); } SetGadgetAttrs((struct Gadget *)g->shared->objects[GID_TABS], g->shared->win, NULL, CLICKTAB_Labels, ~0, TAG_DONE); g->tab_node = AllocClickTabNode(TNA_Text, messages_get("NetSurf"), TNA_Number, g->tab, TNA_UserData, g, TNA_CloseGadget, TRUE, TAG_DONE); if(nsoption_bool(new_tab_last)) { AddTail(&g->shared->tab_list, g->tab_node); } else { struct Node *insert_after = existing->tab_node; if(existing->last_new_tab) insert_after = existing->last_new_tab; Insert(&g->shared->tab_list, g->tab_node, insert_after); existing->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_is_active)) { 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 *)g->shared->objects[GID_TABLAYOUT], g->shared->win, NULL, TRUE); } g->shared->next_tab++; if(nsoption_bool(new_tab_is_active)) ami_switch_tab(g->shared,false); ami_update_buttons(g->shared); ami_schedule(0, ami_gui_refresh_favicon, g->shared); return g; } g->shared = ami_misc_allocvec_clear(sizeof(struct gui_window_2), 0); if(!g->shared) { warn_user("NoMemory",""); return NULL; } ami_NewMinList(&g->shared->shared_pens); g->shared->scrollerhook.h_Entry = (void *)ami_scroller_hook; g->shared->scrollerhook.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; g->shared->ctxmenu_hook = ami_ctxmenu_get_hook(g->shared); g->shared->history_ctxmenu[AMI_CTXMENU_HISTORY_BACK] = NULL; g->shared->history_ctxmenu[AMI_CTXMENU_HISTORY_FORWARD] = NULL; g->shared->clicktab_ctxmenu = NULL; if(nsoption_bool(window_simple_refresh) == true) { refresh_mode = WA_SimpleRefresh; defer_layout = FALSE; /* testing reveals this does work with SimpleRefresh, but the docs say it doesn't so err on the side of caution. */ } else { refresh_mode = WA_SmartRefresh; defer_layout = TRUE; } if(!nsoption_bool(kiosk_mode)) { ULONG addtabclosegadget = TAG_IGNORE; ULONG iconifygadget = FALSE; if (nsoption_charp(pubscreen_name) && (locked_screen == TRUE) && (strcmp(nsoption_charp(pubscreen_name), "Workbench") == 0)) iconifygadget = TRUE; struct Menu *menu = ami_menu_create(g->shared); NewList(&g->shared->tab_list); g->tab_node = AllocClickTabNode(TNA_Text,messages_get("NetSurf"), TNA_Number, 0, TNA_UserData, g, TNA_CloseGadget, TRUE, TAG_DONE); AddTail(&g->shared->tab_list,g->tab_node); g->shared->web_search_list = ami_gui_opts_websearch(); g->shared->search_bm = NULL; g->shared->tabs=1; g->shared->next_tab=1; g->shared->svbuffer = ami_misc_allocvec_clear(2000, 0); g->shared->helphints[GID_BACK] = translate_escape_chars(messages_get("HelpToolbarBack")); g->shared->helphints[GID_FORWARD] = translate_escape_chars(messages_get("HelpToolbarForward")); g->shared->helphints[GID_STOP] = translate_escape_chars(messages_get("HelpToolbarStop")); g->shared->helphints[GID_RELOAD] = translate_escape_chars(messages_get("HelpToolbarReload")); g->shared->helphints[GID_HOME] = translate_escape_chars(messages_get("HelpToolbarHome")); g->shared->helphints[GID_URL] = translate_escape_chars(messages_get("HelpToolbarURL")); g->shared->helphints[GID_SEARCHSTRING] = translate_escape_chars(messages_get("HelpToolbarWebSearch")); g->shared->helphints[GID_ADDTAB] = translate_escape_chars(messages_get("HelpToolbarAddTab")); ami_get_theme_filename(nav_west, "theme_nav_west", false); ami_get_theme_filename(nav_west_s, "theme_nav_west_s", false); ami_get_theme_filename(nav_west_g, "theme_nav_west_g", false); ami_get_theme_filename(nav_east, "theme_nav_east", false); ami_get_theme_filename(nav_east_s, "theme_nav_east_s", false); ami_get_theme_filename(nav_east_g, "theme_nav_east_g", false); ami_get_theme_filename(stop, "theme_stop", false); ami_get_theme_filename(stop_s, "theme_stop_s", false); ami_get_theme_filename(stop_g, "theme_stop_g", false); ami_get_theme_filename(reload, "theme_reload", false); ami_get_theme_filename(reload_s, "theme_reload_s", false); ami_get_theme_filename(reload_g, "theme_reload_g", false); ami_get_theme_filename(home, "theme_home", false); ami_get_theme_filename(home_s, "theme_home_s", false); ami_get_theme_filename(home_g, "theme_home_g", false); ami_get_theme_filename(closetab, "theme_closetab", false); ami_get_theme_filename(closetab_s, "theme_closetab_s", false); ami_get_theme_filename(closetab_g, "theme_closetab_g", false); ami_get_theme_filename(addtab, "theme_addtab", false); ami_get_theme_filename(addtab_s, "theme_addtab_s", false); ami_get_theme_filename(addtab_g, "theme_addtab_g", false); ami_get_theme_filename(tabthrobber, "theme_tab_loading", false); ami_get_theme_filename(fave, "theme_fave", false); ami_get_theme_filename(unfave, "theme_unfave", false); g->shared->objects[GID_FAVE_ADD] = BitMapObj, BITMAP_SourceFile, fave, BITMAP_Screen, scrn, BITMAP_Masking, TRUE, BitMapEnd; g->shared->objects[GID_FAVE_RMV] = BitMapObj, BITMAP_SourceFile, unfave, BITMAP_Screen, scrn, BITMAP_Masking, TRUE, BitMapEnd; g->shared->objects[GID_ADDTAB_BM] = BitMapObj, BITMAP_SourceFile, addtab, BITMAP_SelectSourceFile, addtab_s, BITMAP_DisabledSourceFile, addtab_g, BITMAP_Screen, scrn, BITMAP_Masking, TRUE, BitMapEnd; g->shared->objects[GID_CLOSETAB_BM] = BitMapObj, BITMAP_SourceFile, closetab, BITMAP_SelectSourceFile, closetab_s, BITMAP_DisabledSourceFile, closetab_g, BITMAP_Screen, scrn, BITMAP_Masking, TRUE, BitMapEnd; if(ClickTabBase->lib_Version < 53) { #ifdef __amigaos4__ addtabclosegadget = LAYOUT_AddChild; g->shared->objects[GID_CLOSETAB] = ButtonObj, GA_ID, GID_CLOSETAB, GA_RelVerify, TRUE, BUTTON_RenderImage, g->shared->objects[GID_CLOSETAB_BM], ButtonEnd; g->shared->objects[GID_TABS] = ClickTabObj, GA_ID,GID_TABS, GA_RelVerify,TRUE, GA_Underscore,13, // disable kb shortcuts CLICKTAB_Labels,&g->shared->tab_list, CLICKTAB_LabelTruncate,TRUE, ClickTabEnd; g->shared->objects[GID_ADDTAB] = ButtonObj, GA_ID, GID_ADDTAB, GA_RelVerify, TRUE, GA_Text, "+", BUTTON_RenderImage, g->shared->objects[GID_ADDTAB_BM], ButtonEnd; #else #warning OS3 tab bar permanently disabled! #endif } else { g->shared->objects[GID_TABS_FLAG] = BitMapObj, BITMAP_SourceFile, tabthrobber, BITMAP_Screen,scrn, BITMAP_Masking,TRUE, BitMapEnd; } LOG("Creating window object"); g->shared->objects[OID_MAIN] = WindowObj, WA_ScreenTitle, ami_gui_get_screen_title(), WA_Activate, TRUE, WA_DepthGadget, TRUE, WA_DragBar, TRUE, WA_CloseGadget, TRUE, WA_SizeGadget, TRUE, WA_Top,cury, WA_Left,curx, WA_Width,curw, WA_Height,curh, WA_PubScreen,scrn, WA_ReportMouse,TRUE, refresh_mode, TRUE, WA_SizeBBottom, TRUE, WA_ContextMenuHook, g->shared->ctxmenu_hook, WA_IDCMP, IDCMP_MENUPICK | IDCMP_MOUSEMOVE | IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE | IDCMP_RAWKEY | idcmp_sizeverify | IDCMP_GADGETUP | IDCMP_IDCMPUPDATE | IDCMP_REFRESHWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_EXTENDEDMOUSE, WINDOW_IconifyGadget, iconifygadget, WINDOW_MenuStrip, menu, WINDOW_MenuUserData, WGUD_HOOK, WINDOW_NewPrefsHook, &newprefs_hook, 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, g->shared, WINDOW_ParentGroup, g->shared->objects[GID_MAIN] = LayoutVObj, LAYOUT_DeferLayout, defer_layout, LAYOUT_SpaceOuter, TRUE, LAYOUT_AddChild, g->shared->objects[GID_TOOLBARLAYOUT] = LayoutHObj, LAYOUT_VertAlignment, LALIGN_CENTER, LAYOUT_AddChild, g->shared->objects[GID_BACK] = ButtonObj, GA_ID, GID_BACK, GA_RelVerify, TRUE, GA_Disabled, TRUE, GA_ContextMenu, ami_ctxmenu_history_create(AMI_CTXMENU_HISTORY_BACK, g->shared), GA_HintInfo, g->shared->helphints[GID_BACK], BUTTON_RenderImage,BitMapObj, BITMAP_SourceFile,nav_west, BITMAP_SelectSourceFile,nav_west_s, BITMAP_DisabledSourceFile,nav_west_g, BITMAP_Screen,scrn, BITMAP_Masking,TRUE, BitMapEnd, ButtonEnd, CHILD_WeightedWidth,0, CHILD_WeightedHeight,0, LAYOUT_AddChild, g->shared->objects[GID_FORWARD] = ButtonObj, GA_ID, GID_FORWARD, GA_RelVerify, TRUE, GA_Disabled, TRUE, GA_ContextMenu, ami_ctxmenu_history_create(AMI_CTXMENU_HISTORY_FORWARD, g->shared), GA_HintInfo, g->shared->helphints[GID_FORWARD], BUTTON_RenderImage,BitMapObj, BITMAP_SourceFile,nav_east, BITMAP_SelectSourceFile,nav_east_s, BITMAP_DisabledSourceFile,nav_east_g, BITMAP_Screen,scrn, BITMAP_Masking,TRUE, BitMapEnd, ButtonEnd, CHILD_WeightedWidth,0, CHILD_WeightedHeight,0, LAYOUT_AddChild, g->shared->objects[GID_STOP] = ButtonObj, GA_ID,GID_STOP, GA_RelVerify,TRUE, GA_HintInfo, g->shared->helphints[GID_STOP], BUTTON_RenderImage,BitMapObj, BITMAP_SourceFile,stop, BITMAP_SelectSourceFile,stop_s, BITMAP_DisabledSourceFile,stop_g, BITMAP_Screen,scrn, BITMAP_Masking,TRUE, BitMapEnd, ButtonEnd, CHILD_WeightedWidth,0, CHILD_WeightedHeight,0, LAYOUT_AddChild, g->shared->objects[GID_RELOAD] = ButtonObj, GA_ID,GID_RELOAD, GA_RelVerify,TRUE, GA_HintInfo, g->shared->helphints[GID_RELOAD], BUTTON_RenderImage,BitMapObj, BITMAP_SourceFile,reload, BITMAP_SelectSourceFile,reload_s, BITMAP_DisabledSourceFile,reload_g, BITMAP_Screen,scrn, BITMAP_Masking,TRUE, BitMapEnd, ButtonEnd, CHILD_WeightedWidth,0, CHILD_WeightedHeight,0, LAYOUT_AddChild, g->shared->objects[GID_HOME] = ButtonObj, GA_ID,GID_HOME, GA_RelVerify,TRUE, GA_HintInfo, g->shared->helphints[GID_HOME], BUTTON_RenderImage,BitMapObj, BITMAP_SourceFile,home, BITMAP_SelectSourceFile,home_s, BITMAP_DisabledSourceFile,home_g, BITMAP_Screen,scrn, BITMAP_Masking,TRUE, BitMapEnd, ButtonEnd, CHILD_WeightedWidth,0, CHILD_WeightedHeight,0, LAYOUT_AddChild, LayoutHObj, // FavIcon, URL bar and hotlist star LAYOUT_VertAlignment, LALIGN_CENTER, LAYOUT_AddChild, g->shared->objects[GID_ICON] = SpaceObj, GA_ID, GID_ICON, SPACE_MinWidth, 16, SPACE_MinHeight, 16, SPACE_Transparent, TRUE, // SPACE_RenderHook, &g->shared->favicon_hook, SpaceEnd, CHILD_WeightedWidth, 0, CHILD_WeightedHeight, 0, LAYOUT_AddChild, g->shared->objects[GID_URL] = #ifdef __amigaos4__ NewObject(urlStringClass, NULL, #else StringObj, #endif STRINGA_MaxChars, 2000, GA_ID, GID_URL, GA_RelVerify, TRUE, GA_HintInfo, g->shared->helphints[GID_URL], GA_TabCycle, TRUE, STRINGA_Buffer, g->shared->svbuffer, #ifdef __amigaos4__ STRINGVIEW_Header, URLHistory_GetList(), #endif TAG_DONE), LAYOUT_AddChild, g->shared->objects[GID_FAVE] = ButtonObj, GA_ID, GID_FAVE, GA_RelVerify, TRUE, // GA_HintInfo, g->shared->helphints[GID_FAVE], BUTTON_RenderImage, g->shared->objects[GID_FAVE_ADD], ButtonEnd, CHILD_WeightedWidth, 0, CHILD_WeightedHeight, 0, LayoutEnd, // GA_ID, GID_TOOLBARLAYOUT, // GA_RelVerify, TRUE, // LAYOUT_RelVerify, TRUE, LAYOUT_WeightBar, TRUE, LAYOUT_AddChild, LayoutHObj, LAYOUT_VertAlignment, LALIGN_CENTER, LAYOUT_AddChild, g->shared->objects[GID_SEARCH_ICON] = ChooserObj, GA_ID, GID_SEARCH_ICON, GA_RelVerify, TRUE, CHOOSER_DropDown, TRUE, CHOOSER_Labels, g->shared->web_search_list, CHOOSER_MaxLabels, 40, /* Same as options GUI */ ChooserEnd, CHILD_WeightedWidth,0, CHILD_WeightedHeight,0, LAYOUT_AddChild, g->shared->objects[GID_SEARCHSTRING] = StringObj, GA_ID,GID_SEARCHSTRING, STRINGA_TextVal, NULL, GA_RelVerify,TRUE, GA_HintInfo, g->shared->helphints[GID_SEARCHSTRING], StringEnd, LayoutEnd, CHILD_WeightedWidth, nsoption_int(web_search_width), LAYOUT_AddChild, g->shared->objects[GID_THROBBER] = SpaceObj, GA_ID,GID_THROBBER, SPACE_MinWidth,throbber_width, SPACE_MinHeight,throbber_height, SPACE_Transparent,TRUE, // SPACE_RenderHook, &g->shared->throbber_hook, SpaceEnd, CHILD_WeightedWidth,0, CHILD_WeightedHeight,0, LayoutEnd, CHILD_WeightedHeight,0, LAYOUT_AddImage, BevelObj, BEVEL_Style, BVS_SBAR_VERT, BevelEnd, CHILD_WeightedHeight, 0, LAYOUT_AddChild, g->shared->objects[GID_HOTLISTLAYOUT] = LayoutVObj, LAYOUT_SpaceInner, FALSE, LayoutEnd, CHILD_WeightedHeight,0, LAYOUT_AddChild, g->shared->objects[GID_TABLAYOUT] = LayoutHObj, LAYOUT_SpaceInner,FALSE, addtabclosegadget, g->shared->objects[GID_CLOSETAB], CHILD_WeightedWidth,0, CHILD_WeightedHeight,0, addtabclosegadget, g->shared->objects[GID_TABS], CHILD_CacheDomain,FALSE, addtabclosegadget, g->shared->objects[GID_ADDTAB], CHILD_WeightedWidth,0, CHILD_WeightedHeight,0, LayoutEnd, CHILD_WeightedHeight,0, LAYOUT_AddChild, g->shared->objects[GID_VSCROLLLAYOUT] = LayoutHObj, LAYOUT_AddChild, g->shared->objects[GID_HSCROLLLAYOUT] = LayoutVObj, LAYOUT_AddChild, g->shared->objects[GID_BROWSER] = SpaceObj, GA_ID,GID_BROWSER, SPACE_Transparent,TRUE, SpaceEnd, EndGroup, EndGroup, EndGroup, EndWindow; } else { /* borderless kiosk mode window */ g->tab = 0; g->shared->tabs = 0; g->tab_node = NULL; g->shared->objects[OID_MAIN] = WindowObj, WA_ScreenTitle, ami_gui_get_screen_title(), WA_Activate, TRUE, WA_DepthGadget, FALSE, WA_DragBar, FALSE, WA_CloseGadget, FALSE, WA_Borderless,TRUE, WA_RMBTrap,TRUE, WA_Top,0, WA_Left,0, WA_Width, scrn->Width, WA_Height, scrn->Height, WA_SizeGadget, FALSE, WA_PubScreen, scrn, WA_ReportMouse, TRUE, refresh_mode, TRUE, WA_IDCMP, IDCMP_MENUPICK | IDCMP_MOUSEMOVE | IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE | IDCMP_RAWKEY | IDCMP_REFRESHWINDOW | IDCMP_GADGETUP | IDCMP_IDCMPUPDATE | IDCMP_EXTENDEDMOUSE, WINDOW_IDCMPHook,&g->shared->scrollerhook, WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE | IDCMP_EXTENDEDMOUSE | IDCMP_REFRESHWINDOW, WINDOW_SharedPort,sport, WINDOW_UserData,g->shared, WINDOW_BuiltInScroll,TRUE, WINDOW_ParentGroup, g->shared->objects[GID_MAIN] = LayoutHObj, LAYOUT_DeferLayout, defer_layout, LAYOUT_SpaceOuter, TRUE, LAYOUT_AddChild, g->shared->objects[GID_VSCROLLLAYOUT] = LayoutHObj, LAYOUT_AddChild, g->shared->objects[GID_HSCROLLLAYOUT] = LayoutVObj, LAYOUT_AddChild, g->shared->objects[GID_BROWSER] = SpaceObj, GA_ID,GID_BROWSER, SPACE_Transparent,TRUE, SpaceEnd, EndGroup, EndGroup, EndGroup, EndWindow; } LOG("Opening window"); g->shared->win = (struct Window *)RA_OpenWindow(g->shared->objects[OID_MAIN]); LOG("Window opened, adding border gadgets"); if(!g->shared->win) { warn_user("NoMemory",""); FreeVec(g->shared); FreeVec(g); return NULL; } if(nsoption_bool(kiosk_mode) == false) { ULONG sz, width, height; struct DrawInfo *dri = GetScreenDrawInfo(scrn); sz = ami_get_border_gadget_size(g->shared, (ULONG *)&width, (ULONG *)&height); g->shared->objects[GID_STATUS] = NewObject( NULL, "frbuttonclass", /**\todo find appropriate class which works on OS3 */ GA_ID, GID_STATUS, GA_Left, scrn->WBorLeft + 2, #ifdef __amigaos4__ GA_RelBottom, scrn->WBorBottom - (height/2), GA_BottomBorder, TRUE, #else GA_Top, g->shared->win->Height, #endif GA_Width, width, GA_Height, 1 + height - scrn->WBorBottom, GA_DrawInfo, dri, GA_ReadOnly, TRUE, GA_Disabled, TRUE, GA_Image, (struct Image *)NewObject( NULL, #ifdef __amigaos4__ "gaugeiclass", GAUGEIA_Level, 0, #else "frameiclass", IA_Recessed, TRUE, #endif IA_Top, (int)(- ceil((scrn->WBorBottom + height) / 2)), IA_Left, -4, IA_Height, 2 + height - scrn->WBorBottom, IA_Label, NULL, IA_InBorder, TRUE, IA_Screen, scrn, TAG_DONE), TAG_DONE); 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 *)g->shared->objects[GID_STATUS], g->shared->win, NULL, GA_Width, width, TAG_DONE); RefreshGadgets((APTR)g->shared->objects[GID_STATUS], g->shared->win, NULL); FreeScreenDrawInfo(scrn, dri); ami_gui_hotlist_toolbar_add(g->shared); /* is this the right place for this? */ if(nsoption_bool(tab_always_show)) ami_toggletabbar(g->shared, true); } g->shared->rmbtrapped = FALSE; g->shared->gw = g; cur_gw = g; 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); ami_schedule(0, ami_gui_search_ico_refresh, NULL); ScreenToFront(scrn); return g; } void ami_close_all_tabs(struct gui_window_2 *gwin) { struct Node *tab; struct Node *ntab; if((gwin->tabs > 1) && (nsoption_bool(tab_close_warn) == true)) { char *req_body = ami_utf8_easy(messages_get("MultiTabClose")); int32 res = ami_warn_user_multi(req_body, "Yes", "No", gwin->win); free(req_body); if(res == 0) return; } if(gwin->tabs) { tab = GetHead(&gwin->tab_list); do { ntab=GetSucc(tab); GetClickTabNodeAttrs(tab, TNA_UserData,&gwin->gw, TAG_DONE); browser_window_destroy(gwin->gw->bw); } while((tab=ntab)); } else { browser_window_destroy(gwin->gw->bw); } } static void gui_window_destroy(struct gui_window *g) { struct Node *ptab = NULL; int gid; if(!g) return; if(g->shared->searchwin && (g->shared->searchwin->gwin == g)) { ami_search_close(); win_destroyed = true; } if(g->hw) { ami_history_close(g->hw); win_destroyed = true; } ami_free_download_list(&g->dllist); FreeObjList(g->deferred_rects); gui_window_stop_throbber(g); cur_gw = NULL; if(g->shared->tabs > 1) { SetGadgetAttrs((struct Gadget *)g->shared->objects[GID_TABS],g->shared->win,NULL, CLICKTAB_Labels,~0, TAG_DONE); GetAttr(CLICKTAB_CurrentNode, g->shared->objects[GID_TABS], (ULONG *)&ptab); if(ptab == g->tab_node) { ptab = GetSucc(g->tab_node); if(!ptab) ptab = GetPred(g->tab_node); } Remove(g->tab_node); FreeClickTabNode(g->tab_node); RefreshSetGadgetAttrs((struct Gadget *)g->shared->objects[GID_TABS], g->shared->win, NULL, CLICKTAB_Labels, &g->shared->tab_list, CLICKTAB_CurrentNode, ptab, TAG_DONE); if(ClickTabBase->lib_Version < 53) RethinkLayout((struct Gadget *)g->shared->objects[GID_TABLAYOUT], g->shared->win, NULL, TRUE); g->shared->tabs--; ami_switch_tab(g->shared,true); ami_schedule(0, ami_gui_refresh_favicon, g->shared); if((g->shared->tabs == 1) && (nsoption_bool(tab_always_show) == false)) ami_toggletabbar(g->shared, false); ami_utf8_free(g->tabtitle); FreeVec(g); return; } ami_plot_release_pens(&g->shared->shared_pens); ami_schedule_redraw_remove(g->shared); ami_schedule(-1, ami_gui_refresh_favicon, g->shared); DisposeObject(g->shared->objects[OID_MAIN]); ami_gui_appicon_remove(g->shared); if(g->shared->appwin) RemoveAppWindow(g->shared->appwin); ami_gui_hotlist_toolbar_free(g->shared, &g->shared->hotlist_toolbar_list); /* These aren't freed by the above. * TODO: nav_west etc need freeing too? */ DisposeObject(g->shared->objects[GID_ADDTAB_BM]); DisposeObject(g->shared->objects[GID_CLOSETAB_BM]); DisposeObject(g->shared->objects[GID_TABS_FLAG]); DisposeObject(g->shared->objects[GID_FAVE_ADD]); DisposeObject(g->shared->objects[GID_FAVE_RMV]); ami_gui_opts_websearch_free(g->shared->web_search_list); if(g->shared->search_bm) DisposeObject(g->shared->search_bm); /* This appears to be disposed along with the ClickTab object if(g->shared->clicktab_ctxmenu) DisposeObject((Object *)g->shared->clicktab_ctxmenu); */ DisposeObject((Object *)g->shared->history_ctxmenu[AMI_CTXMENU_HISTORY_BACK]); DisposeObject((Object *)g->shared->history_ctxmenu[AMI_CTXMENU_HISTORY_FORWARD]); ami_ctxmenu_release_hook(g->shared->ctxmenu_hook); ami_free_menulabs(g->shared); ami_menu_free(g->shared); free(g->shared->wintitle); ami_utf8_free(g->shared->status); FreeVec(g->shared->svbuffer); for(gid = 0; gid < GID_LAST; gid++) free(g->shared->helphints[gid]); DelObject(g->shared->node); if(g->tab_node) { Remove(g->tab_node); FreeClickTabNode(g->tab_node); } FreeVec(g); // g->shared should be freed by DelObject() if(IsMinListEmpty(window_list)) { /* last window closed, so exit */ ami_try_quit(); } win_destroyed = true; } static void gui_window_set_title(struct gui_window *g, const char *title) { struct Node *node; char *utf8title; if(!g) return; if(!title) return; utf8title = ami_utf8_easy((char *)title); if(g->tab_node) // && (g->shared->tabs > 1)) { node = g->tab_node; if((g->tabtitle == NULL) || (strcmp(utf8title, g->tabtitle))) { SetGadgetAttrs((struct Gadget *)g->shared->objects[GID_TABS], g->shared->win, NULL, CLICKTAB_Labels, ~0, TAG_DONE); if(g->tabtitle) ami_utf8_free(g->tabtitle); g->tabtitle = strdup(utf8title); SetClickTabNodeAttrs(node, TNA_Text, g->tabtitle, TNA_HintInfo, g->tabtitle, TAG_DONE); RefreshSetGadgetAttrs((struct Gadget *)g->shared->objects[GID_TABS], g->shared->win, NULL, CLICKTAB_Labels, &g->shared->tab_list, TAG_DONE); if(ClickTabBase->lib_Version < 53) RethinkLayout((struct Gadget *)g->shared->objects[GID_TABLAYOUT], g->shared->win, NULL, TRUE); } } if(g == g->shared->gw) { if((g->shared->wintitle == NULL) || (strcmp(utf8title, g->shared->wintitle))) { if(g->shared->wintitle) free(g->shared->wintitle); g->shared->wintitle = strdup(utf8title); SetWindowTitles(g->shared->win, g->shared->wintitle, ami_gui_get_screen_title()); } } ami_utf8_free(utf8title); } static void ami_redraw_callback(void *p) { struct gui_window_2 *gwin = (struct gui_window_2 *)p; if(gwin->redraw_required) { ami_do_redraw(gwin); } ami_gui_window_update_box_deferred(gwin->gw, true); if(gwin->gw->c_h) { gui_window_place_caret(gwin->gw, gwin->gw->c_x, gwin->gw->c_y, gwin->gw->c_h, NULL); } } /** * Schedule a redraw of the browser window - Amiga-specific function * * \param gwin a struct gui_window_2 * \param full_redraw set to true to schedule a full redraw, should only be set to false when called from gui_window_update_box() */ void ami_schedule_redraw(struct gui_window_2 *gwin, bool full_redraw) { int ms = 1; if(full_redraw) gwin->redraw_required = true; ami_schedule(ms, ami_redraw_callback, gwin); } static void ami_schedule_redraw_remove(struct gui_window_2 *gwin) { ami_schedule(-1, ami_redraw_callback, gwin); } static void gui_window_redraw_window(struct gui_window *g) { if(!g) return; if(g == g->shared->gw) ami_schedule_redraw(g->shared, true); } static void ami_gui_window_update_box_deferred(struct gui_window *g, bool draw) { struct nsObject *node; struct nsObject *nnode; struct rect *rect; if(!g) return; if(IsMinListEmpty(g->deferred_rects)) return; if(draw == true) { ami_set_pointer(g->shared, GUI_POINTER_WAIT, false); } else { LOG("Ignoring deferred box redraw queue"); } node = (struct nsObject *)GetHead((struct List *)g->deferred_rects); do { if(draw == true) { rect = (struct rect *)node->objstruct; ami_do_redraw_limits(g, g->bw, false, rect->x0, rect->y0, rect->x1, rect->y1); } nnode=(struct nsObject *)GetSucc((struct Node *)node); DelObject(node); } while((node = nnode)); if(draw == true) ami_reset_pointer(g->shared); } static bool ami_gui_window_update_box_deferred_check(struct MinList *deferred_rects, const struct rect *new_rect) { struct nsObject *node; struct nsObject *nnode; struct rect *rect; if(IsMinListEmpty(deferred_rects)) return true; node = (struct nsObject *)GetHead((struct List *)deferred_rects); do { nnode=(struct nsObject *)GetSucc((struct Node *)node); rect = (struct rect *)node->objstruct; if((rect->x0 <= new_rect->x0) && (rect->y0 <= new_rect->y0) && (rect->x1 >= new_rect->x1) && (rect->y1 >= new_rect->y1)) { return false; } if ((new_rect->x0 <= rect->x0) && (new_rect->y0 <= rect->y0) && (new_rect->x1 >= rect->x1) && (new_rect->y1 >= rect->y1)) { LOG("Removing queued redraw that is a subset of new box redraw"); DelObject(node); /* Don't return - we might find more */ } } while((node = nnode)); return true; } static void gui_window_update_box(struct gui_window *g, const struct rect *rect) { struct nsObject *nsobj; struct rect *deferred_rect; if(!g) return; if(ami_gui_window_update_box_deferred_check(g->deferred_rects, rect)) { deferred_rect = AllocVecTagList(sizeof(struct rect), NULL); CopyMem(rect, deferred_rect, sizeof(struct rect)); nsobj = AddObject(g->deferred_rects, AMINS_RECT); nsobj->objstruct = deferred_rect; } else { LOG("Ignoring duplicate or subset of queued box redraw"); } ami_schedule_redraw(g->shared, false); } /** * callback from core to reformat a window. */ static void amiga_window_reformat(struct gui_window *gw) { struct IBox *bbox; if (gw != NULL) { if(ami_gui_get_space_box((Object *)gw->shared->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } browser_window_reformat(gw->bw, false, bbox->Width, bbox->Height); gw->shared->redraw_scroll = false; ami_gui_free_space_box(bbox); } } static void ami_do_redraw(struct gui_window_2 *gwin) { ULONG hcurrent,vcurrent,xoffset,yoffset,width=800,height=600; struct IBox *bbox; ULONG oldh = gwin->oldh, oldv=gwin->oldv; struct RastPort *temprp; if(browser_window_redraw_ready(gwin->gw->bw) == false) return; ami_get_hscroll_pos(gwin, (ULONG *)&hcurrent); ami_get_vscroll_pos(gwin, (ULONG *)&vcurrent); gwin->gw->scrollx = hcurrent; gwin->gw->scrolly = vcurrent; if(ami_gui_get_space_box((Object *)gwin->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } width=bbox->Width; height=bbox->Height; xoffset=bbox->Left; yoffset=bbox->Top; if(gwin->redraw_scroll) { if((abs(vcurrent-oldv) > height) || (abs(hcurrent-oldh) > width)) gwin->redraw_scroll = false; if(gwin->new_content) gwin->redraw_scroll = false; // if(gwin->gw->scale != 1.0) gwin->redraw_scroll = false; } if(gwin->redraw_scroll) { struct rect rect; gwin->gw->c_h_temp = gwin->gw->c_h; gui_window_remove_caret(gwin->gw); ScrollWindowRaster(gwin->win, hcurrent - oldh, vcurrent - oldv, xoffset, yoffset, xoffset + width - 1, yoffset + height - 1); gwin->gw->c_h = gwin->gw->c_h_temp; if(vcurrent>oldv) /* Going down */ { ami_spacebox_to_ns_coords(gwin, &rect.x0, &rect.y0, 0, height - (vcurrent - oldv) - 1); ami_spacebox_to_ns_coords(gwin, &rect.x1, &rect.y1, width + 1, height + 1); gui_window_update_box(gwin->gw, &rect); } else if(vcurrentgw, &rect); } if(hcurrent>oldh) /* Going right */ { ami_spacebox_to_ns_coords(gwin, &rect.x0, &rect.y0, width - (hcurrent - oldh), 0); ami_spacebox_to_ns_coords(gwin, &rect.x1, &rect.y1, width + 1, height + 1); gui_window_update_box(gwin->gw, &rect); } else if(hcurrentgw, &rect); } } else { struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &amiplot }; glob = &browserglob; if(nsoption_bool(direct_render) == false) { ami_do_redraw_tiled(gwin, true, hcurrent, vcurrent, width, height, hcurrent, vcurrent, bbox, &ctx); } else { browserglob.shared_pens = &gwin->shared_pens; temprp = browserglob.rp; browserglob.rp = gwin->win->RPort; clip.x0 = bbox->Left; clip.y0 = bbox->Top; clip.x1 = bbox->Left + bbox->Width; clip.y1 = bbox->Top + bbox->Height; ami_set_pointer(gwin, GUI_POINTER_WAIT, false); if(browser_window_redraw(gwin->gw->bw, clip.x0 - hcurrent, clip.y0 - vcurrent, &clip, &ctx)) { ami_clearclipreg(&browserglob); browserglob.rp = temprp; } ami_reset_pointer(gwin); } /* Tell NetSurf not to bother with the next queued box redraw, as we've redrawn everything. */ ami_gui_window_update_box_deferred(gwin->gw, false); } ami_update_buttons(gwin); gwin->oldh = hcurrent; gwin->oldv = vcurrent; gwin->redraw_scroll = false; gwin->redraw_required = false; gwin->new_content = false; ami_gui_free_space_box(bbox); } void ami_get_hscroll_pos(struct gui_window_2 *gwin, ULONG *xs) { if(gwin->objects[GID_HSCROLL]) { GetAttr(SCROLLER_Top, (Object *)gwin->objects[GID_HSCROLL], xs); } else { *xs = 0; } *xs /= gwin->gw->scale; } void ami_get_vscroll_pos(struct gui_window_2 *gwin, ULONG *ys) { if(gwin->objects[GID_VSCROLL]) { GetAttr(SCROLLER_Top, gwin->objects[GID_VSCROLL], ys); } else { *ys = 0; } *ys /= gwin->gw->scale; } static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) { ami_get_hscroll_pos(g->shared, (ULONG *)sx); ami_get_vscroll_pos(g->shared, (ULONG *)sy); return true; } static void gui_window_set_scroll(struct gui_window *g, int sx, int sy) { struct IBox *bbox; int width, height; if(!g) return; if(!g->bw || browser_window_has_content(g->bw) == false) return; if(ami_gui_get_space_box((Object *)g->shared->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } if(sx < 0) sx=0; if(sy < 0) sy=0; browser_window_get_extents(g->bw, false, &width, &height); if(sx >= width - bbox->Width) sx = width - bbox->Width; if(sy >= height - bbox->Height) sy = height - bbox->Height; if(width <= bbox->Width) sx = 0; if(height <= bbox->Height) sy = 0; ami_gui_free_space_box(bbox); if(g == g->shared->gw) { if(g->shared->objects[GID_VSCROLL]) { RefreshSetGadgetAttrs((struct Gadget *)(APTR)g->shared->objects[GID_VSCROLL], g->shared->win, NULL, SCROLLER_Top, (ULONG)(sy * g->scale), TAG_DONE); } if(g->shared->objects[GID_HSCROLL]) { RefreshSetGadgetAttrs((struct Gadget *)(APTR)g->shared->objects[GID_HSCROLL], g->shared->win, NULL, SCROLLER_Top, (ULONG)(sx * g->scale), TAG_DONE); } ami_schedule_redraw(g->shared, true); if(nsoption_bool(faster_scroll) == true) g->shared->redraw_scroll = true; else g->shared->redraw_scroll = false; g->scrollx = sx; g->scrolly = sy; } } static void gui_window_update_extent(struct gui_window *g) { struct IBox *bbox; if(!g || !g->bw) return; if(browser_window_has_content(g->bw) == false) return; if(g == g->shared->gw) { int width, height; if(ami_gui_get_space_box((Object *)g->shared->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } if(g->shared->objects[GID_VSCROLL]) { browser_window_get_extents(g->bw, true, &width, &height); RefreshSetGadgetAttrs((struct Gadget *)(APTR)g->shared->objects[GID_VSCROLL],g->shared->win,NULL, SCROLLER_Total, (ULONG)(height), SCROLLER_Visible, bbox->Height, TAG_DONE); } if(g->shared->objects[GID_HSCROLL]) { browser_window_get_extents(g->bw, true, &width, &height); RefreshSetGadgetAttrs((struct Gadget *)(APTR)g->shared->objects[GID_HSCROLL], g->shared->win, NULL, SCROLLER_Total, (ULONG)(width), SCROLLER_Visible, bbox->Width, TAG_DONE); } ami_gui_free_space_box(bbox); } ami_gui_scroller_update(g->shared); g->shared->new_content = true; } static void gui_window_set_status(struct gui_window *g, const char *text) { char *utf8text; ULONG size; UWORD chars; struct TextExtent textex; if(!g) return; if(!text) return; if(!g->shared->objects[GID_STATUS]) return; if(g == g->shared->gw) { utf8text = ami_utf8_easy((char *)text); if(utf8text == NULL) return; GetAttr(GA_Width, g->shared->objects[GID_STATUS], (ULONG *)&size); chars = TextFit(&scrn->RastPort, utf8text, strlen(utf8text), &textex, NULL, 1, size - 4, scrn->RastPort.TxHeight); utf8text[chars] = 0; SetGadgetAttrs((struct Gadget *)g->shared->objects[GID_STATUS], g->shared->win, NULL, GA_Text, utf8text, TAG_DONE); RefreshGList((struct Gadget *)g->shared->objects[GID_STATUS], g->shared->win, NULL, 1); if(g->shared->status) ami_utf8_free(g->shared->status); g->shared->status = utf8text; } } static nserror gui_window_set_url(struct gui_window *g, nsurl *url) { size_t idn_url_l; char *idn_url_s = NULL; char *url_lc = NULL; if(!g) return NSERROR_OK; if(g == g->shared->gw) { if(nsoption_bool(display_decoded_idn) == true) { if (nsurl_get_utf8(url, &idn_url_s, &idn_url_l) == NSERROR_OK) { url_lc = ami_utf8_easy(idn_url_s); } } RefreshSetGadgetAttrs((struct Gadget *)g->shared->objects[GID_URL], g->shared->win, NULL, STRINGA_TextVal, url_lc ? url_lc : nsurl_access(url), TAG_DONE); if(url_lc) { ami_utf8_free(url_lc); if(idn_url_s) free(idn_url_s); } } ami_update_buttons(g->shared); return NSERROR_OK; } HOOKF(uint32, ami_set_favicon_render_hook, APTR, space, struct gpRender *) { ami_schedule(0, ami_gui_refresh_favicon, hook->h_Data); return 0; } /** * Gui callback when search provider details are updated. * * \param provider_name The providers name. * \param ico_bitmap The icon bitmap representing the provider. * \return NSERROR_OK on success else error code. */ static nserror gui_search_web_provider_update(const char *provider_name, struct bitmap *ico_bitmap) { struct BitMap *bm = NULL; struct nsObject *node; struct nsObject *nnode; struct gui_window_2 *gwin; if(IsMinListEmpty(window_list)) return NSERROR_BAD_PARAMETER; if(nsoption_bool(kiosk_mode) == true) return NSERROR_BAD_PARAMETER; if (ico_bitmap != NULL) { bm = ami_bitmap_get_native(ico_bitmap, 16, 16, NULL); } if(bm == NULL) return NSERROR_BAD_PARAMETER; node = (struct nsObject *)GetHead((struct List *)window_list); do { nnode=(struct nsObject *)GetSucc((struct Node *)node); gwin = node->objstruct; if(node->Type == AMINS_WINDOW) { if(gwin->search_bm != NULL) DisposeObject(gwin->search_bm); ULONG bm_masking_tag = TAG_IGNORE; if(LIB_IS_AT_LEAST((struct Library *)ChooserBase, 53, 21)) { /* Broken in earlier versions */ bm_masking_tag = BITMAP_Masking; } gwin->search_bm = BitMapObj, BITMAP_Screen, scrn, BITMAP_Width, 16, BITMAP_Height, 16, BITMAP_BitMap, bm, BITMAP_HasAlpha, TRUE, bm_masking_tag, TRUE, BitMapEnd; RefreshSetGadgetAttrs((struct Gadget *)gwin->objects[GID_SEARCH_ICON], gwin->win, NULL, GA_HintInfo, provider_name, GA_Image, gwin->search_bm, TAG_DONE); } } while((node = nnode)); return NSERROR_OK; } HOOKF(uint32, ami_set_throbber_render_hook, APTR, space, struct gpRender *) { struct gui_window_2 *gwin = hook->h_Data; ami_throbber_redraw_schedule(0, gwin->gw); return 0; } static void gui_window_place_caret(struct gui_window *g, int x, int y, int height, const struct rect *clip) { struct IBox *bbox; int xs,ys; if(!g) return; gui_window_remove_caret(g); xs = g->scrollx; ys = g->scrolly; SetAPen(g->shared->win->RPort,3); if(ami_gui_get_space_box((Object *)g->shared->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return; } if((y-ys+height) > (bbox->Height)) height = bbox->Height-y+ys; if(((x-xs) <= 0) || ((x-xs+2) >= (bbox->Width)) || ((y-ys) <= 0) || ((y-ys) >= (bbox->Height))) { ami_gui_free_space_box(bbox); return; } g->c_w = 2; SetDrMd(g->shared->win->RPort,COMPLEMENT); RectFill(g->shared->win->RPort, x + bbox->Left - xs, y + bbox->Top - ys, x + bbox->Left + g->c_w - xs, y+bbox->Top + height - ys); SetDrMd(g->shared->win->RPort,JAM1); ami_gui_free_space_box(bbox); g->c_x = x; g->c_y = y; g->c_h = height; if((nsoption_bool(kiosk_mode) == false)) OnMenu(g->shared->win, AMI_MENU_PASTE); } static void gui_window_remove_caret(struct gui_window *g) { if(!g) return; if(g->c_h == 0) return; if((nsoption_bool(kiosk_mode) == false)) OffMenu(g->shared->win, AMI_MENU_PASTE); ami_do_redraw_limits(g, g->bw, false, g->c_x, g->c_y, g->c_x + g->c_w + 1, g->c_y + g->c_h + 1); g->c_h = 0; } static void gui_window_new_content(struct gui_window *g) { hlcache_handle *c; if(g && g->shared && g->bw && browser_window_has_content(g->bw)) c = browser_window_get_content(g->bw); else return; ami_clearclipreg(&browserglob); g->shared->new_content = true; g->scrollx = 0; g->scrolly = 0; g->shared->oldh = 0; g->shared->oldv = 0; g->favicon = NULL; ami_plot_release_pens(&g->shared->shared_pens); ami_menu_update_disabled(g, c); ami_gui_update_hotlist_button(g->shared); ami_gui_scroller_update(g->shared); } static bool gui_window_drag_start(struct gui_window *g, gui_drag_type type, const struct rect *rect) { #ifdef __amigaos4__ g->shared->drag_op = type; if(rect) g->shared->ptr_lock = ami_ns_rect_to_ibox(g->shared, rect); if(type == GDRAGGING_NONE) { SetWindowAttrs(g->shared->win, WA_GrabFocus, 0, WA_MouseLimits, NULL, TAG_DONE); if(g->shared->ptr_lock) { FreeVec(g->shared->ptr_lock); g->shared->ptr_lock = NULL; } } #endif return true; } /* return the text box at posn x,y in window coordinates x,y are updated to be document co-ordinates */ bool ami_text_box_at_point(struct gui_window_2 *gwin, ULONG *x, ULONG *y) { struct IBox *bbox; ULONG xs, ys; struct browser_window_features data; if(ami_gui_get_space_box((Object *)gwin->objects[GID_BROWSER], &bbox) != NSERROR_OK) { warn_user("NoMemory", ""); return false; } ami_get_hscroll_pos(gwin, (ULONG *)&xs); *x = *x - (bbox->Left) +xs; ami_get_vscroll_pos(gwin, (ULONG *)&ys); *y = *y - (bbox->Top) + ys; ami_gui_free_space_box(bbox); browser_window_get_features(gwin->gw->bw, *x, *y, &data); if (data.form_features == CTX_FORM_TEXT) return true; return false; } BOOL ami_gadget_hit(Object *obj, int x, int y) { int top, left, width, height; GetAttrs(obj, GA_Left, &left, GA_Top, &top, GA_Width, &width, GA_Height, &height, TAG_DONE); if((x >= left) && (x <= (left + width)) && (y >= top) && (y <= (top + height))) return TRUE; else return FALSE; } Object *ami_gui_splash_open(void) { Object *win_obj, *bm_obj; struct Window *win; struct Screen *wbscreen = LockPubScreen("Workbench"); uint32 top = 0, left = 0; STRPTR ver_string; struct TextAttr tattr; struct TextFont *tfont; win_obj = WindowObj, #ifdef __amigaos4__ WA_ToolBox, TRUE, #endif WA_Borderless, TRUE, WA_BusyPointer, TRUE, WINDOW_Position, WPOS_CENTERSCREEN, WINDOW_LockWidth, TRUE, WINDOW_LockHeight, TRUE, WINDOW_ParentGroup, LayoutVObj, LAYOUT_AddImage, bm_obj = BitMapObj, BITMAP_SourceFile, "PROGDIR:Resources/splash.png", BITMAP_Screen, wbscreen, BITMAP_Precision, PRECISION_IMAGE, BitMapEnd, LayoutEnd, EndWindow; LOG("Attempting to open splash window..."); win = RA_OpenWindow(win_obj); GetAttrs(bm_obj, IA_Top, &top, IA_Left, &left, TAG_DONE); SetDrMd(win->RPort, JAM1); #ifdef __amigaos4__ SetRPAttrs(win->RPort, RPTAG_APenColor, 0xFF3F6DFE, TAG_DONE); tattr.ta_Name = "DejaVu Serif Italic.font"; #else SetAPen(win->RPort, 3); /* Pen 3 is usually blue */ tattr.ta_Name = "ruby.font"; #endif tattr.ta_YSize = 24; tattr.ta_Style = 0; tattr.ta_Flags = 0; if((tfont = ami_font_open_disk_font(&tattr))) { SetFont(win->RPort, tfont); } else { tattr.ta_Name = "DejaVu Serif Oblique.font"; if((tfont = ami_font_open_disk_font(&tattr))) SetFont(win->RPort, tfont); } Move(win->RPort, left + 5, top + 25); Text(win->RPort, "Initialising...", strlen("Initialising...")); if(tfont) ami_font_close_disk_font(tfont); #ifdef __amigaos4__ tattr.ta_Name = "DejaVu Sans.font"; #else tattr.ta_Name = "helvetica.font"; #endif tattr.ta_YSize = 16; tattr.ta_Style = 0; tattr.ta_Flags = 0; if((tfont = ami_font_open_disk_font(&tattr))) SetFont(win->RPort, tfont); ver_string = ASPrintf("%s", netsurf_version); Move(win->RPort, left + 185, top + 220); Text(win->RPort, ver_string, strlen(ver_string)); if(ver_string) FreeVec(ver_string); if(tfont) ami_font_close_disk_font(tfont); UnlockPubScreen(NULL, wbscreen); return win_obj; } void ami_gui_splash_close(Object *win_obj) { if(win_obj == NULL) return; LOG("Closing splash window"); DisposeObject(win_obj); } static void gui_file_gadget_open(struct gui_window *g, hlcache_handle *hl, struct form_control *gadget) { LOG("File open dialog request for %p/%p", g, gadget); if(AslRequestTags(filereq, ASLFR_Window, g->shared->win, ASLFR_SleepWindow, TRUE, ASLFR_TitleText, messages_get("NetSurf"), ASLFR_Screen, scrn, ASLFR_DoSaveMode, FALSE, TAG_DONE)) { char fname[1024]; strlcpy(fname, filereq->fr_Drawer, 1024); AddPart(fname, filereq->fr_File, 1024); browser_window_set_gadget_filename(g->bw, gadget, fname); } } /* exported function documented in amiga/gui.h */ uint32 ami_gui_get_app_id(void) { return ami_appid; } static struct gui_window_table amiga_window_table = { .create = gui_window_create, .destroy = gui_window_destroy, .redraw = gui_window_redraw_window, .update = gui_window_update_box, .get_scroll = gui_window_get_scroll, .set_scroll = gui_window_set_scroll, .get_dimensions = gui_window_get_dimensions, .update_extent = gui_window_update_extent, .reformat = amiga_window_reformat, .set_icon = gui_window_set_icon, .set_title = gui_window_set_title, .set_url = gui_window_set_url, .set_status = gui_window_set_status, .place_caret = gui_window_place_caret, .remove_caret = gui_window_remove_caret, .drag_start = gui_window_drag_start, .new_content = gui_window_new_content, .create_form_select_menu = gui_create_form_select_menu, .file_gadget_open = gui_file_gadget_open, .drag_save_object = gui_drag_save_object, .drag_save_selection =gui_drag_save_selection, .start_selection = gui_start_selection, /* from theme */ .set_pointer = gui_window_set_pointer, .start_throbber = gui_window_start_throbber, .stop_throbber = gui_window_stop_throbber, /* from download */ .save_link = gui_window_save_link, }; static struct gui_fetch_table amiga_fetch_table = { .filetype = fetch_filetype, .get_resource_url = gui_get_resource_url, }; static struct gui_search_web_table amiga_search_web_table = { .provider_update = gui_search_web_provider_update, }; static struct gui_browser_table amiga_browser_table = { .schedule = ami_schedule, .quit = gui_quit, .launch_url = gui_launch_url, .cert_verify = gui_cert_verify, .login = gui_401login_open, }; /** Normal entry point from OS */ int main(int argc, char** argv) { setbuf(stderr, NULL); char messages[100]; char script[1024]; char temp[1024]; STRPTR current_user_cache = NULL; BPTR lock = 0; int32 user = 0; nserror ret; int nargc = 0; char *nargv = NULL; struct netsurf_table amiga_table = { .browser = &amiga_browser_table, .window = &amiga_window_table, .clipboard = amiga_clipboard_table, .download = amiga_download_table, .fetch = &amiga_fetch_table, .file = amiga_file_table, .utf8 = amiga_utf8_table, .search = amiga_search_table, .search_web = &amiga_search_web_table, .llcache = filesystem_llcache_table, .bitmap = amiga_bitmap_table, }; #ifdef __amigaos4__ signal(SIGINT, SIG_IGN); #endif ret = netsurf_register(&amiga_table); if (ret != NSERROR_OK) { ami_misc_fatal_error("NetSurf operation table failed registration"); return RETURN_FAIL; } /* initialise logging. Not fatal if it fails but not much we * can do about it either. */ nslog_init(NULL, &argc, argv); /* Need to do this before opening any splash windows etc... */ if ((ami_libs_open() == false)) { return RETURN_FAIL; } /* Open splash window */ Object *splash_window = ami_gui_splash_open(); if (ami_open_resources() == false) { /* alloc message ports */ ami_misc_fatal_error("Unable to allocate resources"); ami_gui_splash_close(splash_window); ami_libs_close(); return RETURN_FAIL; } if(ami_scheduler_process_create(schedulermsgport) != NSERROR_OK) { ami_misc_fatal_error("Failed to initialise scheduler"); ami_gui_splash_close(splash_window); ami_libs_close(); return RETURN_FAIL; } ami_gui_read_all_tooltypes(argc, argv); struct RDArgs *args = ami_gui_commandline(&argc, argv, &nargc, &nargv); if(current_user == NULL) { user = GetVar("user", temp, 1024, GVF_GLOBAL_ONLY); current_user = ASPrintf("%s", (user == -1) ? "Default" : temp); } LOG("User: %s", current_user); if(users_dir == NULL) { users_dir = ASPrintf("%s", USERS_DIR); if(users_dir == NULL) { ami_misc_fatal_error("Failed to allocate memory"); ami_scheduler_process_delete(); ami_gui_splash_close(splash_window); ami_libs_close(); return RETURN_FAIL; } } if(LIB_IS_AT_LEAST((struct Library *)DOSBase, 51, 96)) { #ifdef __amigaos4__ struct InfoData *infodata = AllocDosObject(DOS_INFODATA, 0); if(infodata == NULL) { ami_misc_fatal_error("Failed to allocate memory"); ami_scheduler_process_delete(); ami_gui_splash_close(splash_window); ami_libs_close(); return RETURN_FAIL; } GetDiskInfoTags(GDI_StringNameInput, users_dir, GDI_InfoData, infodata, TAG_DONE); if(infodata->id_DiskState == ID_DISKSTATE_WRITE_PROTECTED) { FreeDosObject(DOS_INFODATA, infodata); ami_misc_fatal_error("User directory MUST be on a writeable volume"); ami_scheduler_process_delete(); ami_gui_splash_close(splash_window); ami_libs_close(); return RETURN_FAIL; } FreeDosObject(DOS_INFODATA, infodata); #else #warning FIXME for OS3 and older OS4 #endif } else { //TODO: check volume write status using old API } int len = strlen(current_user); len += strlen(users_dir); len += 2; /* for poss path sep and NULL term */ current_user_dir = AllocVecTags(len, NULL); if(current_user_dir == NULL) { ami_misc_fatal_error("Failed to allocate memory"); ami_scheduler_process_delete(); ami_gui_splash_close(splash_window); ami_libs_close(); return RETURN_FAIL; } strlcpy(current_user_dir, users_dir, len); AddPart(current_user_dir, current_user, len); FreeVec(users_dir); LOG("User dir: %s", current_user_dir); if((lock = CreateDirTree(current_user_dir))) UnLock(lock); current_user_options = ASPrintf("%s/Choices", current_user_dir); current_user_cache = ASPrintf("%s/Cache", current_user_dir); current_user_faviconcache = ASPrintf("%s/IconCache", current_user_dir); if((lock = CreateDirTree(current_user_cache))) UnLock(lock); if((lock = CreateDirTree(current_user_faviconcache))) UnLock(lock); ami_mime_init("PROGDIR:Resources/mimetypes"); sprintf(temp, "%s/mimetypes.user", current_user_dir); ami_mime_init(temp); #ifdef __amigaos4__ amiga_plugin_hack_init(); #endif ret = amiga_datatypes_init(); /* user options setup */ ret = nsoption_init(ami_set_options, &nsoptions, &nsoptions_default); if (ret != NSERROR_OK) { ami_misc_fatal_error("Options failed to initialise"); ami_scheduler_process_delete(); ami_gui_splash_close(splash_window); ami_libs_close(); return RETURN_FAIL; } nsoption_read(current_user_options, NULL); if(args != NULL) { nsoption_commandline(&nargc, &nargv, NULL); FreeArgs(args); } if (ami_locate_resource(messages, "Messages") == false) { ami_misc_fatal_error("Cannot open Messages file"); ami_scheduler_process_delete(); ami_gui_splash_close(splash_window); ami_libs_close(); return RETURN_FAIL; } ret = messages_add_from_file(messages); ret = netsurf_init(current_user_cache); if (ret != NSERROR_OK) { ami_misc_fatal_error("NetSurf failed to initialise"); ami_scheduler_process_delete(); ami_gui_splash_close(splash_window); ami_libs_close(); return RETURN_FAIL; } if(current_user_cache != NULL) FreeVec(current_user_cache); ret = amiga_icon_init(); search_web_init(nsoption_charp(search_engines_file)); ami_clipboard_init(); ami_openurl_open(); ami_amiupdate(); /* set env-vars for AmiUpdate */ ami_init_fonts(); save_complete_init(); ami_theme_init(); ami_init_mouse_pointers(); ami_file_req_init(); win_destroyed = false; ami_font_setdevicedpi(0); /* for early font requests, eg treeview init */ window_list = NewObjList(); urldb_load(nsoption_charp(url_file)); urldb_load_cookies(nsoption_charp(cookie_file)); gui_init2(argc, argv); ami_ctxmenu_init(); /* Requires screen pointer */ ami_gui_splash_close(splash_window); strlcpy(script, nsoption_charp(arexx_dir), 1024); AddPart(script, nsoption_charp(arexx_startup), 1024); ami_arexx_execute(script); while (!ami_quit) { ami_get_msg(); } strlcpy(script, nsoption_charp(arexx_dir), 1024); AddPart(script, nsoption_charp(arexx_shutdown), 1024); ami_arexx_execute(script); ami_mime_free(); netsurf_exit(); return RETURN_OK; }