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

  1.  
  2. /* low-level.c.tboxevent
  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:toolbox.h"
  16.  
  17. #include "tboxevent.h"
  18. #include "task.h"
  19. #include "x.h"
  20.  
  21.  
  22. typedef struct s_handler_node s_handler_node;
  23. struct s_handler_node {
  24.   int id: 31;
  25.   unsigned deleted: 1;
  26.   dscape_tboxevent_s_handler *function;
  27.   s_handler_node *next;
  28. };
  29.  
  30. typedef struct s_handler_bucket s_handler_bucket;
  31. struct s_handler_bucket {
  32.   s_handler_node *list;
  33.   unsigned deleted;
  34.   int partial_id;
  35.   s_handler_bucket *next;
  36. };
  37.  
  38. typedef struct c_handler_node c_handler_node;
  39. struct c_handler_node {
  40.   int id;
  41.   void *handle;
  42.   dscape_tboxevent_handler *function;
  43.   toolbox_o object;
  44.   toolbox_c component;
  45.   unsigned object_matches: 3;
  46.   unsigned component_matches: 3;
  47.   unsigned deleted: 1;
  48.   c_handler_node *next;
  49. };
  50.  
  51. typedef struct c_handler_bucket c_handler_bucket;
  52. struct c_handler_bucket {
  53.   c_handler_node *list;
  54.   unsigned deleted;
  55.   int partial_id;
  56.   c_handler_bucket *next;
  57. };
  58.  
  59. #define bottom_hash_mask ((int) 0xFF)
  60. #define top_hash_mask (~bottom_hash_mask)
  61. static s_handler_bucket *s_handlers = 0;
  62. static c_handler_bucket *c_handlers = 0;
  63. static unsigned s_threaded = 0, s_deleted = 0,
  64.         c_threaded = 0, c_deleted = 0;
  65.  
  66. static void tidy_s_buckets(void);
  67. static void tidy_s_bucket(s_handler_bucket *bucket);
  68. static void tidy_c_buckets(void);
  69. static void tidy_c_bucket(c_handler_bucket *bucket);
  70.  
  71. void dscape_tboxevent_dispatch_event(const struct toolbox_action *event,
  72.     const struct toolbox_block *ids)
  73. {
  74.   c_handler_bucket *a;
  75.   s_handler_bucket *b;
  76.   int bottom_id = event->action_no & bottom_hash_mask;
  77.   int claimed = 0;
  78.  
  79.   /*
  80.    * Dispatch the event to all matching complex Toolbox event handlers. If
  81.    * the event is claimed, the event will not be passed on.
  82.    */
  83.   ++c_threaded;
  84.   for(a=c_handlers; a; a=a->next) if(bottom_id == a->partial_id) {
  85.     c_handler_node *h;
  86.     for(h=a->list; h; h=h->next)
  87.       /* check event ids match and the handler has not been deleted */
  88.       if(event->action_no == h->id && !h->deleted &&
  89.         /* check that the object ids match */
  90.         ((h->object == dscape_tboxevent_any_object) ||
  91.           ((h->object_matches & dscape_tboxevent_match_self) &&
  92.             (h->object == ids->this_obj)) ||
  93.           ((h->object_matches & dscape_tboxevent_match_parent) &&
  94.             (h->object == ids->parent_obj)) ||
  95.           ((h->object_matches & dscape_tboxevent_match_ancestor) &&
  96.             (h->object == ids->ancestor_obj))) &&
  97.         /* check that the component ids match */
  98.         ((h->component == dscape_tboxevent_any_component) ||
  99.           ((h->component_matches & dscape_tboxevent_match_self) &&
  100.             (h->component == ids->this_cmp)) ||
  101.           ((h->component_matches & dscape_tboxevent_match_parent) &&
  102.             (h->component == ids->parent_cmp)) ||
  103.           ((h->component_matches & dscape_tboxevent_match_ancestor) &&
  104.             (h->component == ids->ancestor_cmp)))) {
  105.       /* if all matches, call the handler function */
  106.       claimed = h->function(event, ids, h->handle);
  107.       if(claimed) break;
  108.     }
  109.     break;
  110.   }
  111.   --c_threaded;
  112.  
  113.   /*
  114.    * Dispatch the event to all matching simple Toolbox event handlers, as
  115.    * long as the event has not already been claimed.
  116.    */
  117.   if(!claimed) {
  118.     ++s_threaded;
  119.     for(b=s_handlers; b; b=b->next) if(bottom_id == b->partial_id) {
  120.       s_handler_node *h;
  121.       for(h=b->list; h; h=h->next)
  122.           if(event->action_no == h->id && !h->deleted) {
  123.         h->function(event, ids);
  124.         break;
  125.       }
  126.       break;
  127.     }
  128.     --s_threaded;
  129.   }
  130.  
  131.   /*
  132.    * Tidy both sets of hash table buckets.
  133.    */
  134.   if(s_deleted && !s_threaded) tidy_s_buckets();
  135.   if(c_deleted && !c_threaded) tidy_c_buckets();
  136. }
  137.  
  138. static void tidy_s_buckets(void)
  139. {
  140.   /*
  141.    * This private function tidies all simple handler hash table buckets.
  142.    */
  143.   s_handler_bucket **b;
  144.   for(b=&s_handlers; *b&&s_deleted;) {
  145.     tidy_s_bucket(*b);
  146.     if(!(*b)->list) {
  147.       s_handler_bucket *next = (*b)->next;
  148.       free(*b);
  149.       *b = next;
  150.     }
  151.     else {
  152.       b = &(*b)->next;
  153.     }
  154.   }
  155. }
  156.  
  157. static void tidy_s_bucket(s_handler_bucket *bucket)
  158. {
  159.   /*
  160.    * This private function tidies a specific simple handler hash table
  161.    * bucket, removing all handlers that have been marked as deleted.
  162.    */
  163.   s_handler_node **d;
  164.   for(d=&bucket->list; *d&&bucket->deleted;) {
  165.     if((*d)->deleted) {
  166.       s_handler_node *next = (*d)->next;
  167.       free(*d);
  168.       *d = next;
  169.       --bucket->deleted;
  170.       --s_deleted;
  171.     }
  172.     else {
  173.       d = &(*d)->next;
  174.     }
  175.   }
  176. }
  177.  
  178. static void tidy_c_buckets(void)
  179. {
  180.   /*
  181.    * This private function tidies all complex handler hash table buckets.
  182.    */
  183.   c_handler_bucket **b;
  184.   for(b=&c_handlers; *b&&c_deleted;) {
  185.     tidy_c_bucket(*b);
  186.     if(!(*b)->list) {
  187.       c_handler_bucket *next = (*b)->next;
  188.       free(*b);
  189.       *b = next;
  190.     }
  191.     else {
  192.       b = &(*b)->next;
  193.     }
  194.   }
  195. }
  196.  
  197. static void tidy_c_bucket(c_handler_bucket *bucket)
  198. {
  199.   /*
  200.    * This private function tidies a specific complex handler hash table
  201.    * bucket.
  202.    */
  203.   c_handler_node **d;
  204.   for(d=&bucket->list; *d&&bucket->deleted;) {
  205.     if((*d)->deleted) {
  206.       c_handler_node *next = (*d)->next;
  207.       free(*d);
  208.       *d = next;
  209.       --bucket->deleted;
  210.       --c_deleted;
  211.     }
  212.     else {
  213.       d = &(*d)->next;
  214.     }
  215.   }
  216. }
  217.  
  218. void dscape_tboxevent_register_s_handler(int id,
  219.     dscape_tboxevent_s_handler *function)
  220. {
  221.   /*
  222.    * This function registers a simple Toolbox event handler. It will add it
  223.    * to the appropriate hash table bucket, creating a new bucket if
  224.    * necessary.
  225.    */
  226.   s_handler_node *h = malloc(sizeof(s_handler_node));
  227.   s_handler_bucket **b;
  228.   int bottom_id = id & bottom_hash_mask;
  229.   if(!h) x_throw_message(x_msg_memory());
  230.   h->id = id;
  231.   h->function = function;
  232.   h->deleted = 0;
  233.  
  234.   for(b=&s_handlers; *b; b=&(*b)->next)
  235.     if(bottom_id == (*b)->partial_id) break;
  236.   if(!*b) {
  237.     *b = malloc(sizeof(s_handler_bucket));
  238.     if(!*b) {
  239.       free(h);
  240.       x_throw_message(x_msg_memory());
  241.     }
  242.     (*b)->list = 0;
  243.     (*b)->partial_id = bottom_id;
  244.     (*b)->deleted = 0;
  245.     (*b)->next = 0;
  246.   }
  247.   h->next = (*b)->list;
  248.   (*b)->list = h;
  249. }
  250.  
  251. void dscape_tboxevent_deregister_s_handler(int id,
  252.     dscape_tboxevent_s_handler *function)
  253. {
  254.   /*
  255.    * This function will deregister a simple Toolbox event handler. If the
  256.    * dispatcher is not threaded, it will remove the handler data from the
  257.    * list itself, otherwise it will simply mark it as deleted.
  258.    */
  259.   int bottom_id = id & bottom_hash_mask;
  260.  
  261.   if(!s_threaded) {
  262.     s_handler_bucket **b;
  263.     for(b=&s_handlers; *b; b=&(*b)->next) if(bottom_id == (*b)->partial_id) {
  264.       s_handler_node **d;
  265.       for(d=&(*b)->list; *d; d=&(*d)->next)
  266.           if(id == (*d)->id && function == (*d)->function &&
  267.              !(*d)->deleted) {
  268.         s_handler_node *next = (*d)->next;
  269.         free(*d);
  270.         *d = next;
  271.         if(!(*b)->list) {
  272.           s_handler_bucket *next = (*b)->next;
  273.           free(*b);
  274.           *b = next;
  275.         }
  276.         return;
  277.       }
  278.     }
  279.   }
  280.   else {
  281.     s_handler_bucket *b;
  282.     for(b=s_handlers; b; b=b->next) if(bottom_id == b->partial_id) {
  283.       s_handler_node *h;
  284.       for(h=b->list; h; h=h->next)
  285.           if(id == h->id && function == h->function && !h->deleted) {
  286.         h->deleted = 1;
  287.         ++b->deleted;
  288.         ++s_deleted;
  289.         return;
  290.       }
  291.     }
  292.   }
  293.   dscape_task_report_error(x_msg_internal("Warning: simple Toolbox event "
  294.     "handler was not already registered"));
  295. }
  296.  
  297. void dscape_tboxevent_register_o_handler(int id, struct toolbox_o_ *object,
  298.     unsigned object_matches, dscape_tboxevent_handler *function,
  299.     void *handle)
  300. {
  301.   dscape_tboxevent_register_c_handler(id, object, object_matches,
  302.     dscape_tboxevent_any_component, 0, function, handle);
  303. }
  304.  
  305. void dscape_tboxevent_deregister_o_handler(int id, struct toolbox_o_ *object,
  306.     unsigned object_matches, dscape_tboxevent_handler *function,
  307.     void *handle)
  308. {
  309.   dscape_tboxevent_deregister_c_handler(id, object, object_matches,
  310.     dscape_tboxevent_any_component, 0, function, handle);
  311. }
  312.  
  313. void dscape_tboxevent_register_c_handler(int id, struct toolbox_o_ *object,
  314.     unsigned object_matches, int component, unsigned component_matches,
  315.     dscape_tboxevent_handler *function, void *handle)
  316. {
  317.   /*
  318.    * This function registers a complex Toolbox event handler, adding the
  319.    * entry to the appropriate hash table bucket. If a suitable bucket does
  320.    * not exist, a new one will be created and added to the end of the list.
  321.    */
  322.   c_handler_node *h = malloc(sizeof(c_handler_node));
  323.   c_handler_bucket **b;
  324.   int bottom_id = id & bottom_hash_mask;
  325.   if(!h) x_throw_message(x_msg_memory());
  326.   h->id = id;
  327.   h->handle = handle;
  328.   h->function = function;
  329.   h->object = object;
  330.   h->component = component;
  331.   h->object_matches = object_matches ? object_matches :
  332.     dscape_tboxevent_match_self;
  333.   h->component_matches = component_matches ? component_matches :
  334.     dscape_tboxevent_match_self;
  335.   h->deleted = 0;
  336.  
  337.   for(b=&c_handlers; *b; b=&(*b)->next)
  338.     if(bottom_id == (*b)->partial_id) break;
  339.   if(!*b) {
  340.     *b = malloc(sizeof(c_handler_bucket));
  341.     if(!*b) {
  342.       free(h);
  343.       x_throw_message(x_msg_memory());
  344.     }
  345.     (*b)->list = 0;
  346.     (*b)->partial_id = bottom_id;
  347.     (*b)->deleted = 0;
  348.     (*b)->next = 0;
  349.   }
  350.   h->next = (*b)->list;
  351.   (*b)->list = h;
  352. }
  353.  
  354. void dscape_tboxevent_deregister_c_handler(int id, struct toolbox_o_ *object,
  355.     unsigned object_matches, int component, unsigned component_matches,
  356.     dscape_tboxevent_handler *function, void *handle)
  357. {
  358.   /*
  359.    * If the dispatcher is not threaded, this function will remove the
  360.    * handler data from the list itself, otherwise it will simply mark it as
  361.    * deleted.
  362.    */
  363.   int bottom_id = id & bottom_hash_mask;
  364.  
  365.   if(!c_threaded) {
  366.     c_handler_bucket **b;
  367.     for(b=&c_handlers; *b; b=&(*b)->next) if(bottom_id == (*b)->partial_id) {
  368.       c_handler_node **d;
  369.       for(d=&(*b)->list; *d; d=&(*d)->next)
  370.           if(id == (*d)->id && function == (*d)->function &&
  371.              handle == (*d)->handle && object == (*d)->object &&
  372.              component == (*d)->component &&
  373.              ((*d)->object_matches == (object_matches ?
  374.                object_matches : dscape_tboxevent_match_self)) &&
  375.              ((*d)->component_matches == (component_matches ?
  376.                component_matches : dscape_tboxevent_match_self)) &&
  377.              !(*d)->deleted) {
  378.         c_handler_node *next = (*d)->next;
  379.         free(*d);
  380.         *d = next;
  381.         if(!(*b)->list) {
  382.           c_handler_bucket *next = (*b)->next;
  383.           free(*b);
  384.           *b = next;
  385.         }
  386.         return;
  387.       }
  388.     }
  389.   }
  390.   else {
  391.     c_handler_bucket *b;
  392.     for(b=c_handlers; b; b=b->next) if(bottom_id == b->partial_id) {
  393.       c_handler_node *h;
  394.       for(h=b->list; h; h=h->next)
  395.           if(id == h->id && function == h->function && handle == h->handle &&
  396.              object == h->object && component == h->component &&
  397.              (h->object_matches == (object_matches ?
  398.                object_matches : dscape_tboxevent_match_self)) &&
  399.              (h->component_matches == (component_matches ?
  400.                component_matches : dscape_tboxevent_match_self)) &&
  401.              !h->deleted) {
  402.         h->deleted = 1;
  403.         ++b->deleted;
  404.         ++c_deleted;
  405.         return;
  406.       }
  407.     }
  408.   }
  409. }
  410.