home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / dreamscape / source / Dreamscape / Sources / low-level / c / wimpmsg < prev    next >
Encoding:
Text File  |  1996-09-06  |  4.7 KB  |  190 lines

  1.  
  2. /* low-level.c.wimpmsg
  3.  *
  4.  * Dreamscape - C++ class library for RISC OS
  5.  * Copyright (c) 1996 Mark Seaborn <mseaborn@argonet.co.uk>
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Library General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  * See the Dreamscape documentation for more information.
  12.  */
  13.  
  14. #include <stdlib.h>
  15. #include "OS:wimp.h"
  16.  
  17. #include "wimpmsg.h"
  18. #include "task.h"
  19. #include "x.h"
  20.  
  21.  
  22. typedef struct handler_node handler_node;
  23. struct handler_node {
  24.   int id: 31;
  25.   unsigned deleted: 1;
  26.   dscape_wimpmsg_handler *function;
  27.   void *handle;
  28.   handler_node *next;
  29. };
  30.  
  31. typedef struct handler_bucket handler_bucket;
  32. struct handler_bucket {
  33.   handler_node *list;
  34.   unsigned deleted;
  35.   int partial_id;
  36.   handler_bucket *next;
  37. };
  38.  
  39. #define bottom_hash_mask ((int) 0xFF)
  40. #define top_hash_mask (~bottom_hash_mask)
  41. static handler_bucket *handlers = 0;
  42. static unsigned threaded = 0, deleted = 0;
  43.  
  44. static void tidy_buckets(void);
  45. static void tidy_bucket(handler_bucket *bucket);
  46.  
  47. void dscape_wimpmsg_dispatch_message(const struct wimp_message *message)
  48. {
  49.   /*
  50.    * This function dispatches a Wimp message to the appropriate handlers.
  51.    * If a handler claims the message, the message will not be passed on to
  52.    * any more handlers.
  53.    */
  54.   handler_bucket *b;
  55.   int bottom_id = message->action;
  56.  
  57.   ++threaded;
  58.   for(b=handlers; b; b=b->next) if(bottom_id == b->partial_id) {
  59.     handler_node *h;
  60.     for(h=b->list; h; h=h->next)
  61.       if(message->action == h->id && !h->deleted)
  62.         if(h->function(message, h->handle)) break;
  63.     break;
  64.   }
  65.   --threaded;
  66.  
  67.   if(deleted && !threaded) tidy_buckets();
  68. }
  69.  
  70. static void tidy_buckets(void)
  71. {
  72.   /*
  73.    * This private function tidies all the hash table buckets, removing any
  74.    * unneeded empty buckets.
  75.    */
  76.   handler_bucket **b;
  77.   for(b=&handlers; *b&&deleted;) {
  78.     tidy_bucket(*b);
  79.     if(!(*b)->list) {
  80.       handler_bucket *next = (*b)->next;
  81.       free(*b);
  82.       *b = next;
  83.     }
  84.     else {
  85.       b = &(*b)->next;
  86.     }
  87.   }
  88. }
  89.  
  90. static void tidy_bucket(handler_bucket *bucket)
  91. {
  92.   /*
  93.    * This private function tidies a specific hash table bucket, removing
  94.    * any handler nodes that have been marked as deleted.
  95.    */
  96.   handler_node **d;
  97.   for(d=&bucket->list; *d&&bucket->deleted;) {
  98.     if((*d)->deleted) {
  99.       handler_node *next = (*d)->next;
  100.       free(*d);
  101.       *d = next;
  102.       --bucket->deleted;
  103.       --deleted;
  104.     }
  105.     else {
  106.       d = &(*d)->next;
  107.     }
  108.   }
  109. }
  110.  
  111. void dscape_wimpmsg_register_handler(int id,
  112.     dscape_wimpmsg_handler *function, void *handle)
  113. {
  114.   /*
  115.    * This function registers a new Wimp message handler, adding it to the
  116.    * appropriate hash table bucket, creating a new bucket if necessary.
  117.    */
  118.   handler_node *h = malloc(sizeof(handler_node));
  119.   handler_bucket **b = 0;
  120.   int bottom_id = id & bottom_hash_mask;
  121.   if(!h) x_throw_message(x_msg_memory());
  122.   h->function = function;
  123.   h->handle = handle;
  124.   h->id = id;
  125.   h->deleted = 0;
  126.  
  127.   for(b=&handlers; *b; b=&(*b)->next)
  128.     if(bottom_id == (*b)->partial_id) break;
  129.   if(!*b) {
  130.     *b = malloc(sizeof(handler_bucket));
  131.     if(!*b) {
  132.       free(h);
  133.       x_throw_message(x_msg_memory());
  134.     }
  135.     (*b)->list = 0;
  136.     (*b)->partial_id = bottom_id;
  137.     (*b)->deleted = 0;
  138.     (*b)->next = 0;
  139.   }
  140.   h->next = (*b)->list;
  141.   (*b)->list = h;
  142. }
  143.  
  144. void dscape_wimpmsg_deregister_handler(int id,
  145.     dscape_wimpmsg_handler *function, void *handle)
  146. {
  147.   /*
  148.    * This function deregisters a Wimp message handler. If the dispatcher is
  149.    * not threaded, it will remove the handler from the list itself,
  150.    * otherwise it will mark the handler node as deleted.
  151.    */
  152.   int bottom_id = id & bottom_hash_mask;
  153.  
  154.   if(!threaded) {
  155.     handler_bucket **b;
  156.     for(b=&handlers; *b; b=&(*b)->next) if(bottom_id == (*b)->partial_id) {
  157.       handler_node **d;
  158.       for(d=&(*b)->list; *d; d=&(*d)->next)
  159.           if(id == (*d)->id && function == (*d)->function &&
  160.              handle == (*d)->handle && !(*d)->deleted) {
  161.         handler_node *next = (*d)->next;
  162.         free(*d);
  163.         *d = next;
  164.         if(!(*b)->list) {
  165.           handler_bucket *next = (*b)->next;
  166.           free(*b);
  167.           *b = next;
  168.         }
  169.         return;
  170.       }
  171.     }
  172.   }
  173.   else {
  174.     handler_bucket *b;
  175.     for(b=handlers; b; b=b->next) if(bottom_id == b->partial_id) {
  176.       handler_node *h;
  177.       for(h=b->list; h; h=h->next)
  178.           if(id == h->id && function == h->function &&
  179.              handle == h->handle && !h->deleted) {
  180.         h->deleted = 1;
  181.         ++b->deleted;
  182.         ++deleted;
  183.         return;
  184.       }
  185.     }
  186.   }
  187.   dscape_task_report_error(x_msg_internal("Warning: Wimp message handler "
  188.     "was not already registered"));
  189. }
  190.