home *** CD-ROM | disk | FTP | other *** search
-
- /* iconbar.c */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include "swis.h"
- #include "OS:osword.h"
- #include "OS:wimp.h"
- #include "OS:toolbox.h"
- #include "OS:menu.h"
- #include "OS:window.h"
- #include "Dreamscape:tboxevent.h"
- #include "Dreamscape:wimpevent.h"
- #include "Dreamscape:wimpmsg.h"
- #include "Dreamscape:task.h"
- #include "Dreamscape:debug.h"
- #include "Dreamscape:x.h"
-
- #ifdef MemCheck_MEMCHECK
- #include "MemCheck:memcheck.h"
- #endif
-
- #include "iconbar.h"
- #include "hotkeys.h"
- #include "debug.h"
- #include "options.h"
- #include "various.h"
-
-
- /* Private structures */
-
- typedef struct thiniconbar_node thiniconbar_node;
- struct thiniconbar_node {
- thiniconbar_node *prev, *next;
- thin_iconbar *parent;
-
- enum { node_ICON = 1, node_MIDDLE = 2, node_END = 3 } type;
- iconbar_gadget *gadget;
- int priority;
- };
- #define VALIDATE_NODE(node) \
- assert((node)->type >= node_ICON && (node)->type <= node_END)
-
- struct thin_iconbar {
- toolbox_o window,
- menu; /* May be 0. */
-
- /* Bi-directional linked list. */
- thiniconbar_node ends, middle;
-
- unsigned mode_changed: 1; /* Trigger update after a mode change. */
- int total_width; /* Total width of icons (excl. middle). */
- int middle_width; /* Width of middle gap at last update. */
-
- /* Scrolling information. */
- unsigned scroll_state: 1; /* Whether currently scrolling (types 2/3). */
- unsigned scrolled_last: 1; /* Whether scrolled on last null event. */
- unsigned last_null; /* Time of last null event. */
-
- /* It is useful to cache screen info. */
- int screen_width, screen_height;
- short screen_xeig, screen_yeig;
-
- iconbar_arranger arranger;
- };
-
-
- /* Internal function prototypes */
-
- #define MODULE_NAME "thiniconbar"
-
- /* Wimp events */
- static bool click_handler(const wimp_block *event,
- const toolbox_block *ids, void *handle);
- static bool key_handler(const wimp_block *event,
- const toolbox_block *ids, void *handle);
- static bool null_event_handler(const wimp_block *event,
- const toolbox_block *ids, void *handle);
-
- /* Wimp messages */
- static bool mode_change_handler(const wimp_message *message, void *handle);
-
- static bool icon_resize_handler(iconbar_gadget *gadget,
- os_box *old, const os_coord *new_size, void *handle);
-
- static int find_x_extent(const thin_iconbar *obj);
- static int find_middle_width(const thin_iconbar *obj);
- static void set_pointer_bounds(const os_box *box);
- static void reopen_window(thin_iconbar *obj);
- static void read_screen_info(thin_iconbar *obj);
-
- static void *add_icon(iconbar_arranger *arranger, iconbar_gadget *gadget,
- const iconbar_arranger_add_info *info);
- static void remove_icon(iconbar_arranger *arranger, iconbar_gadget *gadget,
- void *handle);
-
-
- /* Initialisation */
-
- thin_iconbar *thiniconbar_create(void)
- {
- thin_iconbar *obj;
- wimp_w our_window;
- LOGFUNC(create);
-
- obj = malloc(sizeof(thin_iconbar));
- if(!obj) x_throw_message(x_msg_memory());
- dscape_task_ensure();
-
- /* Create the iconbar window, changing the background colour. */
- #if 1
- {
- /* It is not documented whether I can modify a template returned by
- the Toolbox. I assume I cannot. However, copying the template just
- to be safe doesn't work for some reason (change not made). So I'll
- just make sure to return the template to its original state. */
- int old_work_bg, old_title_fg;
- toolbox_id t;
- window_window *block;
- /* Look up template. */
- t = toolbox_template_look_up(0, "Iconbar");
- #ifdef MemCheck_MEMCHECK
- MemCheck_RegisterMiscBlock(t, 200);
- #endif
- block = &((window_object *) ((toolbox_resource_file_object *) t)->
- object)->window;
- /* Change values, remembering originals. */
- old_work_bg = block->work_bg;
- old_title_fg = block->title_fg;
- block->work_bg = options->window_bg_colour;
- block->title_fg = options->window_border ?
- wimp_COLOUR_BLACK : wimp_COLOUR_TRANSPARENT;
- /* Create object. */
- obj->window = toolbox_create_object(toolbox_CREATE_GIVEN_OBJECT, t);
- /* Change values back and finish. */
- block->work_bg = old_work_bg;
- block->title_fg = old_title_fg;
- #ifdef MemCheck_MEMCHECK
- MemCheck_UnRegisterMiscBlock(t);
- #endif
- }
- #else
- obj->window = toolbox_create_object(0, (toolbox_id) "Iconbar");
- #endif
- our_window = window_get_wimp_handle(0, obj->window);
-
- /* Initialise function table of base class. */
- obj->arranger.add_icon = add_icon;
- obj->arranger.remove_icon = remove_icon;
-
- /* Initialise icon list. */
- /* End node (list head). */
- obj->ends.next = obj->ends.prev = &obj->middle;
- obj->ends.parent = obj;
- obj->ends.type = node_END;
- obj->ends.gadget = 0;
- obj->ends.priority = 0;
- /* Middle node (separates left and right sides). */
- obj->middle.next = obj->middle.prev = &obj->ends;
- obj->middle.parent = obj;
- obj->middle.type = node_MIDDLE;
- obj->middle.gadget = 0;
- obj->middle.priority = 0;
-
- /* Set variables to initial values */
- obj->menu = 0; /* Menu is given to us later. */
- obj->total_width = 0;
- obj->middle_width = 0; /* Will be filled in by resize handler later. */
- /* Scrolling info. */
- obj->scroll_state = 0;
- obj->scrolled_last = 0;
- obj->last_null = os_read_monotonic_time();
-
- /* Register our Wimp event handlers */
- dscape_wimpevent_register_handler(wimp_MOUSE_CLICK,
- our_window, click_handler, obj);
- dscape_wimpevent_register_handler(wimp_NULL_REASON_CODE,
- 0, null_event_handler, obj);
- /* Register a handler for Shift-F12 keypresses */
- hotkeys_initialise();
- dscape_wimpevent_register_handler(wimp_KEY_PRESSED, 0,
- key_handler, obj);
-
- /* Register our Wimp message handlers */
- dscape_wimpmsg_register_handler(message_MODE_CHANGE,
- mode_change_handler, obj);
-
- /* Set up the window correctly */
- read_screen_info(obj);
- reopen_window(obj);
-
- /* Tell the world the iconbar height. */
- setenv_int("Iconbar$Height", options->window_height);
-
- return obj;
- }
-
- void thiniconbar_destroy(thin_iconbar *obj)
- {
- thiniconbar_node *node;
- wimp_w our_window = window_get_wimp_handle(0, obj->window);
- LOGFUNC(destroy);
-
- /* Remove all icons from the window (doesn't do it properly yet). */
- for(node = obj->ends.next; node->type != node_END; ) {
- VALIDATE_NODE(node);
- if(node->type == node_ICON) {
- thiniconbar_node *old = node;
- node = node->next;
-
- /* Tell the icon manager we're ending control of the icon. */
- iconbar_manager_losing_icon(iconbar_manager_this_task, old->gadget);
- /* We don't need any other finalisation for the icon. */
- free(old);
- }
- else {
- /* Skip other node types. */
- node = node->next;
- }
- }
-
- /* Deregister our Wimp message handlers */
- dscape_wimpmsg_deregister_handler(message_MODE_CHANGE,
- mode_change_handler, obj);
-
- /* Deregister our Wimp event handlers */
- dscape_wimpevent_deregister_handler(wimp_MOUSE_CLICK,
- our_window, click_handler, obj);
- dscape_wimpevent_deregister_handler(wimp_NULL_REASON_CODE,
- 0, null_event_handler, obj);
- dscape_wimpevent_deregister_handler(wimp_KEY_PRESSED, 0,
- key_handler, obj);
-
- /* Destroy our Toolbox objects. */
- toolbox_delete_object(0, obj->window);
-
- /* Revoke iconbar height. */
- unsetenv("Iconbar$Height");
-
- free(obj);
- }
-
-
- /* Inheritance casting */
-
- #ifndef offsetof
- #define offsetof(str, comp) \
- ((char *) &((str *) 0)->comp - (char *) ((str *) 0))
- #endif
-
- thin_iconbar *thiniconbar_castfrom_arranger(iconbar_arranger *arranger)
- {
- if(!arranger) return 0;
- return (thin_iconbar *) ((char *) arranger -
- offsetof(thin_iconbar, arranger));
- }
-
- iconbar_arranger *thiniconbar_castto_arranger(thin_iconbar *obj)
- {
- if(!obj) return 0;
- return &obj->arranger;
- }
-
-
- /* Methods */
-
- void thiniconbar_set_menu(thin_iconbar *obj, toolbox_o menu)
- {
- LOGFUNC(set_menu);
- if(!obj) return;
- obj->menu = menu;
- }
-
-
- /* Internal functions */
-
- /* Returns the horizontal extent of the iconbar window. */
- static int find_x_extent(const thin_iconbar *obj)
- {
- int icons_width;
- LOGFUNC(find_x_extent);
-
- icons_width = obj->total_width + (options->end_gap * 2) +
- options->central_gap - (options->between_gap * 2);
- return icons_width > obj->screen_width ?
- icons_width : obj->screen_width;
- }
-
- /* Returns the width of the gap between left and right hand sides. */
- static int find_middle_width(const thin_iconbar *obj)
- {
- int rest;
- LOGFUNC(find_middle_width);
-
- rest = obj->total_width + (options->end_gap * 2) -
- (options->between_gap * 2);
- return (rest + options->central_gap) > obj->screen_width ?
- options->central_gap :
- obj->screen_width - rest;
- }
-
- /* Resets the window's extent and re-opens it in the correct position at the
- bottom of the screen. read_screen_info() must have been called recently
- to cache mode info. */
- static void reopen_window(thin_iconbar *obj)
- {
- wimp_window_state state;
- os_box extent;
- LOGFUNC(reopen_window);
-
- /* Set the extent of the window appropriately. */
- extent.x0 = 0;
- extent.y0 = -options->window_height;
- extent.x1 = find_x_extent(obj);
- extent.y1 = 0;
- window_set_extent(0, obj->window, &extent);
-
- /* Get the window state. */
- state.w = window_get_wimp_handle(0, obj->window);
- wimp_get_window_state(&state);
- /* If the window is not open currently, make sure it is opened at the
- bottom of the window stack. This prevents another case of window
- disappearance on a mode change. */
- if(!(state.flags & wimp_WINDOW_OPEN)) state.next = wimp_BOTTOM;
-
- /* Set the window's extent. */
- state.visible.x0 = 0;
- state.visible.y0 = 0;
- state.visible.x1 = obj->screen_width;
- state.visible.y1 = options->window_height;
-
- /* And re-open the iconbar! */
- toolbox_show_object(0, obj->window, toolbox_POSITION_FULL,
- (toolbox_position *) &state.visible, 0, -1);
-
- /* Cancel pending refresh even if the pending refresh
- did not cause this call. */
- obj->mode_changed = 0;
- }
-
-
- /* Event handlers */
-
- /* Unfortunately we can't mask this out when the pointer leaves our window,
- because the Wimp stops giving entering/leaving events when a drag is in
- progress, which is useless for our purposes.
- */
- static bool null_event_handler(const wimp_block *event,
- const toolbox_block *ids, void *xhandle)
- {
- thin_iconbar *obj = xhandle;
- bool did_scroll = 0;
- int this_time = os_read_monotonic_time();
- wimp_pointer ptr;
- wimp_w our_window = window_get_wimp_handle(0, obj->window);
- LOGFUNC(null_event_handler);
-
- /* Get the mouse's state. We have to stop IconbarPatch from fiddling the
- info returned, otherwise we can't tell it how to fiddle it for other
- tasks! (And I wondered why it wasn't working properly...) */
- iconbar_manager_get_pointer_info(iconbar_manager_this_task, &ptr);
-
- /* Scroll the iconbar if the pointer is over our window or has gone
- off-screen to scroll it, but only if scrolling is enabled. */
- if(options->scroll_type && (ptr.w == our_window || obj->scroll_state)) {
- wimp_window_state state;
- int scroll_by = 0;
-
- /* Time difference between scrolls, in centiseconds. */
- int between_time = this_time - obj->last_null;
- if(!obj->scrolled_last) between_time = (between_time + 1) / 2;
- if(between_time <= 0) between_time = 1;
-
- state.w = our_window;
- wimp_get_window_state(&state);
-
- switch(options->scroll_type) {
-
- /* Do fixed speed scrolling. */
- case scroll_type_LINEAR:
- case scroll_type_LINEAR_S: {
- /* If the pointer is the margins of the window, do scroll. */
- if(ptr.pos.x < (state.visible.x0 + options->scroll_margin))
- { scroll_by = -1; did_scroll = 1; }
- else if(ptr.pos.x >= (state.visible.x1 - options->scroll_margin))
- { scroll_by = 1; did_scroll = 1; }
- /* Find the scroll step in OS units. */
- if(scroll_by && options->scroll_type == scroll_type_LINEAR)
- scroll_by *= options->scroll_step;
- else scroll_by = scroll_by * options->scroll_speed *
- between_time;
- } break;
-
- /* Do dynamic speed scrolling (pointer goes off-screen). */
- case scroll_type_PROP:
- case scroll_type_MOVE: {
- os_box box;
- /* If we were scrolling, but the pointer moved away, reset its box. */
- if(obj->scroll_state && (ptr.pos.y < state.visible.y0 ||
- ptr.pos.y >= state.visible.y1)) {
- box.x0 = box.y0 = 0;
- box.x1 = obj->screen_width - (1 << obj->screen_xeig);
- box.y1 = obj->screen_height - (1 << obj->screen_yeig);
- set_pointer_bounds(&box);
- obj->scroll_state = 0;
- goto scroll_end; /* Don't scroll now. */
- }
- /* Set the pointer bounds to allow it off-screen. */
- box.y0 = 0;
- box.y1 = obj->screen_height - (1 << obj->screen_yeig);
- box.x0 = state.visible.x0 - state.xscroll;
- box.x1 = state.visible.x0 - state.xscroll + find_x_extent(obj) -
- (1 << obj->screen_xeig);
- set_pointer_bounds(&box);
- obj->scroll_state = 1;
-
- /* Scroll according to distance off-screen. */
- if(ptr.pos.x < state.visible.x0)
- { scroll_by = ptr.pos.x - state.visible.x0; did_scroll = 1; }
- else if(ptr.pos.x >= (state.visible.x1 - (1 << obj->screen_xeig)))
- { scroll_by = ptr.pos.x - state.visible.x1 +
- (1 << obj->screen_xeig); did_scroll = 1; }
- } break;
- }
-
- /* Scroll the window as instructed. */
- if(scroll_by) {
- DEBUGF1("Scrolling window by %i\n", scroll_by);
- state.xscroll += scroll_by;
- wimp_open_window((wimp_open *) &state);
-
- /* Move the pointer with the window as well (type 3 only). */
- if(options->scroll_type == scroll_type_MOVE) {
- int x = ptr.pos.x - scroll_by,
- y = ptr.pos.y;
-
- /* oswordpointer_position_block is also broken. D'uh! */
- struct {
- unsigned char reason, coords[4];
- } b;
- b.reason = 3; /* Move pointer, sub reason code */
- b.coords[0] = x & 0xFF;
- b.coords[1] = (x >> 8) & 0xFF;
- b.coords[2] = y & 0xFF;
- b.coords[3] = (y >> 8) & 0xFF;
- /* OSLib function broken. */
- /* oswordpointer_set_position(
- (oswordpointer_position_block *) &b); */
- _swi(OS_Word, _IN(0)|_IN(1), 21 /* Reason code */, &b);
- }
- }
- scroll_end: ;
- }
- /* Ongoing info for scrolling. */
- obj->scrolled_last = did_scroll;
- obj->last_null = this_time;
-
- /* Update the window if a mode change occurred. */
- if(obj->mode_changed) {
- /* Iconbar's middle gap may need resizing. */
- os_box bbox;
- os_coord size;
- DEBUGF("Handling mode change flag\n");
- bbox.x0 = bbox.y0 = bbox.x1 = bbox.y1 = 0;
- size.x = size.y = 0;
- icon_resize_handler(0, &bbox, &size, &obj->middle);
- reopen_window(obj); /* Unsets mode changed flag */
- }
-
- return 0;
- }
-
- /* Sets the boundaries of the pointer. */
- static void set_pointer_bounds(const os_box *box)
- {
- /* oswordpointer_bbox_block appears to be broken.
- We must define our own structure. */
- struct {
- unsigned char reason, bbox[8];
- } b;
- b.reason = 1; /* Set bbox, sub reason code */
- b.bbox[0] = box->x0 & 0xFF;
- b.bbox[1] = (box->x0 >> 8) & 0xFF;
- b.bbox[2] = box->y0 & 0xFF;
- b.bbox[3] = (box->y0 >> 8) & 0xFF;
- b.bbox[4] = box->x1 & 0xFF;
- b.bbox[5] = (box->x1 >> 8) & 0xFF;
- b.bbox[6] = box->y1 & 0xFF;
- b.bbox[7] = (box->y1 >> 8) & 0xFF;
- /* OSLib's function also seems to be broken. */
- /* oswordpointer_set_bbox((oswordpointer_bbox_block *) &b); */
- _swi(OS_Word, _IN(0)|_IN(1), 21 /* Reason code */, &b);
- }
-
- static bool click_handler(const wimp_block *event,
- const toolbox_block *ids, void *xhandle)
- {
- thin_iconbar *obj = xhandle;
- LOGFUNC(click_handler);
-
- /* If Menu was clicked on an empty area, open our menu (but only if one
- has been attached). If Menu was clicked right at the bottom of the
- screen, ignore it: this ensures the extension module `Toggle' still
- works. */
- if(event->pointer.buttons == 2 && event->pointer.pos.y != 0 && obj->menu) {
- wimp_window_state state;
- os_coord top_left;
-
- state.w = window_get_wimp_handle(0, obj->window);
- wimp_get_window_state(&state);
-
- top_left.x = event->pointer.pos.x - 64;
- top_left.y = state.visible.y1 - options->top_gap -
- options->menu_y_offset + menu_get_height(0, obj->menu);
- toolbox_show_object(0, obj->menu, toolbox_POSITION_TOP_LEFT,
- (toolbox_position *) &top_left, obj->window, -1);
- return 1; /* Claim event */
- }
- return 0; /* Pass event on */
- }
-
- static bool key_handler(const wimp_block *event,
- const toolbox_block *ids, void *xhandle)
- {
- thin_iconbar *obj = xhandle;
- LOGFUNC(key_handler);
-
- /* So, was Shift-F12 pressed? */
- if(event->key.c == 0x1DC) {
- thiniconbar_toggle_front(obj);
- return 1;
- }
-
- /* Pass the key on to another task */
- wimp_process_key(event->key.c);
- return 1;
- }
-
- /* Move iconbar to the front if obscured, or to the back if not. Will also
- change the `backdrop' flag: this avoids a nasty bug where windows get
- hidden behind the Pinboard on a mode change. */
- void thiniconbar_toggle_front(thin_iconbar *obj)
- {
- wimp_window_state state;
- wimp_window_flags set_flags;
- LOGFUNC(toggle_front);
-
- state.w = window_get_wimp_handle(0, obj->window);
- wimp_get_window_state(&state);
-
- if(state.flags & wimp_WINDOW_NOT_COVERED) {
- /* Iconbar is not covered: send to back, set `backdrop' flag. */
- state.next = wimp_BOTTOM;
- set_flags = wimp_WINDOW_BACK;
- }
- else {
- /* Iconbar is covered: put to front, unset `backdrop' flag. */
- state.next = wimp_TOP;
- set_flags = 0;
- }
- /* Flags should be changed before the window is re-opened. */
- set_window_flags(state.w, set_flags, wimp_WINDOW_BACK);
- wimp_open_window((wimp_open *) &state);
- }
-
- /* Update after a mode change has taken place. */
- static bool mode_change_handler(const wimp_message *message, void *xhandle)
- {
- thin_iconbar *obj = xhandle;
- LOGFUNC(mode_change_handler);
-
- /* This is called after the actual screen mode change has taken place.
- Screen info can be read now therefore, but resizing the window has to
- be delayed slightly (IIRC). */
- read_screen_info(obj);
- obj->mode_changed = 1;
-
- return 0; /* Pass event on */
- }
-
- /* Cache info about the current screen mode. */
- static void read_screen_info(thin_iconbar *obj)
- {
- int eig, size;
- LOGFUNC(read_screen_info);
-
- /* Work out how wide the screen is. */
- os_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_XEIG_FACTOR, &eig);
- os_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_XWIND_LIMIT, &size);
- obj->screen_xeig = eig;
- obj->screen_width = (size + 1) << eig;
-
- /* And the height too. */
- os_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_YEIG_FACTOR, &eig);
- os_read_mode_variable(os_CURRENT_MODE, os_MODEVAR_YWIND_LIMIT, &size);
- obj->screen_yeig = eig;
- obj->screen_height = (size + 1) << eig;
- }
-
- static void *add_icon(iconbar_arranger *arranger, iconbar_gadget *gadget,
- const iconbar_arranger_add_info *info)
- {
- thin_iconbar *obj = thiniconbar_castfrom_arranger(arranger);
- thiniconbar_node *node, *ins;
- os_box bbox;
- os_coord size;
- LOGFUNC(add_icon);
-
- /* Create new node. */
- node = malloc(sizeof(thiniconbar_node));
- if(!node) x_throw_message(x_msg_memory());
- /* Fill in the node's fields. */
- node->type = node_ICON;
- node->parent = obj;
- node->gadget = gadget;
- node->priority = info->priority;
-
- /* Search through the list to find correct place for new icon. */
- /* May search through left or right hand lists. */
- ins = (info->priority >= 0 ?
- obj->middle.next : /* Right side */
- obj->ends.next); /* Left side */
- if(info->next_to) {
- /* Search for the icon that this one goes next to. */
- for(; ins->type != node_END; ins = ins->next) {
- VALIDATE_NODE(ins);
- if(ins->type == node_ICON && ins == info->next_to) {
- /* Move on one if this icon goes to the right of the other icon. */
- if(info->tend_higher && ins != &obj->ends) ins = ins->next;
- goto found;
- }
- }
- /* Icon wasn't found so resort to searching by priority. */
- goto by_priority;
- }
- else {
- by_priority:
- /* Look for icons with matching priority. */
- for(; ins->type != node_END; ins = ins->next) {
- VALIDATE_NODE(ins);
- if(ins->type == node_ICON && info->tend_higher ?
- ins->priority > info->priority :
- ins->priority >= info->priority) goto found;
- }
- /* Otherwise insert at the end. */
- }
- found:
-
- /* Link node into list, before the node ins (the one we just found). */
- node->next = ins;
- node->prev = ins->prev;
- ins->prev->next = node;
- ins->prev = node;
-
- iconbar_gadget_get_bbox(gadget, &bbox);
- size.x = bbox.x1 - bbox.x0;
- size.y = options->icon_height;
-
- /* We have to fake a resize event so that other icons are shifted.
- Give a zero width to start with. Work out where the icon goes. */
- {
- int pos = 0;
- thiniconbar_node *prev = node->prev;
-
- /* Take into account the middle gap for icons on the right. */
- if(node->priority >= 0) {
- /* The width of the middle gap must be worked out for *after* the icon
- is added. Change the total width only temporarily, because the
- resize handler will update it permanently. */
- int new_width;
- obj->total_width += size.x + options->between_gap;
- new_width = find_middle_width(obj) - options->between_gap;
- obj->total_width -= size.x + options->between_gap;
-
- if(prev->type == node_MIDDLE) {
- pos += new_width;
- prev = prev->prev;
- }
- else {
- pos += new_width - obj->middle_width + options->between_gap;
- }
- }
-
- /* Move on after the middle gap. */
- if(prev->type == node_END) {
- pos += options->end_gap;
- }
- else { /* prev->type == node_ICON */
- os_box other_bbox;
- iconbar_gadget_get_bbox(prev->gadget, &other_bbox);
- pos += other_bbox.x1 + options->between_gap;
- }
-
- bbox.x0 = bbox.x1 = pos;
- }
- bbox.y1 = -options->top_gap;
- bbox.y0 = -options->top_gap - options->icon_height;
- icon_resize_handler(gadget, &bbox, &size, node);
- iconbar_gadget_set_bbox(gadget, &bbox);
-
- iconbar_gadget_set_resize_handler(gadget, icon_resize_handler, node);
- iconbar_gadget_set_window(gadget, obj->window);
-
- return node;
- }
-
- static void remove_icon(iconbar_arranger *arranger, iconbar_gadget *gadget,
- void *handle)
- {
- thin_iconbar *obj = thiniconbar_castfrom_arranger(arranger);
- thiniconbar_node *node = handle, *next, *prev;
- LOGFUNC(remove_icon);
-
- /* Detach from this window. */
- iconbar_gadget_set_window(gadget, 0);
-
- /* Fake another resize event so that other icons are shifted back. */
- /* Give the new size as zero. */
- {
- os_box bbox;
- os_coord size;
- iconbar_gadget_get_bbox(gadget, &bbox);
- size.x = 0;
- size.y = bbox.y1 - bbox.y0;
- icon_resize_handler(gadget, &bbox, &size, node);
- }
-
- /* Remove icon from the list. */
- next = node->next;
- prev = node->prev;
- next->prev = prev;
- prev->next = next;
- free(node);
- }
-
- /* Gives the bounding box of an icon being resized, and shuffles the other
- icons on the iconbar in order to accommodate it. */
- static bool icon_resize_handler(iconbar_gadget *gadget,
- os_box *box, const os_coord *new_size, void *handle)
- {
- thiniconbar_node *node = handle, *n;
- thin_iconbar *obj = node->parent;
- int old_width = box->x1 - box->x0,
- move = 0;
- LOGFUNC(icon_resize_handler);
-
- /* Update the bounding box of this icon. */
- obj->total_width += new_size->x - old_width;
- box->x1 = box->x0 + new_size->x;
- box->y0 = box->y1 - new_size->y;
-
- /* Handle special cases of adding and removing an icon. */
- if(old_width == 0) obj->total_width += options->between_gap;
- else if(new_size->x == 0) obj->total_width -= options->between_gap;
-
- /* If the icon was on the right, shuffle all icons on the right (since the
- middle gap may also be resized). Otherwise, only shuffle icons to the
- right of the icon being resized. */
- n = (node->priority >= 0 ? &obj->middle : node);
- while(n->type != node_END) {
- VALIDATE_NODE(n);
- if(n->type == node_ICON && n == node) {
- /* Encountered the icon being resized, so change amount to move by. */
- move += new_size->x - old_width;
- /* Special cases. */
- if(old_width == 0) move += options->between_gap;
- else if(new_size->x == 0) move -= options->between_gap;
- }
- else if(n->type == node_ICON) {
- /* Move an icon (not the one being resized). */
- if(move != 0) {
- os_box b;
- iconbar_gadget_get_bbox(n->gadget, &b);
- b.x0 += move;
- b.x1 += move;
- iconbar_gadget_set_bbox(n->gadget, &b);
- }
- }
- else if(n->type == node_MIDDLE) {
- /* Account for the middle gap changing in width. */
- int new_width = find_middle_width(obj);
- move += new_width - obj->middle_width;
- obj->middle_width = new_width;
- }
- n = n->next;
- }
-
- /* Window might need resizing. */
- reopen_window(obj);
-
- return 0; /* Success */
- }
-