/* 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 "ChoiceDefs.h" #include "FetchPage.h" #include "Filetypes.h" #include "Menus.h" #include "Mouse.h" #include "Multiuser.h" #include "Protocols.h" #include "Save.h" #include "Toolbars.h" #include "URLUtils.h" #include "Windows.h" #include "Hotlist.h" /* Internationalisation support */ #ifdef UNIFONT #define CHARSET_SPECIFIER "\n" #else #define CHARSET_SPECIFIER "\n" #endif /* Local definitions */ #define HotlistWrite(fn) {written = (fn); if (written < 0) goto hotlist_save_error;} /* 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 = NULL_ObjectId; /* 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 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 */ /* Local structures */ typedef struct hl_dragging_details { char drag_type; /* One of HOTIST_NOT_DRAGGING, HOTLIST_BOX_DRAG, HOTLIST_SOLID_DRAG_OBJECT, */ /* HOTLIST_SOLID_DRAG_SPRITE, or HOTLIST_BOX_DRAG_SELECTION - See Hotlist.h */ unsigned int using_adjust :1; } hl_dragging_details; static hl_dragging_details hotlist_dragging; /* 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_select_all_handler; static ToolboxEventHandler hotlist_clear_selection_handler; static ToolboxEventHandler hotlist_menu_openall_handler; static ToolboxEventHandler hotlist_menu_closeall_handler; static ToolboxEventHandler hotlist_menu_delete_handler; static ToolboxEventHandler hotlist_save_to_server_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 ToolboxEventHandler hotlist_drag_stop_handler; static ToolboxEventHandler hotlist_close_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_desc, 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_r (hotlist_item * list); /* Counting items */ 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 _kernel_oserror * hotlist_redraw_now (void); static _kernel_oserror * hotlist_redraw_now_r (hotlist_item * list, int * curr_item); static _kernel_oserror * hotlist_get_shape (int * xmin, int * xmax, hotlist_item * item); static _kernel_oserror * hotlist_directory_open_close (hotlist_item * item, unsigned int itemno); static _kernel_oserror * hotlist_redraw_items (unsigned int firstitem, unsigned int lastitem); static _kernel_oserror * 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 int hotlist_preopen (void); static _kernel_oserror * hotlist_set_menu_details (ObjectId menuid); static _kernel_oserror * hotlist_save_entries (FILE * fileptr, hotlist_item * list, int type, int save_read_only); static void hotlist_lower_tags (char * string); static void hotlist_drag_renderer (hotlist_item * item, unsigned int item_height, unsigned int item_dir_width, unsigned int item_url_width); static _kernel_oserror * hotlist_start_drag (void); static _kernel_oserror * hotlist_start_drag_backend (void); static _kernel_oserror * hotlist_modified (unsigned int type); static void hotlist_convert_drag_selection (hotlist_item * item); static _kernel_oserror * hotlist_autoscroll (int window); static _kernel_oserror * hotlist_load_directory (FILE * fileptr, hotlist_item * target); static int hotlist_get_selected_shape (BBox * box); static _kernel_oserror * hotlist_get_selected_shape_r (hotlist_item * list, BBox * box, unsigned int * itemno, int * found, unsigned int item_height); static _kernel_oserror * hotlist_select_box (unsigned int first_item, unsigned int last_item, int minx, int maxx); static _kernel_oserror * hotlist_select_box_r (unsigned int first_item, unsigned int last_item, hotlist_item *item, unsigned int *itemno, int minx, int maxx); static void hotlist_find_match_r (char * buffer, int buffer_size, hotlist_item * item, hotlist_item ** lowest_item, int * lowest_offset, int * lowest_diff); /* Save Protocol */ static _kernel_oserror * hotlist_initiate_uri_save (hotlist_item *sourceitem); static _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_is_inside() */ // /* */ // /* Checks if one hotlist_item is held inside */ // /* the directory structure of another */ // /* hotlist_item */ // /* */ // /* Parameters: Pointer to the hotlist_item that */ // /* may be inside the parent; */ // /* */ // /* Pointer to the parent */ // /* hotlist_item. */ // /* */ // /* Returns: 1 if item is inside, else 0. */ // /*************************************************/ // // static int hotlist_is_inside(hotlist_item * inside, hotlist_item * outside) // { // while (inside) // { // if (inside == outside) return 1; // inside = inside->parent; // } // // return 0; // } /*************************************************/ /* 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; int is_untitled = 0; if (!directory_name) is_untitled = 1; else { while (*directory_name && *directory_name <= ' ') directory_name ++; if (!*directory_name) is_untitled = 1; else { int len = strlen(directory_name); while (len && directory_name[len - 1] <= ' ') len--; if (!len) is_untitled = 1; else directory_name[len] = '\0'; } } if (is_untitled) directory_name = lookup_token("HotlistUntitled:(Untitled)",0,0); /* 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_desc, char * url) { char * perm_url_desc; char * perm_url; hotlist_item * item; _kernel_oserror * e; /* Do we have a URL string? */ if (!url) return NULL; while (*url && *url <= ' ') url++; if (!*url) return NULL; /* Do we have a useful title string? */ if (!url_desc) url_desc = url; else { while (*url_desc && *url_desc <= ' ') url_desc ++; if (!*url_desc) url_desc = url; else { int len = strlen(url_desc) - 1; while (len && url_desc[len] <= ' ') len--; if (!len) url_desc = url; else url_desc[len + 1] = '\0'; } } /* Allocate a new hotlist_item structure */ if ((item = malloc(sizeof(hotlist_item))) == NULL) { #ifdef TRACE if (tl & (1<<25)) Printf("hotlist_new_url: 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_desc) + 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_desc); 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) { hotlist_item * newdir, * tempptr; /* If the item is read only, don't move it; copy instead. */ if (source->flags & HOTLIST_G_IS_READ_ONLY) { return hotlist_copy_item(source, target, position, NULL); } /* Otherwise, moving it is OK */ 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) { hotlist_item * newdir; newdir = NULL; switch(source->type) { /* For a URL, create a new item based on the source one */ case hl_url: { RetError(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) { 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. */ /*************************************************/ 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. */ /*************************************************/ static 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. */ /* */ /* If you want to know if all items are selected */ /* use hotlist_contents_selected. If you want to */ /* know if no items are selected, it is faster */ /* to use hotlist_no_contents_selected than */ /* compare the return value of this function */ /* against zero (this function *must* scan all */ /* hotlist items, whereas the other can exit as */ /* soon as a selected item is found). */ /* */ /* Returns: The number of selected items. */ /*************************************************/ 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 (count */ /* the visible items from the top of */ /* the window downwards starting at */ /* an item number of zero); */ /* */ /* Last item number to draw. */ /*************************************************/ static _kernel_oserror * hotlist_draw(hotlist_item * list, unsigned int first_item, unsigned int last_item) { 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 (count */ /* the visible items from the top of */ /* the window downwards starting at */ /* an item number of zero); */ /* */ /* 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) { 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) ? 1 : 0) ^ ((list->flags & HOTLIST_G_DRAG_SELECTED) ? 1 : 0) ) 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 = !(list->flags & HOTLIST_G_IS_READ_ONLY) ? URL_SPRITE : RESOURCES_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 = !(list->flags & HOTLIST_G_IS_READ_ONLY) ? OPEN_DIRECTORY_SPRITE : OPEN_RESOURCES_DIRECTORY_SPRITE; } else { icon.data.is.sprite = !(list->flags & HOTLIST_G_IS_READ_ONLY) ? CLOSED_DIRECTORY_SPRITE : CLOSED_RESOURCES_DIRECTORY_SPRITE; } icon.data.is.sprite_name_length = strlen(icon.data.is.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); icon.data.it.validation = NULL; } 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); icon.data.it.validation = NULL; } /* 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) ? 1 : 0) ^ ((list->flags & HOTLIST_G_DRAG_SELECTED) ? 1 : 0)) 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 _kernel_oserror * hotlist_redraw_now(void) { int curr_item = 0; return 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 _kernel_oserror * hotlist_redraw_now_r(hotlist_item * list, int * curr_item) { while (list) { if (list->flags & HOTLIST_G_REDRAW_NOW) { /* Redraw just the one item */ RetError(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 */ RetError(hotlist_redraw_now_r(list->data.directory_content, curr_item)); } list = list->next; } return NULL; } /*************************************************/ /* 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; hotlist_item * target; int type; target = hotlist_find_selected_item(); if (!target) { position = at_bottom ? HOTLIST_POSITION_END : HOTLIST_POSITION_BEGINNING; target = hotlist_root; type = 1; /* If adding to the beginning of the hotlist, skip any */ /* read-only items at the top first. */ if (position == HOTLIST_POSITION_BEGINNING) { hotlist_item * check = target->data.directory_content; /* Look for something not read-only */ while (check && check->next) { if (check->next->flags & HOTLIST_G_IS_READ_ONLY) check = check->next; else break; } if (check && (check->flags & HOTLIST_G_IS_READ_ONLY)) { position = HOTLIST_POSITION_AFTER; target = check; } } } else { if (target->type == hl_directory) { position = HOTLIST_POSITION_BEGINNING; } else { position = HOTLIST_POSITION_AFTER; } type = 2; } /* Add the item and ensure the window extent etc. is correct */ e = hotlist_new_url(target, position, description, url); if (!e) hotlist_preopen(); /* 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: { if (type == 1) { hotlist_redraw_items(0, hotlist_count_displayed_items(hotlist_root->data.directory_content)); } else { if (target->flags & HOTLIST_D_IS_OPEN) { hotlist_redraw_items(hotlist_find_no_from_item(target), hotlist_count_displayed_items(hotlist_root->data.directory_content)); } } } break; case HOTLIST_POSITION_BEFORE: case HOTLIST_POSITION_AFTER: { hotlist_redraw_items(hotlist_find_no_from_item(hotlist_newitem), hotlist_count_displayed_items(hotlist_root->data.directory_content)); } } 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: Pointer to an int, in which the */ /* xmin offset (in OS units) from */ /* the left hand edge is returned; */ /* */ /* Similarly, a pointer to an int to */ /* take the xmax offset; */ /* */ /* Pointer to the hotlist_item to */ /* examine. */ /* */ /* Assumes: Any pointer may be NULL. */ /*************************************************/ static _kernel_oserror * hotlist_get_shape(int * xmin, int * xmax, hotlist_item * item) { hotlist_item * tempitem; unsigned int item_height, item_dir_width, item_url_width; int icon_width; int text_width; int count = 0; if (xmin) *xmin = 0; if (xmax) *xmax = 0; if (!item) return NULL; /* Find entry sizes */ RetError(hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width)); /* Count how many parent items we have. This allows */ /* the left hand indent to be calculated. */ tempitem = item; while (tempitem) { tempitem = tempitem->parent; count++; } count -= 2; /* Find the text width */ 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); /* Add in the sprite width */ switch (item->type) { case hl_directory: icon_width = item_dir_width; break; case hl_url: icon_width = item_url_width; break; default: icon_width = 0; break; } /* Add up the total and exit */ if (xmin) *xmin = count * item_dir_width; if (xmax) *xmax = count * item_dir_width + icon_width + 2 + text_width + 12; return NULL; } /*************************************************/ /* hotlist_directory_open_close() */ /* */ /* This function opens or closes a directory, */ /* dealing with all required redrawing. */ /* */ /* Parameters: Pointer to the hotlist_item */ /* struct representing the directory */ /* to open or close; */ /* */ /* Number of that item (counting the */ /* visible hotlist items from the */ /* top of the window downwards, */ /* starting at zero). */ /*************************************************/ static _kernel_oserror * 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; RetError(hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width)); /* Swap the flag saying whether the directory is open or not */ item->flags ^= HOTLIST_D_IS_OPEN; /* Clear all selected items within the directory */ hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW); /* Do the appropriate redrawing */ hotlist_preopen(); RetError(window_get_wimp_handle(0, hotlist_windowid, &window_handle)); RetError(window_get_extent(0, hotlist_windowid, &bbox)); top = -itemno * item_height; if (item->data.directory_content) { RetError(wimp_force_redraw(window_handle, bbox.xmin, bbox.ymin, bbox.xmax, top)); } else { RetError(wimp_force_redraw(window_handle, bbox.xmin, top-item_height, bbox.xmax, top)); } return NULL; } /*************************************************/ /* hotlist_redraw_items() */ /* */ /* This function forces the redraw of a set of */ /* items. */ /* */ /* Parameters: Item number of the first item to */ /* redraw (counting the visible */ /* items from the top of the window */ /* downwards, starting at zero) - */ /* this is inclusive; */ /* */ /* Item number of the last item to */ /* redraw (also inclusive). */ /*************************************************/ static _kernel_oserror * hotlist_redraw_items(unsigned int firstitem, unsigned int lastitem) { unsigned int item_height, item_dir_width, item_url_width; BBox bbox; int window_handle; /* Get the entry sizes */ RetError(hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width)); /* Find the window extent */ RetError(window_get_wimp_handle(0, hotlist_windowid, &window_handle)); RetError(window_get_extent(0, hotlist_windowid, &bbox)); /* Force a redraw for the whole extent width, over a vertical */ /* span determined by the given item numbers. */ return wimp_force_redraw(window_handle, bbox.xmin, - (lastitem + 1) * item_height, bbox.xmax, - firstitem * item_height); } /*************************************************/ /* hotlist_clear_selection() */ /* */ /* This function unselects all items, redrawing */ /* as required. */ /*************************************************/ _kernel_oserror * hotlist_clear_selection(void) { if ( hotlist_clear_flags(hotlist_root->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED) ) return hotlist_redraw_now(); return NULL; } /*************************************************/ /* hotlist_launch_url() */ /* */ /* This function launches the url in the passed */ /* item. */ /* */ /* Parameters: Pointer to a hotlist_item struct */ /* holding the URL to launch. */ /*************************************************/ static _kernel_oserror * hotlist_launch_url(hotlist_item * item) { #ifdef TRACE if (tl & (1u<<25)) hotlist_display_item(item); #endif return windows_create_browser(item->data.url, NULL, NULL, NULL, Windows_CreateBrowser_Normal); } /*************************************************/ /* hotlist_process_click_on_item() */ /* */ /* Deal with clicks on hotlist items. */ /* */ /* Parameters: Item number that was clicked upon */ /* (counting visible items from the */ /* top of the window downwards, */ /* starting with item number 0); */ /* */ /* Pointer to a hotlist_item struct */ /* representing the item clicked on; */ /* */ /* State of the mouse buttons, as */ /* Wimp_GetPointerInfo would return */ /* for clicks on a window of button */ /* type 10 (Double/Click/Drag); */ /* */ /* Screen x coordinate of the click; */ /* */ /* Screen y coordinate of the click. */ /*************************************************/ static _kernel_oserror * hotlist_process_click_on_item(unsigned int itemno, hotlist_item * item, int buttons, int x, int y) { _kernel_oserror * e = NULL; switch (buttons) { /* The window button type is Double/Click/Drag, so */ /* this represents a double click with Select. */ case Wimp_MouseButtonSelect: { /* Open or close directories, open URLs in a new window */ if (last_selected_item == itemno) { switch(item->type) { case hl_directory: e = hotlist_directory_open_close(item, itemno); break; case hl_url: e = hotlist_launch_url(item); break; } if (e) show_error_ret(e); /* Deselect the item that was double-clicked upon */ item->flags &= ~HOTLIST_G_IS_SELECTED; e = hotlist_redraw_items(itemno, itemno); } } break; /* Double-click with Adjust */ case Wimp_MouseButtonAdjust: { /* Open or close directories, but for URLs, open them in */ /* a new window and close the hotlist. */ if (last_selected_item == itemno) { switch(item->type) { case hl_directory: e = hotlist_directory_open_close(item, itemno); break; case hl_url: { e = hotlist_launch_url(item); if (!e) toolbox_hide_object(0, hotlist_windowid); } break; } if (e) show_error_ret(e); /* Deselect the item that was double-clicked upon */ item->flags &= ~HOTLIST_G_IS_SELECTED; e = hotlist_redraw_items(itemno, itemno); } } break; /* Drag with Select */ case 64: { e = hotlist_start_drag(); } break; /* Drag with Adjust */ case 16: { /* If the item clicked upon wasn't selected, select it */ if (!(item->flags & HOTLIST_G_IS_SELECTED)) { item->flags |= HOTLIST_G_IS_SELECTED; last_selected_item = itemno; } /* Start the drag and redraw the item clicked upon */ e = hotlist_start_drag(); if (!e) e = hotlist_redraw_items(itemno, itemno); } break; /* Click with Select */ case 1024: { if (!(item->flags & HOTLIST_G_IS_SELECTED)) /* (Do nothing when selected) */ { /* Clear the selected flags of everything else */ e = hotlist_clear_selection(); /* Select this item and if a directory, all items within it */ 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); /* Redraw to reflect the selection */ if (!e) e = hotlist_redraw_now(); } last_selected_item = itemno; } break; /* Click with Adjust */ case 256: { /* Swap the selected state of the item */ item->flags ^= HOTLIST_G_IS_SELECTED; item->flags |= HOTLIST_G_REDRAW_NOW; last_selected_item = itemno; /* If a directory, select or deselect the contents */ 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); } } /* Redraw to reflect the selection */ e = hotlist_redraw_now(); } break; } /* Return any errors that may have been generated */ return e; } /*************************************************/ /* hotlist_process_click() */ /* */ /* This function deals with mouse clicks on the */ /* hotlist window. */ /* */ /* Parameters: X position of click, in window */ /* coords; */ /* */ /* Y position of click, in window */ /* coords; */ /* */ /* Button state (as returned by */ /* Wimp_GetPointerInfo). */ /*************************************************/ static _kernel_oserror * hotlist_process_click(int x, int y, int buttons) { _kernel_oserror * e = NULL; hotlist_item * item; unsigned int item_height, item_dir_width, item_url_width; unsigned int itemno; int xmin, xmax; /* Get information on what was clicked upon */ RetError(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) RetError(hotlist_get_shape(&xmin, &xmax, item)); if (item && x >= xmin && x <= xmax) { /* If we have a specific item, process the click on it */ return hotlist_process_click_on_item(itemno, item, buttons, x, y); } else { /* Otherwise, actions depend on the button type */ switch(buttons) { /* Drag with Select */ case 64: { RetError(hotlist_clear_selection()); e = hotlist_selection_box_start(); } break; /* Drag with Adjust */ case 16: { e = hotlist_selection_box_start(); } break; /* Click with Select */ case 1024: { e = hotlist_clear_selection(); last_selected_item = 0xffffffff; } break; /* Click with Adjust */ case 256: { last_selected_item = 0xffffffff; } break; } } return e; } /*************************************************/ /* hotlist_preopen() */ /* */ /* This function should be called before opening */ /* the hotlist window. If the window is already */ /* showing, then the extent may be altered but */ /* it will never shrink the visible area of the */ /* window. If the window is currently closed, it */ /* will set the extent to the minimum possible */ /* value, which may well drag the visible area */ /* down too. */ /* */ /* Returns: 1 if window was already open, */ /* or 0 if it was closed. */ /*************************************************/ static int hotlist_preopen(void) { _kernel_oserror * e; WimpGetWindowStateBlock state; BBox bbox; ObjectId parent_id; ComponentId parent_component; unsigned int item_height, item_dir_width, item_url_width; unsigned int number, maxlen; unsigned int objectstate; int height, width; #define HotlistPreopen_ShowError(e) {if(e){show_error_ret(e);return 0;}} /* Is the window open or closed? */ e = toolbox_get_object_state(0, hotlist_windowid, &objectstate); HotlistPreopen_ShowError(e); /* Get entry sizes */ e = hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width); HotlistPreopen_ShowError(e); /* General information */ number = hotlist_count_displayed_items(hotlist_root->data.directory_content); maxlen = hotlist_get_max_width(hotlist_root->data.directory_content) + 4; /* Find out window details */ e = window_get_wimp_handle(0, hotlist_windowid, &state.window_handle); HotlistPreopen_ShowError(e); e = wimp_get_window_state(&state); HotlistPreopen_ShowError(e); /* Sanity check... */ if (number < HOTLIST_WINDOW_MIN_HEIGHT) number = HOTLIST_WINDOW_MIN_HEIGHT; if (maxlen < HOTLIST_WINDOW_MIN_WIDTH) maxlen = HOTLIST_WINDOW_MIN_WIDTH; /* If the window is open, get its extent */ if (objectstate & Toolbox_GetObjectState_Showing) { e = window_get_extent(0, hotlist_windowid, &bbox); HotlistPreopen_ShowError(e); } /* Work out the y extent and x extent required for showing */ /* as much of the visible items in the hotlist as possible */ bbox.ymin = -number * item_height; bbox.xmax = maxlen; /* If the window was already open, don't let the visible */ /* area change - otherwise go for a best fit to the */ /* items, as worked out above. */ if (objectstate & Toolbox_GetObjectState_Showing) { 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; } /* Account for a button bar, if one were present. */ bbox.ymax = hotlist_bbar_size; bbox.xmin = 0; /* Set the extent */ e = window_set_extent(0, hotlist_windowid, &bbox); HotlistPreopen_ShowError(e); /* (Re)open the window */ if (objectstate & Toolbox_GetObjectState_Showing) { e = window_get_wimp_handle(0, hotlist_windowid, &state.window_handle); if (!e) e = wimp_get_window_state(&state); if (!e) e = toolbox_get_parent(0, hotlist_windowid, &parent_id, &parent_component); if (!e) e = toolbox_show_object(0, hotlist_windowid, Toolbox_ShowObject_FullSpec, &(state.visible_area), parent_id, parent_component); HotlistPreopen_ShowError(e); } return !!(objectstate & Toolbox_GetObjectState_Showing); } /*************************************************/ /* hotlist_redraw_handler() */ /* */ /* This handles redraw events from the Wimp, for */ /* the hotlist window. */ /* */ /* Parameters are as standard for a Wimp event */ /* handler. */ /*************************************************/ static int hotlist_redraw_handler(int event_code, WimpPollBlock * event, IdBlock * id_block, void * handle) { _kernel_oserror * e = NULL; WimpRedrawWindowBlock block; unsigned int item_height, item_dir_width, item_url_width; unsigned int first_item, last_item; int more; /* Get entry sizes */ ChkError(hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width)); block.window_handle = event->redraw_window_request.window_handle; /* Start the redraw loop */ wimp_redraw_window(&block, &more); while (more && !e) { /* Work out which bits to redraw... */ 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; /* ...and redraw them */ e = hotlist_draw(hotlist_root->data.directory_content, first_item, last_item); /* Get the next redraw rectangle */ if (!e) e = wimp_get_rectangle(&block, &more); } return 1; } /*************************************************/ /* hotlist_mouse_click_handler() */ /* */ /* Event handler to deal with mouse clicks in */ /* the hotlist window; converts coordinates from */ /* screen to window, and runs the result through */ /* hotlist_process_click. */ /* */ /* Parameters are as standard for a Wimp event */ /* handler. */ /*************************************************/ 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); ChkError(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 1; } /*************************************************/ /* hotlist_menuclose_handler() */ /* */ /* Called when menus close. */ /* */ /* Parameters are as standard for a Toolbox */ /* event handler. */ /*************************************************/ static int hotlist_menuclose_handler(int event_code, ToolboxEvent * event, IdBlock * id_block, void * handle) { ObjectId submenu_id; /* Deselect any items selected by the menu */ if (menu_select) { hotlist_clear_selection(); menu_select = 0; } /* Get rid of any submenus */ ChkError(menu_get_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, &submenu_id)); if (submenu_id) ChkError(toolbox_delete_object(0, submenu_id)); ChkError(menu_set_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, 0)); return 1; } /*************************************************/ /* hotlist_set_menu_details() */ /* */ /* When a menu is to be opened or the hotlist */ /* state changes in a way that can affect open */ /* menus, this can be used to update the menu */ /* contents. */ /* */ /* Parameters: Object ID of the hotlist root */ /* menu. */ /*************************************************/ static _kernel_oserror * hotlist_set_menu_details(ObjectId menuid) { hotlist_item * item; char entrytext[Limits_Hotlist_ItemName]; ObjectId submenu_id; switch (hotlist_count_selected_items()) { /* No selected items - set the URL/Directory name string to */ /* "URL ''" and grey it out, along with the Clear Selection */ /* entry. */ case 0: { RetError(menu_set_entry_text(0, menuid, HOTLIST_URL_MENUITEM, "URL ''")); RetError(menu_set_fade(0, menuid, HOTLIST_URL_MENUITEM, 1)); RetError(menu_set_fade(0, menuid, HOTLIST_CLEARSELECTION_MENUITEM, 1)); } break; /* Only 1 item selected */ case 1: { int name_len; item = hotlist_find_selected_item(); switch(item->type) { /* One directory selected - set the URL/Directory name */ /* string to a relevant value, and create and attach */ /* the relevant submenu. */ case hl_directory: { StrNCpy0(entrytext, "Dir. '"); RetError(toolbox_create_object(0, "HLDirmenu", &submenu_id)); RetError(menu_set_sub_menu_show(0, menuid, HOTLIST_URL_MENUITEM, submenu_id)); /* If the item is read-only, grey out the 'delete' entry */ if (item->flags & HOTLIST_G_IS_READ_ONLY) menu_set_fade(0, submenu_id, HOTLIST_DELETE_SUBMENUITEM, 1); else menu_set_fade(0, submenu_id, HOTLIST_DELETE_SUBMENUITEM, 0); } break; /* Similarly, deal with a single URL being selected */ case hl_url: { StrNCpy0(entrytext, "URL '"); RetError(toolbox_create_object(0, "HLURLmenu", &submenu_id)); RetError(menu_set_sub_menu_show(0, menuid, HOTLIST_URL_MENUITEM, submenu_id)); if (item->flags & HOTLIST_G_IS_READ_ONLY) menu_set_fade(0, submenu_id, HOTLIST_DELETE_SUBMENUITEM, 1); else menu_set_fade(0, submenu_id, HOTLIST_DELETE_SUBMENUITEM, 0); } break; } name_len = strlen(item->name); /* Add the item name in. If the whole item will not fit, put as much as */ /* will do, followed by '...'. */ if (name_len < sizeof(entrytext) - strlen(entrytext) - 1) strcat(entrytext, item->name); /* ('<' accounts for terminator, -1 accounts for closing "'") */ else if (sizeof(entrytext) - strlen(entrytext) > 5) { strncat(entrytext, item->name, sizeof(entrytext) - strlen(entrytext) - 5); /* (-5 accounts for closing "'", "..." and terminator) */ strcat(entrytext, "..."); } if (strlen(entrytext) < sizeof(entrytext) - 1) strcat(entrytext, "'"); /* Set the text, unfade the item, and unfade the Clear Selection item */ RetError(menu_set_entry_text(0, menuid, HOTLIST_URL_MENUITEM, entrytext)); RetError(menu_set_fade(0, menuid, HOTLIST_URL_MENUITEM, 0)); RetError(menu_set_fade(0, menuid, HOTLIST_CLEARSELECTION_MENUITEM, 0)); } break; /* Many items selected */ default: { /* Set the URL/Directory name string, ungrey that item and Clear Selection, */ /* and create and attach an appropriate submenu. */ RetError(menu_set_entry_text(0, menuid, HOTLIST_URL_MENUITEM, "Selection")); RetError(menu_set_fade(0, menuid, HOTLIST_URL_MENUITEM, 0)); RetError(menu_set_fade(0, menuid, HOTLIST_CLEARSELECTION_MENUITEM, 0)); RetError(toolbox_create_object(0, "HLSlctmenu", &submenu_id)); RetError(menu_set_sub_menu_show(0, menuid, HOTLIST_URL_MENUITEM, submenu_id)); } break; } /* If *everything* is selected, want to grey out Select All; */ /* else ungrey it. */ if (hotlist_contents_selected(hotlist_root)) RetError(menu_set_fade(0, menuid, HOTLIST_SELECTALL_MENUITEM, 1)) else RetError(menu_set_fade(0, menuid, HOTLIST_SELECTALL_MENUITEM, 0)) /* Set the ticks on 'Show Descriptions' or 'Show URLs' in the */ /* Display submenu. */ RetError(menu_get_sub_menu_show(0, menuid, HOTLIST_DISPLAY_MENUITEM, &submenu_id)); if (hl_show_urls) { RetError(menu_set_tick(0, submenu_id, HOTLIST_MENU_SHOWDESCRIPTIONS, 0)); RetError(menu_set_tick(0, submenu_id, HOTLIST_MENU_SHOWURLS, 1)); } else { RetError(menu_set_tick(0, submenu_id, HOTLIST_MENU_SHOWDESCRIPTIONS, 1)); RetError(menu_set_tick(0, submenu_id, HOTLIST_MENU_SHOWURLS, 0)); } /* Finished */ return NULL; } /*************************************************/ /* hotlist_menuopen_handler() */ /* */ /* Handles events raised when menus are about to */ /* be shown. */ /* */ /* Parameters are as standard for a Toolbox */ /* event handler. */ /*************************************************/ 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; int xmin, xmax, window_handle; ObjectId sub_menu; /* Get entry sizes. */ ChkError(hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width)); if (event_code == EHotlistToBeShown) { /* Work out which item the pointer was over. */ ChkError(window_get_wimp_handle(0, hotlist_windowid, &window_handle)); state.window_handle = window_handle; ChkError(wimp_get_window_state(&state)); ChkError(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; } ChkError(menu_get_sub_menu_show(0, id_block->self_id, HOTLIST_DISPLAY_MENUITEM, &sub_menu)); /* If there are no selected items, select the one the menu */ /* was opened over. */ if (hotlist_count_selected_items() == 0) { item = hotlist_find_item(hotlist_root->data.directory_content, menu_itemno); if (item) ChkError(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; ChkError(hotlist_redraw_now()); } } /* Update the menus */ ChkError(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, */ /* but in both cases obey the next */ /* parameter; */ /* */ /* 0 - don't save read-only items, */ /* 1 - allow saving of read-only */ /* items. */ /* */ /* 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 save_read_only) { int written; /* Follow the directory list */ while (list) { /* Don't save read-only entries unless told to */ if (save_read_only || !(list->flags & HOTLIST_G_IS_READ_ONLY)) { 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)) { if (type == 0 || (type == 1 && list->flags & HOTLIST_G_IS_SELECTED)) { HotlistWrite(fprintf(fileptr, "

    %s

    \n", list->name)); if (list->flags & HOTLIST_D_IS_OPEN) { HotlistWrite(fprintf(fileptr, "