home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 3
/
TheARMClub_PDCD3.iso
/
programs
/
desktop
/
newbar
/
Source
/
NewBar
/
c
/
iconmgr
< prev
next >
Wrap
Text File
|
1998-08-07
|
28KB
|
865 lines
/* iconmgr.c */
#include <stdlib.h>
#include "OS:os.h"
#include "OS:osmodule.h"
#include "OS:wimp.h"
#include "OS:toolbox.h"
#include "OS:window.h"
#include "OS:taskmanager.h"
#include "Dreamscape:task.h"
#include "Dreamscape:wimpevent.h"
#include "Dreamscape:wimpmsg.h"
#include "Dreamscape:x.h"
#ifdef MemCheck_MEMCHECK
#include "MemCheck:MemCheck.h"
#endif
#include "iconmgr.h"
#include "debug.h"
#include "options.h"
#include "various.h"
/* Private structures */
typedef struct iconbar_manager_icon iconbar_manager_icon;
typedef struct iconbar_manager_node iconbar_manager_node;
struct iconbar_manager_icon {
ibarpatch_add_info *ibarpatch_block; /* To update later. */
iconbar_gadget *gadget;
void *external_handle; /* Used by the icon arranger. */
/* Information about icon from IconbarPatch. */
int icon_handle;
wimp_t task;
wimp_icon_flags flags;
wimp_icon_data data;
/* Data we've worked out. */
int priority;
unsigned update_poll_id;
};
struct iconbar_manager_node {
iconbar_manager_icon i;
iconbar_manager_node *next;
};
struct iconbar_manager_task {
ibarpatch_block *module;
iconbar_manager_node *icons;
iconbar_arranger *arranger;
unsigned poll_id;
iconbar_manager_icon *pointer_icon; /* Icon under pointer is cached. */
};
/* Internal function prototypes */
#define MODULE_NAME "iconbar_manager"
/* Event handlers */
static bool click_handler(const wimp_block *event,
const toolbox_block *ids, void *handle);
static bool pollword_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);
static bool task_quitting_handler(const wimp_message *message, void *handle);
static iconbar_manager_icon *icon_from_pointer(iconbar_manager_task *task,
const os_coord *pos, toolbox_o window, wimp_w wimp_window);
static bool process_ibarpatch_event(iconbar_manager_task *task,
ibarpatch_element *e);
static void add_icon(iconbar_manager_task *task, ibarpatch_add_info *i,
const char *task_name);
static void update_icon(iconbar_manager_task *task,
iconbar_manager_icon *icon);
static void remove_icon(iconbar_manager_task *task,
iconbar_manager_node **node_ptr);
/* Initialisation and finalisation */
iconbar_manager_task *iconbar_manager_initialise(iconbar_arranger *arranger)
{
iconbar_manager_task *task = malloc(sizeof(iconbar_manager_task));
LOGFUNC(initialise);
if(!task) return 0;
/* Initialise variables. */
task->icons = 0;
task->arranger = arranger;
task->poll_id = 0;
task->pointer_icon = 0;
/* Find module's block and increment usage count. */
osmodule_lookup("IconbarPatch", 0, 0, (void **) &task->module, 0);
#ifdef MemCheck_MEMCHECK
MemCheck_RegisterMiscBlock(task->module, sizeof(ibarpatch_block));
#endif
++task->module->usage_count;
/* Wimp event handlers. */
dscape_wimpevent_register_handler(wimp_MOUSE_CLICK, 0,
click_handler, task);
dscape_wimpevent_register_handler(wimp_NULL_REASON_CODE, 0,
null_event_handler, task);
/* Set up our poll word non-zero handler (with low priority) */
dscape_task_set_poll_word((int *) &task->module->list.begin, 0);
dscape_wimpevent_register_handler(wimp_POLLWORD_NON_ZERO,
0, pollword_handler, task);
/* Wimp message handlers. */
dscape_wimpmsg_register_handler(message_TASK_CLOSE_DOWN,
task_quitting_handler, task);
/* Read list of previous icons set up. */
{
ibarpatch_element *e = task->module->list_keep.begin, *next;
while(e) {
#ifdef MemCheck_MEMCHECK
MemCheck_RegisterMiscBlock(e, sizeof(ibarpatch_element));
#endif
process_ibarpatch_event(task, e); /* Ignore return value */
next = e->next;
#ifdef MemCheck_MEMCHECK
MemCheck_UnRegisterMiscBlock(e);
#endif
e = next;
}
}
return task;
}
void iconbar_manager_finalise(iconbar_manager_task *task)
{
LOGFUNC(finalise);
if(!task) return;
/* Delete all icons. */
while(task->icons) {
iconbar_manager_node *old = task->icons;
task->icons = old->next;
/* Finalise this icon, and free the node. */
task->arranger->remove_icon(task->arranger, old->i.gadget,
old->i.external_handle);
iconbar_gadget_destroy(old->i.gadget);
/* Don't remove icon from keep list. */
free(old);
}
/* Reset pointer values if necessary. */
if(task_handle_from_window(task->module->window, -1) ==
dscape_task_get_handle()) {
task->module->window = 0;
task->module->pointer_icon = -1;
task->module->pointer_task = 0;
}
/* Wimp message handlers. */
dscape_wimpmsg_deregister_handler(message_TASK_CLOSE_DOWN,
task_quitting_handler, task);
/* Wimp event handlers. */
dscape_wimpevent_deregister_handler(wimp_MOUSE_CLICK, 0,
click_handler, task);
dscape_wimpevent_deregister_handler(wimp_NULL_REASON_CODE, 0,
null_event_handler, task);
/* Poll word non-zero handler. */
dscape_task_set_poll_word(0, 0);
dscape_wimpevent_deregister_handler(wimp_POLLWORD_NON_ZERO,
0, pollword_handler, task);
/* We have finished with the module. */
--task->module->usage_count;
#ifdef MemCheck_MEMCHECK
MemCheck_UnRegisterMiscBlock(task->module);
#endif
free(task);
}
/* Event handlers */
/* Handle clicks on icons. */
static bool click_handler(const wimp_block *event,
const toolbox_block *ids, void *xhandle)
{
iconbar_manager_task *task = xhandle;
iconbar_manager_icon *icon;
LOGFUNC(click_handler);
/* Ignore if Menu was clicked at the very bottom of the screen. This
allows the `Toggle' module to still work. */
if(event->pointer.buttons == 2 && event->pointer.pos.y == 0)
return 0; /* Pass event on */
icon = icon_from_pointer(task, &event->pointer.pos, ids->this_obj,
event->pointer.w);
if(icon) {
/* Re-send the mouse click event to the task in question. */
wimp_block message = *event;
DEBUGF1("Sending mouse click to task (buttons %i)\n",
event->pointer.buttons);
message.pointer.w = wimp_ICON_BAR;
message.pointer.i = icon->icon_handle;
wimp_send_message(wimp_MOUSE_CLICK,
(wimp_message *) &message, icon->task);
/* If Menu was clicked, alter where the menu will appear. */
if(event->pointer.buttons == 2) {
/* Open the base of the menu a given distance below the top of the
icon. (NB. 96 is the position menu bases would otherwise be
opened at.) */
os_box bbox;
wimp_window_state state;
iconbar_gadget_get_bbox(icon->gadget, &bbox);
state.w = window_get_wimp_handle(0,
iconbar_gadget_get_window(icon->gadget));
wimp_get_window_state(&state);
task->module->y_offset = (bbox.y1 + state.visible.y1 - state.yscroll)
- (96 + options->menu_y_offset);
}
return 1; /* Claim event */
}
return 0; /* Pass event on */
}
/* For a given mouse state (the pointer position and window it is over),
returns which icon the pointer is over, if any. If no pointer position is
given, it reads the current state (including window). */
static iconbar_manager_icon *icon_from_pointer(iconbar_manager_task *task,
const os_coord *pos, toolbox_o window, wimp_w wimp_window)
{
iconbar_manager_node *node;
os_coord pos_read,
work_pos; /* Work area pointer position */
LOGFUNC(icon_from_pointer);
/* Read the mouse state if none was passed. */
if(!pos) {
wimp_w current;
wimp_pointer ptr;
/* We have to tell IconbarPatch not to fiddle with returned data. This
might be necessary for Window_WimpToToolbox too, since it *could*
send a message to the window to find its owning task first (not
likely, but possible). */
iconbar_manager_get_pointer_info(task, &ptr);
/* Pointer position. */
pos_read = ptr.pos;
pos = &pos_read;
/* Pointer window. */
wimp_window = ptr.w;
/* This next call was giving me address exceptions at seemingly random
times. This could either be a Toolbox bug, or it could be returning
an error and the error handler went pear-shaped (although this SWI
should not give an error). As X-form, it seems to work. Also, don't
tell it the icon handle (why should we?). */
current = task->module->window;
task->module->window = 0;
if(xwindow_wimp_to_toolbox(0, ptr.w, -1, &window, 0))
window = 0; /* Just in case. */
task->module->window = current;
}
/* Only care about this task's Toolbox windows. */
if(!window) return task->pointer_icon = 0; /* Not over icon */
/* Find pointer position in window's work area. */
{
wimp_window_state state;
state.w = wimp_window;
wimp_get_window_state(&state);
work_pos.x = pos->x - state.visible.x0 + state.xscroll;
work_pos.y = pos->y - state.visible.y1 + state.yscroll;
}
/* Check last cached icon under pointer. */
if(task->pointer_icon &&
iconbar_gadget_get_window(task->pointer_icon->gadget) == window) {
os_box bbox;
iconbar_gadget_get_bbox(task->pointer_icon->gadget, &bbox);
if(work_pos.x >= bbox.x0 && work_pos.x < bbox.x1 &&
work_pos.y >= bbox.y0 && work_pos.y < bbox.y1)
return task->pointer_icon;
}
/* Go through list of icons to find a match for both window and bbox. */
for(node = task->icons; node; node = node->next) {
if(iconbar_gadget_get_window(node->i.gadget) == window) {
os_box bbox;
iconbar_gadget_get_bbox(node->i.gadget, &bbox);
if(work_pos.x >= bbox.x0 && work_pos.x < bbox.x1 &&
work_pos.y >= bbox.y0 && work_pos.y < bbox.y1) {
DEBUGF1("Icon under pointer is number %i\n", node->i.icon_handle);
return task->pointer_icon = &node->i;
}
}
}
return task->pointer_icon = 0; /* Not over icon */
}
/* Does wimp_get_pointer_info without fudging window handles, etc. */
void iconbar_manager_get_pointer_info(iconbar_manager_task *task,
wimp_pointer *pointer)
{
wimp_w current;
LOGFUNC(get_pointer_info);
if(!task) return;
/* Unsets the iconbar window temporarily so that it looks like a
normal window. */
current = task->module->window;
task->module->window = 0;
wimp_get_pointer_info(pointer);
task->module->window = current;
}
/* Defines a function and macro to check the integrity of one of the
IconbarPatch module's event lists. The check is done for MemCheck and
debug builds, and is typically done after the list has been modified.
It is impossible to use MemCheck to check our handling of the lists
(because we don't create the blocks), and I would like peace of mind that
they aren't being corrupted. */
#if defined MemCheck_MEMCHECK || defined DEBUG
# define PFX "List-check: "
static void check_module_list_integrity(ibarpatch_list *list,
const char *name)
{
char *rma;
int rma_size, count = 0;
ibarpatch_element **e;
bool fail = 0;
DEBUGF2(PFX "Checking list `%s' (%i blocks recorded)\n",
name, list->count);
/* Find where the module area is (all blocks must be in the RMA). */
rma = (char *) os_read_dynamic_area(os_DYNAMIC_AREA_RMA, &rma_size, 0);
#ifdef MemCheck_MEMCHECK
/* It is easiest to turn checking off throughout this. */
MemCheck_SetChecking(0, 0);
#endif
/* Go through the list. */
e = &list->begin;
while(1) {
if(!*e) {
/* The last element: make sure this tallies. */
if(e != list->end) {
fprintf(stderr, PFX "List end doesn't tally (%i blocks found)\n",
count);
fail = 1;
}
break;
}
/* Check that the block pointer is in the module area. */
if((char *) *e < rma || (char *) *e >= (rma + rma_size)) {
/* End the check since it will lead to never-never land. */
fprintf(stderr, PFX "Block %i not in module area (check aborted)\n",
count);
fail = 1;
break;
}
++count;
e = &(*e)->next;
}
#ifdef MemCheck_MEMCHECK
MemCheck_SetChecking(1, 1);
#endif
/* Check that block counts match. */
if(count != list->count) {
fprintf(stderr, PFX "Block count mismatch (%i recorded, %i found)\n",
list->count, count);
fail = 1;
}
if(fail) {
fprintf(stderr, PFX "List `%s' failed check\n", name);
abort();
}
}
# undef PFX
# define CHECK_INTEGRITY(list, name) check_module_list_integrity(list, name)
#else
# define CHECK_INTEGRITY(list, name) ((void) 0)
#endif
#define CHECK_EVENT_LIST(mod) CHECK_INTEGRITY(&mod->list, "event")
#define CHECK_KEEP_LIST(mod) CHECK_INTEGRITY(&mod->list_keep, "keep")
/* Handle any new events from IconbarPatch. */
static bool pollword_handler(const wimp_block *event,
const toolbox_block *ids, void *xhandle)
{
iconbar_manager_task *task = xhandle;
LOGFUNC(pollword_handler);
++task->poll_id;
CHECK_EVENT_LIST(task->module);
CHECK_KEEP_LIST(task->module);
/* Handle any events queued by the module */
while(task->module->list.begin) {
bool remove;
ibarpatch_element *e = task->module->list.begin;
#ifdef MemCheck_MEMCHECK
MemCheck_RegisterMiscBlock(e, sizeof(ibarpatch_element));
#endif
/* Handle the event. */
remove = process_ibarpatch_event(task, e);
/* An add event is a useful record, so move it to the keep list.
It goes at the end of the list so that icons can be re-created in
order. (Unless the task died, in which case throw it away. */
if(e->type == ibarpatch_add_type && !remove) {
/* Unlink event from list. */
task->module->list.begin = e->next;
if(task->module->list.end == &e->next)
task->module->list.end = &task->module->list.begin;
/* Add it to the keep list. */
#ifdef MemCheck_MEMCHECK
MemCheck_RegisterMiscBlock(task->module->list_keep.end, 4);
#endif
*task->module->list_keep.end = e;
#ifdef MemCheck_MEMCHECK
MemCheck_UnRegisterMiscBlock(task->module->list_keep.end);
#endif
e->next = 0;
task->module->list_keep.end = &e->next;
--task->module->list.count;
++task->module->list_keep.count;
CHECK_EVENT_LIST(task->module);
CHECK_KEEP_LIST(task->module);
}
/* Update and remove events will be deleted from list. Mostly add events
will be kept, but out-of-date ones are deleted. */
if(remove) {
/* Remove event from list. */
task->module->list.begin = e->next;
if(task->module->list.end == &e->next)
task->module->list.end = &task->module->list.begin;
osmodule_free(e);
--task->module->list.count;
CHECK_EVENT_LIST(task->module);
}
#ifdef MemCheck_MEMCHECK
MemCheck_UnRegisterMiscBlock(e);
#endif
}
return 1;
}
/* Deals with an IconbarPatch event. Does not unlink the event from the
list of events (this is the task of the caller), but returns true if the
event should be deleted. */
static bool process_ibarpatch_event(iconbar_manager_task *task,
ibarpatch_element *e)
{
bool remove = 0;
x_declare(error);
LOGFUNC(process_ibarpatch_event);
x_try switch(e->type) {
/* Add an iconbar icon. */
case ibarpatch_add_type: {
/* Check to see if the task still exists. If it doesn't, it's likely
that it died as soon as it started up, so we don't want to display
its icon. */
char *task_name;
os_error *x = xtaskmanager_task_name_from_handle(e->data.add.task,
&task_name);
/* The error number the Task Manager seems to return for `Task not
found' is 3. We don't want to fail for any old error, because
the Task Manager might not be present (eg. on an NC). */
#ifdef MemCheck_MEMCHECK
if(x) MemCheck_RegisterMiscBlock(x, sizeof(os_error));
#endif
if(!(x && x->errnum == 3)) {
if(!x) {
/* Copy the task name. I wish the PRMs would say how strings are
terminated. I have to copy it on the off-chance it isn't
null-terminated. */
int len = 0;
char *b;
#ifdef MemCheck_MEMCHECK
MemCheck_RegisterMiscBlock(task_name, 256);
#endif
while(task_name[len] >= 32 && len < 256) ++len;
b = malloc(len + 1);
if(!b) x_throw_message(x_msg_memory());
memcpy(b, task_name, len);
#ifdef MemCheck_MEMCHECK
MemCheck_UnRegisterMiscBlock(task_name);
#endif
b[len] = 0;
task_name = b;
}
else {
task_name = 0;
}
DEBUGF2("Adding new icon, number %i (task `%s')\n",
e->data.add.icon_handle, task_name ? task_name : "");
add_icon(task, &e->data.add, task_name);
free(task_name);
}
else {
DEBUGF1("Icon number %i not added (task has died)\n",
e->data.add.icon_handle);
remove = 1;
}
#ifdef MemCheck_MEMCHECK
if(x) MemCheck_UnRegisterMiscBlock(x);
#endif
} break;
/* Remove an iconbar icon. */
case ibarpatch_remove_type: {
iconbar_manager_node **find;
remove = 1;
DEBUGF1("Removing icon, number %i\n", e->data.remove.icon_handle);
for(find = &task->icons; *find; find = &(*find)->next)
if((*find)->i.icon_handle == e->data.remove.icon_handle)
{ remove_icon(task, find); break; }
} break;
/* Update an iconbar icon. */
case ibarpatch_update_type: {
iconbar_manager_node *find;
remove = 1;
DEBUGF1("Updating icon, number %i\n", e->data.update.icon_handle);
for(find = task->icons; find; find = find->next)
if(find->i.icon_handle == e->data.update.icon_handle) {
/* Don't bother updating the icon again if it was just updated. */
if(!e->data.update.bic && !e->data.update.eor &&
find->i.update_poll_id == task->poll_id) break;
find->i.flags = (find->i.flags &~ e->data.update.bic)
^ e->data.update.eor;
/* Copy flags back, for the record. */
#ifdef MemCheck_MEMCHECK
MemCheck_RegisterMiscBlock(find->i.ibarpatch_block,
sizeof(ibarpatch_add_info));
#endif
find->i.ibarpatch_block->flags = find->i.flags;
#ifdef MemCheck_MEMCHECK
MemCheck_UnRegisterMiscBlock(find->i.ibarpatch_block);
#endif
update_icon(task, &find->i);
break;
}
} break;
/* Remove unknown events to stop them wasting our time. */
default:
remove = 1;
break;
}
x_catch(error) {
dscape_task_report_error(error->errmess);
}
return remove;
}
/* Keep IconbarPatch up-to-date about which icon the pointer is over so that
it can return modified info. */
static bool null_event_handler(const wimp_block *event,
const toolbox_block *ids, void *xhandle)
{
iconbar_manager_task *task = xhandle;
iconbar_manager_icon *icon;
LOGFUNC(null_event_handler);
/* Tell IconbarPatch which icon handle the pointer is over. */
icon = icon_from_pointer(task, 0, 0, 0);
if(icon) {
/* Pointer is over icon, so set details. */
wimp_w wimp_window = window_get_wimp_handle(0,
iconbar_gadget_get_window(icon->gadget));
wimp_window_state state;
/* Copy window state (for Wimp_GetWindowState on iconbar). */
state.w = wimp_window;
wimp_get_window_state(&state);
task->module->iconbar_state = state;
/* Copy rest of data. */
task->module->window = wimp_window;
task->module->pointer_icon = icon->icon_handle;
task->module->pointer_task = icon->task;
}
else if(task->module->window) {
/* The pointer is not over an icon, but do we have to unset details? */
wimp_t owning_task;
wimp_w owning_window = task->module->window;
/* Find out which task owns the current window. */
wimp_message msg;
msg.size = 5*4;
msg.my_ref = msg.your_ref = 0;
msg.action = -1;
/* Unset this so that message gets through to Wimp. */
task->module->window = 0;
if(!owning_window ||
xwimp_send_message_to_window(wimp_USER_MESSAGE_ACKNOWLEDGE,
&msg, owning_window, -1, &owning_task))
owning_task = 0;
/* If that task was us, unset details. */
if(owning_task == dscape_task_get_handle()) {
task->module->window = 0;
task->module->pointer_icon = -1;
task->module->pointer_task = 0;
}
else task->module->window = owning_window; /* Set it back again */
}
return 0; /* Pass event on */
}
/* When a task quits, this removes all icons on the iconbar owned by it. */
static bool task_quitting_handler(const wimp_message *message, void *xhandle)
{
iconbar_manager_task *task = xhandle;
iconbar_manager_node **find;
LOGFUNC(task_quitting_handler);
/* Search has to be restarted because list may be reshuffled. */
restart:
for(find = &task->icons; *find; find = &(*find)->next)
if((*find)->i.task == message->sender)
{ remove_icon(task, find); goto restart; }
return 0; /* Pass event on */
}
/* Talk to the icon arranger component */
/* Add an icon. */
static void add_icon(iconbar_manager_task *task, ibarpatch_add_info *i,
const char *task_name)
{
iconbar_manager_node *node;
iconbar_manager_icon *icon;
iconbar_gadget *gadget;
ibarpatch_icon_properties *icon_info;
iconbar_arranger_add_info add_info;
LOGFUNC(add_icon);
/* Create new list node. */
node = malloc(sizeof(iconbar_manager_node));
if(!node) x_throw_message(x_msg_memory());
icon = &node->i;
/* Copy across the simple details. */
icon->icon_handle = i->icon_handle;
icon->task = i->task;
icon->flags = i->flags;
icon->data = i->data;
/* Set last update time. */
icon->update_poll_id = task->poll_id;
/* Keep block address (allows later updates). */
icon->ibarpatch_block = i;
/* Convert the icon's priority, and see if it goes next to another icon.
Fill out the add_info block. */
if((i->position == wimp_ICON_BAR_LEFT_RELATIVE ||
i->position == wimp_ICON_BAR_RIGHT_RELATIVE) &&
i->extra.priority != -1 /* Means extreme left/right */ ) {
/* The app wants its icon placed next to another icon. */
iconbar_manager_node *find;
for(find = task->icons; find; find = find->next) {
if(i->extra.next_to == find->i.icon_handle) {
/* Our new icon inherits the priority of the other icon. */
add_info.priority = find->i.priority;
add_info.tend_higher =
(i->position == wimp_ICON_BAR_RIGHT_RELATIVE);
add_info.next_to = find->i.external_handle;
/* Copy these details back to record (useful later). */
if(find->i.priority >= 0) {
i->position = wimp_ICON_BAR_RIGHT_LOW_PRIORITY;
i->extra.priority = (find->i.priority - 0x80000) * 0x10000;
}
else {
i->position = wimp_ICON_BAR_LEFT_LOW_PRIORITY;
i->extra.priority = (-find->i.priority - 0x80000) * 0x10000;
}
break;
}
}
/* If the other icon wasn't found, give this one a default position. */
if(!find) {
i->position = wimp_ICON_BAR_RIGHT;
goto by_priority;
}
}
else {
/* The app has specified a side (and maybe a priority). */
bool left_side;
int priority;
by_priority:
priority = i->extra.priority;
/* Which side shall it go on? */
left_side =
i->position == wimp_ICON_BAR_LEFT ||
i->position == wimp_ICON_BAR_LEFT_RELATIVE /* Not a mistake */ ||
i->position == wimp_ICON_BAR_LEFT_HIGH_PRIORITY ||
i->position == wimp_ICON_BAR_LEFT_LOW_PRIORITY;
/* Handle case where icon goes on extreme left or right. */
if(i->extra.next_to == -1) { priority = 0x78000000; }
/* Set priority to zero in simple case. */
if(i->position == wimp_ICON_BAR_LEFT ||
i->position == wimp_ICON_BAR_RIGHT) { priority = 0; }
/* Depending on the scan direction, some icons will be to the right of
other icons with the same priority. */
add_info.tend_higher =
i->position == wimp_ICON_BAR_LEFT ||
i->position == wimp_ICON_BAR_RIGHT_RELATIVE || /* Not a mistake */
i->position == wimp_ICON_BAR_LEFT_LOW_PRIORITY || /* Left reversed */
i->position == wimp_ICON_BAR_RIGHT_HIGH_PRIORITY;
/* Now we fudge the original icon priorities into a set of values that
are easier to compare. Negative numbers are towards the left,
positive numbers towards the right. */
DEBUGF2("Original priorities: %x, %x\n", priority,
(priority / 0x10000) + 0x80000);
add_info.priority = (priority / 0x10000) + 0x80000;
if(left_side) add_info.priority = -add_info.priority;
add_info.next_to = 0;
}
icon->priority = add_info.priority;
DEBUGF2("Icon priority is %i (%x)\n",
add_info.priority, add_info.priority);
/* Find icon's details and give them to a newly-spawned gadget. */
icon_info = ibarpatch_extract_info(icon->task, icon->flags, &icon->data);
icon->gadget = gadget = iconbar_gadget_create();
iconbar_gadget_set_sprite(gadget, &icon_info->sprite);
iconbar_gadget_set_text(gadget, icon_info->text);
iconbar_gadget_set_task_name(gadget, task_name);
ibarpatch_free_info(icon_info);
/* Link node into list. */
node->next = task->icons;
task->icons = node;
icon->external_handle = task->arranger->add_icon(task->arranger,
gadget, &add_info);
}
/* Update an icon gadget (icon arranger gets event indirectly). */
static void update_icon(iconbar_manager_task *task,
iconbar_manager_icon *icon)
{
iconbar_gadget *gadget = icon->gadget;
ibarpatch_icon_properties *icon_info;
LOGFUNC(update_icon);
/* Tell the gadget the new icon info. */
icon_info = ibarpatch_extract_info(icon->task, icon->flags, &icon->data);
iconbar_gadget_set_sprite(gadget, &icon_info->sprite);
iconbar_gadget_set_text(gadget, icon_info->text);
ibarpatch_free_info(icon_info);
icon->update_poll_id = task->poll_id;
}
/* Remove an icon. */
static void remove_icon(iconbar_manager_task *task,
iconbar_manager_node **node_ptr)
{
iconbar_manager_node *node = *node_ptr;
iconbar_manager_icon *icon = &node->i;
iconbar_gadget *gadget = icon->gadget;
int icon_handle = icon->icon_handle;
LOGFUNC(remove_icon);
task->arranger->remove_icon(task->arranger, gadget, icon->external_handle);
iconbar_gadget_destroy(gadget);
/* Remove the corresponding add record from IconbarPatch's keep list. */
{
ibarpatch_element **rem;
#ifdef MemCheck_MEMCHECK
/* It is easiest to turn checking off throughout this. */
MemCheck_SetChecking(0, 0);
#endif
for(rem = &task->module->list_keep.begin; *rem; rem = &(*rem)->next) {
if((*rem)->type == ibarpatch_add_type &&
(*rem)->data.add.icon_handle == icon_handle) {
/* We have found the matching add event. Now remove it. */
ibarpatch_element *old = *rem;
/* Make sure to handle the special case of this being
the last in the list. */
if(task->module->list_keep.end == &(*rem)->next)
task->module->list_keep.end = rem;
*rem = (*rem)->next;
osmodule_free(old);
--task->module->list_keep.count;
CHECK_KEEP_LIST(task->module);
break;
}
}
#ifdef MemCheck_MEMCHECK
MemCheck_SetChecking(1, 1);
#endif
}
/* If the pointer was over the icon, restore IconbarPatch's values to a
safer setting. This prevents interactive help from dying after an
app is quit. */
if(task->module->pointer_icon == icon->icon_handle) {
task->module->window = 0;
task->module->pointer_icon = -1;
task->module->pointer_task = 0;
}
if(task->pointer_icon == icon) task->pointer_icon = 0;
/* Remove node from list. */
*node_ptr = node->next;
free(node);
}
/* The arranger's method for telling us that it will no longer be handling
the given gadget. */
void iconbar_manager_losing_icon(iconbar_manager_task *task,
iconbar_gadget *gadget)
{
iconbar_manager_node **node;
LOGFUNC(losing_icon);
/* Search for the corresponding node in the list and remove it. */
for(node = &task->icons; *node; node = &(*node)->next)
if((*node)->i.gadget == gadget) {
iconbar_manager_node *old = *node;
*node = old->next;
/* Make pointer values safe. */
if(task->module->pointer_icon == old->i.icon_handle) {
task->module->window = 0;
task->module->pointer_icon = -1;
task->module->pointer_task = 0;
}
if(task->pointer_icon == &old->i) task->pointer_icon = 0;
/* Free the node. */
free(old);
break;
}
/* Destroy the gadget. */
iconbar_gadget_destroy(gadget);
}