/* 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 : Hotlist.c */ /* */ /* Purpose: Managing a hotlist in the browser. */ /* */ /* Author : D.T.A.Brown */ /* */ /* History: 06-Aug-97: Created. */ /* 22-Aug-97: (ADH/DTAB) Integrated into */ /* main browser code. */ /***************************************************/ #include #include #include #include #include "swis.h" #include "toolbox.h" #include "wimp.h" #include "wimplib.h" #include "menu.h" #include "event.h" #include "gadgets.h" #include "svcprint.h" #include "Global.h" #include "FromROSLib.h" #include "Utils.h" #include "FetchPage.h" #include "Save.h" #include "Toolbars.h" #include "URLUtils.h" #include "Windows.h" #include "Hotlist.h" /* Local definitions */ #define HotlistWrite(fn) {written = (fn); if (written < 0) return _kernel_last_oserror();} /* Local statics */ static int autoopen_oldtime; /* Base time for autoopen directory */ static hotlist_item * hotlist_root = NULL; /* Pointer to the hotlist root directory item */ static int hotlist_windowid; /* Object ID of the hotlist window */ static hotlist_item * hotlist_newitem; /* When ever a new item is created this points to it */ static int menu_itemno = 0; /* Item over which menu was pressed */ static int menu_select = 0; /* 1 if an item had to be selected when the menu was opened */ static unsigned int last_selected_item = 0xffffffff; /* The last item which was selected */ static int hotlist_dragging = 0; /* Holds a set of values for different dragging cases (see Hotlist.h) */ static unsigned int highlighted_itemno; /* During dragging, the number of a directory item using the '...+' sprite */ static hotlist_item * hotlist_current_highlighted = NULL; /* To save scanning lists, pointer to the highlighted item */ static int hl_show_urls; /* 0 when url descriptions to be shown, 1 to show urls */ static unsigned int hotlist_bbar_size = 0; /* Height in OS units of the button bar */ static unsigned int alter_new; /* Remembers if the edit dialogue is Alter or New; see */ /* HOTLIST_MENUSECTION_NEW and HOTLIST_MENUSECTION_ALTER */ static hotlist_item * hotlist_save_item = NULL; /* Item whose URL is being saved */ static int hotlist_ram_transfer_sent; /* Number of bytes which have already been sent by ram transfer */ static int hotlist_save_type = HL_SAVE_NONE; /* Variety of save currently in progress */ /* Event handler prototypes */ // Write these out in full, to clearly state exactly what parameters are needed? // Or is this in fact more robust, as the compiler will fault mismatched functions // in this source as opposed to wherever a registration of the handler occurs? static _kernel_oserror * hotlist_selection_box_start(void); static WimpEventHandler hotlist_redraw_handler; static WimpEventHandler hotlist_mouse_click_handler; static WimpEventHandler hotlist_drag_completed_handler; static WimpEventHandler hotlist_null_handler; static WimpEventHandler hotlist_null_drag_select_handler; static ToolboxEventHandler hotlist_menuopen_handler; static ToolboxEventHandler hotlist_menuclose_handler; static ToolboxEventHandler hotlist_menu_selectall_handler; static ToolboxEventHandler hotlist_menu_clearselect_handler; static ToolboxEventHandler hotlist_menu_openall_handler; static ToolboxEventHandler hotlist_menu_closeall_handler; static ToolboxEventHandler hotlist_menu_delete_handler; static ToolboxEventHandler hotlist_show_editurl_handler; static ToolboxEventHandler hotlist_show_rendirectory_handler; static ToolboxEventHandler hotlist_show_newurl_handler; static ToolboxEventHandler hotlist_show_newdirectory_handler; static ToolboxEventHandler hotlist_newedit_url_handler; static ToolboxEventHandler hotlist_newren_directory_handler; static ToolboxEventHandler hotlist_reset_url_handler; static ToolboxEventHandler hotlist_reset_directory_handler; static ToolboxEventHandler hotlist_show_descriptions_handler; static ToolboxEventHandler hotlist_show_urls_handler; static WimpMessageHandler hotlist_data_save_ack_handler; static WimpMessageHandler hotlist_ram_fetch_handler; /* Debug functions */ #ifdef TRACE static void hotlist_display_item(hotlist_item * item); static void hotlist_display_tree(hotlist_item * list, int indent); #endif /* List enquiry and manupulation */ static _kernel_oserror * hotlist_link (hotlist_item * item, hotlist_item * target, unsigned int position); static void hotlist_unlink (hotlist_item * item); static _kernel_oserror * hotlist_new_directory (hotlist_item * parent, char * directory_name, unsigned int position, hotlist_item ** new); static _kernel_oserror * hotlist_new_url (hotlist_item * parent, unsigned int position, char * url_description, char * url); static void hotlist_delete_item (hotlist_item * item); static _kernel_oserror * hotlist_move_item (hotlist_item * source, hotlist_item * target, unsigned int position); static _kernel_oserror * hotlist_copy_item (hotlist_item * source, hotlist_item * target, unsigned int position, hotlist_item ** new_item); /* Item enquiry and manipulation */ static _kernel_oserror * hotlist_get_entry_sizes (unsigned int * item_height, unsigned int * item_dir_width, unsigned int * item_url_width); static int hotlist_set_flags (hotlist_item * list, hotlist_type type, unsigned int flags); static int hotlist_clear_flags (hotlist_item * list, hotlist_type type, unsigned int flags); /* Finding items */ static hotlist_item * hotlist_find_item (hotlist_item * list, unsigned int item_no); static hotlist_item * hotlist_find_item_r (hotlist_item * list, unsigned int item_no, int * curr_item); static int hotlist_find_no_from_item (hotlist_item * item); static int hotlist_find_no_from_item_r (hotlist_item * list, hotlist_item * item, int * curr_item); static hotlist_item * hotlist_find_selected_item (void); static hotlist_item * hotlist_find_selected_item_r (hotlist_item * list); /* Counting items */ static unsigned int hotlist_count_selected_items (void); static void hotlist_count_selected_items_r (hotlist_item * list, int * count); static unsigned int hotlist_count_displayed_items (hotlist_item * list); static void hotlist_count_displayed_items_r (hotlist_item * list, int * count); // Categorisation work in progress... static _kernel_oserror * hotlist_draw (hotlist_item * list, unsigned int first_item, unsigned int last_item); static _kernel_oserror * hotlist_draw_r (hotlist_item *list, unsigned int first_item, unsigned int last_item, int * curr_item, unsigned int indent, unsigned int item_height, unsigned int item_dir_width, unsigned int item_url_width); static unsigned int hotlist_contents_selected (hotlist_item * item); static unsigned int hotlist_no_contents_selected (hotlist_item * item); static unsigned int hotlist_get_max_width (hotlist_item * list); static _kernel_oserror * hotlist_get_max_width_r (hotlist_item *list, unsigned int indent, int * max_width, unsigned int item_height, unsigned int item_dir_width, unsigned int item_url_width); static void hotlist_redraw_now (void); static void hotlist_redraw_now_r (hotlist_item * list, int * curr_item); static void hotlist_get_shape (unsigned int * xmin, unsigned int * xmax, hotlist_item * item); static void hotlist_directory_open_close (hotlist_item * item, unsigned int itemno); static void hotlist_redraw_items (unsigned int firstitem, unsigned int lastitem); static void hotlist_clear_selection (void); static void hotlist_launch_url (hotlist_item * item); static _kernel_oserror * hotlist_process_click_on_item (unsigned int itemno, hotlist_item * item, int buttons, int x, int y); static _kernel_oserror * hotlist_process_click (int x, int y, int buttons); static void hotlist_window_preopen (hl_opentype type); static void hotlist_set_menu_details (ObjectId menuid); static _kernel_oserror * hotlist_save_entries (FILE * fileptr, hotlist_item * list, int type); static void hotlist_lower_tags (char * string); static _kernel_oserror * hotlist_load_directory (FILE * fileptr, hotlist_item * target); static void hotlist_drag_renderer (hotlist_item * item, unsigned int item_height, unsigned int item_dir_width, unsigned int item_url_width); static void hotlist_start_drag (void); static _kernel_oserror * hotlist_modified (unsigned int type); /* Save Protocol */ _kernel_oserror * hotlist_initiate_uri_save (hotlist_item *sourceitem); _kernel_oserror * hotlist_initiate_html_save (char *filename); #ifdef TRACE /*************************************************/ /* hotlist_display_item() */ /* */ /* This function display the data held by a */ /* single hotlist_item */ /* */ /* Parameters: Pointer to a hotlist_item */ /*************************************************/ static void hotlist_display_item(hotlist_item * item) { Printf("\nhotlist_display_item for %p\n",item); Printf("--------------------\n"); Printf("type = %d\n", item->type); Printf("name = %s\n", item->name); Printf("flags = %d\n", item->flags); Printf("parent = %p\n", item->parent); Printf("previous = %p\n", item->previous); Printf("next = %p\n", item->next); Printf("data.generic_data = %p ", item->data.generic_data); switch(item->type) { case hl_url: { Printf("URL(%s)\n", item->data.url); } break; case hl_directory: { Printf("sub directory pointer\n"); } break; default: { Printf("\n"); } break; } } /*************************************************/ /* hotlist_display_tree() */ /* */ /* Recursivly display the hotlist tree starting */ /* from the passed item */ /* */ /* Parameters: Pointer to a hotlist_item */ /* value to start indent at */ /* recommended 0 */ /*************************************************/ static void hotlist_display_tree(hotlist_item * list, int indent) { int count; Printf("\nhotlist_display_tree for %p, indent %d\n", list, indent); Printf("--------------------\n\n"); while (list) { for (count = 0; count < indent; count++) Printf("| "); switch (list->type) { case hl_url: { Printf("%s:URL(%s)\n", list->name, list->data.url); } break; case hl_directory: { Printf("%s:DIRECTORY", list->name); } if (list->flags & HOTLIST_D_IS_OPEN) { Printf(" (Open)\n"); hotlist_display_tree(list->data.directory_content, indent + 1); } else { Printf(" (Closed)\n"); hotlist_display_tree(list->data.directory_content, indent + 1); } break; default: { Printf("%s:UNRECOGNISED TYPE\n", list->name); } break; } list = list->next; } } #endif /*************************************************/ /* hotlist_link() */ /* */ /* This function links the passed item to the */ /* passed target. */ /* */ /* It can link the item in four different ways; */ /* before or after the target, or if the target */ /* is a directory, at the beginning or end of */ /* that directory's contents. */ /* */ /* Parameters: Pointer to the hotlist_item */ /* struct to link in; */ /* */ /* Pointer to the hotlist_item */ /* struct to link to; */ /* */ /* Position to link to - */ /* HOTLIST_POSITION_BEGINNING */ /* HOTLIST_POSITION_END */ /* HOTLIST_POSITION_BEFORE or */ /* HOTLIST_POSITION_AFTER. */ /* */ /* Assumes: The item and target pointers are */ /* not NULL and are valid; */ /* */ /* That if adding to the beginning */ /* or end, the target is a directory */ /* (in both cases, an error will be */ /* raised in TRACE builds if the */ /* assumptions are violated). */ /*************************************************/ static _kernel_oserror * hotlist_link(hotlist_item * item, hotlist_item * target, unsigned int position) { #ifdef TRACE /* Test certain basic assumptions are not violated */ if (!item || !target) { erb.errnum = Utils_Error_Custom_Normal; strcpy(erb.errmess, "NULL hotlist item or target pointer in hotlist_link"); show_error_ret(&erb); return NULL; } if ( ( position == HOTLIST_POSITION_BEGINNING || position == HOTLIST_POSITION_END ) && target->type != hl_directory ) { erb.errnum = Utils_Error_Custom_Normal; strcpy(erb.errmess, "Cannot insert at item at the beginning or end when the target is not a directory, in hotlist_link"); show_error_ret(&erb); return NULL; } #endif switch (position) { case HOTLIST_POSITION_BEFORE: { /* Simple insertion above the target item */ item->next = target; item->previous = target->previous; item->parent = target->parent; target->previous = item; if (item->previous) item->previous->next = item; if (item->parent && item->parent->data.directory_content == target) item->parent->data.directory_content = item; } break; default: /* We'll allow a default to adding after the target item */ case HOTLIST_POSITION_AFTER: { /* Again, a simple insertion after the target item */ item->previous = target; item->next = target->next; item->parent = target->parent; target->next = item; if (item->next) item->next->previous = item; } break; case HOTLIST_POSITION_BEGINNING: { /* A bit harder - insert at the top of a directory. */ /* First a quick sanity check - TRACE builds will */ /* already have faulted this, but For non-TRACE */ /* builds, at least this will stop things dying. */ if (target->type != hl_directory) return NULL; /* This item is going to be at the beginning of a */ /* directory, so there is never a previous item. */ item->previous = NULL; /* The next item is the one that used to be at the top */ /* of the directory, and the parent for this item will */ /* obviously be the target. */ item->next = target->data.directory_content; item->parent = target; /* If we have a next item, make sure its previous field */ /* now points to the new item at the top. */ if (item->next) item->next->previous = item; /* The target should point to the new top item, too. */ target->data.directory_content = item; } break; case HOTLIST_POSITION_END: { hotlist_item * last; /* Similarly, add to the end of the directory */ if (target->type != hl_directory) return NULL; /* As before the parent must be the target item */ item->parent = target; /* Now look from the start of the directory downwards for */ /* the last item currently present. */ last = target->data.directory_content; while(last && last->next) last = last->next; /* The new item must point to that one as in its previous field, */ /* and has no next item to point to. */ item->previous = last; item->next = NULL; if (last) { /* If there were any items in the directory, make sure that the */ /* last one points to the new bottom entry. */ last->next = item; } else { /* Otherwise, the parent directory should point to this item */ target->data.directory_content = item; } } break; } /* Finished... */ return NULL; } /*************************************************/ /* hotlist_unlink() */ /* */ /* This function unlinks the passed item from */ /* the items linked in before and after it. */ /* */ /* Parameters: Pointer to the hotlist_item */ /* struct to remove. */ /*************************************************/ static void hotlist_unlink(hotlist_item *item) { if (item->parent && item->parent->data.directory_content == item) item->parent->data.directory_content = item->next; if (item->previous) item->previous->next = item->next; if (item->next) item->next->previous = item->previous; /* Not strictly needed, but added to ensure robustness */ item->next = NULL; item->previous = NULL; item->parent = NULL; } /*************************************************/ /* hotlist_new_directory() */ /* */ /* This function creates a new directory */ /* at the beginning of the given parent. */ /* */ /* */ /* Parameters: Pointer to a hotlist_item of type */ /* directory that represents the */ /* parent item for this new entry; */ /* */ /* Name of new directory to create; */ /* */ /* Position to create the new item */ /* relative to the parent (as for */ /* hotlist_link); */ /* */ /* Pointer to a pointer to a */ /* hotlist_item struct, which will */ /* be filled in with the address of */ /* the new item (unless there is an */ /* error returned). */ /* */ /* Assumes: That the pointer to a pointer to */ /* a hotlist_item struct is not NULL */ /* (it would make little sense to */ /* allow this...). */ /*************************************************/ static _kernel_oserror * hotlist_new_directory(hotlist_item * parent, char * directory_name, unsigned int position, hotlist_item ** new) { char * perm_dirname; hotlist_item * item; _kernel_oserror * e; if (!directory_name) return NULL; /* Allocate space for the item and its name */ item = malloc(sizeof(hotlist_item)); if (!item) return make_no_memory_error(4); perm_dirname = malloc(strlen(directory_name) + 1); if (!perm_dirname) { free(item); return make_no_memory_error(5); } /* Copy the name into the new buffer */ strcpy(perm_dirname, directory_name); /* Initialise the new hotlist item */ item->type = hl_directory; item->flags = DIRECTORY_FLAGS; item->name = perm_dirname; item->data.directory_content = NULL; if (parent) { /* If we have been given a parent item, link this new */ /* directory to it. */ e = hotlist_link(item, parent, position); /* If there's an error, free the item structure and name, */ /* and return that error. */ if (e) { free(item); free(perm_dirname); return e; } } else { /* If there's no parent item, fill the various pointers */ /* to other things in the list with NULL. */ item->next = NULL; item->previous = NULL; item->parent = NULL; } /* Record the new item in the hotlist_newitem static */ hotlist_newitem = item; /* Return the address of the new item and exit */ *new = item; return NULL; } /*************************************************/ /* hotlist_new_url() */ /* */ /* This function creates a new url */ /* at the end of the passed directory */ /* */ /* Parameters: Pointer to a hotlist_item struct */ /* representing a directory to add */ /* the URL to; */ /* */ /* Position within that directory */ /* to link to (number of items from */ /* the start); */ /* */ /* Description of the URL (e.g. from */ /* the page title); */ /* */ /* Pointer to the URL itself. */ /*************************************************/ static _kernel_oserror * hotlist_new_url(hotlist_item * parent, unsigned int position, char * url_description, char * url) { char * perm_url_desc; char * perm_url; hotlist_item * item; _kernel_oserror * e; /* Allocate a new hotlist_item structure */ if ((item = malloc(sizeof(hotlist_item))) == NULL) { #ifdef TRACE if (tl & (1<<25)) Printf("Error: Could not allocate room for new URL item\n"); #endif goto hotlist_new_url_no_memory; /* See bottom of function */ } /* Allocate space for the description string */ perm_url_desc = malloc(strlen(url_description) + 1); if (perm_url_desc == NULL) goto hotlist_new_url_no_memory; /* See bottom of function */ /* Allocate space for the URL */ perm_url = malloc(strlen(url) + 1); if (perm_url == NULL) { free(perm_url_desc); goto hotlist_new_url_no_memory; /* See bottom of function */ } /* Copy the given description and URL to the allocated space */ strcpy(perm_url_desc, url_description); strcpy(perm_url, url); /* Fill in miscellaneous parts of the hotlist_item structure */ item->type = hl_url; item->flags = URL_FLAGS; item->name = perm_url_desc; item->data.url = perm_url; /* Link the item to the rest of the hotlist */ e = hotlist_link(item, parent, position); if (e) { free(item); free(perm_url_desc); free(perm_url); return e; } /* Remember which item was added in the hotlist_newitem static */ /* and exit with no error. */ hotlist_newitem = item; return NULL; /* Code for a common error case */ hotlist_new_url_no_memory: erb.errnum = Utils_Error_Custom_Normal; StrNCpy0(erb.errmess, lookup_token("NoMemURL:There is not enough free memory to add another URL to the hotlist.", 0, 0)); return &erb; } /*************************************************/ /* hotlist_delete_item() */ /* */ /* This function deletes an item from the */ /* hotlist structure; it will recursively delete */ /* directories. */ /* */ /* Parameters: Pointer to the hotlist_item */ /* struct to delete. */ /*************************************************/ static void hotlist_delete_item(hotlist_item * item) { if (item) { switch (item->type) { /* For a URL item, unlink it from the list */ /* and free associated memory. */ case hl_url: { hotlist_unlink(item); free(item->name); free(item->data.url); free(item); } break; case hl_directory: { /* Recursively delete all items in the directory */ while (item->data.directory_content) { hotlist_delete_item(item->data.directory_content); } /* Now unlink the item */ hotlist_unlink(item); /* Free associated memory */ free(item); free(item->name); } break; default: { #ifdef TRACE /* A 'should never happen' case! */ erb.errnum = Utils_Error_Custom_Message; strcpy(erb.errmess, "Unrecognised item type in hotlist_delete_item - possibly memory corruption?"); show_error_ret(&erb); #endif } break; } } } /*************************************************/ /* hotlist_move_item() */ /* */ /* This function takes an item and moves its */ /* position within the directory tree. */ /* */ /* Parameters: Pointer to the hotlist_item */ /* struct to move; */ /* */ /* Pointer to the hotlist_item */ /* structure to move to; */ /* */ /* Position relative to that struct */ /* for the item to go to, as for */ /* hotlist_link. */ /* */ /* Assumes: It is assumed that if the object */ /* is a directory it is not being */ /* moved into it self or one of its */ /* children. If this is not the case */ /* then both it and its children */ /* will become unlinked from the */ /* hotlist structure (nasty...). */ /*************************************************/ static _kernel_oserror * hotlist_move_item(hotlist_item * source, hotlist_item * target, unsigned int position) { _kernel_oserror * e; hotlist_item * newdir, * tempptr; if (!(source->type == hl_directory && !hotlist_contents_selected(source->data.directory_content))) { /* Unlink item from directory structure */ hotlist_unlink(source); /* Link into new position in directory structure */ return hotlist_link(source, target, position); } else { /* Special case - moving a directory whose contents are only partially selected. */ /* We can't move a directory whose contents are only partially to be moved, */ /* there would be nowhere to leave the items which were not moved with it. */ /* So, create a new directory based on the old */ RetError(hotlist_new_directory(target, source->name, position, &newdir)); /* Move the contents recursively into the new directory */ source = source->data.directory_content; while(source) { tempptr = source->next; if (source->flags & HOTLIST_G_IS_SELECTED) { hotlist_move_item(source, newdir, HOTLIST_POSITION_END); source->flags &= ~HOTLIST_G_IS_SELECTED; } source = tempptr; } } return NULL; } /*************************************************/ /* hotlist_copy_item() */ /* */ /* This function copies an item, and in the case */ /* of it being a directory, its children, to the */ /* specified place. */ /* */ /* Parameters: Pointer to the hotlist_item */ /* struct to copy; */ /* */ /* Pointer to the hotlist_item */ /* struct to copy to; */ /* */ /* Position relative to that item to */ /* copy to, as for hotlist_link; */ /* */ /* Pointer to a pointer to a */ /* hotlist_item struct, in which the */ /* address of the new item is */ /* returned. */ /* */ /* Assumes: It is assumed that if the object */ /* is a directory it is not being */ /* copied into it self or one of its */ /* children - if it is the function */ /* will keep recursing and */ /* eventually run out of stack; */ /* */ /* The pointer to the pointer to the */ /* hotlist_item struct may be NULL. */ /*************************************************/ static _kernel_oserror * hotlist_copy_item(hotlist_item * source, hotlist_item * target, unsigned int position, hotlist_item ** new_item) { _kernel_oserror * e; hotlist_item * newdir; newdir = NULL; switch(source->type) { /* For a URL, create a new item based on the source one */ case hl_url: { return hotlist_new_url(target, position, source->name, source->data.url); } break; /* For a directory, first create a new item based on the source one */ case hl_directory: { hotlist_item * content; RetError(hotlist_new_directory(target, source->name, position, &newdir)); /* Now copy the contents recursively */ content = source->data.directory_content; while (content) { if (content->flags & HOTLIST_G_IS_SELECTED) { RetError(hotlist_copy_item(content, newdir, HOTLIST_POSITION_END, NULL)); } content = content->next; } } break; } /* Fill in the new_item return value */ if (new_item) { if (newdir) *new_item = newdir; else *new_item = hotlist_newitem; } return NULL; } /*************************************************/ /* hotlist_get_entry_sizes() */ /* */ /* This function reads the size of the sprites */ /* to be used by the hotlist and from them */ /* determines the size of the hotlist entries. */ /* */ /* Parameters: Pointer to an int, in which the */ /* height of an item is placed in */ /* OS units; */ /* */ /* Pointer to an int, in which the */ /* minimum width of a directory item */ /* is returned, in OS units; */ /* */ /* Pointer to an int, in which the */ /* minimum width of a URL item is */ /* returned, in OS units. */ /* */ /* Assumes: Any of the pointers may be NULL. */ /*************************************************/ static _kernel_oserror * hotlist_get_entry_sizes(unsigned int * item_height, unsigned int * item_dir_width, unsigned int * item_url_width) { _kernel_oserror * e; int width, height; /* Get the open directory sprite size */ RetError(read_sprite_size(OPEN_DIRECTORY_SPRITE, &width, &height)); /* Use this for the minimum width of a directory entry */ /* and the height of an item. */ if (item_dir_width) *item_dir_width = width; if (item_height) *item_height = height; /* Now read the closed sprite; if the size is greater */ /* than the width or height found above, use the new */ /* sizes instead. */ RetError(read_sprite_size(CLOSED_DIRECTORY_SPRITE, &width, &height)); if (item_height && height > *item_height) *item_height = height; if (item_dir_width && width > *item_dir_width) *item_dir_width = width; /* Similarly for the insert item sprite. */ RetError(read_sprite_size(INSERT_DIRECTORY_SPRITE, &width, &height)); if (item_height && height > *item_height) *item_height = height; if (item_dir_width && width > *item_dir_width) *item_dir_width = width; /* Find the URL sprite size, and if required increase the */ /* minimum entry height again based on this. */ RetError(read_sprite_size(URL_SPRITE, &width, &height)); if (item_height && height > *item_height) *item_height= height; /* Set the URL width to the value found above and add 8 to */ /* all of them for aesthetics. */ if (item_url_width) *item_url_width = width + 8; if (item_dir_width) *item_dir_width += 8; if (item_height) *item_height += 8; return NULL; } /*************************************************/ /* hotlist_set_flags() */ /* */ /* This function will recursively set flags for */ /* either a specified type of hotlist_item or */ /* all hotlist_items, to the given value. All */ /* items which are changed will have their */ /* HOTLIST_G_REDRAW_NOW bit set. */ /* */ /* Parameters: Pointer to a hotlist_item struct */ /* to start on; */ /* */ /* Type of hotlist_item to set flags */ /* for, or hl_ALL for all types; */ /* */ /* Flags to set. */ /* */ /* Returns: 1 if any flags were set, else 0. */ /*************************************************/ static int hotlist_set_flags(hotlist_item * list, hotlist_type type, unsigned int flags) { int changed = 0; while (list) { /* Alter all items, or those of the correct type */ if (type == hl_ALL || type == list->type) { if (list->flags | flags != list->flags) { list->flags |= HOTLIST_G_REDRAW_NOW; changed = 1; } list->flags |= flags; } /* Recursive call for directories */ if (list->type == hl_directory) { if (hotlist_set_flags(list->data.directory_content, type, flags)) changed = 1; } list = list->next; } return changed; } /*************************************************/ /* hotlist_clear_flags() */ /* */ /* This function will recursively clear flags */ /* for either a specified type of hotlist_item */ /* or all hotlist_items. All items changed will */ /* have their HOTLIST_G_REDRAW_NOW bit set, */ /* unless, of course, the routine is called to */ /* clear that bit. */ /* */ /* Parameters: Pointer to a hotlist_item struct */ /* to start on; */ /* */ /* Type of hotlist_item to set flags */ /* for, or hl_ALL for all types; */ /* */ /* Flags clear word (any bits set in */ /* this word are cleared in the item */ /* flags). */ /* */ /* Returns: 1 if flags were cleared, else 0. */ /*************************************************/ static int hotlist_clear_flags(hotlist_item * list, hotlist_type type, unsigned int flags) { int changed = 0; while (list) { /* Only alter the requested item types */ if (type == hl_ALL || type == list->type) { if (list->flags & ~flags != list->flags) { list->flags |= HOTLIST_G_REDRAW_NOW; changed = 1; } list->flags &= ~flags; } /* Recursive call for directories */ if (list->type == hl_directory) { if (hotlist_clear_flags(list->data.directory_content, type, flags)) changed = 1; } list = list->next; } return changed; } /*************************************************/ /* hotlist_find_item() */ /* */ /* This function will recursivly scan through */ /* a hotlist structure and return a pointer to */ /* the n'th item. It will only recurse through */ /* open directories. */ /* */ /* Parameters: Pointer to a hotlist_item at the */ /* top of the directory to scan; */ /* */ /* The nth item to return within it. */ /* */ /* Returns: Pointer to the requested item or */ /* NULL if it does not exist. */ /*************************************************/ static hotlist_item * hotlist_find_item(hotlist_item * list, unsigned int item_no) { int curr_item = 0; return hotlist_find_item_r(list, item_no, &curr_item); } /*************************************************/ /* hotlist_find_item_r() */ /* */ /* Recursive back-end to hotlist_find_item. */ /* */ /* Parameters: Pointer to a hotlist_item at the */ /* top of the directory to scan; */ /* */ /* The nth item to return within it; */ /* */ /* Pointer to an int, in which the */ /* number of the current item is */ /* accumulated (initialised to an */ /* appropriate value, usually 0). */ /* */ /* Returns: As hotlist_find_item. */ /* */ /* Assumes: The pointer to the int may *not* */ /* be NULL. */ /*************************************************/ static hotlist_item * hotlist_find_item_r(hotlist_item * list, unsigned int item_no, int * curr_item) { hotlist_item * temp; while (list) { if (*curr_item == item_no) return list; /* Found the list item */ /* Increment the item counter */ *curr_item += 1; /* Recursively scan open directories */ if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN) { temp = hotlist_find_item_r(list->data.directory_content, item_no, curr_item); if (temp) return temp; } /* Move to the next list item */ list = list->next; } return NULL; /* List does not extend far enough */ } /*************************************************/ /* hotlist_find_no_from_item() */ /* */ /* This function will recursivly scan through */ /* a hotlist structure and return the position */ /* of the specified item. It will only recurse */ /* through open directories. */ /* */ /* Parameters: Pointer to a hotlist_item to */ /* start at; */ /* */ /* Pointer to the item whos position */ /* is to be returned. */ /* */ /* Returns: The item position or -1 if it is */ /* not found. */ /*************************************************/ static int hotlist_find_no_from_item(hotlist_item * item) { int curr_item = 0; return hotlist_find_no_from_item_r(hotlist_root->data.directory_content, item, &curr_item); } /*************************************************/ /* hotlist_find_no_from_item_r() */ /* */ /* Recursive back-end to */ /* hotlist_find_no_from_item. */ /* */ /* Parameters: Pointer to a hotlist_item to */ /* start at; */ /* */ /* Pointer to the item whos position */ /* is to be returned; */ /* */ /* Pointer to an int, in which the */ /* number of the current item is */ /* accumulated (initialised to an */ /* appropriate value, usually 0). */ /* */ /* Returns: As hotlist_find_no_from_item. */ /* */ /* Assumes: The pointer to the int may *not* */ /* be NULL. */ /*************************************************/ static int hotlist_find_no_from_item_r(hotlist_item * list, hotlist_item * item, int * curr_item) { /* Start the search at the given item */ while (list) { if (item == list) return *curr_item; /* Found the list item */ *curr_item += 1; /* Recursively scan open directories */ if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN) { int found; found = hotlist_find_no_from_item_r(list->data.directory_content, item, curr_item); if (found >= 0) return found; } /* Move to the next item */ list = list->next; } /* Didn't find it */ return -1; } /*************************************************/ /* hotlist_find_selected_item() */ /* */ /* This function returns a pointer to the first */ /* selected item found. */ /* */ /* Returns: Pointer to a hotlist_item struct */ /* which was the first selected item */ /* found in a search starting */ /* from the root, or NULL if there */ /* is nothing selected. */ /*************************************************/ static hotlist_item * hotlist_find_selected_item(void) { return hotlist_find_selected_item_r(hotlist_root); } /*************************************************/ /* hotlist_find_selected_item_r() */ /* */ /* Recursive back-end to */ /* hotlist_find_selected_item. */ /* */ /* Parameters: Pointer to a hotlist_item */ /* struct to start at. */ /* */ /* Returns: As hotlist_find_selected_item. */ /*************************************************/ hotlist_item * hotlist_find_selected_item_r(hotlist_item * list) { while (list) { if (list->flags & HOTLIST_G_IS_SELECTED) return list; /* Found it */ /* Recursively scan all directories */ if (list->type == hl_directory) { hotlist_item * found; found = hotlist_find_selected_item_r(list->data.directory_content); if (found) return found; } /* Move to the next item */ list = list->next; } /* Didn't find it */ return NULL; } /*************************************************/ /* hotlist_count_selected_items() */ /* */ /* Count the number of items that are currently */ /* selected in the hotlist window. */ /* */ /* Returns: The number of selected items. */ /*************************************************/ static unsigned int hotlist_count_selected_items(void) { int count = 0; hotlist_count_selected_items_r(hotlist_root->data.directory_content, &count); return count; } /*************************************************/ /* hotlist_count_selected_items_r() */ /* */ /* Recursive back-end to */ /* hotlist_count_selected_items. */ /* */ /* Parameters: Pointer to a hotlist_item struct */ /* representing the first item in a */ /* directory to count; */ /* */ /* Pointer to an int, in which the */ /* total is accumulated. */ /* */ /* Assumes: The pointer to the int may *not* */ /* be NULL. */ /*************************************************/ static void hotlist_count_selected_items_r(hotlist_item * list, int * count) { while (list) { if (list->flags & HOTLIST_G_IS_SELECTED) { *count += 1; } else { /* Only recurse through directories which are not selected */ if (list->type == hl_directory) { hotlist_count_selected_items_r(list->data.directory_content, count); } } list = list->next; } } /*************************************************/ /* hotlist_count_displayed_items() */ /* */ /* This routine counts the number of items */ /* displayed in the hotlist window. */ /* */ /* Parameters: Pointer to a hotlist_item struct */ /* to start at. */ /* */ /* Returns: The number of displayed items. */ /*************************************************/ static unsigned int hotlist_count_displayed_items(hotlist_item * list) { int count = 0; hotlist_count_displayed_items_r(list, &count); return count; } /*************************************************/ /* hotlist_count_displayed_items_r() */ /* */ /* Recursive back-end to */ /* hotlist_count_displayed_items. */ /* */ /* Parameters: Pointer to a hotlist_item struct */ /* to start at; */ /* */ /* Pointer to an int, in which the */ /* total is accumulated. */ /* */ /* Assumes: The pointer to the int may *not* */ /* be NULL. */ /*************************************************/ static void hotlist_count_displayed_items_r(hotlist_item *list, int * count) { while (list) { /* Recursive scan for open directories */ if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN) { hotlist_count_displayed_items_r(list->data.directory_content, count); } list = list->next; *count += 1; } } /*************************************************/ /* hotlist_draw() */ /* */ /* Redraws a specified region of the hotlist. */ /* Assumes graphics rectangles are set up */ /* appropriately (e.g. the function is called */ /* during a Wimp redraw session). */ /* */ /* Parameters: Pointer to a hotlist_item giving */ /* the list that we're to draw; */ /* */ /* First item number to draw; */ /* */ /* Last item number to draw. */ /*************************************************/ static _kernel_oserror * hotlist_draw(hotlist_item * list, unsigned int first_item, unsigned int last_item) { _kernel_oserror * e; int curr_item = 0; unsigned int item_height, item_dir_width, item_url_width; RetError(hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width)); return hotlist_draw_r(list, first_item, last_item, &curr_item, 0, item_height, item_dir_width, item_url_width); } /*************************************************/ /* hotlist_draw_r() */ /* */ /* Recursive back-end to hotlist_draw. */ /* */ /* Parameters: Pointer to a hotlist_item giving */ /* the list that we're to draw; */ /* */ /* First item number to draw; */ /* */ /* Last item number to draw; */ /* */ /* Pointer to an int, which is used */ /* to accumulate the current item */ /* number - the contents should be */ /* initialised to an appropriate */ /* value for the first three */ /* parameters (usually, zero); */ /* */ /* Level of indentation (OS units); */ /* */ /* Height of an item (OS units); */ /* */ /* Width of a directory item (OS */ /* units); */ /* */ /* Width of a URL item (OS units). */ /* */ /* Assumes: The pointer to the int may *not* */ /* be NULL. */ /*************************************************/ static _kernel_oserror * hotlist_draw_r(hotlist_item *list, unsigned int first_item, unsigned int last_item, int * curr_item, unsigned int indent, unsigned int item_height, unsigned int item_dir_width, unsigned int item_url_width) { _kernel_oserror * e; WimpIconBlock icon; unsigned int temp_width; int text_width; while (list) { /* Break out if done all items to be displayed */ if (*curr_item > last_item) return NULL; /* Don't draw until we reach the required first item */ if (*curr_item >= first_item) { /* Construct an icon block for Wimp_PlotIcon. First, icon flags. */ icon.flags = HOTLIST_SPRITE_ICON_FLAGS; if (list->flags & HOTLIST_G_IS_SELECTED) icon.flags |= WimpIcon_Selected; /* Point to the main sprite pool */ icon.data.is.sprite_area = (void*) sprite_block; /* Set type-dependent characteristics */ switch(list->type) { case hl_url: { /* A URL item; set the sprite name and item width accordingly */ icon.data.is.sprite = URL_SPRITE; icon.data.is.sprite_name_length = strlen(URL_SPRITE); temp_width = item_url_width; } break; case hl_directory: { /* Directories are a bit more complex, as they can be open, */ /* closed, or showing a '+' if a dragged item is hovering */ /* over it and would drop 'into' the directory if released. */ temp_width = item_dir_width; /* Width is based on the widest sprite of the three */ if (list->flags & HOTLIST_D_IS_HIGHLIGHTED) { /* The item is either selected (something is 'hovering' over it)... */ icon.data.is.sprite = INSERT_DIRECTORY_SPRITE; icon.data.is.sprite_name_length = strlen(INSERT_DIRECTORY_SPRITE); } else { /* ...or unselected. In that case it is either open or closed. */ if (list->flags & HOTLIST_D_IS_OPEN) { icon.data.is.sprite = OPEN_DIRECTORY_SPRITE; icon.data.is.sprite_name_length = strlen(OPEN_DIRECTORY_SPRITE); } else { icon.data.is.sprite = CLOSED_DIRECTORY_SPRITE; icon.data.is.sprite_name_length = strlen(CLOSED_DIRECTORY_SPRITE); } } } break; default: { temp_width = 0; /* Should never happen... */ } break; } /* Set the item bounding box appropriately */ icon.bbox.xmin = indent; icon.bbox.xmax = indent + temp_width; icon.bbox.ymin = -item_height * (*curr_item) - item_height; icon.bbox.ymax = -item_height * (*curr_item); /* Plot the item */ RetError(wimp_plot_icon(&icon)); /* We now need to plot the item text. First, get the width, */ /* taking the opportunity to point the icon that we'll plot */ /* to the appropriate text, too. */ if (list->type == hl_url && hl_show_urls) { /* If this is a URL item and we are to show URLs, then find */ /* the width of the URL rather than the description. */ RetError(utils_text_width(list->data.url, &text_width, 0)); /* Point to the URL text */ icon.data.it.buffer = list->data.url; icon.data.it.buffer_size = strlen(list->data.url); } else { /* Otherwise (any other item, or a URL item when we're showing */ /* descriptions) just find the name's width. */ RetError(utils_text_width(list->name, &text_width, 0)); /* Point to the description */ icon.data.it.buffer = list->name; icon.data.it.buffer_size = strlen(list->name); } /* Set the bounding box for the text. The hard coded */ /* constants are nothing critical - just aesthetics. */ icon.bbox.xmin = indent + temp_width + 2; icon.bbox.xmax = indent + temp_width + 2 + text_width + 12; icon.bbox.ymin = -item_height * (*curr_item) - item_height + 2; icon.bbox.ymax = -item_height * (*curr_item) - 2; /* Set the flags accordingly if the text is selected or unselected */ if (list->flags & HOTLIST_G_IS_SELECTED) icon.flags = HOTLIST_TEXT_ICON_FLAGS_SELECTED; else icon.flags = HOTLIST_TEXT_ICON_FLAGS_UNSELECTED; /* Finally, plot the item. */ RetError(wimp_plot_icon(&icon)); } /* Increment the item number */ *curr_item += 1; /* Recursive redraw for directories */ if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN) { RetError(hotlist_draw_r(list->data.directory_content, first_item, last_item, curr_item, indent + item_dir_width, item_height, item_dir_width, item_url_width)); } /* Move on down the list */ list = list->next; } return NULL; } /*************************************************/ /* hotlist_get_max_width_r */ /* */ /* Recursive back-end to hotlist_get_max_width. */ /* */ /* Parameters: Pointer to a hotlist_item struct */ /* to start at; */ /* */ /* An indent in OS units, as for */ /* redrawing the hotlist; */ /* */ /* Pointer to an int, in which the */ /* width of the widest item so far */ /* is accumulated; */ /* */ /* Height of a hotlist item in OS */ /* units; */ /* */ /* Width of a hotlist directory */ /* sprite in OS units; */ /* */ /* Width of a hotlist URL sprite in */ /* OS units. */ /* */ /* Assumes: The pointer to the int may *not* */ /* be NULL. */ /*************************************************/ static _kernel_oserror * hotlist_get_max_width_r(hotlist_item *list, unsigned int indent, int * max_width, unsigned int item_height, unsigned int item_dir_width, unsigned int item_url_width) { _kernel_oserror * e; unsigned int item_width; int text_width; while (list) { /* Get width of the icon */ switch (list->type) { case hl_directory: item_width = item_dir_width; break; case hl_url: item_width = item_url_width; break; default: item_width = 0; break; } /* Work out width of the text */ if (list->type == hl_url && hl_show_urls) e = utils_text_width(list->data.url, &text_width, 0); else e = utils_text_width(list->name, &text_width, 0); if (e) return e; /* Account for the indent and spacers (aesthetics) */ item_width += indent + 2 + text_width + 12; /* If this is wider than so far recorded, store the new value */ if (item_width > *max_width) *max_width = item_width; /* Recursive call for open directories */ if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN) { RetError(hotlist_get_max_width_r(list->data.directory_content, indent + item_dir_width, max_width, item_height, item_dir_width, item_url_width)); } /* Move on down the list */ list = list->next; } return NULL; } /*************************************************/ /* hotlist_get_max_width() */ /* */ /* This function returns the maximum width of */ /* of the displayed hotlist entries. */ /* */ /* Parameters: Pointer to a hotlist_item struct */ /* to start at. This is assumed to */ /* be at zero indent from the left */ /* hand side. */ /* */ /* Returns: Of all visible entries, the width */ /* of the widest, in OS units. */ /*************************************************/ static unsigned int hotlist_get_max_width(hotlist_item * list) { unsigned int item_height, item_dir_width, item_url_width; int widest = 0; /* Find basic item size information */ if (hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width)) return 0; /* Scan the directory and all open directories with in it for */ /* the widest item */ if (hotlist_get_max_width_r(list, 0, &widest, item_height, item_dir_width, item_url_width)) return 0; /* Return the result */ return widest; } /*************************************************/ /* hotlist_redraw_now() */ /* */ /* This function redraws all visible items with */ /* the HOTLIST_G_REDRAW_NOW bit set. */ /*************************************************/ static void hotlist_redraw_now(void) { int curr_item = 0; hotlist_redraw_now_r(hotlist_root->data.directory_content, &curr_item); } /*************************************************/ /* hotlist_redraw_now_r() */ /* */ /* Recursive back-end to hotlist_redraw_now. */ /* */ /* Parameters: Pointer to a hotlist_item struct */ /* to start on; */ /* */ /* Pointer to an int, in which the */ /* current item number being redrawn */ /* is accumulated. */ /* */ /* Assumes: The pointer to the int may *not* */ /* be NULL. */ /*************************************************/ static void hotlist_redraw_now_r(hotlist_item * list, int * curr_item) { while (list) { if (list->flags & HOTLIST_G_REDRAW_NOW) { /* Redraw just the one item */ hotlist_redraw_items(*curr_item, *curr_item); /* Clear the flag */ list->flags &= ~HOTLIST_G_REDRAW_NOW; } *curr_item += 1; if (list->type == hl_directory && list->flags & HOTLIST_D_IS_OPEN) { /* Recursive call for open directories */ hotlist_redraw_now_r(list->data.directory_content, curr_item); } list = list->next; } } /*************************************************/ /* hotlist_add() */ /* */ /* Add a new URL to the hotlist. */ /* */ /* Parameters: Description of the URL (e.g. from */ /* the page title); */ /* */ /* Pointer to the URL itself; */ /* */ /* 0 to add to the top, 1 to add to */ /* the bottom. */ /*************************************************/ _kernel_oserror * hotlist_add(char * description, char * url, int at_bottom) { _kernel_oserror * e = NULL; int position; position = at_bottom ? HOTLIST_POSITION_END : HOTLIST_POSITION_BEGINNING; /* Add the item and ensure the window extent etc. is correct */ e = hotlist_new_url(hotlist_root, position, description, url); if (!e) hotlist_window_preopen(already_open); /* Optimise the redraw to do as little as possible depending */ /* upon where in the list the item was added. */ switch (position) { default: case HOTLIST_POSITION_END: { hotlist_redraw_now(); } break; case HOTLIST_POSITION_BEGINNING: { hotlist_redraw_items(0, hotlist_count_displayed_items(hotlist_root->data.directory_content)); } break; } if (!e) return hotlist_modified(HL_MODIFIED_ADD); return e; } /*************************************************/ /* hotlist_get_shape() */ /* */ /* This function calculates the xmin and xmax */ /* of the passed hotlist_item */ /* */ /* Parameters: *xmin */ /* *xmax */ /* item */ /*************************************************/ static void hotlist_get_shape(unsigned int *xmin, unsigned int *xmax, hotlist_item *item) { unsigned int item_height, item_dir_width, item_url_width; int count = 0, temp_width, text_width; hotlist_item *tempitem; hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); tempitem = item; while(tempitem) { tempitem = tempitem->parent; count++; } count -= 2; if (item->type == hl_url && hl_show_urls) utils_text_width(item->data.url, &text_width, 0); else utils_text_width(item->name, &text_width, 0); switch(item->type) { case hl_directory: temp_width = item_dir_width; break; case hl_url: temp_width = item_url_width; break; default: temp_width = 0; break; } *xmin = count * item_dir_width; *xmax = count * item_dir_width + temp_width + 2 + text_width + 12; } /*************************************************/ /* hotlist_directory_open_close() */ /* */ /* This function opens or closes a directory */ /* along with all required redrawing */ /* */ /* Parameters: hotlist_item */ /* item number on screen */ /*************************************************/ static void hotlist_directory_open_close(hotlist_item *item, unsigned int itemno) { unsigned int item_height, item_dir_width, item_url_width; int top, window_handle; BBox bbox; hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); item->flags ^= HOTLIST_D_IS_OPEN; hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); hotlist_window_preopen(already_open); show_error(window_get_wimp_handle(0, hotlist_windowid, &window_handle)); window_get_extent(0, hotlist_windowid, &bbox); top = -itemno * item_height; /* Window relative coordinate */ if (item->data.directory_content) { show_error(wimp_force_redraw(window_handle, bbox.xmin, bbox.ymin, bbox.xmax, top)); } else { show_error(wimp_force_redraw(window_handle, bbox.xmin, top-item_height, bbox.xmax, top)); } } /*************************************************/ /* hotlist_redraw_items() */ /* */ /* This function forces the redraw of a set of */ /* items */ /* */ /* Parameters: itemno */ /*************************************************/ static void hotlist_redraw_items(unsigned int firstitem, unsigned int lastitem) { unsigned int item_height, item_dir_width, item_url_width; BBox bbox; int window_handle; hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); show_error(window_get_wimp_handle(0, hotlist_windowid, &window_handle)); window_get_extent(0, hotlist_windowid, &bbox); wimp_force_redraw(window_handle, bbox.xmin, - (lastitem + 1) * item_height, bbox.xmax, - firstitem * item_height); } /*************************************************/ /* hotlist_clear_selection() */ /* */ /* This function unselects all items and redraws */ /* appropriate items */ /*************************************************/ static void hotlist_clear_selection(void) { hotlist_clear_flags(hotlist_root->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); hotlist_redraw_now(); } /*************************************************/ /* hotlist_launch_url() */ /* */ /* This function launches the url in the passed */ /* item */ /* */ /* Parameters: hotlist_item */ /*************************************************/ static void hotlist_launch_url(hotlist_item * item) { #ifdef TRACE if (tl & (1u<<25)) hotlist_display_item(item); #endif windows_create_browser(item->data.url, NULL, NULL, NULL, 0); } /*************************************************/ /* hotlist_process_click_on_item() */ /* */ /* This function handles mouse clicks on hotlist */ /* items */ /*************************************************/ static _kernel_oserror * hotlist_process_click_on_item(unsigned int itemno, hotlist_item *item, int buttons, int x, int y) { switch(buttons) { case Wimp_MouseButtonSelect: if (last_selected_item == itemno) { switch(item->type) { case hl_directory: hotlist_directory_open_close(item, itemno); break; case hl_url: hotlist_launch_url(item); break; } item->flags &= ~HOTLIST_G_IS_SELECTED; hotlist_redraw_items(itemno, itemno); } break; /* Double click select */ case Wimp_MouseButtonAdjust: if (last_selected_item == itemno) { switch(item->type) { case hl_directory: hotlist_directory_open_close(item, itemno); break; case hl_url: hotlist_launch_url(item); toolbox_hide_object(0, hotlist_windowid); break; } item->flags &= ~HOTLIST_G_IS_SELECTED; hotlist_redraw_items(itemno, itemno); } break; /* Double click adjust */ case 64: /* Drag select */ hotlist_start_drag(); break; case 16: /* Drag adjust */ if (!(item->flags & HOTLIST_G_IS_SELECTED)) { item->flags |= HOTLIST_G_IS_SELECTED; last_selected_item = itemno; } hotlist_start_drag(); hotlist_redraw_items(itemno, itemno); break; case 1024: /* Click select */ if (item->flags & HOTLIST_G_IS_SELECTED) { /* Do nothing when selected */ } else { hotlist_clear_selection(); item->flags |= HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW; if (item->type == hl_directory) { hotlist_set_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); } hotlist_redraw_now(); } last_selected_item = itemno; break; case 256: /* Click adjust */ item->flags ^= HOTLIST_G_IS_SELECTED; item->flags |= HOTLIST_G_REDRAW_NOW; last_selected_item = itemno; if (item->type == hl_directory) { if (item->flags & HOTLIST_G_IS_SELECTED) { hotlist_set_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); } else { hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); } } hotlist_redraw_now(); break; } return NULL; } /*************************************************/ /* hotlist_process_click() */ /* */ /* This function handles mouse clicks on the */ /* hotlist window */ /* */ /* Parameters: x position */ /* y position */ /* button state */ /*************************************************/ static _kernel_oserror * hotlist_process_click(int x, int y, int buttons) { unsigned int item_height, item_dir_width, item_url_width; hotlist_item *item; unsigned int xmin, xmax, itemno; hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); itemno = -y / item_height; item = hotlist_find_item(hotlist_root->data.directory_content, itemno); if (item) hotlist_get_shape(&xmin, &xmax, item); if (item && x >= xmin && x <= xmax) { return hotlist_process_click_on_item(itemno, item, buttons, x, y); } else { switch(buttons) { case Wimp_MouseButtonSelect: break; /* Double click select */ case Wimp_MouseButtonAdjust: break; /* Double click adjust */ case 64: /* Drag select */ hotlist_clear_selection(); hotlist_selection_box_start(); break; case 16: /* Drag adjust */ hotlist_clear_selection(); hotlist_selection_box_start(); break; case 1024: hotlist_clear_selection(); last_selected_item = 0xffffffff; break; /* Click select */ case 256: last_selected_item = 0xffffffff; break; /* Click adjust */ } } return NULL; } /*************************************************/ /* hotlist_window_preopen() */ /* */ /* This function should be called before opening */ /* the hotlist window. When opentype is */ /* not_open the window is opened as large as is */ /* required to show all items. When opentype is */ /* already_open the window size will grow enough */ /* to allow all items to fit but its screen size */ /* will not change, if the window needs to */ /* it will do so but its work area will not get */ /* any smaller than the current visible area */ /* */ /* Parameters: opentype */ /* */ /*************************************************/ static void hotlist_window_preopen(hl_opentype type) { unsigned int item_height, item_dir_width, item_url_width; unsigned int number, maxlen; BBox bbox; WimpGetWindowStateBlock state; int height, width; unsigned int objectstate; ObjectId parent_id; ComponentId parent_component; if (type == already_open) { toolbox_get_object_state(0, hotlist_windowid, &objectstate); if (!objectstate & Toolbox_GetObjectState_Showing) return; } hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); number = hotlist_count_displayed_items(hotlist_root->data.directory_content); maxlen = hotlist_get_max_width(hotlist_root->data.directory_content) + 4; show_error(window_get_wimp_handle(0, hotlist_windowid, &state.window_handle)); wimp_get_window_state(&state); if (number < HOTLIST_WINDOW_MIN_HEIGHT) number = HOTLIST_WINDOW_MIN_HEIGHT; if (maxlen < HOTLIST_WINDOW_MIN_WIDTH) maxlen = HOTLIST_WINDOW_MIN_WIDTH; if (type == already_open) window_get_extent(0, hotlist_windowid, &bbox); bbox.ymin = -number * item_height; bbox.xmax = maxlen; if (type == already_open) { width = state.visible_area.xmax - state.visible_area.xmin; height = state.visible_area.ymax - state.visible_area.ymin + hotlist_bbar_size; if (bbox.ymin > -height) bbox.ymin = -height; if (bbox.xmax < width) bbox.xmax = width; } bbox.ymax = hotlist_bbar_size; bbox.xmin = 0; window_set_extent(0, hotlist_windowid, &bbox); if (type == already_open) { show_error(window_get_wimp_handle(0, hotlist_windowid, &state.window_handle)); wimp_get_window_state(&state); toolbox_get_parent(0, hotlist_windowid, &parent_id, &parent_component); toolbox_show_object(0, hotlist_windowid, Toolbox_ShowObject_FullSpec, &(state.visible_area), parent_id, parent_component); // wimp_open_window((WimpOpenWindowBlock*)&state); } } /*************************************************/ /* hotlist_redraw_handler() */ /* */ /* This function redraws the hotlist window */ /*************************************************/ static int hotlist_redraw_handler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle) { unsigned int item_height, item_dir_width, item_url_width; unsigned int first_item, last_item; int more; WimpRedrawWindowBlock block; hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); block.window_handle = event->redraw_window_request.window_handle; wimp_redraw_window(&block, &more); while(more) { first_item = -(block.redraw_area.ymax - (block.visible_area.ymax - block.yscroll)) / item_height; last_item = (-(block.redraw_area.ymin - (block.visible_area.ymax - block.yscroll)) / item_height) + 1; hotlist_draw(hotlist_root->data.directory_content, first_item, last_item); wimp_get_rectangle(&block, &more); } return 0; } /*************************************************/ /* hotlist_mouse_click_handler() */ /* */ /* This function handles mouse clicks in the */ /* hotlist window */ /*************************************************/ static int hotlist_mouse_click_handler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle) { WimpGetWindowStateBlock state; state.window_handle = event->mouse_click.window_handle; wimp_get_window_state(&state); wimp_set_caret_position(state.window_handle, -1, 0, 0, -1, -1); hotlist_process_click(event->mouse_click.mouse_x + (state.xscroll - state.visible_area.xmin), event->mouse_click.mouse_y + (state.yscroll - state.visible_area.ymax), event->mouse_click.buttons); return 0; } /*************************************************/ /* hotlist_menuclose_handler() */ /* */ /* This function handles closed menu events */ /*************************************************/ static int hotlist_menuclose_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { ObjectId submenu_id; if (menu_select) { hotlist_clear_selection(); menu_select = 0; } show_error(menu_get_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, &submenu_id)); if (submenu_id) show_error(toolbox_delete_object(0, submenu_id)); menu_set_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, 0); return 0; } void hotlist_set_menu_details(ObjectId menuid) { hotlist_item * item; char entrytext[32]; ObjectId submenu_id; switch(hotlist_count_selected_items()) { case 0: menu_set_entry_text(0, menuid, HOTLIST_URL_MENUITEM, "URL ''"); menu_set_fade(0, menuid, HOTLIST_URL_MENUITEM, 1); menu_set_fade(0, menuid, HOTLIST_CLEARSELECTION_MENUITEM, 1); /* Fade clear selection */ break; case -1: case 1: item = hotlist_find_selected_item(); /* One item selected */ switch(item->type) { case hl_directory: strcpy(entrytext, "Dir. '"); toolbox_create_object(0, "HLDirmenu", &submenu_id); menu_set_sub_menu_show(0, menuid, HOTLIST_URL_MENUITEM, submenu_id); break; case hl_url: strcpy(entrytext, "URL '"); toolbox_create_object(0, "HLURLmenu", &submenu_id); menu_set_sub_menu_show(0, menuid, HOTLIST_URL_MENUITEM, submenu_id); break; } strncat(entrytext, item->name, 10); if (strlen(item->name) > 10) strcat(entrytext, "..."); strcat(entrytext, "'"); menu_set_entry_text(0, menuid, HOTLIST_URL_MENUITEM, entrytext); menu_set_fade(0, menuid, HOTLIST_URL_MENUITEM, 0); /* unfade URL '' */ menu_set_fade(0, menuid, HOTLIST_CLEARSELECTION_MENUITEM, 0); /* unfade clear selection */ break; default: menu_set_entry_text(0, menuid, HOTLIST_URL_MENUITEM, "Selection"); /* Multiple items selected */ menu_set_fade(0, menuid, HOTLIST_URL_MENUITEM, 0); /* unfade URL '' */ menu_set_fade(0, menuid, HOTLIST_CLEARSELECTION_MENUITEM, 0); /* unfade clear selection */ toolbox_create_object(0, "HLSlctmenu", &submenu_id); menu_set_sub_menu_show(0, menuid, HOTLIST_URL_MENUITEM, submenu_id); break; } menu_get_sub_menu_show(0, menuid, HOTLIST_DISPLAY_MENUITEM, &submenu_id); if (hl_show_urls) { menu_set_tick(0, submenu_id, HOTLIST_MENU_SHOWDESCRIPTIONS, 0); menu_set_tick(0, submenu_id, HOTLIST_MENU_SHOWURLS, 1); } else { menu_set_tick(0, submenu_id, HOTLIST_MENU_SHOWDESCRIPTIONS, 1); menu_set_tick(0, submenu_id, HOTLIST_MENU_SHOWURLS, 0); } } /*************************************************/ /* hotlist_menuopen_handler() */ /* */ /* This function handles opened menu events */ /*************************************************/ static int hotlist_menuopen_handler(int event_code, ToolboxEvent * event, IdBlock * id_block, void * handle) { WimpGetWindowStateBlock state; WimpGetPointerInfoBlock pointerblock; hotlist_item * item; unsigned int item_height, item_dir_width, item_url_width; unsigned int xmin, xmax; int window_handle; ObjectId sub_menu; hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); if (event_code == HotlistMenuOpened) { window_get_wimp_handle(0, hotlist_windowid, &window_handle); state.window_handle = window_handle; wimp_get_window_state(&state); wimp_get_pointer_info(&pointerblock); pointerblock.x = pointerblock.x + (state.xscroll - state.visible_area.xmin); pointerblock.y = pointerblock.y + (state.yscroll - state.visible_area.ymax); menu_itemno = -pointerblock.y / item_height; } menu_get_sub_menu_show(0, id_block->self_id, HOTLIST_DISPLAY_MENUITEM, &sub_menu); if (hotlist_count_selected_items() == 0) { item = hotlist_find_item(hotlist_root->data.directory_content, menu_itemno); if (item) { hotlist_get_shape(&xmin, &xmax, item); } if (item && pointerblock.x >= xmin && pointerblock.x <= xmax) { item->flags |= HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW; if (item->type == hl_directory) hotlist_set_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); menu_select = 1; hotlist_redraw_now(); } } hotlist_set_menu_details(id_block->self_id); return 0; } /*************************************************/ /* hotlist_save_entries() */ /* */ /* This function recurses through the hotlist */ /* directory structure saving all directories */ /* and entries as it goes. */ /* */ /* Parameters: Pointer to a FILE struct for the */ /* file to write to; */ /* */ /* Pointer to a hotlist_item struct */ /* representing the first item in */ /* the directory to save (which may */ /* itself be a directory). */ /* */ /* 0 - save all of hotlist */ /* 1 - only save selection portions */ /* */ /* Assumes: The FILE pointer must not be NULL */ /* however the hotlist_item pointer */ /* can be (e.g. an empty directory). */ /*************************************************/ static _kernel_oserror * hotlist_save_entries(FILE * fileptr, hotlist_item * list, int type) { int written; _kernel_oserror * e; /* Follow the directory list */ while (list) { switch (list->type) { /* Write a link for URLs */ case hl_url: { if (type == 0 || (type == 1 && list->flags & HOTLIST_G_IS_SELECTED)) { HotlistWrite(fprintf(fileptr, "
  • %s\n", list->data.url, list->name)); } } break; /* Write a heading for directories */ case hl_directory: { if (type == 0 || !hotlist_no_contents_selected(list->data.directory_content)) { HotlistWrite(fprintf(fileptr, "

    %s

    \n", list->name)); /* Recursive call for the directory contents. First, */ /* write the entry header. */ HotlistWrite(fprintf(fileptr, "
      \n")); /* Do the contents */ RetError(hotlist_save_entries(fileptr, list->data.directory_content, type)); /* Write the entry footer */ HotlistWrite(fprintf(fileptr, "
    \n")); } } break; } /* Continue down the list */ list = list->next; } return NULL; } /*************************************************/ /* hotlist_save_hotlist() */ /* */ /* This function saves the hotlist as an HTML */ /* file. */ /* */ /* Parameters: Pointer to the filename to save */ /* to (null terminated); */ /* */ /* 0 to save all of hotlist, 1 to */ /* save only the selected portions. */ /*************************************************/ _kernel_oserror * hotlist_save_hotlist(char * filename, int type) { FILE * fileptr; _kernel_oserror * e; int written; /* Open the file for writng */ fileptr = fopen(filename, "wb"); /* Complain if it fails */ if (fileptr == NULL) return _kernel_last_oserror(); /* Write the file header */ HotlistWrite(fprintf(fileptr, "\n")); HotlistWrite(fprintf(fileptr, "Hotlist\n")); HotlistWrite(fprintf(fileptr, "\n")); /* Fill in the body */ e = hotlist_save_entries(fileptr, hotlist_root->data.directory_content, type); if (e) { fclose(fileptr); return e; } /* Write the footer and close the file */ HotlistWrite(fprintf(fileptr, "\n")); HotlistWrite(fprintf(fileptr, "\n")); fclose(fileptr); /* Set the filetype to HTML (0xfaf) */ return _swix(OS_File, _INR(0,2), 18, filename, FileType_HTML); } /*************************************************/ /* hotlist_save() */ /* */ /* Veneer onto hotlist_save_hotlist - saves all */ /* of the hotlist, created to preserve API. */ /* */ /* Parameters: Pointer to the filename to save */ /* under (null terminated). */ /*************************************************/ _kernel_oserror * hotlist_save(char * filename) { return hotlist_save_hotlist(filename, 0); /* Save entire hotlist */ } /*************************************************/ /* hotlist_lower_tags() */ /* */ /* This function processes the passed string */ /* turning all characters within a tag to lower */ /* case. It will detect characters within quotes */ /* and leave their case the same; this will */ /* preserve the case of URLs. */ /* */ /* Obviously, this assumes that the HTML file */ /* being fed in is not broken; tags and quoted */ /* text must always be correctly closed, and */ /* in both cases must not span multiple lines. */ /* */ /* Parameters: Pointer to the string to process. */ /*************************************************/ static void hotlist_lower_tags(char *string) { int intag = 0, inquotes = 0; while (*string) { if (intag) { if (inquotes) { if (*string == '"') inquotes = 0; } else { if (*string == '"') inquotes = 1; if (*string == '>') intag --; *string = tolower(*string); } } else { if (*string == '<') intag++; } string++; } } /*************************************************/ /* hotlist_load_directory() */ /* */ /* This function loads the directory contents of */ /* a hotlist HTML file previously saved by */ /* hotlist_save or a compatible source. For */ /* example, at the time of creation this can */ /* correctly load and understand hotlist files */ /* from at least one other popular browser. */ /* */ /* Parameters: Pointer to a FILE struct through */ /* which data will be read; */ /* */ /* Pointer to a hotlist_item; new */ /* data structures generated from */ /* the file contents are added to */ /* the linked list that this struct */ /* lies in. */ /*************************************************/ static _kernel_oserror * hotlist_load_directory(FILE * fileptr, hotlist_item * target) { _kernel_oserror * e = NULL; static char * next_directory_name = NULL; static char * string_buffer = NULL; static char * str_ptr; char * url; hotlist_item * new_dir; unsigned int unfollowed_uls = 0; long int file_position; int character, count; /* Go through the file in chunks */ while (!feof(fileptr)) /* In theory the code below means you'll never get this; but just to be safe... */ { file_position = ftell(fileptr); /* Scan ahead to find the end of line - marked by any */ /* control character, in this case; need to include */ /* as many consecutive control chars as are present */ /* in the file, in the count. */ do { /* First, get to either a control char or EOF */ character = fgetc(fileptr); } while (character > 31 && character != EOF); while (character < 32 && character != EOF) { /* If we're not on EOF, continue until we're no longer */ /* on a control char or hit EOF. */ character = fgetc(fileptr); } /* Work out how many bytes we've read */ count = (int) (ftell(fileptr) - file_position); /* If count is zero, we're at the end of the file */ if (!count) break; /* If we're not on EOF and don't have a control char, then */ /* we overshot by one; so we would want to subtract one */ /* from count. However, to ensure string manipulation */ /* works OK, we'll need one char to null terminate the */ /* string. So in that case, we need to *add* one to count */ /* if the above condition isn't true. */ if (!(character > 31 && character != EOF)) count ++; /* Right, after all that messing around rewind to the stored */ /* file position and allocate a buffer for this string. */ if (fseek(fileptr, file_position, SEEK_SET)) { e = _kernel_last_oserror(); goto hotlist_load_directory_exit; /* (See near end of function) */ } /* Note that string_buffer is a static, as this way only one */ /* of these buffers ever exists, even for recursive calls. */ if (string_buffer) free(string_buffer); string_buffer = malloc(count); /* Complain if the allocation fails */ if (!string_buffer) { e = make_no_memory_error(2); goto hotlist_load_directory_exit; /* (See near end of function) */ } /* Read the data and force a terminator at the end of the buffer, */ /* just to be safe. */ if (fread(string_buffer, sizeof(char), count - 1, fileptr) != count - 1) { e = _kernel_last_oserror(); goto hotlist_load_directory_exit; /* (See near end of function) */ } string_buffer[count - 1] = 0; /* Convert tags to lower case */ hotlist_lower_tags(string_buffer); /* Treat any opening '' tag (header) as the title to a directory */ str_ptr = strstr(string_buffer, "= '1' && str_ptr[2] <= '6' && str_ptr[3] == '>' ) { /* Read the directory name (up to the closing '') */ str_ptr = strtok(str_ptr + 4, "<"); /* Allocate space for it */ if (next_directory_name) free(next_directory_name); next_directory_name = malloc(strlen(str_ptr) + 1); /* Complain if the allocation fails */ if (!next_directory_name) { e = make_no_memory_error(3); goto hotlist_load_directory_exit; /* (See near end of function) */ } /* Otherwise, copy the name in */ strcpy(next_directory_name, str_ptr); } /* Treat any '' attribute contents (link) as a URL for the hotlist */ else if ((str_ptr = strstr(string_buffer, "' of the ''. */ str_ptr = strtok(NULL, "><"); /* Add this item */ e = hotlist_new_url(target, HOTLIST_POSITION_END, str_ptr, url); if (e) goto hotlist_load_directory_exit; /* (See near end of function) */ } /* Treat any '
      ' tags as the start of a new directory. The name comes */ /* from a preceeding '' tag (see above). */ else if ((str_ptr = strstr(string_buffer, "
        ")) != NULL) /* New directory */ { if (!next_directory_name) { /* If we don't have a directory name for this one, apparently, flag it */ /* by incrementing the unmatched '
          ' counter. */ unfollowed_uls ++; } else { /* Otherwise, add the directory */ e = hotlist_new_directory(target, next_directory_name, HOTLIST_POSITION_END, &new_dir); if (e) goto hotlist_load_directory_exit; free(next_directory_name); next_directory_name = NULL; /* If the directory was added, recursively load the contents */ if (new_dir) { /* Note this will invalidate string_buffer. The contents must */ /* not be used after the call! */ e = hotlist_load_directory(fileptr, new_dir); if (e) goto hotlist_load_directory_exit; /* (See near end of function) */ } else { /* If the directory was not added, flag it */ unfollowed_uls ++; } } } /* Treat any '
        ' tags as the end of a directory. */ else if ((str_ptr = strstr(string_buffer, "
      ")) != NULL) /* Close directory */ { /* If we have unfollowed '
        ' tags, decrement the counter; */ /* otherwise, exit quietly. */ if (unfollowed_uls) unfollowed_uls--; else goto hotlist_load_directory_exit; /* (See near end of function) */ } } /* This section is not necessarily an error exit condition, so */ /* the code falls through to it in normal running. If 'e' is */ /* NULL there's still no error returned in the end. Note */ /* though how the various buffers are freed, and thus */ /* invalidated, at this point; so during recursive routines, */ /* they must not be accessed after the recursive call has */ /* been made (unless, of course, they are reallocated). */ hotlist_load_directory_exit: /* Free up the temporary buffers */ if (string_buffer) { free(string_buffer); string_buffer = NULL; } if (next_directory_name) { free(next_directory_name); next_directory_name = NULL; } // We could at this point give a warning if unfollowed_uls is non-zero. return e; } /*************************************************/ /* hotlist_load() */ /* */ /* This function loads an HTML file previously */ /* saved by hotlist_save as the new hotlist. */ /* */ /* Parameters: Pointer to the filename to load */ /* (null terminated). */ /*************************************************/ _kernel_oserror * hotlist_load(char * filename) { _kernel_oserror * e; FILE * fileptr; /* First delete all the existing hotlist items */ while (hotlist_root->data.directory_content) { hotlist_delete_item(hotlist_root->data.directory_content); } /* Open the file */ fileptr = fopen(filename, "r"); if (fileptr == NULL) { erb.errnum = Utils_Error_Custom_Normal; StrNCpy0(erb.errmess, lookup_token("HlCantLoad:Hotlist file could not be loaded", 0, 0)); return &erb; } /* Load it (any errors are returned right at the end) */ e = hotlist_load_directory(fileptr, hotlist_root); fclose(fileptr); /* Clear all of the various flags for redraw, */ /* selection etc. now that we have a new */ /* hotlist. */ hotlist_clear_flags(hotlist_root, hl_ALL, HOTLIST_G_REDRAW_NOW); #ifdef TRACE /* Show the tree now the file is loaded */ if (tl & (1u<<25)) hotlist_display_tree(hotlist_root, 0); #endif /* Finished; redraw issues are left to the caller */ if (!e) return hotlist_modified(HL_MODIFIED_LOAD); return e; } /*************************************************/ /* hotlist_initialise() */ /* */ /* This function initialises the hotlist library */ /* routines, and must be called before any other */ /* hotlist functions. */ /*************************************************/ _kernel_oserror * hotlist_initialise(void) { _kernel_oserror * e; ObjectId toolbar; ObjectId menu_id; BBox bbox; /* Create root directory item */ RetError(hotlist_new_directory(NULL, "Root", 0, &hotlist_root)); /* Create the hotlist window */ RetError(toolbox_create_object(0, "HotlistWind", &hotlist_windowid)); /* Is there a toolbar? */ RetError(window_get_tool_bars(InternalTopLeft, hotlist_windowid, NULL, &toolbar, NULL, NULL)); /* If so, read the size */ if (toolbar != 0) { RetError(window_get_extent(0, toolbar, &bbox)); hotlist_bbar_size = bbox.ymax - bbox.ymin; } else hotlist_bbar_size = 0; /* Register event handlers for redraw, clicks and drags in the */ /* main hotlist window. */ RetError(event_register_wimp_handler(hotlist_windowid, Wimp_ERedrawWindow, hotlist_redraw_handler, NULL)); RetError(event_register_wimp_handler(hotlist_windowid, Wimp_EMouseClick, hotlist_mouse_click_handler, NULL)); RetError(event_register_wimp_handler(-1, Wimp_EUserDrag, hotlist_drag_completed_handler, NULL)); /* Menu handlers */ RetError(window_get_menu(0, hotlist_windowid, &menu_id)); RetError(event_register_toolbox_handler(menu_id, HotlistMenuOpened, hotlist_menuopen_handler, NULL)); RetError(event_register_toolbox_handler(menu_id, HotlistMenuClosed, hotlist_menuclose_handler, NULL)); /* Main menu items */ RetError(event_register_toolbox_handler(-1, HotlistSelectAll, hotlist_menu_selectall_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistClearSelect, hotlist_menu_clearselect_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistOpenAll, hotlist_menu_openall_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistCloseAll, hotlist_menu_closeall_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistDelete, hotlist_menu_delete_handler, NULL)); /* Submenu warning events */ RetError(event_register_toolbox_handler(-1, HotlistShowEditURL, hotlist_show_editurl_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistShowRenameDirectory, hotlist_show_rendirectory_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistShowNewURL, hotlist_show_newurl_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistShowNewDirectory, hotlist_show_newdirectory_handler, NULL)); /* Hotlist related dialogue events */ RetError(event_register_toolbox_handler(-1, HotlistNewEditURLOk, hotlist_newedit_url_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistNewRenameDirectoryOk, hotlist_newren_directory_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistNewEditURLCancel, hotlist_reset_url_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistNewRenameDirectoryCancel, hotlist_reset_directory_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistShowDesc, hotlist_show_descriptions_handler, NULL)); RetError(event_register_toolbox_handler(-1, HotlistShowURLs, hotlist_show_urls_handler, NULL)); RetError(event_register_message_handler(Wimp_MDataSaveAck, hotlist_data_save_ack_handler, NULL)); RetError(event_register_message_handler(Wimp_MRAMFetch, hotlist_ram_fetch_handler, NULL)); return NULL; } /*************************************************/ /* hotlist_open() */ /* */ /* Opens the hotlist window. */ /* */ /* Parameters: Show type (as for a call to */ /* Toolbox_ShowObject); */ /* */ /* Show block (as for a call to */ /* Toolbox_ShowObject); */ /* */ /* 0 to open showing descriptions, */ /* or 1 to open showing URLs. */ /*************************************************/ _kernel_oserror * hotlist_open(int show_type, void * type, int show_urls) { /* Sets show descriptions / show URLs */ hl_show_urls = show_urls; /* Set the size of the window etc. */ hotlist_window_preopen(not_open); /* Show the hotlist */ return toolbox_show_object(0, hotlist_windowid, show_type, type, 0, 0); } /*************************************************/ /* hotlist_close() */ /* */ /* Closes the hotlist window. */ /*************************************************/ _kernel_oserror * hotlist_close(void) { return toolbox_hide_object(0, hotlist_windowid); } /*************************************************/ /* hotlist_menu_selectall_handler() */ /* */ /* This function handles the 'select all' menu */ /* item. */ /* */ /* Parameters are as standard for a Toolbox */ /* event handler. */ /*************************************************/ static int hotlist_menu_selectall_handler(int event_code, ToolboxEvent * event, IdBlock * id_block, void * handle) { hotlist_item * item; ObjectId sub_menu; if (!hotlist_root->data.directory_content) return 0; item = hotlist_find_item(hotlist_root->data.directory_content, menu_itemno); if (item && item->parent) { item = item->parent->data.directory_content; while (item) { item->flags |= HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW; if (item->type == hl_directory) hotlist_set_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); item = item->next; } hotlist_redraw_now(); menu_get_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, &sub_menu); menu_set_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, 0); if (sub_menu) toolbox_delete_object(0, sub_menu); hotlist_set_menu_details(id_block->self_id); } menu_select = 0; return 1; } /*************************************************/ /* hotlist_menu_clearselection_handler() */ /* */ /* This function handles the clear selection */ /* menu item */ /*************************************************/ static int hotlist_menu_clearselect_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { hotlist_clear_selection(); menu_set_entry_text(0, id_block->self_id, 0x05, "URL ''"); menu_set_fade(0, id_block->self_id, 0x05, 1); /* Fade URL'' selection */ menu_set_fade(0, id_block->self_id, 0x01, 1); /* Fade clear selection */ return 0; } /*************************************************/ /* hotlist_menu_openall_handler() */ /* */ /* This function handles the open all menu item */ /*************************************************/ static int hotlist_menu_openall_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { if (hotlist_root->data.directory_content) { menu_itemno = 0; hotlist_set_flags(hotlist_root->data.directory_content, hl_directory, HOTLIST_D_IS_OPEN); hotlist_clear_flags(hotlist_root->data.directory_content, hl_directory, HOTLIST_G_REDRAW_NOW); hotlist_redraw_items(0, hotlist_count_displayed_items(hotlist_root->data.directory_content)); hotlist_window_preopen(already_open); } return 0; } /*************************************************/ /* hotlist_menu_closeall_handler() */ /* */ /* This function handles the close all menu */ /* item */ /*************************************************/ static int hotlist_menu_closeall_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { unsigned int noitems; if (hotlist_root->data.directory_content) { menu_itemno = 0; noitems = hotlist_count_displayed_items(hotlist_root->data.directory_content); hotlist_clear_flags(hotlist_root->data.directory_content, hl_directory, HOTLIST_D_IS_OPEN | HOTLIST_G_REDRAW_NOW); hotlist_clear_selection(); hotlist_redraw_items(0, noitems); menu_set_entry_text(0, id_block->self_id, HOTLIST_URL_MENUITEM, "URL ''"); menu_set_fade(0, id_block->self_id, HOTLIST_URL_MENUITEM, 1); /* Fade URL'' selection */ menu_set_fade(0, id_block->self_id, HOTLIST_CLEARSELECTION_MENUITEM, 1); /* Fade clear selection */ hotlist_window_preopen(already_open); } return 0; } /*************************************************/ /* hotlist_menu_delete_handler() */ /* */ /* This function handles the delete menu item */ /*************************************************/ static int hotlist_menu_delete_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { hotlist_item *item; unsigned int noitems; noitems = hotlist_count_displayed_items(hotlist_root->data.directory_content); if (!hotlist_count_selected_items()) return 0; while((item = hotlist_find_selected_item())!=NULL) { hotlist_delete_item(item); } hotlist_redraw_items(0, noitems); hotlist_window_preopen(already_open); toolbox_hide_object(0, id_block->ancestor_id); hotlist_modified(HL_MODIFIED_DELETE); return 0; } /*************************************************/ /* hotlist_show_editurl_handler() */ /* */ /* This function fills in the description and */ /* url fields of the edit url dialogue box */ /*************************************************/ static int hotlist_show_editurl_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { hotlist_item *item; ObjectId dboxid; #ifdef TRACE Printf("hotlist_show_editurl_handler\n"); #endif item = hotlist_find_selected_item(); if (!item) return 0; menu_get_sub_menu_show(0, id_block->self_id, id_block->self_component, &dboxid); alter_new = HOTLIST_MENUSECTION_ALTER; window_set_title(0, dboxid, "Edit URL"); writablefield_set_value(0, dboxid, 0x01, item->name); writablefield_set_value(0, dboxid, 0x05, item->data.url); actionbutton_set_text(0, dboxid, 0x02, "Alter"); return 0; } /*************************************************/ /* hotlist_show_rendirectory_handler() */ /* */ /* This function fills in the name field of the */ /* rename directory dialogue box */ /*************************************************/ static int hotlist_show_rendirectory_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { hotlist_item *item; ObjectId dboxid; #ifdef TRACE Printf("hotlist_show_rendirectory_handler\n"); #endif item = hotlist_find_selected_item(); if (!item) return 0; menu_get_sub_menu_show(0, id_block->self_id, id_block->self_component, &dboxid); alter_new = HOTLIST_MENUSECTION_ALTER; window_set_title(0, dboxid, "Rename Directory"); writablefield_set_value(0, dboxid, 0x01, item->name); actionbutton_set_text(0, dboxid, 0x02, "Rename"); return 0; } /*************************************************/ /* hotlist_show_newurl_handler() */ /* */ /* This function emptys the description and url */ /* fields of the new url dialogue box */ /*************************************************/ static int hotlist_show_newurl_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { ObjectId dboxid; #ifdef TRACE Printf("hotlist_show_newurl_handler\n"); #endif menu_get_sub_menu_show(0, id_block->self_id, id_block->self_component, &dboxid); alter_new = HOTLIST_MENUSECTION_NEW; writablefield_set_value(0, dboxid, 0x01, ""); writablefield_set_value(0, dboxid, 0x05, ""); window_set_title(0, dboxid, "Create new URL"); actionbutton_set_text(0, dboxid, 0x02, "Create"); return 0; } /*************************************************/ /* hotlist_show_newdirectory_handler() */ /* */ /* This function emptys the name field of the */ /* new directory dialogue box */ /*************************************************/ static int hotlist_show_newdirectory_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { ObjectId dboxid; #ifdef TRACE Printf("hotlist_show_newdirectory_handler\n"); #endif menu_get_sub_menu_show(0, id_block->self_id, id_block->self_component, &dboxid); alter_new = HOTLIST_MENUSECTION_NEW; writablefield_set_value(0, dboxid, 0x01, ""); window_set_title(0, dboxid, "Create new Directory"); actionbutton_set_text(0, dboxid, 0x02, "Create"); return 0; } /*************************************************/ /* hotlist_newedit_url_handler() */ /* */ /* This function either alters the selected urls */ /* name and url fields or creates a new url in */ /* the directory the pointer was in when menu */ /* was clicked in the hotlist window. */ /*************************************************/ static int hotlist_newedit_url_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { hotlist_item *item, *tempitem; char *tempdesc, *tempurl; int size; item = hotlist_find_selected_item(); writablefield_get_value(0, id_block->self_id, HOTLIST_NEWURL_NAME, NULL, 0, &size); tempdesc = malloc(size); if (!tempdesc) return 0; /* ERROR can't rename */ writablefield_get_value(0, id_block->self_id, HOTLIST_NEWURL_NAME, tempdesc, size, &size); writablefield_get_value(0, id_block->self_id, HOTLIST_NEWURL_URL, NULL, 0, &size); tempurl = malloc(size); if (!tempurl) { free(tempdesc); return 0; /* ERROR can't rename */ } writablefield_get_value(0, id_block->self_id, HOTLIST_NEWURL_URL, tempurl, size, &size); switch(alter_new) { case HOTLIST_MENUSECTION_NEW: tempitem = hotlist_find_item(hotlist_root->data.directory_content, menu_itemno); if (!tempitem) tempitem = hotlist_root; else { tempitem = tempitem->parent; } show_error(hotlist_new_url(tempitem, HOTLIST_POSITION_END, tempdesc, tempurl)); hotlist_window_preopen(already_open); hotlist_redraw_items(menu_itemno, hotlist_count_displayed_items(hotlist_root->data.directory_content)); hotlist_clear_flags(hotlist_root, hl_ALL, HOTLIST_G_REDRAW_NOW); hotlist_modified(HL_MODIFIED_ADD); free(tempdesc); free(tempurl); break; case HOTLIST_MENUSECTION_ALTER: free(item->name); free(item->data.url); item->name = tempdesc; item->data.url = tempurl; item->flags |= HOTLIST_G_REDRAW_NOW; hotlist_window_preopen(already_open); hotlist_redraw_now(); hotlist_modified(HL_MODIFIED_ALTER); break; } return 0; } /*************************************************/ /* hotlist_newren_directory_handler() */ /* */ /* This function either alters the selected */ /* directorys name or creates a new directory in */ /* the directory the pointer was in when menu */ /* was clicked in the hotlist window. */ /*************************************************/ static int hotlist_newren_directory_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { int size; hotlist_item *item, *tempitem; char *tempname; item = hotlist_find_selected_item(); writablefield_get_value(0, id_block->self_id, HOTLIST_NEWDIRECTORY_NAME, NULL, 0, &size); tempname = malloc(size); if (!tempname) return 0; /* ERROR can't rename */ writablefield_get_value(0, id_block->self_id, HOTLIST_NEWDIRECTORY_NAME, tempname, size, &size); switch(alter_new) { case HOTLIST_MENUSECTION_NEW: tempitem = hotlist_find_item(hotlist_root->data.directory_content, menu_itemno); if (!tempitem) tempitem = hotlist_root; else tempitem = tempitem->parent; hotlist_new_directory(tempitem, tempname, HOTLIST_POSITION_END, &tempitem); hotlist_window_preopen(already_open); hotlist_redraw_items(menu_itemno, hotlist_count_displayed_items(hotlist_root->data.directory_content)); hotlist_clear_flags(hotlist_root, hl_ALL, HOTLIST_G_REDRAW_NOW); hotlist_modified(HL_MODIFIED_ADD); free(tempname); break; case HOTLIST_MENUSECTION_ALTER: free(item->name); item->name = tempname; item->flags |= HOTLIST_G_REDRAW_NOW; hotlist_window_preopen(already_open); hotlist_redraw_now(); hotlist_modified(HL_MODIFIED_ALTER); //toolbox_hide_object(0, id_block->ancestor_id); break; } return 0; } /*************************************************/ /* hotlist_newren_directory_handler() */ /* */ /* This function is called when Cancel is */ /* clicked on in the new or edit url dialogue */ /* box. It resets the contents to their */ /* previous state. */ /*************************************************/ static int hotlist_reset_url_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { hotlist_item *item; switch(alter_new) { case HOTLIST_MENUSECTION_NEW: writablefield_set_value(0, id_block->self_id, 0x01, ""); writablefield_set_value(0, id_block->self_id, 0x05, ""); break; case HOTLIST_MENUSECTION_ALTER: item = hotlist_find_selected_item(); writablefield_set_value(0, id_block->self_id, 0x01, item->name); writablefield_set_value(0, id_block->self_id, 0x05, item->data.url); break; } return 0; } /*************************************************/ /* hotlist_reset_directory_handler() */ /* */ /* This function is called when Cancel is */ /* clicked on in the new or rename directory */ /* dialogue box. It resets the contents to */ /* their previous state. */ /*************************************************/ static int hotlist_reset_directory_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { hotlist_item *item; switch(alter_new) { case HOTLIST_MENUSECTION_NEW: writablefield_set_value(0, id_block->self_id, 0x01, ""); break; case HOTLIST_MENUSECTION_ALTER: item = hotlist_find_selected_item(); writablefield_set_value(0, id_block->self_id, 0x01, item->name); break; } return 0; } /*************************************************/ /* hotlist_drag_renderer() */ /* */ /* renders a single hotlist item at 0,0 for use */ /* with draganobject */ /* */ /* Parameters: pointer to the item to render */ /*************************************************/ static void hotlist_drag_renderer(hotlist_item *item, unsigned int item_height, unsigned int item_dir_width, unsigned int item_url_width) { /* DONT PUT Printf's in here, doesn't work (on pipefs anyway) */ WimpIconBlock hotlist_iconblock; int temp_width, text_width; hotlist_iconblock.flags = HOTLIST_SPRITE_ICON_FLAGS; hotlist_iconblock.data.is.sprite_area = (void*)sprite_block; switch(item->type) /* Set appropriate sprite and width of sprite */ { case hl_url: hotlist_iconblock.data.is.sprite = URL_SPRITE; hotlist_iconblock.data.is.sprite_name_length = strlen(URL_SPRITE); temp_width = item_url_width; break; case hl_directory: temp_width = item_dir_width; hotlist_iconblock.data.is.sprite = CLOSED_DIRECTORY_SPRITE; hotlist_iconblock.data.is.sprite_name_length = strlen(CLOSED_DIRECTORY_SPRITE); break; default: temp_width = 0; /* Prevent warnings */ break; } hotlist_iconblock.bbox.xmin = 2; hotlist_iconblock.bbox.xmax = 2 + temp_width; hotlist_iconblock.bbox.ymax = 2 + item_height; hotlist_iconblock.bbox.ymin = 2; if (wimp_plot_icon(&hotlist_iconblock)) /* Plot sprite icon */ { /* Error has happened, don't know what to do about it */ } if (item->type == hl_url && hl_show_urls) utils_text_width(item->data.url, &text_width, 0); else utils_text_width(item->name, &text_width, 0); hotlist_iconblock.flags = HOTLIST_TEXT_ICON_FLAGS_DRAG; hotlist_iconblock.bbox.xmin = temp_width + 4; hotlist_iconblock.bbox.xmax = temp_width + text_width + 16; hotlist_iconblock.bbox.ymax = item_height; hotlist_iconblock.bbox.ymin = 4; if (item->type == hl_url && hl_show_urls) { hotlist_iconblock.data.it.buffer = item->data.url; hotlist_iconblock.data.it.buffer_size = strlen(item->data.url); } else { hotlist_iconblock.data.it.buffer = item->name; hotlist_iconblock.data.it.buffer_size = strlen(item->name); } if (wimp_plot_icon(&hotlist_iconblock)) { /* Error has happened, don't know what to do about it */ } } /*************************************************/ /* hotlist_start_drag() */ /* */ /* This function is called to start a drag */ /* operation from the hotlist window. A drag */ /* box will be initiated bounding all selected */ /* items. */ /*************************************************/ static _kernel_oserror *_hotlist_start_drag(void) { _kernel_swi_regs regs; _kernel_oserror *err; unsigned int item_height, item_dir_width, item_url_width; hotlist_item *item; WimpDragBox box; WimpGetPointerInfoBlock pointerblock; unsigned int xmin, xmax, xlow, xhigh; int top, bottom, item_no, xorigin, yorigin, screenwidth, screenheight, tempint; WimpGetWindowStateBlock state; int redraw_params[4]; int width, height; wimp_get_pointer_info(&pointerblock); /* Read pointer position */ hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); item = hotlist_find_selected_item(); item_no = hotlist_find_no_from_item(item); top = -item_no * item_height; bottom = -(item_no + 1) * item_height; if (item_no < 0) return NULL; /* Selected item not found, this should never happen */ hotlist_get_shape(&xmin, &xmax, item); item = item->next; if (hotlist_count_selected_items() > 1) { while(item) { item_no++; hotlist_get_shape(&xlow, &xhigh, item); if (item->flags & HOTLIST_G_IS_SELECTED) { if (xlow < xmin) xmin = xlow; /* Should never happen, left hand side should not be ragged */ if (xhigh > xmax) xmax = xhigh; bottom = -(item_no + 1) * item_height; } item = item->next; } } show_error(window_get_wimp_handle(0, hotlist_windowid, &state.window_handle)); wimp_get_window_state(&state); xorigin = state.xscroll - state.visible_area.xmin; yorigin = state.yscroll - state.visible_area.ymax; _swix(OS_ReadModeVariable, _INR(0,1) | _OUT(2), -1, 11, &screenwidth); _swix(OS_ReadModeVariable, _INR(0,1) | _OUT(2), -1, 12, &screenheight); _swix(OS_ReadModeVariable, _INR(0,1) | _OUT(2), -1, 4, &tempint); screenwidth <<= tempint; _swix(OS_ReadModeVariable, _INR(0,1) | _OUT(2), -1, 5, &tempint); screenheight <<= tempint; if (_kernel_osbyte(161, 28, 0) & (1<<(8+1))) /* solid drag */ { item = hotlist_find_selected_item(); if ( (hotlist_count_selected_items() == 1 && item->type == hl_url) || ( hotlist_count_selected_items() == 1 && item->type == hl_directory && ( !(item->flags & HOTLIST_D_IS_OPEN) || hotlist_no_contents_selected(item->data.directory_content) || item->data.directory_content == NULL ) ) ) { box.dragging_box.xmin = xmin-xorigin; /* box shape */ box.dragging_box.ymin = bottom-yorigin; box.dragging_box.xmax = xmax-xorigin; box.dragging_box.ymax = top-yorigin; redraw_params[0] = (int)hotlist_find_selected_item(); redraw_params[1] = (int)item_height; redraw_params[2] = (int)item_dir_width; redraw_params[3] = (int)item_url_width; regs.r[0] = (2<<0) | (2<<2) | (1<<6) | (1<<7) | (1<<16); regs.r[1] = (int)hotlist_drag_renderer; regs.r[2] = (int)redraw_params; regs.r[3] = (int)&(box.dragging_box); if (!_kernel_swi(DragAnObject_Start, ®s, ®s)) { hotlist_dragging = HOTLIST_SOLID_DRAG_OBJECT; /* Set global variable saying we are currently dragging */ /* so we know whether to process a user_drag_box event */ return NULL; } } else { if (!read_sprite_size(SELECTION_SPRITE, &width, &height)) { box.dragging_box.xmin = pointerblock.x - (width/2 + 10); /* box shape */ box.dragging_box.ymin = pointerblock.y - (height/2 + 10); box.dragging_box.xmax = pointerblock.x + (width/2 + 10); box.dragging_box.ymax = pointerblock.y + (height/2 + 10); regs.r[0] = (1<<0) | (1<<2) | (1<<6) | (1<<7); regs.r[1] = (int)sprite_block; /* browser sprite area */ regs.r[2] = (int)"package"; regs.r[3] = (int)&(box.dragging_box); if (!_kernel_swi(DragASprite_Start, ®s, ®s)) { hotlist_dragging = HOTLIST_SOLID_DRAG_SPRITE; return NULL; } } } } box.drag_type = Wimp_DragBox_DragFixedDash; box.dragging_box.xmin = xmin-xorigin; /* box shape */ box.dragging_box.xmax = xmax-xorigin; box.dragging_box.ymin = bottom-yorigin; box.dragging_box.ymax = top-yorigin; box.parent_box.xmin = -(pointerblock.x - box.dragging_box.xmin); /* Bounding box for dragged box */ box.parent_box.xmax = screenwidth+(box.dragging_box.xmax - pointerblock.x); box.parent_box.ymin = -(pointerblock.y - box.dragging_box.ymin); box.parent_box.ymax = screenheight+(box.dragging_box.ymax - pointerblock.y); err = wimp_drag_box(&box); /* start drag box */ if (err) return err; hotlist_dragging = HOTLIST_BOX_DRAG; /* Set global variable saying we are currently dragging */ /* so we know whether to process a user_drag_box event */ return NULL; } void hotlist_start_drag(void) { _kernel_oserror *err; err = _hotlist_start_drag(); if (err) { show_error_ret(err); return; } /* Register NULL handler */ register_null_claimant(Wimp_ENull, hotlist_null_handler, NULL); } /*************************************************/ /* hotlist_is_inside() */ /* */ /* Checks if one hotlist_item is held inside */ /* the directory structure of another */ /* hotlist_item */ /* */ /* Parameters: pointer to possibly inside item */ /* pointer to outside item */ /* */ /* Returns: 1 if item is inside, 0 otherwise */ /*************************************************/ /* This routine is no longer used but the code will be left incase it is needed */ // static int hotlist_is_inside(hotlist_item *inside, hotlist_item *outside) // { // while(inside) // { // if (inside == outside) return 1; // inside = inside->parent; // } // return 0; // } /*************************************************/ /* hotlist_drag_completed_handler() */ /* */ /* This function is called when a user_drag */ /* completes. If the drag is one started by the */ /* hotlist section it is processed. Dropping */ /* the drag in the hotlist window will move or */ /* copy the items being dragged. */ /* Dropping the drag in any other window is */ /* currently ignored */ /*************************************************/ static int hotlist_drag_completed_handler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle) { unsigned int item_height, item_dir_width, item_url_width; ObjectId window_handle; ComponentId comp; WimpGetPointerInfoBlock pointerblock; WimpGetWindowStateBlock state; int winx, winy, shift; unsigned int top, bottom, bottom2, tempint, position, xmin, xmax; hotlist_item *targetitem, *sourceitem; _swix(OS_Byte, _INR(0,1) | _OUT(1), 121, 128, &shift); /* Check if SHIFT is pressed */ if (!hotlist_dragging) return 0; switch(hotlist_dragging) { case HOTLIST_SOLID_DRAG_OBJECT: _swix(DragAnObject_Stop, 0); break; case HOTLIST_SOLID_DRAG_SPRITE: _swix(DragASprite_Stop, 0); break; case HOTLIST_BOX_DRAG_SELECTION: deregister_null_claimant(Wimp_ENull, hotlist_null_drag_select_handler, NULL); return 0; /* No action taken at end of drag, selection is done by null handler during drag */ break; default: break; } if (hotlist_current_highlighted) { hotlist_current_highlighted->flags &= ~HOTLIST_D_IS_HIGHLIGHTED; hotlist_redraw_items(highlighted_itemno, highlighted_itemno); hotlist_current_highlighted = NULL; } deregister_null_claimant(Wimp_ENull, hotlist_null_handler, NULL); hotlist_dragging = 0; wimp_get_pointer_info(&pointerblock); show_error(window_wimp_to_toolbox(0, pointerblock.window_handle, pointerblock.icon_handle, &window_handle, &comp)); if (window_handle == hotlist_windowid) { /* Drag was dropped in hotlist window */ if (pointerblock.icon_handle != -1) return 0; /* Only understand drops on workspace */ hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); state.window_handle = pointerblock.window_handle; wimp_get_window_state(&state); winx = pointerblock.x + (state.xscroll - state.visible_area.xmin); winy = pointerblock.y + (state.yscroll - state.visible_area.ymax); targetitem = hotlist_find_item(hotlist_root->data.directory_content, -winy/item_height); top = -winy/item_height; /* Decide where to put the items */ if (targetitem) { hotlist_get_shape(&xmin, &xmax, targetitem); if (targetitem->type == hl_directory && winx >= xmin && winx <= xmin+item_dir_width) { position = HOTLIST_POSITION_BEGINNING; /* Put in directory */ } else { if ((-winy % item_height) > item_height / 2) position = HOTLIST_POSITION_AFTER; /* Put items after target item */ else position = HOTLIST_POSITION_BEFORE; /* Put items before target item */ } } else { targetitem = hotlist_root; position = HOTLIST_POSITION_END; } tempint = hotlist_find_no_from_item(hotlist_find_selected_item()); if (tempint < top) top = tempint; bottom = hotlist_count_displayed_items(hotlist_root->data.directory_content); if (targetitem->flags & HOTLIST_G_IS_SELECTED) return 0; /* do nothing if dropped on selected items */ sourceitem = hotlist_find_selected_item(); sourceitem->flags &= ~HOTLIST_G_IS_SELECTED; if (!shift) { /* Move selected items */ hotlist_move_item(sourceitem, targetitem, position); /* Move first item to specified position */ /* before/after/in target */ if (sourceitem->type == hl_directory) hotlist_clear_flags(sourceitem->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); targetitem = sourceitem; while((sourceitem = hotlist_find_selected_item()) != NULL) { sourceitem->flags &= ~HOTLIST_G_IS_SELECTED; hotlist_move_item(sourceitem, targetitem, HOTLIST_POSITION_AFTER); /* Move all subsequent items to follow */ /* first moved item */ if (sourceitem->type == hl_directory) hotlist_clear_flags(sourceitem->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); targetitem = sourceitem; } hotlist_modified(HL_MODIFIED_MOVE); } else { /* Copy selected items */ hotlist_copy_item(sourceitem, targetitem, position, &targetitem); /* Copy first item to specified position */ /* before/after/in target */ if (sourceitem->type == hl_directory) hotlist_clear_flags(sourceitem->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); while((sourceitem = hotlist_find_selected_item()) != NULL) { sourceitem->flags &= ~HOTLIST_G_IS_SELECTED; hotlist_copy_item(sourceitem, /* Copy all subsequent items to follow */ targetitem, /* first copied item */ HOTLIST_POSITION_AFTER, &targetitem); if (sourceitem->type == hl_directory) hotlist_clear_flags(sourceitem->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); } hotlist_modified(HL_MODIFIED_COPY); } bottom2 = hotlist_count_displayed_items(hotlist_root->data.directory_content); if (bottom2 > bottom) bottom = bottom2; hotlist_redraw_items(top, bottom); hotlist_window_preopen(already_open); } else { if (hotlist_count_selected_items() == 1 && (sourceitem = hotlist_find_selected_item())->type == hl_url) { /* Dropped in non hotlist window - save as a URI file */ hotlist_initiate_uri_save(sourceitem); } else { /* Can't save URI file when saving more than one URL so save HTML file instead*/ hotlist_initiate_html_save("Hotlist"); } /* Drag was dropped in non-hotlist window */ } return 0; } void hotlist_autoscroll(int x, int y, int window_handle) { ObjectId object, parent; ComponentId component; int scroll_changed; WimpGetWindowStateBlock state; BBox extent; static unsigned int hscroll_speed, vscroll_speed; /* Separate h/v velocities */ static int last_window_handle = 0; /* No error as autoscroll not working is not a major problem */ if (window_wimp_to_toolbox(0, window_handle, -1, &object, NULL)) return; state.window_handle = window_handle; if (last_window_handle != window_handle) { last_window_handle = window_handle; hscroll_speed = 0; vscroll_speed = 0; } wimp_get_window_state(&state); window_get_extent(0, object, &extent); /* Auto scrolling of hotlist window when dragging */ scroll_changed = 0; if ((y > state.visible_area.ymax - HOTLIST_SCROLL_BOUNDARY_SIZE) && y < state.visible_area.ymax) { /* Don't scroll if already at bottom edge */ if (state.yscroll < extent.ymax) { state.yscroll += vscroll_speed; scroll_changed |= 1; } } else if ((y < state.visible_area.ymin + HOTLIST_SCROLL_BOUNDARY_SIZE) && y > state.visible_area.ymin) { /* Don't scroll if already at top edge */ if (state.yscroll > extent.ymin + (state.visible_area.ymax - state.visible_area.ymin)) /////// { state.yscroll -= vscroll_speed; scroll_changed |= 1; } } if ((x > state.visible_area.xmax - HOTLIST_SCROLL_BOUNDARY_SIZE) && x < state.visible_area.xmax) { /* Don't scroll if already at right hand edge */ if (state.xscroll < extent.xmax - (state.visible_area.xmax - state.visible_area.xmin)) /////// { state.xscroll += hscroll_speed; scroll_changed |= 2; } } else if ((x < state.visible_area.xmin + HOTLIST_SCROLL_BOUNDARY_SIZE) && x > state.visible_area.xmin) { /* Don't scroll if already at left hand edge */ if (state.xscroll > extent.xmin) { state.xscroll -= hscroll_speed; scroll_changed |= 2; } } if (scroll_changed) { toolbox_get_parent(0, object, &parent, &component); toolbox_show_object(0, object, Toolbox_ShowObject_FullSpec, &(state.visible_area), parent, component); } if (scroll_changed & 1) { vscroll_speed += HOTLIST_SCROLL_SPEED_INC; if (vscroll_speed > HOTLIST_SCROLL_SPEED_MAX) vscroll_speed = HOTLIST_SCROLL_SPEED_MAX; } else { vscroll_speed = HOTLIST_SCROLL_SPEED_MIN; } if (scroll_changed & 2) { hscroll_speed += HOTLIST_SCROLL_SPEED_INC; if (hscroll_speed > HOTLIST_SCROLL_SPEED_MAX) hscroll_speed = HOTLIST_SCROLL_SPEED_MAX; } else { hscroll_speed = HOTLIST_SCROLL_SPEED_MIN; } } /*************************************************/ /* hotlist_null_handler() */ /* */ /* Called every null event while drag is in */ /* operation */ /*************************************************/ static int hotlist_null_handler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle) { int x, y, buttons; unsigned int itemno, xmin, xmax; unsigned int item_height, item_dir_width, item_url_width; int new_time; hotlist_item *item; ObjectId window; ComponentId component; WimpGetWindowStateBlock state; window_get_pointer_info(0, &x, &y, &buttons, &window, &component); if (window == hotlist_windowid) { window_get_wimp_handle(0, window, &state.window_handle); hotlist_autoscroll(x, y, state.window_handle); /* Display arrow pointing into directory to say that dropping */ /* here will put in directory rather than next to it */ wimp_get_window_state(&state); hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); x += (state.xscroll - state.visible_area.xmin); y += (state.yscroll - state.visible_area.ymax); itemno = -y / item_height; item = hotlist_find_item(hotlist_root->data.directory_content, itemno); if (item && item->type == hl_directory && !(item->flags & HOTLIST_G_IS_SELECTED)) { hotlist_get_shape(&xmin, &xmax, item); if (x >= xmin && x <= xmin + item_dir_width) { if (hotlist_current_highlighted != item) { if (hotlist_current_highlighted) { hotlist_current_highlighted->flags &= ~HOTLIST_D_IS_HIGHLIGHTED; hotlist_redraw_items(highlighted_itemno, highlighted_itemno); } item->flags |= HOTLIST_D_IS_HIGHLIGHTED; hotlist_current_highlighted = item; highlighted_itemno = itemno; hotlist_redraw_items(highlighted_itemno, highlighted_itemno); _swix(OS_ReadMonotonicTime, _OUTR(0, 0), &autoopen_oldtime); } else { _swix(OS_ReadMonotonicTime, _OUTR(0, 0), &new_time); /* Auto open directories */ if (choices.autoopen_delay && !(item->flags & HOTLIST_D_IS_OPEN) && (new_time - autoopen_oldtime) > choices.autoopen_delay) { item->flags |= HOTLIST_D_IS_OPEN; hotlist_window_preopen(already_open); hotlist_redraw_items(highlighted_itemno, hotlist_count_displayed_items(hotlist_root->data.directory_content)); } } } else { if (hotlist_current_highlighted) { hotlist_current_highlighted->flags &= ~HOTLIST_D_IS_HIGHLIGHTED; hotlist_redraw_items(highlighted_itemno, highlighted_itemno); hotlist_current_highlighted = NULL; } } } else { if (hotlist_current_highlighted) { hotlist_current_highlighted->flags &= ~HOTLIST_D_IS_HIGHLIGHTED; hotlist_redraw_items(highlighted_itemno, highlighted_itemno); hotlist_current_highlighted = NULL; } } } else { /* non hotlist window */ if (hotlist_current_highlighted) { hotlist_current_highlighted->flags &= ~HOTLIST_D_IS_HIGHLIGHTED; hotlist_redraw_items(highlighted_itemno, highlighted_itemno); hotlist_current_highlighted = NULL; } } return 0; } /* Simple non-scrolling selection box, to be improved later */ /* Workarea relative corner of selection box may not be needed later */ static int selection_x, selection_y; /*************************************************/ /* hotlist_start_drag() */ /* */ /* This function is called to start a selection */ /* box operation in the hotlist window. */ /*************************************************/ _kernel_oserror *hotlist_selection_box_start(void) { _kernel_oserror *err; WimpDragBox box; WimpGetPointerInfoBlock pointerblock; WimpGetWindowStateBlock state; wimp_get_pointer_info(&pointerblock); /* Read pointer position */ show_error(window_get_wimp_handle(0, hotlist_windowid, &state.window_handle)); wimp_get_window_state(&state); selection_x = pointerblock.x + (state.xscroll - state.visible_area.xmin); selection_y = pointerblock.y + (state.yscroll - state.visible_area.ymax); box.drag_type = Wimp_DragBox_DragRubberDash; box.dragging_box.xmin = pointerblock.x; /* box shape */ box.dragging_box.xmax = pointerblock.x; box.dragging_box.ymin = pointerblock.y; box.dragging_box.ymax = pointerblock.y; box.parent_box.xmin = state.visible_area.xmin; /* Bounding box for dragged box */ box.parent_box.xmax = state.visible_area.xmax; box.parent_box.ymin = state.visible_area.ymin; box.parent_box.ymax = state.visible_area.ymax; err = wimp_drag_box(&box); /* start drag box */ if (err) return err; hotlist_dragging = HOTLIST_BOX_DRAG_SELECTION; /* Set global variable saying we are currently dragging */ /* so we know whether to process a user_drag_box event */ register_null_claimant(Wimp_ENull, hotlist_null_drag_select_handler, NULL); return NULL; } /*************************************************/ /* hotlist_null_drag_select_handler() */ /* */ /* This function is called as a null handler; */ /* it is responsible for selecting and */ /* deselecting items within and outside the */ /* rubber drag box started by */ /* hotlist_selection_box_start. */ /* */ /* Parameters are as standard for a Wimp event */ /* handler. */ /*************************************************/ int hotlist_null_drag_select_handler(int event_code, WimpPollBlock * event, IdBlock * id_block, void * handle) { WimpGetPointerInfoBlock pointerblock; unsigned int item_height, item_dir_width, item_url_width; int workx, worky; hotlist_item *item; WimpGetWindowStateBlock state; unsigned int item_min, item_max, itemno, itemxmin, itemxmax; int minx, maxx; int last_item; wimp_get_pointer_info(&pointerblock); /* Read pointer position */ show_error(window_get_wimp_handle(0, hotlist_windowid, &state.window_handle)); wimp_get_window_state(&state); hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); workx = pointerblock.x + (state.xscroll - state.visible_area.xmin); worky = pointerblock.y + (state.yscroll - state.visible_area.ymax); item_min = -worky / item_height; if (-selection_y / item_height < item_min) item_min = -selection_y / item_height; item_max = (-worky / item_height); if ((-selection_y / item_height) > item_max) item_max = (-selection_y / item_height); if (selection_x < workx) { minx = selection_x; maxx = workx; } else { minx = workx; maxx = selection_x; } last_item = hotlist_count_displayed_items(hotlist_root->data.directory_content); for(itemno = 0; itemno <= last_item; itemno++) { item = hotlist_find_item(hotlist_root->data.directory_content, itemno); if (item) { if (itemno >= item_min && itemno <= item_max) { hotlist_get_shape(&itemxmin, &itemxmax, item); if ((!(maxx < itemxmin || minx > itemxmax))) { if (!(item->flags & HOTLIST_G_IS_SELECTED)) { item->flags |= HOTLIST_G_IS_SELECTED; hotlist_redraw_items(itemno, itemno); if (item->type == hl_directory && !(item->flags & HOTLIST_D_IS_OPEN)) /* If directory is closed select everything in it */ { hotlist_set_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED); hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_REDRAW_NOW); } } } else { if (item->flags & HOTLIST_G_IS_SELECTED) { item->flags &= ~HOTLIST_G_IS_SELECTED; hotlist_redraw_items(itemno, itemno); if (item->type == hl_directory && !(item->flags & HOTLIST_D_IS_OPEN)) /* If directory is closed unselect everything in it */ { hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW); } } } } else { if (item->flags & HOTLIST_G_IS_SELECTED) { item->flags &= ~HOTLIST_G_IS_SELECTED; hotlist_redraw_items(itemno, itemno); if (item->type == hl_directory && !(item->flags & HOTLIST_D_IS_OPEN)) /* If directory is closed unselect everything in it */ { hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW); } } } } } return 0; } /*************************************************/ /* hotlist_contents_selected() */ /* */ /* Checks if all items and subdirectories are */ /* selected. */ /* */ /* Parameters: Pointer to the first hotlist_item */ /* to check. */ /* */ /* Returns: 1 if all items are selected, else */ /* 0 (there are unselected items). */ /*************************************************/ static unsigned int hotlist_contents_selected(hotlist_item * item) { while(item) { /* Keep trying to find an unselected item and */ /* immediately return 0 if found. */ if (!item->flags & HOTLIST_G_IS_SELECTED) return 0; if (item->type == hl_directory) { if (!hotlist_contents_selected(item->data.directory_content)) return 0; } item = item->next; } return 1; } /*************************************************/ /* hotlist_no_contents_selected() */ /* */ /* Checks if all items and subdirectories are */ /* unselected. */ /* */ /* Parameters: Pointer to the first hotlist_item */ /* to check. */ /* */ /* Returns: 1 if all items are unselected, */ /* or 0 (there are selected items). */ /*************************************************/ static unsigned int hotlist_no_contents_selected(hotlist_item * item) { while (item) { /* Keep trying to find a selected item and */ /* immediately return 0 if found. */ if (item->flags & HOTLIST_G_IS_SELECTED) return 0; if (item->type == hl_directory) { if (!hotlist_no_contents_selected(item->data.directory_content)) return 0; } item = item->next; } return 1; } /*************************************************/ /* hotlist_show_descriptions_handler() */ /* */ /* Selects show descriptions and redraws hotlist */ /* window and menu to reflect this */ /*************************************************/ static int hotlist_show_descriptions_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { hl_show_urls = 0; hotlist_set_menu_details(id_block->parent_id); hotlist_window_preopen(already_open); hotlist_redraw_items(0, hotlist_count_displayed_items(hotlist_root->data.directory_content)); return 1; } /*************************************************/ /* hotlist_show_urls_handler() */ /* */ /* Selects show urls and redraws hotlist window */ /* and menu to reflect this */ /*************************************************/ static int hotlist_show_urls_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle) { hl_show_urls = 1; hotlist_set_menu_details(id_block->parent_id); hotlist_window_preopen(already_open); hotlist_redraw_items(0, hotlist_count_displayed_items(hotlist_root->data.directory_content)); return 1; } /*************************************************/ /* hotlist_modified() */ /* */ /* Called whenever the hotlist is modified */ /*************************************************/ static _kernel_oserror *hotlist_modified(unsigned int type) { return NULL; } _kernel_oserror *hotlist_initiate_uri_save(hotlist_item *item) { WimpGetPointerInfoBlock block; WimpMessage message; int new_task_handle; wimp_get_pointer_info(&block); message.hdr.size = sizeof(WimpMessage); message.hdr.your_ref = 0; message.hdr.action_code = Wimp_MDataSave; message.data.data_save.destination_window = block.window_handle; message.data.data_save.destination_icon = block.icon_handle; message.data.data_save.destination_x = block.x; message.data.data_save.destination_y = block.y; message.data.data_save.estimated_size = strlen(item->data.url)+1; message.data.data_save.file_type = 0xf91; /* URI file - to be replaced with a defined value */ urlutils_leafname_from_url(item->data.url, message.data.data_save.leaf_name, 212); wimp_send_message(Wimp_EUserMessageRecorded, &message, block.window_handle, block.icon_handle, &new_task_handle); hotlist_save_item = item; hotlist_ram_transfer_sent = 0; hotlist_save_type = HL_SAVE_URI; return NULL; } _kernel_oserror *hotlist_initiate_html_save(char *filename) { WimpGetPointerInfoBlock block; WimpMessage message; int new_task_handle; wimp_get_pointer_info(&block); message.hdr.size = sizeof(WimpMessage); message.hdr.your_ref = 0; message.hdr.action_code = Wimp_MDataSave; message.data.data_save.destination_window = block.window_handle; message.data.data_save.destination_icon = block.icon_handle; message.data.data_save.destination_x = block.x; message.data.data_save.destination_y = block.y; message.data.data_save.estimated_size = -1; /* Dunno how big it's going to be */ message.data.data_save.file_type = FileType_HTML; strncpy(message.data.data_save.leaf_name, filename, 212); wimp_send_message(Wimp_EUserMessageRecorded, &message, block.window_handle, block.icon_handle, &new_task_handle); hotlist_ram_transfer_sent = 0; hotlist_save_type = HL_SAVE_HTML; return NULL; } int hotlist_data_save_ack_handler(WimpMessage *message, void *handle) { FILE *fileptr; int new_task_handle; _kernel_oserror *e; switch(hotlist_save_type) { case HL_SAVE_URI: if (hotlist_save_item) { fileptr = fopen(message->data.data_save_ack.leaf_name, "w"); if (fileptr) { fprintf(fileptr, hotlist_save_item->data.url); if (fclose(fileptr)) { show_error_ret(_kernel_last_oserror()); hotlist_save_item = NULL; hotlist_save_type = HL_SAVE_NONE; return 1; } e = _swix(OS_File, _INR(0,2), 18, message->data.data_save_ack.leaf_name, 0xf91); if (e) { show_error_ret(e); hotlist_save_item = NULL; hotlist_save_type = HL_SAVE_NONE; return 1; } message->hdr.action_code = Wimp_MDataLoad; message->hdr.your_ref = message->hdr.my_ref; e = wimp_send_message(Wimp_EUserMessageRecorded, message, message->hdr.sender, 0, &new_task_handle); if (e) { show_error_ret(e); if (remove(message->data.data_save_ack.leaf_name)) { show_error_ret(_kernel_last_oserror()); } hotlist_save_item = NULL; hotlist_save_type = HL_SAVE_NONE; return 1; } } else { show_error_ret(_kernel_last_oserror()); } hotlist_save_item = NULL; hotlist_save_type = HL_SAVE_NONE; return 1; } break; case HL_SAVE_HTML: e = hotlist_save_hotlist(message->data.data_save_ack.leaf_name, 1); hotlist_clear_selection(); if (e) { show_error_ret(e); hotlist_save_type = HL_SAVE_NONE; } message->hdr.action_code = Wimp_MDataLoad; message->hdr.your_ref = message->hdr.my_ref; e = wimp_send_message(Wimp_EUserMessageRecorded, message, message->hdr.sender, 0, &new_task_handle); if (e) { show_error_ret(e); if (remove(message->data.data_save_ack.leaf_name)) { show_error_ret(_kernel_last_oserror()); } hotlist_save_type = HL_SAVE_NONE; } return 1; break; default: break; } return 0; } int hotlist_ram_fetch_handler(WimpMessage *message, void *handle) { int left, towrite, new_task_handle; _kernel_oserror *e; if (hotlist_save_item) { /* Calculate the number of bytes left to send */ /* Don't include the terminating null as it is not required for URI files*/ left = (strlen(hotlist_save_item->data.url)) - hotlist_ram_transfer_sent; /* Use the smaller of the buffer size and the number of bytes to write */ towrite = message->data.ram_fetch.buffer_size > left ? left : message->data.ram_fetch.buffer_size; e = wimp_transfer_block(task_handle, (char*)(hotlist_save_item->data.url) + hotlist_ram_transfer_sent, message->hdr.sender, message->data.ram_fetch.buffer, towrite); if (e) { hotlist_save_item = NULL; show_error_ret(e); return 1; } message->hdr.your_ref = message->hdr.my_ref; message->hdr.action_code = Wimp_MRAMTransmit; message->data.ram_transmit.nbytes = towrite; e = wimp_send_message(Wimp_EUserMessage, message, message->hdr.sender, 0, &new_task_handle); if (e) { hotlist_save_item = NULL; show_error_ret(e); return 1; } /* If no bytes were transmitted this is the last part of the ram transfer */ if (!left) { hotlist_save_item = NULL; hotlist_ram_transfer_sent = 0; return 1; } /* Increase the total number of bytes send by the number just send */ hotlist_ram_transfer_sent += towrite; return 1; } return 0; }