/* Copyright 1997 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /***************************************************/ /* File : Windows.c */ /* */ /* Purpose: Window related functions for the */ /* browser (open, close, create, etc.). */ /* */ /* Author : A.D.Hodgkinson */ /* */ /* History: 20-Nov-96: Created. */ /* 15-Mar-97: Split up to form Browser.c. */ /***************************************************/ #include <stdlib.h> #include <string.h> #include "swis.h" #include "flex.h" #include "wimp.h" #include "wimplib.h" #include "event.h" #include "toolbox.h" #include "window.h" #include "Dialler.h" #include "NestWimp.h" #include "svcprint.h" #include "Global.h" #include "FromROSLib.h" #include "MiscDefs.h" #include "Utils.h" #include "Browser.h" #include "ChoiceDefs.h" #include "Fetch.h" /* (Which itself includes URLstat.h) */ #include "FetchHTML.h" #include "FetchPage.h" #include "FontManage.h" #include "Forms.h" #include "Frames.h" #include "Handlers.h" #include "History.h" #include "Images.h" #include "Main.h" #include "Memory.h" #include "Menus.h" #include "Meta.h" #include "Object.h" #include "OpenURL.h" #include "PlugIn.h" #include "Printing.h" #include "Redraw.h" #include "Reformat.h" #include "Tables.h" #include "Toolbars.h" #include "URLutils.h" #include "Windows.h" /* Static function prototypes */ static void windows_check_reformat (browser_data * b, BBox * size, int old_width); /* Locals */ static int title_height = 0; static int vscroll_width = 0; static int hscroll_height = 0; /*************************************************/ /* windows_check_reformat() */ /* */ /* After resizing, checks whether the contents */ /* of a given browser need reformatting and */ /* ensures tool presence is up to date. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the browser; */ /* */ /* Pointer to a BBox describing the */ /* new visible area of the window; */ /* */ /* The old display_width field of */ /* the browser_data struct to */ /* compare against the width defined */ /* by the given BBox. */ /*************************************************/ static void windows_check_reformat(browser_data * b, BBox * size, int old_width) { /* If the width has changed, need to reformat. Notice that the */ /* horizontal extent is forced up to at least a certain minimum */ /* value, but is never shrunk. */ if (size->xmax - size->xmin != old_width) { int h1, h2; b->display_extent = b->display_width = size->xmax - size->xmin; if (b->display_extent < MinimumWidth) b->display_extent = MinimumWidth; h1 = toolbars_button_height(b) + toolbars_url_height(b); h2 = toolbars_status_height(b); if (h1) h1 += wimpt_dy(); if (h2) h2 += wimpt_dy(); b->display_height = size->ymax - size->ymin - h1 - h2; if (b->ancestor || b->full_screen) windows_set_tools(b, size, !b->ancestor, 0, 0, 0); reformat_format_from(b, -1, 1, -1); } // Blimey. This *really* needs sorting out. As for the windows_remember_size // call - which duplicates this functionality more or less! - you should NOT // need to redraw here. The display_width has not changed, so centered objects // will not move. If it *has* changed, whatever changed it screwed up! // /* Otherwise just force a redraw (to make sure centred objects */ // /* are OK) and check the tools are up to date. */ // // else // { // WimpGetWindowStateBlock state; // // state.window_handle = b->window_handle; // // if (!wimp_get_window_state(&state)) // { // coords_box_toworkarea(&state.visible_area, (WimpRedrawWindowBlock *) &state); // // wimp_force_redraw(state.window_handle, // state.visible_area.xmin, // state.visible_area.ymin, // state.visible_area.xmax, // state.visible_area.ymax); // } // // windows_check_tools(b, NULL); // } } /*************************************************/ /* windows_new_browser() */ /* */ /* Creates a new Browser window. Parameters are */ /* as standard for a Toolbox event handler, with */ /* void * handle being NULL to open with the */ /* current home page, else a pointer to a URL. */ /*************************************************/ int windows_new_browser(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle) { #ifndef SINGLE_USER /* If in a multiuser build and not logged in, claim */ /* the event but don't do anything with it. */ if (!logged_in) return 1; #endif if (handle) ChkError(windows_create_browser((char *) handle, NULL, NULL, NULL, Windows_CreateBrowser_Normal)); else { char home[Limits_URL]; urlutils_create_home_url(home, sizeof(home)); ChkError(windows_create_browser(home, NULL, NULL, NULL, Windows_CreateBrowser_Normal)); } return 1; } /*************************************************/ /* windows_shut_browser() */ /* */ /* Close a browser window. Closes the ancestor */ /* and all child frames. Parameters are as */ /* standard for a Toolbox event handler. */ /*************************************************/ int windows_shut_browser(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle) { browser_data * b; ObjectId browser = idb->ancestor_id; if (!browser) browser = idb->self_id; ChkError(toolbox_get_client_handle(0, browser, (void *) &b)); if (!is_known_browser(b)) return 0; /* Always use the ancestor */ b = utils_ancestor(b); /* Close it */ return handle_close_browser(0, NULL, NULL, b); } /*************************************************/ /* windows_create_browser() */ /* */ /* Creates and initialises a browser_data struct */ /* and may create an associated window object. */ /* */ /* Parameters: Pointer to a URL to fetch (or */ /* NULL to fetch none); */ /* */ /* Pointer to a parent structure if */ /* this is a frame, else NULL; */ /* */ /* Pointer to a BBox describing the */ /* visible area, or NULL to use */ /* default sizes and a window */ /* position based on the last */ /* default open position; */ /* */ /* Pointer to the name for this */ /* window (for targetted URLs), or */ /* NULL for none. The string will be */ /* copied to a browser local malloc */ /* block, so it can come from pretty */ /* much anywhere that isn't going to */ /* shift over a function call */ /* boundary (i.e. not flex!); */ /* */ /* Fetch type value; see definitions */ /* in Windows.h. Note that the */ /* ForUIElement type is not */ /* implemented - don't use it! */ /*************************************************/ _kernel_oserror * windows_create_browser(const char * url, browser_data * real_parent, BBox * size, const char * name, int save_type) { ObjectId o; browser_data * b; reformat_cell * cell; _kernel_oserror * e = NULL; int width, height; /* If no size BBox is given, use the Choices file specified sizes, */ /* else use the sizes defined by the BBox. */ if (!size) width = choices.width, height = choices.height; else width = size->xmax - size->xmin, height = size->ymax - size->ymin; /* malloc a block of space, treating it as holding a browser_data */ /* structure. This is defined in global.h, and holds all the */ /* information needed with a given browser window (e.g. the */ /* document currently on display in that window, etc). */ #ifdef TRACE if (tl & (1u<<12)) { Printf("windows_create_browser: memory_alloc_and_set %d for 'browser_data' structure\n",sizeof(browser_data)); Printf(" and %d for 'reformat_cell' structure\n",sizeof(reformat_cell)); } #endif b = (browser_data *) memory_alloc_and_set(sizeof(browser_data), 0); cell = (reformat_cell *) memory_alloc_and_set(sizeof(reformat_cell), 0); if (!b || !cell) { erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, lookup_token("NoMemWin:There is not enough free memory to open another browser window.", 0, 0)); return &erb; } else { #ifdef TRACE malloccount += (sizeof(browser_data) + sizeof(reformat_cell)); if (tl & (1u<<13)) Printf("** malloccount (windows_create_browser): \0211%d\0217\n",malloccount); #endif /* The allocation succeeded, so create the object, fill in the browser_data */ /* stucture, and link the stucture into the list of structures for all the */ /* browser windows. The toolbox is given a pointer to the structure as a */ /* client handle for the window, so whenever we get an event relating to */ /* the window this pointer is also supplied. */ b->cell = cell; if (save_type != Windows_CreateBrowser_Normal && controls.use_small) { /* If the browser is created just to save an object, */ /* build a 'mini' browser for just that. */ e = toolbox_create_object(0, "BrowsrFetch", &o); b->small_fetch = 1; } else { /* Otherwise, build a base browser, or if this is a frame, a child */ /* browser object. */ if (!real_parent) e = toolbox_create_object(0, "Browser", &o); else { if (nested_wimp) e = toolbox_create_object(0, "BrChild", &o); else e = toolbox_create_object(0, "BrChildBrdr", &o); } } if (e) return e; RetError(toolbox_set_client_handle(0, o, b)); /* Regardless of whether this is an ancestor browser window or a frame, */ /* its next pointer must still be set to NULL. */ b->next = NULL; /* Link this into the list of browser_data structures only if it's a parent */ /* browser window - i.e. not part of a frame set; there will be no parent */ /* browser_data struct passed into the function as this means you're a child. */ b->previous = last_browser; if (last_browser) last_browser->next = b; last_browser = b; /* Sort out parent/child linking considerations */ if (!real_parent) { b->ancestor = NULL; /* If not a child, this is an ancestor object */ b->parent = NULL; b->real_parent = NULL; } else { /* Allocate memory in the array of children for this entry */ RetError(memory_set_chunk_size(real_parent, NULL, CK_CHIL, (real_parent->nchildren + 1) * sizeof(browser_data *))); /* Add the entry - nchildren hasn't been incremented yet, so */ /* [real_parent->nchildren] is correct for the new entry. */ real_parent->children[real_parent->nchildren] = b; /* Fill in the child's parent and ancestor fields */ b->real_parent = real_parent; b->parent = real_parent; b->ancestor = real_parent->ancestor; if (!b->ancestor) b->ancestor = real_parent; /* Finally, increment the parent's number of children counter */ real_parent->nchildren++; } b->self_id = o; #ifdef TRACE if (tl & (1u<<3)) { Printf("\nCreated object ID %p\n",(void *) o); Printf("Associated structure is %p\n\n",(void *) b); } #endif /* Opening width considerations... */ b->display_width = b->display_extent = width; if (b->display_extent < MinimumWidth) b->display_extent = MinimumWidth, b->display_width = MinimumWidth; /* ...and opening height */ b->display_height = height; /* Default page layout information */ b->left_margin = choices.left_margin; b->right_margin = choices.right_margin; b->quote_margin = choices.quote_margin; b->leading = choices.leading; b->left_indent = choices.left_indent; /* Default encoding */ b->encoding = choices.encoding; b->encoding_priority = priority_default; /* Set up the deferred reformatter */ b->refo_time = 0; b->refo_line = Reformat_UnrealisticallyHighLineNumber; /* Remember the Wimp window handle to save having to ask for it elsewhere */ RetError(window_get_wimp_handle(0,o,&(b->window_handle))); /* Allocate memory for the fetching URL and write that */ /* URL into the block */ b->urlddata = NULL; /* No current displayed URL */ /* If handle is non-zero treat as a pointer to a URL, else */ /* fetch the Home Page. */ if (url) { #ifdef TRACE if (tl & (1u<<12)) Printf("windows_create_browser: Chunk CK_FURL set to %d\n",strlen(url) + 1); #endif RetError(memory_set_chunk_size(b, NULL, CK_FURL, strlen(url) + 1)); strcpy(b->urlfdata, url); } /* If there's a given window name, set it */ if (name && *name) { #ifdef TRACE if (tl & (1u<<12)) Printf("windows_create_browser: Chunk CK_NAME set to %d\n",strlen(name) + 1); #endif RetError(memory_set_chunk_size(b, NULL, CK_NAME, strlen(name) + 1)); strcpy(b->window_name, name); } /* Set some local options according to the global Choices */ b->underline_links = choices.underline_links; b->use_source_cols = choices.use_source_cols; b->show_foreground = choices.show_foreground; b->show_background = choices.show_background; /* Initialise various other fields */ b->background_image = -1; b->full_screen = !real_parent ? choices.full_screen : 0; b->full_size = 0; if (save_type != Windows_CreateBrowser_Normal) b->save_link = 1; else b->save_link = 0; /* Register some browser-specific Wimp event handlers */ RetError(event_register_wimp_handler(o, Wimp_ERedrawWindow, (WimpEventHandler *) windows_redraw_browser, b)); RetError(event_register_wimp_handler(o, Wimp_EOpenWindow, (WimpEventHandler *) windows_open_browser, b)); RetError(event_register_wimp_handler(o, Wimp_EScrollRequest, (WimpEventHandler *) handle_scroll_requests, b)); RetError(event_register_wimp_handler(o, Wimp_EKeyPressed, (WimpEventHandler *) handle_keys_from_browser, b)); /* For toolbars and titles, need to be a parent (i.e. have no */ /* parent browser_data struct, as that means you're a child). */ if (!real_parent) { ObjectId ttop, tbot; int scrap; char text[Limits_URLBarWrit]; if (!b->small_fetch) { /* Set the window title to contain the default URL for rendering. */ RetError(window_set_title(0, o, lookup_token("BlankPage:Blank page",0,0))); } else { /* Set the window title to contain a default string for file fetching. */ RetError(window_set_title(0, o, lookup_token("DataFetch:Fetching to file...",0,0))); } /* Set various toolbar flags up, and make */ /* sure the right toolbars are visible. */ if (save_type != Windows_CreateBrowser_Normal && controls.use_small) { b->url_bar = 1; b->button_bar = 1; b->status_bar = 1; } else { b->url_bar = choices.url_bar; b->button_bar = choices.button_bar; b->status_bar = choices.status_bar; } /* Work out what toolbars are available */ RetError(window_get_tool_bars(InternalTopLeft | InternalBottomLeft, o, &tbot, &ttop, NULL, NULL)); if (!ttop) b->all_in_bottom = 1; if (!tbot) b->all_in_top = 1; /* Now make sure that ttop and tbot reflect the updated values in */ /* light of the all_in_bottom/all_in_top/swap_bars flags. */ ttop = toolbars_get_upper(b); tbot = toolbars_get_lower(b); /* (These are needed further down). */ /* Read scroll bar choices */ b->frame_hscroll = choices.h_scroll; b->frame_vscroll = choices.v_scroll; /* Only allow Wimp events to close a window if it's a parent; */ /* otherwise, want entirely browser-driven control of when */ /* the child closes (for example, it Would Be Bad if some */ /* dodgy PD application that closed the window under the */ /* pointer on noticing some hotkey was activated on a child). */ RetError(event_register_wimp_handler(o, Wimp_ECloseWindow, (WimpEventHandler *) handle_close_browser, b)); /* Register event handlers for toolbar items, if a parent. Similarly, work out */ /* what to do with toolbar buttons and writables, etc., only if a parent (a */ /* child as no toolbars). */ if (ttop) { RetError(event_register_wimp_handler(ttop, Wimp_EMouseClick, (WimpEventHandler *) handle_clicks, b)); /* If there's a dialler display field, install a long-term handler */ /* to keep it up to date. */ e = gadget_get_type(0, ttop, URLBarDiallerStatus, &scrap); if (!e) { if (!taskmodule_ds_registered) { /* Register the dialler's 'status changed' service call */ /* with TaskModule. This allows a Wimp message to be */ /* sent whenever the status changes. */ e = _swix(TaskModule_RegisterService, _INR(0, 2), 0, Service_DiallerStatus, task_handle); /* If the above fails, don't bother reporting the error, */ /* just skip the function - it is non-essential and the */ /* most likely cause of failure - unknown SWI - is taken */ /* as an indicator that the dialler service is not */ /* needed. */ if (!e) taskmodule_ds_registered = 1; } else e = NULL; if (!e) { /* Message handler for the TaskModule's Message_Service message, */ /* which is sent when the dialler sends out a 'status changed' */ /* service call following the above registration SWI call. */ RetError(event_register_message_handler(Message_Service, handle_dialler_service, b)); } } } /* Handle border and colour control of the URL writable, status */ /* field, and dialler display field. */ if (ttop) { /* URL writable */ RetError(windows_process_component_text(ttop, URLBarWrit, text, sizeof(text), 0, 1)); /* Dialler status display field */ RetError(windows_process_component_text(ttop, URLBarDiallerStatus, text, sizeof(text), 0, 1)); } if (tbot) { int bytes_flags; /* Main status display field */ RetError(windows_process_component_text(tbot, StatusBarStatus, text, sizeof(text), 0, 1)); /* Progress indicator */ RetError(windows_process_component_text(tbot, StatusBarProgress, text, sizeof(text), 0, 1)); /* Remember whatever foreground colour the StatusBarProgress gadget now has */ if (!button_get_flags(0, tbot, StatusBarProgress, &bytes_flags)); { b->progress_colour = (bytes_flags & 0x0f000000) >> 24; } } /* Are the URL writable and status display to be merged? */ /* Can only merge them if the toolbars are merged. */ /* */ /* Take this opportunity to look for bistate and */ /* tristate button definitions, in the same way. */ if (b->all_in_top || b->all_in_bottom) { /* If the toolbars are merged, it doesn't matter if we try */ /* to get the upper or lower toolbar object ID - the */ /* returned result will be the same. */ /* */ /* Can only merge things if there's a toolbar to look at! */ if (ttop) { /* See if the URL writable and status displays are to be merged. */ { BBox sta, url; /* If finding the BBox of either generates an error, can't */ /* say they're to be merged. */ if ( !gadget_get_bbox(0, ttop, URLBarWrit, &url) && !gadget_get_bbox(0, ttop, StatusBarStatus, &sta) ) { /* Otherwise, compare their bounding boxes. If identical, */ /* the two are to be merged. */ if ( url.xmin == sta.xmin && url.ymin == sta.ymin && url.xmax == sta.xmax && url.ymax == sta.ymax ) { b->merged_url = 1; toolbars_merged_to_status(b, ttop); } /* Closure of long 'if' checking that the bounding boxes of */ /* the URL writable and status display fields were obtained */ /* without error (the code above excutes if this is true). */ } } /* See if there are any recognised bistate buttons present. */ /* Code is similar to the above URL/status merge code. */ { BBox s1, s2; int scrap; /* Must have a working gadget, component ID ButtonBarBistate, */ /* to use the bistate button. */ if (!gadget_get_type(0, ttop, ButtonBarBistate, &scrap)) { /* Check for type BiState_Cancel_Back */ if ( !gadget_get_bbox(0, ttop, ButtonBarCancel, &s1) && !gadget_get_bbox(0, ttop, ButtonBarBack, &s2) ) { if ( s1.xmin == s2.xmin && s1.ymin == s2.ymin && s1.xmax == s2.xmax && s1.ymax == s2.ymax ) { b->bistate = BiState_Cancel_Back; /* Ensure the reference gadgets are hidden */ hide_gadget(ttop, ButtonBarBack); hide_gadget(ttop, ButtonBarCancel); /* Set the default starting state to 'Back' */ toolbars_set_bistate_state(b, ttop, 1); } } } } /* See if there are any recognised tristate buttons present. */ /* Code is similar to the above bistate button code. */ { BBox s1, s2, s3; int scrap; /* Must have a working gadget, component ID ButtonBarTristate, */ /* to use the tristate button. */ if (!gadget_get_type(0, ttop, ButtonBarTristate, &scrap)) { /* Check for type TriState_Go_GoTo_Stop */ if ( !gadget_get_bbox(0, ttop, ButtonBarGo, &s1) && !gadget_get_bbox(0, ttop, ButtonBarGoTo, &s2) && !gadget_get_bbox(0, ttop, ButtonBarStop, &s3) ) { if ( s1.xmin == s2.xmin && s1.ymin == s2.ymin && s1.xmax == s2.xmax && s1.ymax == s2.ymax && s1.xmin == s3.xmin && s1.ymin == s3.ymin && s1.xmax == s3.xmax && s1.ymax == s3.ymax ) { b->tristate = TriState_Go_GoTo_Stop; /* Ensure the reference gadgets are hidden */ hide_gadget(ttop, ButtonBarGoTo); hide_gadget(ttop, ButtonBarGo); hide_gadget(ttop, ButtonBarStop); /* If fetching, set the tristate to 'stop', else 'go to'. */ if (url) toolbars_set_tristate_state(b, ttop, 2); else toolbars_set_tristate_state(b, ttop, 1); } } } } /* Closure of long 'if' checking the upper toolbar object ID */ /* was non-zero. If so, the code above executes. */ } /* Closure of long 'if' checking that the upper and lower toolbars */ /* are merged into one; the code above executes if so. */ } /* Set the default status. Must do this after the */ /* routines that process icon text etc. have been */ /* run, or the status routines could trash a */ /* special icon string before it's dealt with... */ toolbars_update_status(b, Toolbars_Status_Ready); /* Closure of long 'if' checking if the window was a parent. The */ /* code above executes if so. */ } /* Handler for on-page clicks */ RetError(event_register_wimp_handler(o, Wimp_EMouseClick, (WimpEventHandler *) handle_link_clicks, b)); /* Open the window and register a Wimp handler that will be called */ /* whenever there is an Open Window request generated for the window */ /* (this deals with window extent settings etc.). */ if (!size) b->small_size.visible_area.xmin = b->small_size.visible_area.ymin = -1; else b->small_size.visible_area = *size; /* This call will fill in small_size depending on the above. */ if (save_type != Windows_CreateBrowser_ForPlugIn || choices.see_fetches) windows_show_browser(b); /* Ensure the URL bar is up to date, and set the fetch status to BS_START. */ if (url) { toolbars_update_url(b); b->fetch_status = BS_START; } /* Must be called after windows_show_browser so the parent/ancestor IDs are set up */ if (!real_parent) { BBox w; toolbars_set_presence(b, InternalTopLeft | InternalBottomLeft); /* Ensure that the window extent is at least as wide and tall */ /* as the minimum extent settings require. */ if (!b->small_fetch) { RetError(window_get_extent(0,o,&w)); if ((w.xmax - w.xmin) < MinimumWidth) w.xmin = 0, w.xmax = MinimumWidth; if ((w.ymax - w.ymin) < MinimumHeight) w.ymin = -MinimumHeight, w.ymax = 0; RetError(window_set_extent(0,o,&w)); /* Give the window the input focus, if it's an ancestor */ RetError(browser_give_general_focus(b)); } } /* Start a fetch for this page's current URL. Note the allow_cancel */ /* flag is unset, so that any flags set up above, which cancel */ /* functions may touch (e.g. save_link), will not be altered. */ if (url) e = fetchpage_new(b, b->urlfdata, 0, 0); else if (b->small_fetch) { /* For a small fetch window, we may have no URL (Plug-Ins - already */ /* have the data in a file, and want the fetcher to be kicked */ /* briefly to notice the fetch is finished before it even started */ /* and fire off the relevant messages). */ fetchpage_claim_nulls(b); } /* Now ensure that future fetches may call fetch_cancel */ /* before proceeding. */ b->allow_cancel = 1; return e; /* Closure of long 'if' ensuring the mallocs for the browser_data */ /* and associated reformat_cell structures were successful - the */ /* code above only executes if so. */ } } /*************************************************/ /* windows_open_browser() */ /* */ /* (Re)opens a Browser window, setting extent if */ /* necessary. Parameters are as standard for a */ /* Wimp event handler. */ /* */ /* Assumes: The poll block and ID block */ /* pointers may be NULL, though in */ /* the latter case only for full */ /* screen opening; */ /* */ /* The event code is not read and */ /* can by any integer value; */ /* */ /* That the browser_data pointer is */ /* not NULL. */ /*************************************************/ int windows_open_browser(int eventcode, WimpPollBlock * b, IdBlock * idb, browser_data * handle) { /* Internally... */ /* */ /* 's' holds the browser window state, and is a WimpGetWindowStateBlock */ /* 'w' holds various bits of data, and is a BBox. It always ends up holding */ /* information for setting the window extent. */ /* 't' is a BBox holding the browser window's initial extent. */ /* 'o' holds the current window outline, and is a WimpGetWindowOutlineBlock. */ /* It's used for the part of the code dealing with toggle size. */ /* 'i' is a WimpGetPointerInfoBlock and is briefly used in the toggle size */ /* code to see if Adjust was pressed, since then you don't want to bring */ /* the window to the front. */ /* */ /* The Wimp will have sent a poll block containing open_window_request */ /* data; this is in 'b'. The toolbox will have filled in an ID block 'idb' */ /* and the routine is called with 'handle' containing a pointer to a */ /* browser_data structure (though it has to be declared as a void * rather */ /* than browser_data * for the function to be a Wimp event handler, hence */ /* all the casting that goes on). */ WimpGetWindowStateBlock s; BBox w, t; /* One simple case is Full Screen handling. The '!idb' check is */ /* used for external functions which want to go to full screen */ /* mode; they can call this function with 0, NULL, NULL and the */ /* browser_data pointer (with full_screen set to 1, as this is */ /* needed generally) without worrying that part of idb may be */ /* needed within the function for some reason - it is used */ /* further down and if conditions on this first 'if' failed, */ /* there would be a problem if idb were not filled in. */ if ((handle->full_screen && modechanged) || !idb) { WimpGetWindowStateBlock state; if (modechanged) { windows_open_full_screen(handle, 1, 0, choices.v_scroll, choices.h_scroll); modechanged = 0; } /* Reformat if required */ state.window_handle = handle->window_handle; ChkError(wimp_get_window_state(&state)); ChkError(frames_resize_frameset(handle, &state.visible_area)); windows_check_reformat(handle, &state.visible_area, handle->display_width); } else { int old_display_width; /* Remember the current visible area width for use later, */ /* to see if a page reformat is needed. */ old_display_width = handle->display_width; s.window_handle = b->open_window_request.window_handle; ChkError(wimp_get_window_state(&s)); ChkError(window_get_extent(0,idb->self_id,&t)); /* Was this a toggle size event? If so, handle manually */ if ((s.flags & WimpWindow_Toggled) != 0) { WimpGetWindowOutlineBlock o; int shift, ctrl, cmos; /* First check if Shift is pressed; the 'shift' variable will hold */ /* 255 if pressed or 0 if not. This is because the full size window */ /* shouldn't obscure the icon bar if shift is held down. */ _swix(OS_Byte, _INR(0,1) | _OUT(1), 121, 128, &shift); /* Similarly check for Control being held down. We'll only increase */ /* the vertical size if this is the case. */ _swix(OS_Byte, _INR(0,1) | _OUT(1), 121, 129, &ctrl); /* Check CMOS RAM byte 28, bit 4 - if set, reverse the sense of Shift */ _swix(OS_Byte, _INR(0,1) | _OUT(2), 161, 28, &cmos); if (cmos & (1u<<4)) shift = shift ? 0 : 255; /* Read the screen size in OS units */ w.xmin = bbc_modevar(-1, BBC_XEigFactor); w.ymin = bbc_modevar(-1, BBC_YEigFactor); w.xmax = bbc_modevar(-1, BBC_XWindLimit); w.ymax = bbc_modevar(-1, BBC_YWindLimit); w.xmax = (w.xmax + 1) << w.xmin; w.ymax = (w.ymax + 1) << w.ymin; /* This isn't good enough, as we need to take account of the window */ /* frame and tools. Since the window must already be open, we can */ /* use Wimp_GetWindowOutline and compare this to the visible size, */ /* where the difference is the size of borders and tools. */ o.window_handle = b->open_window_request.window_handle; ChkError(wimp_get_window_outline(&o)); w.xmin = (o.outline.xmax - o.outline.xmin) - (s.visible_area.xmax - s.visible_area.xmin); w.ymin = (o.outline.ymax - o.outline.ymin) - (s.visible_area.ymax - s.visible_area.ymin); /* Now have the information on the window dimensions to occupy the */ /* whole screen. */ if (!handle->full_size) { int h1, h2; /* Toggle up to full size. First, remember the current (small) size. */ handle->small_size.visible_area = s.visible_area; handle->small_size.xscroll = s.xscroll; handle->small_size.yscroll = s.yscroll; handle->small_size.behind = find_behind(b->open_window_request.window_handle); /* Set the poll block contents to open the window in the right place. */ /* Notice if Shift is held down and don't cover icon bar, and if Ctrl */ /* is held down we leave the X positions alone. */ if (!ctrl) { b->open_window_request.visible_area.xmin = 2; b->open_window_request.visible_area.xmax = w.xmax - w.xmin + 2; } else { b->open_window_request.visible_area.xmin = s.visible_area.xmin; b->open_window_request.visible_area.xmax = s.visible_area.xmax; w.xmin = s.visible_area.xmin; w.xmax = s.visible_area.xmax; } b->open_window_request.visible_area.ymin = s.visible_area.ymin - o.outline.ymin + (shift ? 128 : 0); b->open_window_request.visible_area.ymax = w.ymax - w.ymin + (s.visible_area.ymin - o.outline.ymin); /* Is adjust being pressed? If so, want to open at the same place */ /* in the window stack as at present. NB, the Wimp seems to take */ /* Select as higher priority than Adjust, so if both are pressed */ /* the window is brought to the front. This is why the code looks */ /* at the state of both buttons. */ { WimpGetPointerInfoBlock i; ChkError(wimp_get_pointer_info(&i)); if ( (i.button_state & Wimp_MouseButtonAdjust) != 0 && (i.button_state & Wimp_MouseButtonSelect) == 0 ) b->open_window_request.behind = s.behind; else b->open_window_request.behind = -1; } /* Ensure horizontal and vertical extent isn't too small, and don't ever */ /* shrink them - only reformat_set_extent is allowed to do that, in */ /* Reformat.c. The exception case is if the parent window has child */ /* frames, in which case we want the extent to track the visible area */ /* exactly, at all times. */ if (!handle->nchildren) { BBox extent; if (w.xmax - w.xmin < handle->display_extent) w.xmin = 0, w.xmax = handle->display_extent; window_get_extent(0,idb->self_id,&extent); if (w.ymax - w.ymin < extent.ymax - extent.ymin) w.ymax = w.ymin + extent.ymax - extent.ymin; if (w.ymax - w.ymin < MinimumHeight) w.ymax = w.ymin + MinimumHeight; } ChkError(set_corrected_extent(0, idb->self_id, &w)); /* Show the object */ ChkError(toolbox_show_object(0, idb->self_id, 1, &(b->open_window_request.visible_area), idb->parent_id, -1)); /* Flag that the window is full size */ handle->full_size = 1; /* Make sure the toolbars, if present, are up to date */ if (choices.move_gadgets != Choices_MoveGadgets_Never) toolbars_move_gadgets(handle); /* Update the visible area width and height fields */ handle->display_width = b->open_window_request.visible_area.xmax - b->open_window_request.visible_area.xmin; h1 = toolbars_button_height(handle) + toolbars_url_height(handle); h2 = toolbars_status_height(handle); if (h1) h1 += wimpt_dy(); if (h2) h2 += wimpt_dy(); handle->display_height = b->open_window_request.visible_area.ymax - b->open_window_request.visible_area.ymin - h1 - h2; /* Resize any child frames and reformat if necessary */ ChkError(frames_resize_frameset(handle, &b->open_window_request.visible_area)); windows_check_reformat(handle, &b->open_window_request.visible_area, old_display_width); } else { int h1, h2; w = handle->small_size.visible_area; /* An irritating feature of the Wimp - if you call Wimp_SetExtent, */ /* then the next Wimp_OpenWindow call is forced on-screen. This */ /* means that if toggle size is used when the window is partially */ /* dragged off-screen, then the shrinking horizontal extent when */ /* it is toggled back would ensure that the window was brought */ /* back fully on screen. Sometimes this is annoying. */ /* */ /* It turns out though, that if the window is *already* partially */ /* off-screen when the SetExtent call is made, the Wimp brings the */ /* window (internally) back on screen, and doesn't bother to do */ /* this on the next OpenWindow call. So to allow the window to be */ /* toggled back to a small size which may be partially off-screen, */ /* we open the window miles off screen somewhere before setting */ /* the extent. */ /* */ /* This is not pretty but it is relatively solid; the worst that */ /* can happen is the Wimp *does* decide to force the window back */ /* on screen at the next OpenWindow call, in which case the */ /* behaviour is as it would be without the extra code here. */ b->open_window_request.visible_area.xmin = w.xmin + 16384; b->open_window_request.visible_area.ymin = w.ymin - 16384; b->open_window_request.visible_area.xmax = w.xmax + 16384; b->open_window_request.visible_area.ymax = w.ymax - 16384; b->open_window_request.behind = handle->small_size.behind; toolbox_show_object(0, idb->self_id, 1, &(b->open_window_request.visible_area), idb->parent_id, -1); /* Store the new details in b for later use in the show_object call */ b->open_window_request.visible_area = w; b->open_window_request.xscroll = handle->small_size.xscroll; b->open_window_request.yscroll = handle->small_size.yscroll; b->open_window_request.behind = handle->small_size.behind; /* Set the extent, with usual restrictions on when not to shrink it (see */ /* elsewhere for more information, around similar pieces of code) */ if (!handle->nchildren) { BBox extent; if (w.xmax - w.xmin < handle->display_extent) w.xmin = 0, w.xmax = handle->display_extent; window_get_extent(0,idb->self_id,&extent); if (w.ymax - w.ymin < extent.ymax - extent.ymin) w.ymax = w.ymin + extent.ymax - extent.ymin; if (w.ymax - w.ymin < MinimumHeight) w.ymax = w.ymin + MinimumHeight; } ChkError(set_corrected_extent(0, idb->self_id, &w)); ChkError(toolbox_show_object(0, idb->self_id, 1, &(b->open_window_request.visible_area), idb->parent_id, -1)); handle->full_size = 0; /* Make sure the toolbars, if present, are up to date */ if (choices.move_gadgets != Choices_MoveGadgets_Never) toolbars_move_gadgets(handle); /* Update the visible area width and height fields */ handle->display_width = b->open_window_request.visible_area.xmax - b->open_window_request.visible_area.xmin; h1 = toolbars_button_height(handle) + toolbars_url_height(handle); h2 = toolbars_status_height(handle); if (h1) h1 += wimpt_dy(); if (h2) h2 += wimpt_dy(); handle->display_height = b->open_window_request.visible_area.ymax - b->open_window_request.visible_area.ymin - h1 - h2; /* Resize any child frames and reformat if needed */ ChkError(frames_resize_frameset(handle, &b->open_window_request.visible_area)); windows_check_reformat(handle, &b->open_window_request.visible_area, old_display_width); } } /* This isn't a Toggle Size event; so move or resize. Whilst the */ /* Toggle Size code above remembers the small size of a window if */ /* toggling up to full screen, this isn't enough as the user can */ /* drag the window to full size, particularly if the machine has */ /* been configured to allow windows off screen to the bottom and */ /* right of the screen. In this case, dragging the resize icon of */ /* a window off screen shuffles the window up and/or left, so it */ /* becomes easy to drag out to full screen. In this case, we don't */ /* know what the small size of the window was before the drag */ /* began, and so we can't return to it when the toggle size icon */ /* is used - you end up with the *previously stored* small size. */ /* */ /* To get round this, we need to install a null event handler when */ /* a window drag is detected. As soon as a null event is received */ /* without a mouse button being pressed, the drag must have ended. */ /* We can then check the size of the window, and if it isn't full */ /* screen, remember that size for toggle size later on. It's very */ /* long winded but that's what you get for taking over the window */ /* handling to such an extent...! */ else { /* For child frames (i.e. browser_data structs with a filled in ancestor field), */ /* this function will only be called from frames_resize_frames itself. This in */ /* turn is originally only called if the ancestor window resizes in some way. */ /* It's not possible to apply the 'has the visible area changed' check as */ /* rounding errors can lead to some frames just shuffling a bit, not resizing, */ /* and any children they had would then not be resized (or rather, moved) to fit */ /* the parent. */ /* */ /* We would in theory want to resize (and implicitly move) any frames even if */ /* the parent window moves, but doesn't resize. In the case of the nested Wimp */ /* though, the children are moved for you and moving them again produces some */ /* very odd effects! Consequently there are checks for the nested_wimp flag in */ /* the code. */ if (handle->ancestor || !nested_wimp) { ChkError(frames_resize_frameset(handle, &b->open_window_request.visible_area)); } /* Claim null events, if they aren't already being claimed */ if (!handle->watching_resize) { register_null_claimant(Wimp_ENull,(WimpEventHandler *) windows_remember_size,(void *) idb->self_id); handle->watching_resize = 1; } /* If the current and Wimp requested visible areas are the same in */ /* terms of horizontal and vertical size, the window is being */ /* moved; so don't do any extent setting stuff. However, if the */ /* Force On Screen bit is set, the then window has been shrunk or */ /* moved due to a mode change, so make sure the extent is right */ /* and the toolbars are set up correctly. Because the Wimp won't */ /* actually set the window size up for us until the next call to */ /* WimpOpenWindow, we need a separate handler for this case. */ if ( b->open_window_request.visible_area.xmax - b->open_window_request.visible_area.xmin != s.visible_area.xmax - s.visible_area.xmin || b->open_window_request.visible_area.ymax - b->open_window_request.visible_area.ymin != s.visible_area.ymax - s.visible_area.ymin || modechanged ) { /* See comments on the previous line that called frames_resize_frameset; */ /* for the ancestor, want to only resize frames if the ancestor resized, */ /* unless in a non-nested Wimp variant. */ if (nested_wimp && !handle->ancestor) { ChkError(frames_resize_frameset(handle, &b->open_window_request.visible_area)); } if (modechanged) { /* If there's been a mode change, call Wimp_OpenWindow to get the window's */ /* correct visible area and then sort out the correct extent. */ toolbox_show_object(0, idb->self_id, 1, &(b->open_window_request.visible_area), idb->parent_id, -1); wimp_get_window_state(&s); w = s.visible_area; } else { /* The requested visible area is different, so consider this to be a window */ /* resize event. In this case, set the horizontal extent to the visible */ /* area, provided this means the extent has grown. */ w = b->open_window_request.visible_area; } /* Set the extent, with usual restrictions on when not to shrink it (see */ /* elsewhere for more information, around similar pieces of code) */ if (!handle->nchildren) { BBox extent; //Printf("woo, resizing\n"); if (w.xmax - w.xmin < handle->display_extent) w.xmin = 0, w.xmax = handle->display_extent; window_get_extent(0,idb->self_id,&extent); if (w.ymax - w.ymin < extent.ymax - extent.ymin) w.ymax = w.ymin + extent.ymax - extent.ymin; if (w.ymax - w.ymin < MinimumHeight) w.ymax = w.ymin + MinimumHeight; } ChkError(set_corrected_extent(0, idb->self_id, &w)); if (modechanged) modechanged = 0; /* Show the object */ toolbox_show_object(0, idb->self_id, 1, &(b->open_window_request.visible_area), idb->parent_id, -1); /* Ensure toolbar gadgets are up to date */ if (choices.move_gadgets == Choices_MoveGadgets_During) toolbars_move_gadgets(handle); /* If an ancestor is highlighted, remove the highlight */ if (!handle->ancestor && handle == highlight_frame) frames_remove_highlight(); } else { /* Nothing has altered size; just move the window */ toolbox_show_object(0, idb->self_id, 1, &(b->open_window_request.visible_area), idb->parent_id, -1); } } } return 1; } /*************************************************/ /* windows_remember_size() */ /* */ /* This event handler is registered when an Open */ /* Window request is received by the event */ /* handler windows_open_browser, which should be */ /* referred to for more information. This */ /* handler is called on null polls, and when no */ /* mouse buttons are being pressed, deregisters */ /* itself and looks at the browser window it is */ /* associated with. If the window is not open */ /* full size, the size is remembered so that the */ /* toggle size code in windows_open_browser can */ /* operate correctly. */ /*************************************************/ int windows_remember_size(int eventcode, WimpPollBlock * b, IdBlock * idb, void * handle) { WimpGetPointerInfoBlock p; browser_data * d; #ifdef TRACE if (tl & (1u<<3)) Printf("windows_remember_size: Called\n"); #endif /* First thing - move the gadgets, if the choices indicate that */ /* we should, to fit the current window size. */ ChkError(toolbox_get_client_handle(0, (ObjectId) handle, (void *) &d)); /* Is this a valid pointer? If not, exit */ if (!is_known_browser(d)) return 0; /* Otherwise, proceed */ if (choices.move_gadgets == Choices_MoveGadgets_AtEnd) toolbars_move_gadgets(d); /* Are buttons being pressed? */ ChkError(wimp_get_pointer_info(&p)); /* If not... */ if (!p.button_state) { WimpGetWindowOutlineBlock o; WimpGetWindowStateBlock s; BBox w; /* Deregister the null event handler and flag that we */ /* are not watching resize events anymore. */ deregister_null_claimant(Wimp_ENull,(WimpEventHandler *) windows_remember_size,handle); d->watching_resize = 0; /* Get the window state (of interest is the visible area) */ /* and it's outline. This is so we can later work out the */ /* size of the window's tools. */ s.window_handle = d->window_handle; o.window_handle = s.window_handle; ChkError(wimp_get_window_state(&s)); ChkError(wimp_get_window_outline(&o)); /* Read the screen size in OS units */ w.xmin = bbc_modevar(-1, BBC_XEigFactor); w.ymin = bbc_modevar(-1, BBC_YEigFactor); w.xmax = bbc_modevar(-1, BBC_XWindLimit); w.ymax = bbc_modevar(-1, BBC_YWindLimit); w.xmax = (w.xmax + 1) << w.xmin; w.ymax = (w.ymax + 1) << w.ymin; /* Take account of window tools using Wimp_GetWindowOutline info from above */ w.xmin = (o.outline.xmax - o.outline.xmin) - (s.visible_area.xmax - s.visible_area.xmin); w.ymin = (o.outline.ymax - o.outline.ymin) - (s.visible_area.ymax - s.visible_area.ymin); /* Now know what the extent would be for a full screen window, so */ /* compare that to the current visible size. */ if (((s.visible_area.xmax - s.visible_area.xmin) < (w.xmax - w.xmin)) | ((s.visible_area.ymax - s.visible_area.ymin) < (w.ymax - w.ymin))) { /* Window isn't full screen, so remember the size */ d->small_size.visible_area = s.visible_area; d->small_size.behind = find_behind(s.window_handle); d->full_size = 0; } else d->full_size = 1; /* Update the visible area width field */ { int width; width = s.visible_area.xmax - s.visible_area.xmin; if (width < MinimumWidth) width = MinimumWidth; /* Tolerance is defined in Windows.h. We leave the display_width */ /* field alone until the change since it was last updated has */ /* exceeded the tolerance value, at which point it is set to the */ /* visible width (along with display_extent) and the page gets */ /* reformatted from the top. */ if (width != d->display_width) { if ( width - d->display_width > Tolerance || width - d->display_width < -Tolerance ) { if (!d->page_is_text) { int h1, h2; d->display_extent = d->display_width = width; h1 = toolbars_button_height(d) + toolbars_url_height(d); h2 = toolbars_status_height(d); if (h1) h1 += wimpt_dy(); if (h2) h2 += wimpt_dy(); d->display_height = s.visible_area.ymax - s.visible_area.ymin - h1 - h2; if (d->ancestor) windows_set_tools(d, &s.visible_area, 0, 0, 0, 0); reformat_format_from(d, -1, 1, -1); } } /* Leaving display_width alone has the side effect that centred */ /* objects stay centred relative to that value, not the slightly */ /* altered visible width, so no redraw problems occur if we */ /* don't bother forcing a redraw if the reformat isn't done. */ /* */ /* Hence, no 'else' case here. */ } } /* In any case remember the scroll position, or it could jump */ /* around when the small window size is later restored. */ d->small_size.xscroll = s.xscroll; d->small_size.yscroll = s.yscroll; } #ifdef TRACE if (tl & (1u<<3)) Printf("windows_remember_size: Successful\n"); #endif return 0; } /*************************************************/ /* windows_close_browser() */ /* */ /* Closes a Browser window, freeing up memory */ /* claimed for it. */ /* */ /* This DOES NOT CLOSE FRAMESETS, and memory */ /* claimed for that isn't freed. You should use */ /* the frames collapsing functions in Frames.c */ /* to do this. If there's any doubt, always */ /* close through the general handler in */ /* c.Handlers as this takes care of frames. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the window. */ /*************************************************/ void windows_close_browser(browser_data * handle) { browser_data * ancestor = handle->ancestor; /* Not utils_ancestor() as we want to know if 'ancestor' is NULL later */ #ifdef TRACE if (tl & (1u<<3)) Printf("windows_close_browser: Called\n"); #endif /* This may take a while if there's lots of flex freeing to do... */ _swix(Hourglass_Start, _IN(0), 10); /* Cancel any fetches */ ChkError(fetch_cancel(handle)); /* Stop the later code trying to destroy source / close the stream twice */ if (handle->fetch_handle == handle->display_handle) handle->display_handle = 0; /* If this frame is highlighted, this will clear that highlight */ ChkError(frames_remove_highlight_if_present(handle)); /* If the Open URL dialogue was opened from the window, this will close it */ ChkError(openurl_close(handle->self_id, 0)); /* If a main menu is open for the window, this closes it */ menus_close_document_if_mine(handle); /* If the Print dialogue was opened from the window, this will close */ /* it and the Print Style window (again, if open). */ ChkError(print_close(handle->self_id, 0)); /* If there is an ancestor and it has a selected token, */ /* is that token in this window? If so, want to clear */ /* that selection. At the same time, deal with status */ /* bar issues. */ if (ancestor) { if (ancestor->selected_owner == handle) { ancestor->selected = NULL; ancestor->selected_owner = NULL; } if (ancestor->selected_frame == handle) ancestor->selected_frame = NULL; /* Ensure that this window is removed from the array of */ /* status_contents structures associated with the */ /* ancestor's status bar. */ ChkError(toolbars_remove_status_item(handle, ancestor)); } /* Get rid of any attached event handlers on the window and its */ /* toolbars (if any). */ /* */ /* Because null events need to be claimed/released through the */ /* pollword, need to still use the internal routine to get rid */ /* of null event handlers, before calling the general eventlib */ /* routine to remove anything else. Otherwise the internal */ /* counter checking if nulls should be released won't be */ /* decremented correctly (Bad Things May Then Happen...). */ if (handle->watching_resize) deregister_null_claimant(Wimp_ENull,(WimpEventHandler *) windows_remember_size,(void *) handle->self_id); handle->watching_resize = 0; if (handle->fetch_handler) fetchpage_release_nulls(handle); if (handle->anim_drift) { deregister_null_claimant(Wimp_ENull,(WimpEventHandler *) toolbars_animation_drift, handle); handle->anim_drift = 0; } if (handle->plugin_active) { deregister_null_claimant(Wimp_ENull,(WimpEventHandler *) toolbars_animation, handle); handle->plugin_active = 0; } if (handle->status_handler) deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) toolbars_timeout_status, handle); handle->status_handler = 0; reformat_stop_pending(handle); /* Deregisters stuff as required */ if (handle->meta_refresh_at) deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) meta_check_refresh, handle); handle->meta_refresh_at = 0; if (handle->dragging) deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) handle_drags, handle); handle->dragging = 0; drag_in_progress = 0; /* If watching the dialler's status changed service call, */ /* or displaying online time, remove the relevant handlers. */ if (handle->dialler_status) event_deregister_message_handler(Message_Service, handle_dialler_service, handle); if (handle->dialler_last) deregister_null_claimant(Wimp_ENull, (WimpEventHandler *) handle_dialler_display, handle); handle->dialler_status = 0; handle->dialler_last = 0; /* Remove any pointer-related handlers */ browser_pointer_over_deleted(handle); /* Now release everything else */ { ObjectId tupper, tlower; /* Handlers for the main window */ ChkError(event_deregister_wimp_handlers_for_object(handle->self_id)); ChkError(event_deregister_toolbox_handlers_for_object(handle->self_id)); tupper = toolbars_get_upper(handle); if (tupper) { /* Handlers for the upper toolbar */ ChkError(event_deregister_wimp_handlers_for_object(tupper)); ChkError(event_deregister_toolbox_handlers_for_object(tupper)); } tlower = toolbars_get_lower(handle); if (tlower && tlower != tupper) { /* Handlers for the lower toolbar */ ChkError(event_deregister_wimp_handlers_for_object(tlower)); ChkError(event_deregister_toolbox_handlers_for_object(tlower)); } } /* Delete any related run-time created objects */ if (handle->save_dbox) { ChkError(toolbox_delete_object(0, handle->save_dbox)); handle->save_dbox = 0; } /* Get rid of the fetched source / stream */ browser_destroy_source(handle); if (handle->fetch_handle) { ChkError(html_close(handle->fetch_handle)); } if (handle->display_handle) { ChkError(html_close(handle->display_handle)); } /* Close any saving files */ if (handle->save_file) { fclose(handle->save_file); handle->save_file = NULL; } /* Get rid of any pending message blocks */ if (handle->pending_data_load) { free(handle->pending_data_load); #ifdef TRACE malloccount -= sizeof(WimpMessage); if (tl & (1u<<13)) Printf("** malloccount (windows_close_browser): \0211%d\0217\n",malloccount); #endif } /* If we were streaming data for a Plug-In, close the */ /* stream. */ if (handle->pstream) plugin_abort_stream(handle); /* Get rid of forms related data */ ChkError(form_discard(handle)); /* Get rid of any extra forms data */ #ifdef TRACE if (handle->post_data) { if (tl & (1u<<12)) Printf("windows_close_browser: flex_free block %p\n",&handle->post_data); flexcount -= flex_size((flex_ptr) &handle->post_data); if (tl & (1u<<13)) Printf("** flexcount: %d\n",flexcount); } #endif if (handle->post_data) flex_free((flex_ptr) &handle->post_data); /* Remove any Plug-In status message */ free(handle->plugin_status); handle->plugin_status = NULL; /* Remove any History references */ history_remove(handle, NULL); /* Get rid of images and Objects */ ChkError(image_discard(handle)); ChkError(object_discard(handle)); #ifdef TRACE if ((tl & (1u<<3)) && handle->ancestor) { Printf("\nwindows_close_browser: Structure %p is a child structure, ancestor %p\n",handle,handle->ancestor); if (handle->nchildren) Printf(" and has children.\n"); else Printf(" and has no children.\n"); } #endif /* Delete the window object. */ ChkError(toolbox_delete_object(0,handle->self_id)); #ifdef TRACE if (tl & (1u<<3)) Printf("\nDeleted object ID %p\n",(void *) handle->self_id); #endif /* Ensure any line list data relating to tables is freed */ #ifdef TRACE if (tl & (1u<<12)) Printf("windows_close_browser: Freeing table chunks\n"); #endif tables_free_memory(1, handle, handle->cell, 0); /* Ensure all memory chunks are freed */ #ifdef TRACE if (tl & (1u<<12)) Printf("windows_close_browser: Chunk CK_FURL\n" " CK_DURL\n" " CK_CHIL\n" " CK_NAME\n" " CK_FWID\n" " CK_FHEI\n" " CK_LINE\n" " CK_LDAT\n" " CK_STAT set to 0\n"); #endif ChkError(memory_set_chunk_size(handle, NULL, CK_FURL, 0)); ChkError(memory_set_chunk_size(handle, NULL, CK_DURL, 0)); ChkError(memory_set_chunk_size(handle, NULL, CK_CHIL, 0)); ChkError(memory_set_chunk_size(handle, NULL, CK_NAME, 0)); ChkError(memory_set_chunk_size(handle, NULL, CK_FWID, 0)); ChkError(memory_set_chunk_size(handle, NULL, CK_FHEI, 0)); ChkError(memory_set_chunk_size(handle, NULL, CK_LINE, 0)); ChkError(memory_set_chunk_size(handle, NULL, CK_LDAT, 0)); ChkError(memory_set_chunk_size(handle, NULL, CK_STAT, 0)); /* Lose any claimed fonts */ fm_lose_fonts(handle); /* Sort out the linked list next and previous pointers in */ /* the previous and next entries to this one (if they are */ /* present) */ if (handle->previous) (handle->previous)->next = handle->next; if (handle->next) (handle->next)->previous = handle->previous; else last_browser = handle->previous; #ifdef TRACE if (tl & (1u<<3)) { if (handle->previous) Printf("Previous structure %p: Next field pointed at %p.\n",(void *) handle->previous, (void *) handle->next); else Printf("No Previous structure\n"); if (handle->next) Printf("Next structure %p: Previous field pointed at %p.\n",(void *) handle->next, (void *) handle->previous); else Printf("No Next structure, last_browser set to previous\n"); } #endif /* Finally, free the browser_data and associated reformat_cell structures */ #ifdef TRACE if (tl & (1u<<12)) Printf("windows_close_browser: free block %p, which held 'reformat_cell' structure\n",handle->cell); malloccount -= sizeof(reformat_cell); if (tl & (1u<<13)) Printf("** malloccount (windows_close_browser): \0212%d\0217\n",malloccount); #endif free(handle->cell); #ifdef TRACE if (tl & (1u<<12)) Printf("windows_close_browser: free block %p, which held 'browser_data' structure\n",handle); malloccount -= sizeof(browser_data); if (tl & (1u<<13)) Printf("** malloccount (windows_close_browser): \0212%d\0217\n",malloccount); #endif free(handle); #ifdef TRACE if (tl & (1u<<3)) Printf("Structure memory freed\n"); #endif _swix(Hourglass_Off, 0); #ifdef TRACE if (tl & (1u<<3)) Printf("windows_close_browser: Successful\n"); #endif return; } /*************************************************/ /* windows_redraw_browser() */ /* */ /* Called on receiving a redraw request from the */ /* Wimp. Calls the browser redraw routines. */ /* */ /* Parameters are as for a standard Wimp event */ /* handler. */ /*************************************************/ int windows_redraw_browser(int eventcode, WimpPollBlock * b, IdBlock * idb, browser_data * handle) { WimpRedrawWindowBlock * redraw = (WimpRedrawWindowBlock *) b; int more; ChkError(wimp_redraw_window(redraw, &more)); if (more) { ChkError(redraw_draw(handle, redraw, 0, 0)); } return 1; } /*************************************************/ /* windows_show_browser() */ /* */ /* Shows a browser window, initially centred on */ /* the screen but futher windows are opened at */ /* successive sensible offsets to avoid them */ /* exactly overlapping one another. */ /* */ /* This default show position can be overridden */ /* in two ways; though the Choices specifying an */ /* absolute position to open at, or through the */ /* small_size.visible_area field of the */ /* browser_data struct holding an xmin and ymin */ /* that are not -1 on entry. */ /* */ /* Small fetch windows will be shown near the */ /* pointer. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the window, with the */ /* small_size.visible_area BBox */ /* filled in with -1 or a valid */ /* visible area as described above. */ /*************************************************/ void windows_show_browser(browser_data * b) { WimpOpenWindowBlock w; static int offset; ObjectId p, o; int fixed_size = 0; #ifdef TRACE if (tl & (1u<<3)) Printf("windows_show_browser: Called\n"); #endif o = b->self_id; if (!b->small_fetch) { /* Is there a valid small_size.visible_area block? */ if (b->small_size.visible_area.xmin != -1 && b->small_size.visible_area.ymin != -1) { w.visible_area = b->small_size.visible_area; fixed_size = 1; } else { fixed_size = 0; /* Find the screen x and y size in pixels and scale them */ /* to OS units using OS_ReadModeVariable calls via. the */ /* bbc_modevar function; also work out the top left */ /* coordinates at the same time. */ if (!choices.override_x) { w.visible_area.xmax = choices.width; w.xscroll = bbc_modevar(-1, BBC_XWindLimit); w.yscroll = bbc_modevar(-1, BBC_XEigFactor); w.visible_area.xmin = (((w.xscroll + 1) << w.yscroll) - w.visible_area.xmax) / 2; w.visible_area.xmax += w.visible_area.xmin; } else { w.visible_area.xmin = choices.override_x; w.visible_area.xmax = choices.width + choices.override_x; } if (!choices.override_y) { w.visible_area.ymin = choices.height; w.xscroll = bbc_modevar(-1, BBC_YWindLimit); w.yscroll = bbc_modevar(-1, BBC_YEigFactor); w.visible_area.ymax = (((w.xscroll + 1) << w.yscroll) + w.visible_area.ymin) / 2; w.visible_area.ymin = w.visible_area.ymax - w.visible_area.ymin; } else { w.visible_area.ymin = choices.override_y; w.visible_area.ymax = choices.height + choices.override_y; } /* Handle offset for successive windows, but don't cover */ /* up the icon bar */ if ((w.visible_area.ymin - offset) >= 132) { w.visible_area.ymin -= offset; w.visible_area.ymax -= offset; offset += 48; } else offset = 48; } w.xscroll = 0; w.yscroll = 0; w.behind = -1; ChkError(set_corrected_extent(0, o, &w.visible_area)); } ChkError(toolbox_get_parent(0,o,&p,NULL)); if (!b->ancestor || !nested_wimp) { /* For an ancestor window (i.e. a window which does not have */ /* an ancestor itself) or no nested Wimp, open it as normal. */ if (!b->small_fetch) { ChkError(toolbox_show_object(0, o, Toolbox_ShowObject_FullSpec, &w.visible_area, p, -1)); } else { ChkError(toolbox_show_object(0, o, Toolbox_ShowObject_AtPointer, NULL, p, -1)); } } else { /* Otherwise, take advantage of the nested Wimp for child windows */ WindowShowObjectBlock show; WimpGetWindowStateBlock state; state.window_handle = b->ancestor->window_handle; ChkError(wimp_get_window_state(&state)); show.visible_area = w.visible_area; show.xscroll = w.xscroll; show.yscroll = w.yscroll; show.behind = w.behind; show.parent_window_handle = (b->ancestor)->window_handle; show.alignment_flags = Alignment_LeftEdge_WorkArea | Alignment_RightEdge_WorkArea | Alignment_TopEdge_WorkArea | Alignment_BottomEdge_WorkArea | Alignment_XScroll_WorkArea | Alignment_YScroll_WorkArea; ChkError(toolbox_show_object(Toolbox_ShowObject_AsSubWindow, o, Toolbox_ShowObject_FullSpec, &show, p, -1)); } if (!fixed_size && !b->small_fetch) { /* Fill in the small_size information for the window in its */ /* browser_data structure */ b->small_size.visible_area = w.visible_area; /* Now that the window is open, can get it's outline etc.; */ /* so can go up to full screen if required. */ if (b->full_screen) windows_open_full_screen(b, 1, 0, choices.v_scroll, choices.h_scroll); } /* If the requested size was larger than the available screen, */ /* (most often seen on A5000s where 640x480x256 is in use and */ /* a new browser window is opened - the Choices want to make */ /* it larger than the space that's availale) */ // // // // /* Opening width considerations... */ // // b->display_width = b->display_extent = width; // // if (b->display_extent < MinimumWidth) b->display_extent = MinimumWidth, b->display_width = MinimumWidth; // // /* ...and opening height */ // // b->display_height = height; // // #ifdef TRACE if (tl & (1u<<3)) Printf("windows_show_browser: Successful\n"); #endif } /*************************************************/ /* windows_open_full_screen() */ /* */ /* Opens a browser window Full Screen or small, */ /* optionally recording its previous size in the */ /* small_size fields when going to Full Screen. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the window; */ /* */ /* 1 for Full Screen, else 0; */ /* */ /* 1 to record the size, else 0; */ /* */ /* 1 to leave a vertical scroll bar */ /* visible, else 0; */ /* */ /* 1 to leave a horizontal scroll */ /* bar visible, else 0. */ /*************************************************/ _kernel_oserror * windows_open_full_screen(browser_data * b, int full_screen, int record, int vertsc, int horisc) { BBox w; WimpOpenWindowBlock o; WimpGetWindowStateBlock s; WimpGetWindowOutlineBlock outline; ObjectId parent; #ifdef TRACE if (tl & (1u<<3)) Printf("windows_open_full_screen: Called\n"); #endif /* Get the window state (for flags, scroll etc.) and its outline. */ s.window_handle = o.window_handle = outline.window_handle = b->window_handle; RetError(wimp_get_window_state(&s)); RetError(wimp_get_window_outline(&outline)); /* If being asked to open to Full Screen, set up the BBox 'w' to */ /* hold a visible area appropriate to a full screen window. */ if (full_screen) { /* Get the screen size in OS units */ w.xmin = bbc_modevar(-1, BBC_XEigFactor); w.ymin = bbc_modevar(-1, BBC_YEigFactor); w.xmax = bbc_modevar(-1, BBC_XWindLimit); w.ymax = bbc_modevar(-1, BBC_YWindLimit); w.xmax = (w.xmax + 1) << w.xmin; w.ymax = (w.ymax + 1) << w.ymin; w.xmax -= ((s.flags & WimpWindow_VScroll) && (choices.v_scroll)) ? (outline.outline.xmax - s.visible_area.xmax) : 2; w.xmin = 2; w.ymax -= 2; w.ymin = ((s.flags & WimpWindow_HScroll) && (choices.h_scroll)) ? (s.visible_area.ymin - outline.outline.ymin) : 2; if (record) { /* Remember the current (small) size */ b->small_size.visible_area = s.visible_area; b->small_size.xscroll = s.xscroll; b->small_size.yscroll = s.yscroll; b->small_size.behind = -1; } } /* Otherwise, go back to the visible area stored in the window's */ /* small_size.visible_area BBox. */ else { /* Revert to a previously stored small size */ w = b->small_size.visible_area; } /* An irritating feature of the Wimp - if you call Wimp_SetExtent, */ /* then the next Wimp_OpenWindow call is forced on-screen. This */ /* means that if toggle size is used when the window is partially */ /* dragged off-screen, then the shrinking horizontal extent when */ /* it is toggled back would ensure that the window was brought */ /* back fully on screen. Sometimes this is annoying. */ /* */ /* It turns out though, that if the window is *already* partially */ /* off-screen when the SetExtent call is made, the Wimp brings the */ /* window (internally) back on screen, and doesn't bother to do */ /* this on the next OpenWindow call. So to allow the window to be */ /* toggled back to a small size which may be partially off-screen, */ /* we open the window miles off screen somewhere before setting */ /* the extent. */ /* */ /* This is not pretty but it is relatively solid; the worst that */ /* can happen is the Wimp *does* decide to force the window back */ /* on screen at the next OpenWindow call, in which case the */ /* behaviour is as it would be without the extra code here. */ o.visible_area.xmin = w.xmin + 16384; o.visible_area.ymin = w.ymin - 16384; o.visible_area.xmax = w.xmax + 16384; o.visible_area.ymax = w.ymax - 16384; o.behind = -1; /* Show the object off-screen, making sure we don't trash the parent object ID information */ RetError(toolbox_get_parent (0, b->self_id, &parent, NULL)); RetError(toolbox_show_object(0, b->self_id, 1, &o.visible_area,parent, -1)); /* Set up the OpenWindow block */ o.window_handle = b->window_handle; o.visible_area = w; o.xscroll = s.xscroll; o.yscroll = s.yscroll; o.behind = -1; /* w holds the extent we require. If the horizontal extent is smaller */ /* than the horizontal minimum defined for this window, make sure it */ /* is increased to that minimum. Ensure also that the vertical */ /* extent isn't too small, and never shrink it either. Note that the */ /* exception case is for when the parent has child frames - in that */ /* case, leave w alone, so the extent will track the visible area */ /* exactly (which is the desired effect). */ if (!b->nchildren) { BBox extent; if (w.xmax - w.xmin < MinimumWidth) w.xmax = w.xmin + MinimumWidth; window_get_extent(0,b->self_id,&extent); if (w.ymax - w.ymin < extent.ymax - extent.ymin) w.ymax = w.ymin + extent.ymax - extent.ymin; if (w.ymax - w.ymin < MinimumHeight) w.ymax = w.ymin + MinimumHeight; } RetError(set_corrected_extent(0, b->self_id, &w)); /* If the Wimp supports changing window flags, set the */ /* Back and No Bounds bits for a full screen show, */ /* else clear them. */ if (nested_wimp) { unsigned int clear, eor; clear = ( (choices.full_screen && controls.back_window) ? WimpWindow_Back : 0 ) | WimpWindow_NoBounds; if (full_screen) eor = clear; else eor = 0; RetError(set_window_flags(b->window_handle, clear, eor)); } /* Show the object in the correct on-screen position */ RetError(toolbox_show_object(0, b->self_id, 1, &o.visible_area, parent, -1)); /* Make sure the toolbars, if present, are up to date */ if (choices.move_gadgets != Choices_MoveGadgets_Never) toolbars_move_gadgets(b); /* Update the visible area width and height fields */ b->display_width = b->display_extent = o.visible_area.xmax - o.visible_area.xmin; if (b->display_extent < MinimumWidth) b->display_width = b->display_extent = MinimumWidth; { int h1, h2; h1 = toolbars_button_height(b) + toolbars_url_height(b); h2 = toolbars_status_height(b); if (h1) h1 += wimpt_dy(); if (h2) h2 += wimpt_dy(); b->display_height = o.visible_area.ymax - o.visible_area.ymin - h1 - h2; } /* Ensure any child frames are resized to fit */ #ifdef TRACE if (tl & (1u<<3)) Printf("windows_open_full_screen: Exitting through frames_resize_frameset\n"); #endif return frames_resize_frameset(b, &o.visible_area); } /*************************************************/ /* windows_process_icon_text() */ /* */ /* Takes a Wimp icon handle and looks at a given */ /* text string, which can contain a special */ /* string of characters instructing the function */ /* to perform various changes to the icon. */ /* */ /* The string must start with '@!' to indicate */ /* it isn't some ordinary preinitialised string, */ /* and can contain these comma separated values: */ /* */ /* N Ensure the icon has (N)o border. */ /* H Ensure the icon (H)as a border. */ /* Bn Set background to colour n (n=hex). */ /* Fn Set foreground to colour n (n=hex). */ /* */ /* Parameters: Pointer to WimpGetIconStateBlock */ /* holding the window handle the */ /* icon is in and the icon's handle */ /* (the full icon state will be */ /* read in by this function, it does */ /* not need to be done externally); */ /* */ /* Pointer to the special text; */ /* */ /* 1 to set the first character of */ /* the text to a null byte (i.e. get */ /* rid of the string) if it is a */ /* special string (otherwise it is */ /* left untouched), else 0. */ /*************************************************/ void windows_process_icon_text(WimpGetIconStateBlock * icon, char * text, int remove) { /* Check this is special text */ if (!text || strlen(text) < 3) return; if (text[0] != '@' || text[1] != '!') return; /* It is, so process it */ if (wimp_get_icon_state(icon)) return; else { WimpSetIconStateBlock state; int array, value; unsigned int flags; array = 2; flags = icon->icon.flags; /* Parse the text */ while (text[array]) { switch (text[array]) { case 'N': flags &= ~WimpIcon_Border, array++; break; case 'H': flags |= WimpIcon_Border, array++; break; case 'B': case 'F': case 'C': { unsigned int mask, shift; if (text[array] == 'B') shift = WimpIcon_BGColour; else if (text[array] == 'C') shift = WimpIcon_ButtonType; else shift = WimpIcon_FGColour; array ++; value = (int) strtoul(text + array, NULL, 16); array ++; if (value < 0) value = 0; if (value > 15) value = 15; mask = 15 * shift; flags &= ~mask; flags |= (value * shift); } break; default: array++; break; } while (text[array] == ',') array++; } /* Set the new flags, if they've changed */ if (flags != icon->icon.flags) { state.window_handle = icon->window_handle; state.icon_handle = icon->icon_handle; state.clear_word = 0xffffffff; state.EOR_word = flags; wimp_set_icon_state(&state); } } /* Remove the text, if asked to do so */ if (remove) text[0] = 0; return; } /*************************************************/ /* windows_process_component_text() */ /* */ /* Calls windows_process_icon_text for a given */ /* component of a given Toolbox object. */ /* */ /* Parameters: Object ID the component lies in; */ /* */ /* The component ID; */ /* */ /* Pointer to a buffer to hold the */ /* icon's text; */ /* */ /* Size of the buffer; */ /* */ /* Out of the icons that make up the */ /* component, the number of the one */ /* to alter (starting from 0); */ /* */ /* 1 to set the first character of */ /* the text to a null byte (i.e. get */ /* rid of the string) if it is a */ /* special string (otherwise it is */ /* left untouched), else 0. */ /*************************************************/ _kernel_oserror * windows_process_component_text(ObjectId o, ComponentId c, char * buffer, int buffsize, int iconnum, int remove) { _kernel_oserror * e; WimpGetIconStateBlock icon; int iconlist[10]; if (buffsize < 2) return NULL; /* Get the object's window handle and the icon handle for the given component */ e = window_get_wimp_handle(0, o, &icon.window_handle); #ifdef TRACE if (e) return e; #else if (e) return NULL; #endif e = gadget_get_icon_list(0, o, c, iconlist, sizeof(iconlist), NULL); if (e) return NULL; /* Don't throw errors as may not want this component for some builds */ icon.icon_handle = iconlist[iconnum]; /* Read, process, and set the text */ e = wimp_get_icon_state(&icon); if (e) return NULL; strncpy(buffer, icon.icon.data.it.buffer, buffsize - 1); buffer[buffsize - 1] = 0; windows_process_icon_text(&icon, buffer, remove); if (icon.icon.data.it.buffer_size > 1) strncpy(icon.icon.data.it.buffer, buffer, icon.icon.data.it.buffer_size - 1); return NULL; } /*************************************************/ /* windows_initialise_tool_sizes() */ /* */ /* Sets up local copies of the current window */ /* tool sizes through find_tool_sizes. */ /*************************************************/ _kernel_oserror * windows_initialise_tool_sizes(void) { return find_tool_sizes(&title_height, &hscroll_height, &vscroll_width); } /*************************************************/ /* windows_return_tool_sizes() */ /* */ /* Returns the title bar and scroll bar widths */ /* in OS units, including their outlines (some */ /* of which will form part of the visible area */ /* border). */ /* */ /* This will only work correctly if a call to */ /* windows_initialise_tool_sizes has been made */ /* at least once before. */ /* */ /* Parameters: Pointer to an int, in which the */ /* title bar height is placed; */ /* */ /* Pointer to an int, in which the */ /* horizontal scroll bar bar height */ /* is placed; */ /* */ /* Pointer to an int, in which the */ /* vertical scroll bar width is */ /* placed. */ /* */ /* Assumes: Any of the pointers may be NULL. */ /*************************************************/ void windows_return_tool_sizes(int * theight, int * hheight, int * vwidth) { if (theight) *theight = title_height; if (hheight) *hheight = hscroll_height; if (vwidth) *vwidth = vscroll_width; return; } /*************************************************/ /* windows_set_tools() */ /* */ /* If using the nested Wimp, turns on/off */ /* selected tools around a window. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the window; */ /* */ /* Pointer to a BBox, in which the */ /* proposed visible area of the */ /* window may be placed. If NULL, */ /* it will be read from a call to */ /* Wimp_GetWindowState - however, */ /* scrollbars that you're trying to */ /* remove may have forced the area */ /* up somewhat, hence the ability to */ /* give a desired pre-removal BBox; */ /* */ /* 1 for a title bar, else 0; */ /* */ /* 1 for a vertical scroll bar, else */ /* 0; */ /* */ /* 1 for a horizontal scroll bar, */ /* else 0; */ /* */ /* 1 for a resize icon, else 0. */ /* */ /* Assumes: The BBox pointer may be NULL. */ /*************************************************/ _kernel_oserror * windows_set_tools(browser_data * b, BBox * box, int title, int vscroll, int hscroll, int resize) { if (!nested_wimp) return NULL; else { _kernel_oserror * e; WimpGetWindowStateBlock s; BBox extent; unsigned int parent, align; unsigned int old_flags; int th, hh, vw, must_redraw = 0, must_reformat = 0; /* If there's a highlight on this frame, remove it to avoid */ /* complications with it getting left in the wrong place. */ if (b == highlight_frame) frames_remove_highlight(); /* Get the window state and extent */ s.window_handle = b->window_handle; RetError(_swix(Wimp_GetWindowState, _INR(1, 2) | _OUTR(3, 4), &s, Magic_Word_TASK, /* See MiscDefs.h */ &parent, &align)); RetError(window_get_extent(0, b->self_id, &extent)); /* Without the following line, the resize routines (such as windows_remember_size) can */ /* set up display_extent and display_width to appropriate values and call the */ /* reformatter, waiting for it to set the actual extent to match these values. However */ /* if this function gets in first - and it usually will - it will read the extent and */ /* then (re)set the values to the old settings; unless, that is, the following line is */ /* included to spot that the actual extent and display_extent settings differ. */ /* */ /* Of course, it's never *that* easy, so what we have to do is only set it if the */ /* extent we would have used is smaller. This is because during resizes of frames, */ /* documents can continue to reformat or reload (client pull) in the background, since */ /* null events are coming in (compare to a parent window resize, where event 1, */ /* Wimp_EOpenWindow, is being generated). This can mean that display_extent is out of */ /* date, and forcing the extent to it shrinks the window. The right hand edge of the */ /* frame thus suddenly gets pulled along with the left (or vice versa) and the visual */ /* effect is that the frameset tears itself apart. Not nice. */ /* */ /* And yes, I know this is *another* overlong comment, but necessary nonetheless. */ if (extent.xmax - extent.xmin < b->display_extent) extent.xmax = extent.xmin + b->display_extent; /* Flags will only be set if they've changed */ old_flags = s.flags; /* Need to know the window tool sizes */ windows_return_tool_sizes(&th, &hh, &vw); /* The Wimp won't try to keep the visible footprint of the window */ /* the same as border icons appear and disappear. This is pretty */ /* useless from the browser's point of view; need to manually */ /* play around with the visible area to cope. */ if ((s.flags & WimpWindow_TitleIcon) && !title) s.visible_area.ymax += th, extent.ymax += th; if (!(s.flags & WimpWindow_TitleIcon) && title) s.visible_area.ymax -= th, extent.ymax -= th; if ((s.flags & WimpWindow_VScroll) && !vscroll) s.visible_area.xmax += vw, extent.xmax += vw, must_redraw = 1; if (!(s.flags & WimpWindow_VScroll) && vscroll) s.visible_area.xmax -= vw, extent.xmax -= vw, must_redraw = 1, must_reformat = 1; if ((s.flags & WimpWindow_HScroll) && !hscroll) s.visible_area.ymin -= hh, extent.ymin -= hh; if (!(s.flags & WimpWindow_HScroll) && hscroll) s.visible_area.ymin += hh, extent.ymin += hh; /* Modify them */ if (title) s.flags = s.flags | WimpWindow_TitleIcon; else s.flags = s.flags &~ WimpWindow_TitleIcon; if (vscroll) s.flags = s.flags | WimpWindow_VScroll; else s.flags = s.flags &~ WimpWindow_VScroll; if (hscroll) s.flags = s.flags | WimpWindow_HScroll; else s.flags = s.flags &~ WimpWindow_HScroll; if (resize) s.flags = s.flags | WimpWindow_SizeIcon; else s.flags = s.flags &~ WimpWindow_SizeIcon; /* If the flags have changed... */ if (s.flags != old_flags) { WindowShowObjectBlock show; ObjectId tparent; /* If there's a highlight on this frame, remove it to avoid */ /* complications with it getting left in the wrong place. */ if (b == highlight_frame) frames_remove_highlight(); /* Ensure the extent is corrected for the addition or removal of tools */ RetError(window_set_extent(0, b->self_id, &extent)); /* Alter the flags */ show.visible_area = s.visible_area; show.xscroll = s.xscroll; show.yscroll = s.yscroll; show.behind = s.behind; show.window_flags = s.flags; show.parent_window_handle = parent; show.alignment_flags = align | Alignment_NewFlagsGiven; RetError(toolbox_get_parent(0, b->self_id, &tparent, NULL)); if (nested_wimp) { /* For the nested Wimp, simple - just reopen with the new-style call */ e = toolbox_show_object(Toolbox_ShowObject_AsSubWindow, b->self_id, Toolbox_ShowObject_FullSpec, &show, tparent, -1); } else { // This code not done yet (not urgent enough for now). // *If* eventually implemented, the 'if' wrapper around // the whole of this function's code obviously needs to // be removed first. e = NULL; } if (e) return e; /* If must_redraw is set, redraw errors could occur unless the window is redrawn now. */ if (must_redraw) { BBox workarea = s.visible_area; coords_box_toworkarea(&workarea, (WimpRedrawWindowBlock *) &s); RetError(wimp_force_redraw(s.window_handle, workarea.xmin, workarea.ymin, workarea.xmax, workarea.ymax)); /* May well need to move the toolbar gadgets, too */ if (choices.move_gadgets != Choices_MoveGadgets_Never) toolbars_move_gadgets(b); } /* If must_reformat is set, for childless windows, reformat the page */ if (must_reformat && !b->nchildren) reformat_format_from(b, -1, 1, -1); } /* Update the various browser width records in light of any */ /* changes in the window, and similarly update the height */ b->display_extent = extent.xmax - extent.xmin; b->display_width = s.visible_area.xmax - s.visible_area.xmin; if (b->display_width < MinimumWidth) b->display_width = MinimumWidth; { int h1, h2; h1 = toolbars_button_height(b) + toolbars_url_height(b); h2 = toolbars_status_height(b); if (h1) h1 += wimpt_dy(); if (h2) h2 += wimpt_dy(); b->display_height = s.visible_area.ymax - s.visible_area.ymin - h1 - h2; } /* If there are children and this is an ancestor window, resize the children */ if (!b->ancestor && b->nchildren) frames_resize_frameset(b, &s.visible_area); return NULL; } } /*************************************************/ /* windows_check_tools() */ /* */ /* Looks at a window, and if in a certain */ /* direction the visible area and extent are */ /* the same, turns off scroll bars (they aren't */ /* needed). */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the window; */ /* */ /* Pointer to a BBox, passed on to */ /* windows_set_tools (see that */ /* function for details). */ /*************************************************/ _kernel_oserror * windows_check_tools(browser_data * b, BBox * box) { WimpGetWindowStateBlock s; BBox extent; int hscroll = 0, vscroll = 0; /* For small fetch windows, don't want to touch the tools */ if (b->small_fetch) return NULL; /* Otherwise, proceed */ s.window_handle = b->window_handle; RetError(wimp_get_window_state(&s)); RetError(window_get_extent(0, b->self_id, &extent)); /* Turn on scroll bars if the visible area is less than the */ /* extent in the appropriate direction. */ if (s.visible_area.xmax - s.visible_area.xmin < extent.xmax - extent.xmin) hscroll = 1; if (s.visible_area.ymax - s.visible_area.ymin < extent.ymax - extent.ymin) vscroll = 1; if (!b->ancestor && !b->full_screen) { /* Ancestor windows should always have both scroll bars, unless */ /* running full screen. */ hscroll = vscroll = 1; } else { /* Otherwise, read the scroll bar flags */ if (!b->nchildren) { /* Frames or full screen windows with no children themselves*/ if (b->frame_hscroll == 0) hscroll = 0; /* No */ else if (b->frame_hscroll == 2) hscroll = 1; /* Yes, else use values found above (i.e. auto) */ /* If there is a vertical scroll bar present already, and this window */ /* has no children, don't want to remove that bar. This is so that */ /* frames can start with no scroll bar, then later the reformatter */ /* may decide to add one. Since the page width changes the */ /* windows_set_tools call will call the reformatter again. However, */ /* the new reformat could turn off the vertical scroll bar - so the */ /* reformatter locks into a recursive loop. Hence, can only ever */ /* remove a vscroll for a childless window by an explicit call to */ /* windows_set_tools; otherwise, once it's added, it stays. */ /* */ /* The exception, of course, is for frames with scrolling explicitly */ /* set to 'no'. */ if (!b->frame_vscroll) vscroll = 0; else if (b->frame_vscroll == 2 || (s.flags & WimpWindow_VScroll)) vscroll = 1; // if (b->frame_vscroll == 0) vscroll = 0; // else if (b->frame_vscroll == 2) vscroll = 1; } else { /* Frames with children *must* have no scroll bars, or resize routines */ /* later on, which read visible areas, will fail, and the bars will be */ /* visible in gaps between frames. */ hscroll = vscroll = 0; } } RetError(windows_set_tools(b, box, !b->ancestor, vscroll, hscroll, !b->full_screen && !b->ancestor)); return NULL; }