home *** CD-ROM | disk | FTP | other *** search
-
- /* low-level.c.tboxevent
- *
- * Dreamscape - C++ class library for RISC OS
- * Copyright (c) 1996 Mark Seaborn <mseaborn@argonet.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * See the Dreamscape documentation for more information.
- */
-
- #include <stdlib.h>
- #include "OS:toolbox.h"
-
- #include "tboxevent.h"
- #include "task.h"
- #include "x.h"
-
-
- typedef struct s_handler_node s_handler_node;
- struct s_handler_node {
- int id: 31;
- unsigned deleted: 1;
- dscape_tboxevent_s_handler *function;
- s_handler_node *next;
- };
-
- typedef struct s_handler_bucket s_handler_bucket;
- struct s_handler_bucket {
- s_handler_node *list;
- unsigned deleted;
- int partial_id;
- s_handler_bucket *next;
- };
-
- typedef struct c_handler_node c_handler_node;
- struct c_handler_node {
- int id;
- void *handle;
- dscape_tboxevent_handler *function;
- toolbox_o object;
- toolbox_c component;
- unsigned object_matches: 3;
- unsigned component_matches: 3;
- unsigned deleted: 1;
- c_handler_node *next;
- };
-
- typedef struct c_handler_bucket c_handler_bucket;
- struct c_handler_bucket {
- c_handler_node *list;
- unsigned deleted;
- int partial_id;
- c_handler_bucket *next;
- };
-
- #define bottom_hash_mask ((int) 0xFF)
- #define top_hash_mask (~bottom_hash_mask)
- static s_handler_bucket *s_handlers = 0;
- static c_handler_bucket *c_handlers = 0;
- static unsigned s_threaded = 0, s_deleted = 0,
- c_threaded = 0, c_deleted = 0;
-
- static void tidy_s_buckets(void);
- static void tidy_s_bucket(s_handler_bucket *bucket);
- static void tidy_c_buckets(void);
- static void tidy_c_bucket(c_handler_bucket *bucket);
-
- void dscape_tboxevent_dispatch_event(const struct toolbox_action *event,
- const struct toolbox_block *ids)
- {
- c_handler_bucket *a;
- s_handler_bucket *b;
- int bottom_id = event->action_no & bottom_hash_mask;
- int claimed = 0;
-
- /*
- * Dispatch the event to all matching complex Toolbox event handlers. If
- * the event is claimed, the event will not be passed on.
- */
- ++c_threaded;
- for(a=c_handlers; a; a=a->next) if(bottom_id == a->partial_id) {
- c_handler_node *h;
- for(h=a->list; h; h=h->next)
- /* check event ids match and the handler has not been deleted */
- if(event->action_no == h->id && !h->deleted &&
- /* check that the object ids match */
- ((h->object == dscape_tboxevent_any_object) ||
- ((h->object_matches & dscape_tboxevent_match_self) &&
- (h->object == ids->this_obj)) ||
- ((h->object_matches & dscape_tboxevent_match_parent) &&
- (h->object == ids->parent_obj)) ||
- ((h->object_matches & dscape_tboxevent_match_ancestor) &&
- (h->object == ids->ancestor_obj))) &&
- /* check that the component ids match */
- ((h->component == dscape_tboxevent_any_component) ||
- ((h->component_matches & dscape_tboxevent_match_self) &&
- (h->component == ids->this_cmp)) ||
- ((h->component_matches & dscape_tboxevent_match_parent) &&
- (h->component == ids->parent_cmp)) ||
- ((h->component_matches & dscape_tboxevent_match_ancestor) &&
- (h->component == ids->ancestor_cmp)))) {
- /* if all matches, call the handler function */
- claimed = h->function(event, ids, h->handle);
- if(claimed) break;
- }
- break;
- }
- --c_threaded;
-
- /*
- * Dispatch the event to all matching simple Toolbox event handlers, as
- * long as the event has not already been claimed.
- */
- if(!claimed) {
- ++s_threaded;
- for(b=s_handlers; b; b=b->next) if(bottom_id == b->partial_id) {
- s_handler_node *h;
- for(h=b->list; h; h=h->next)
- if(event->action_no == h->id && !h->deleted) {
- h->function(event, ids);
- break;
- }
- break;
- }
- --s_threaded;
- }
-
- /*
- * Tidy both sets of hash table buckets.
- */
- if(s_deleted && !s_threaded) tidy_s_buckets();
- if(c_deleted && !c_threaded) tidy_c_buckets();
- }
-
- static void tidy_s_buckets(void)
- {
- /*
- * This private function tidies all simple handler hash table buckets.
- */
- s_handler_bucket **b;
- for(b=&s_handlers; *b&&s_deleted;) {
- tidy_s_bucket(*b);
- if(!(*b)->list) {
- s_handler_bucket *next = (*b)->next;
- free(*b);
- *b = next;
- }
- else {
- b = &(*b)->next;
- }
- }
- }
-
- static void tidy_s_bucket(s_handler_bucket *bucket)
- {
- /*
- * This private function tidies a specific simple handler hash table
- * bucket, removing all handlers that have been marked as deleted.
- */
- s_handler_node **d;
- for(d=&bucket->list; *d&&bucket->deleted;) {
- if((*d)->deleted) {
- s_handler_node *next = (*d)->next;
- free(*d);
- *d = next;
- --bucket->deleted;
- --s_deleted;
- }
- else {
- d = &(*d)->next;
- }
- }
- }
-
- static void tidy_c_buckets(void)
- {
- /*
- * This private function tidies all complex handler hash table buckets.
- */
- c_handler_bucket **b;
- for(b=&c_handlers; *b&&c_deleted;) {
- tidy_c_bucket(*b);
- if(!(*b)->list) {
- c_handler_bucket *next = (*b)->next;
- free(*b);
- *b = next;
- }
- else {
- b = &(*b)->next;
- }
- }
- }
-
- static void tidy_c_bucket(c_handler_bucket *bucket)
- {
- /*
- * This private function tidies a specific complex handler hash table
- * bucket.
- */
- c_handler_node **d;
- for(d=&bucket->list; *d&&bucket->deleted;) {
- if((*d)->deleted) {
- c_handler_node *next = (*d)->next;
- free(*d);
- *d = next;
- --bucket->deleted;
- --c_deleted;
- }
- else {
- d = &(*d)->next;
- }
- }
- }
-
- void dscape_tboxevent_register_s_handler(int id,
- dscape_tboxevent_s_handler *function)
- {
- /*
- * This function registers a simple Toolbox event handler. It will add it
- * to the appropriate hash table bucket, creating a new bucket if
- * necessary.
- */
- s_handler_node *h = malloc(sizeof(s_handler_node));
- s_handler_bucket **b;
- int bottom_id = id & bottom_hash_mask;
- if(!h) x_throw_message(x_msg_memory());
- h->id = id;
- h->function = function;
- h->deleted = 0;
-
- for(b=&s_handlers; *b; b=&(*b)->next)
- if(bottom_id == (*b)->partial_id) break;
- if(!*b) {
- *b = malloc(sizeof(s_handler_bucket));
- if(!*b) {
- free(h);
- x_throw_message(x_msg_memory());
- }
- (*b)->list = 0;
- (*b)->partial_id = bottom_id;
- (*b)->deleted = 0;
- (*b)->next = 0;
- }
- h->next = (*b)->list;
- (*b)->list = h;
- }
-
- void dscape_tboxevent_deregister_s_handler(int id,
- dscape_tboxevent_s_handler *function)
- {
- /*
- * This function will deregister a simple Toolbox event handler. If the
- * dispatcher is not threaded, it will remove the handler data from the
- * list itself, otherwise it will simply mark it as deleted.
- */
- int bottom_id = id & bottom_hash_mask;
-
- if(!s_threaded) {
- s_handler_bucket **b;
- for(b=&s_handlers; *b; b=&(*b)->next) if(bottom_id == (*b)->partial_id) {
- s_handler_node **d;
- for(d=&(*b)->list; *d; d=&(*d)->next)
- if(id == (*d)->id && function == (*d)->function &&
- !(*d)->deleted) {
- s_handler_node *next = (*d)->next;
- free(*d);
- *d = next;
- if(!(*b)->list) {
- s_handler_bucket *next = (*b)->next;
- free(*b);
- *b = next;
- }
- return;
- }
- }
- }
- else {
- s_handler_bucket *b;
- for(b=s_handlers; b; b=b->next) if(bottom_id == b->partial_id) {
- s_handler_node *h;
- for(h=b->list; h; h=h->next)
- if(id == h->id && function == h->function && !h->deleted) {
- h->deleted = 1;
- ++b->deleted;
- ++s_deleted;
- return;
- }
- }
- }
- dscape_task_report_error(x_msg_internal("Warning: simple Toolbox event "
- "handler was not already registered"));
- }
-
- void dscape_tboxevent_register_o_handler(int id, struct toolbox_o_ *object,
- unsigned object_matches, dscape_tboxevent_handler *function,
- void *handle)
- {
- dscape_tboxevent_register_c_handler(id, object, object_matches,
- dscape_tboxevent_any_component, 0, function, handle);
- }
-
- void dscape_tboxevent_deregister_o_handler(int id, struct toolbox_o_ *object,
- unsigned object_matches, dscape_tboxevent_handler *function,
- void *handle)
- {
- dscape_tboxevent_deregister_c_handler(id, object, object_matches,
- dscape_tboxevent_any_component, 0, function, handle);
- }
-
- void dscape_tboxevent_register_c_handler(int id, struct toolbox_o_ *object,
- unsigned object_matches, int component, unsigned component_matches,
- dscape_tboxevent_handler *function, void *handle)
- {
- /*
- * This function registers a complex Toolbox event handler, adding the
- * entry to the appropriate hash table bucket. If a suitable bucket does
- * not exist, a new one will be created and added to the end of the list.
- */
- c_handler_node *h = malloc(sizeof(c_handler_node));
- c_handler_bucket **b;
- int bottom_id = id & bottom_hash_mask;
- if(!h) x_throw_message(x_msg_memory());
- h->id = id;
- h->handle = handle;
- h->function = function;
- h->object = object;
- h->component = component;
- h->object_matches = object_matches ? object_matches :
- dscape_tboxevent_match_self;
- h->component_matches = component_matches ? component_matches :
- dscape_tboxevent_match_self;
- h->deleted = 0;
-
- for(b=&c_handlers; *b; b=&(*b)->next)
- if(bottom_id == (*b)->partial_id) break;
- if(!*b) {
- *b = malloc(sizeof(c_handler_bucket));
- if(!*b) {
- free(h);
- x_throw_message(x_msg_memory());
- }
- (*b)->list = 0;
- (*b)->partial_id = bottom_id;
- (*b)->deleted = 0;
- (*b)->next = 0;
- }
- h->next = (*b)->list;
- (*b)->list = h;
- }
-
- void dscape_tboxevent_deregister_c_handler(int id, struct toolbox_o_ *object,
- unsigned object_matches, int component, unsigned component_matches,
- dscape_tboxevent_handler *function, void *handle)
- {
- /*
- * If the dispatcher is not threaded, this function will remove the
- * handler data from the list itself, otherwise it will simply mark it as
- * deleted.
- */
- int bottom_id = id & bottom_hash_mask;
-
- if(!c_threaded) {
- c_handler_bucket **b;
- for(b=&c_handlers; *b; b=&(*b)->next) if(bottom_id == (*b)->partial_id) {
- c_handler_node **d;
- for(d=&(*b)->list; *d; d=&(*d)->next)
- if(id == (*d)->id && function == (*d)->function &&
- handle == (*d)->handle && object == (*d)->object &&
- component == (*d)->component &&
- ((*d)->object_matches == (object_matches ?
- object_matches : dscape_tboxevent_match_self)) &&
- ((*d)->component_matches == (component_matches ?
- component_matches : dscape_tboxevent_match_self)) &&
- !(*d)->deleted) {
- c_handler_node *next = (*d)->next;
- free(*d);
- *d = next;
- if(!(*b)->list) {
- c_handler_bucket *next = (*b)->next;
- free(*b);
- *b = next;
- }
- return;
- }
- }
- }
- else {
- c_handler_bucket *b;
- for(b=c_handlers; b; b=b->next) if(bottom_id == b->partial_id) {
- c_handler_node *h;
- for(h=b->list; h; h=h->next)
- if(id == h->id && function == h->function && handle == h->handle &&
- object == h->object && component == h->component &&
- (h->object_matches == (object_matches ?
- object_matches : dscape_tboxevent_match_self)) &&
- (h->component_matches == (component_matches ?
- component_matches : dscape_tboxevent_match_self)) &&
- !h->deleted) {
- h->deleted = 1;
- ++b->deleted;
- ++c_deleted;
- return;
- }
- }
- }
- }
-