home *** CD-ROM | disk | FTP | other *** search
-
- /* low-level.c.wimpmsg
- *
- * 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:wimp.h"
-
- #include "wimpmsg.h"
- #include "task.h"
- #include "x.h"
-
-
- typedef struct handler_node handler_node;
- struct handler_node {
- int id: 31;
- unsigned deleted: 1;
- dscape_wimpmsg_handler *function;
- void *handle;
- handler_node *next;
- };
-
- typedef struct handler_bucket handler_bucket;
- struct handler_bucket {
- handler_node *list;
- unsigned deleted;
- int partial_id;
- handler_bucket *next;
- };
-
- #define bottom_hash_mask ((int) 0xFF)
- #define top_hash_mask (~bottom_hash_mask)
- static handler_bucket *handlers = 0;
- static unsigned threaded = 0, deleted = 0;
-
- static void tidy_buckets(void);
- static void tidy_bucket(handler_bucket *bucket);
-
- void dscape_wimpmsg_dispatch_message(const struct wimp_message *message)
- {
- /*
- * This function dispatches a Wimp message to the appropriate handlers.
- * If a handler claims the message, the message will not be passed on to
- * any more handlers.
- */
- handler_bucket *b;
- int bottom_id = message->action;
-
- ++threaded;
- for(b=handlers; b; b=b->next) if(bottom_id == b->partial_id) {
- handler_node *h;
- for(h=b->list; h; h=h->next)
- if(message->action == h->id && !h->deleted)
- if(h->function(message, h->handle)) break;
- break;
- }
- --threaded;
-
- if(deleted && !threaded) tidy_buckets();
- }
-
- static void tidy_buckets(void)
- {
- /*
- * This private function tidies all the hash table buckets, removing any
- * unneeded empty buckets.
- */
- handler_bucket **b;
- for(b=&handlers; *b&&deleted;) {
- tidy_bucket(*b);
- if(!(*b)->list) {
- handler_bucket *next = (*b)->next;
- free(*b);
- *b = next;
- }
- else {
- b = &(*b)->next;
- }
- }
- }
-
- static void tidy_bucket(handler_bucket *bucket)
- {
- /*
- * This private function tidies a specific hash table bucket, removing
- * any handler nodes that have been marked as deleted.
- */
- handler_node **d;
- for(d=&bucket->list; *d&&bucket->deleted;) {
- if((*d)->deleted) {
- handler_node *next = (*d)->next;
- free(*d);
- *d = next;
- --bucket->deleted;
- --deleted;
- }
- else {
- d = &(*d)->next;
- }
- }
- }
-
- void dscape_wimpmsg_register_handler(int id,
- dscape_wimpmsg_handler *function, void *handle)
- {
- /*
- * This function registers a new Wimp message handler, adding it to the
- * appropriate hash table bucket, creating a new bucket if necessary.
- */
- handler_node *h = malloc(sizeof(handler_node));
- handler_bucket **b = 0;
- int bottom_id = id & bottom_hash_mask;
- if(!h) x_throw_message(x_msg_memory());
- h->function = function;
- h->handle = handle;
- h->id = id;
- h->deleted = 0;
-
- for(b=&handlers; *b; b=&(*b)->next)
- if(bottom_id == (*b)->partial_id) break;
- if(!*b) {
- *b = malloc(sizeof(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_wimpmsg_deregister_handler(int id,
- dscape_wimpmsg_handler *function, void *handle)
- {
- /*
- * This function deregisters a Wimp message handler. If the dispatcher is
- * not threaded, it will remove the handler from the list itself,
- * otherwise it will mark the handler node as deleted.
- */
- int bottom_id = id & bottom_hash_mask;
-
- if(!threaded) {
- handler_bucket **b;
- for(b=&handlers; *b; b=&(*b)->next) if(bottom_id == (*b)->partial_id) {
- handler_node **d;
- for(d=&(*b)->list; *d; d=&(*d)->next)
- if(id == (*d)->id && function == (*d)->function &&
- handle == (*d)->handle && !(*d)->deleted) {
- handler_node *next = (*d)->next;
- free(*d);
- *d = next;
- if(!(*b)->list) {
- handler_bucket *next = (*b)->next;
- free(*b);
- *b = next;
- }
- return;
- }
- }
- }
- else {
- handler_bucket *b;
- for(b=handlers; b; b=b->next) if(bottom_id == b->partial_id) {
- handler_node *h;
- for(h=b->list; h; h=h->next)
- if(id == h->id && function == h->function &&
- handle == h->handle && !h->deleted) {
- h->deleted = 1;
- ++b->deleted;
- ++deleted;
- return;
- }
- }
- }
- dscape_task_report_error(x_msg_internal("Warning: Wimp message handler "
- "was not already registered"));
- }
-