home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / Development / Source / Notify Source / notify.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-07  |  6.0 KB  |  189 lines  |  [TEXT/KAHL]

  1. /*
  2.  ***********************************************************************
  3.  *
  4.  * The set of functions below let a (backgound) application post 
  5.  * synchronous or asynchronous notification messages to the user.
  6.  * Synchronous posting means that the posting function does not return until
  7.  * the notification message is displayed and the user dismisses it.
  8.  * In asynchronous mode, the posting function returns as soon as the
  9.  * message is queued into the notification queue (but not yet displayed!).
  10.  * The functions use the Notification Manager and the EventManager (via
  11.  * function sleep() defined elsewhere to relinquish the CPU control while
  12.  * sleeping).
  13.  *
  14.  * Synchronization between the Notification Manager and the present functions
  15.  * A field nmRefCon of the Notification Queue element is used for the
  16.  * synchronization: it is reset to 0 when the element is queued and set to
  17.  * 1 by a completion routine when the message has been posted.
  18.  * 
  19.  ***********************************************************************
  20.  */
  21.  
  22. /* MacHeaders Included */
  23. #include <string.h>
  24. #include <stdarg.h>
  25. #include <stdio.h>
  26.  
  27.  
  28.                                 // Completion routine
  29. static pascal void On_completion(NMRecPtr el)
  30. {
  31.     NMRemove(el);                        // Remove the notification request from
  32.                                         // the manager's queue
  33.     el->nmRefCon = 1;                    // Mark the notification element as posted
  34. }
  35.  
  36.                                 // Create a new notification element
  37. static NMRecPtr new_element(const char * mesg)
  38. {
  39.                                     // Allocate space for the element and the string
  40.     NMRecPtr el = (NMRecPtr)NewPtr(sizeof(NMRec) + sizeof(Str255));
  41.     el->qLink = 0;
  42.     el->qType = nmType;
  43.     el->nmMark = 0;
  44.     el->nmIcon = nil;
  45.     el->nmSound = nil;                        // String is allocated right after the
  46.     el->nmStr = (unsigned char *)((char *)el + sizeof(NMRec));    // element
  47.     el->nmResp = On_completion;
  48.     el->nmRefCon = 0;
  49.     
  50.     strncpy((char *)(el->nmStr),mesg,254);
  51.     CtoPstr((char *)el->nmStr);
  52.     
  53.     return el;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
  54. }
  55.  
  56.                                 // Wait until the given element is marked as
  57.                                 // completed (nmRefCon changes its value from 0
  58.                                 // to 1).
  59.                                 // The waiting though busy is gracious enough to let
  60.                                 // other processes running.
  61. static void wait_for_completion(NMRecPtr el)
  62. {
  63.     assert( el != 0 );
  64.     while( el->nmRefCon == 0 )
  65.         sleep(10);
  66.     assert( el->nmRefCon == 1 );
  67. }
  68.  
  69.                                 // Simply check if a request is posted
  70. static Boolean check_if_posted(const NMRecPtr el)
  71. {
  72.     return el->nmRefCon == 0 ? FALSE : TRUE;
  73. }
  74.  
  75.                                 // Dispose of the element
  76. static void dispose_element(NMRecPtr el)
  77. {
  78.     assert( el != 0 );
  79.     DisposePtr((char *)el);
  80. }
  81.  
  82. /*
  83.  *----------------------------------------------------------------------------
  84.  *                Managing the queue of pending notification requests
  85.  *                    Note the queue is just a circular list
  86.  */
  87.  
  88. #define Queue_size 5
  89. static  NMRecPtr Queue[Queue_size];
  90. static  unsigned int Queue_free_slot_no = 0;
  91. static  unsigned int Queue_no_filled_slots = 0;
  92.  
  93.                                 // Enqueue the element. return FALSE if the queue
  94.                                 // is filled up
  95. static Boolean enqueue(const NMRecPtr el)
  96. {
  97.     if( Queue_no_filled_slots >= Queue_size )
  98.       return FALSE;                            // The queue is filled up
  99.     Queue[Queue_free_slot_no] = el;
  100.     Queue_no_filled_slots++;
  101.     if( ++Queue_free_slot_no >= Queue_size )    // Adjust the pointer in a circular way
  102.       Queue_free_slot_no = 0;
  103.     return TRUE;
  104. }
  105.  
  106.                                 // Return the head elememt of the queue, or 0 if the
  107.                                 // queue is empty
  108. static NMRecPtr get_head(void)
  109. {
  110.     register int index;
  111.     if( Queue_no_filled_slots == 0 )
  112.       return (NMRecPtr)0;
  113.       
  114.     assert( Queue_free_slot_no < Queue_size );
  115.     index = Queue_free_slot_no - Queue_no_filled_slots;
  116.     if( index < 0 )
  117.       index += Queue_size;
  118.     return Queue[index];
  119. }
  120.  
  121.                                 // Remove the head of the queue
  122. static void remove_head(void)
  123. {
  124.     register NMRecPtr el;
  125.     assert( Queue_no_filled_slots > 0 && Queue_no_filled_slots <= Queue_size );
  126.     el = get_head();
  127.     dispose_element(el);
  128.     Queue_no_filled_slots--;
  129. }
  130.  
  131.                                 // Check out if some request in the queue of pending
  132.                                 // request have been posted. If so, remove them
  133.                                 // from the queue.
  134.                                 // Note that we expect requests are posted in the
  135.                                 // order they enqueued, i.e. in the FIFO order
  136. static void check_queue(void)
  137. {
  138.     register NMRecPtr el;
  139.     
  140.     while( (el=get_head()) != (NMRecPtr)0 && check_if_posted(el) )
  141.       remove_head();
  142. }
  143.  
  144. /*
  145.  *----------------------------------------------------------------------------
  146.  *                            Routing modules
  147.  */
  148.  
  149. void notify_and_wait(const char * messg,...)
  150. {
  151.       va_list args;
  152.       char buffer[300];
  153.     register NMRecPtr el;
  154.  
  155.       va_start(args,messg);            // Init 'args' to the beginning of
  156.                                     // the variable length list of args
  157.     assert(strlen(messg) < sizeof(buffer)-100);
  158.       vsprintf(buffer,messg,args);
  159.       
  160.       check_queue();
  161.       el = new_element(buffer);
  162.       assert( NMInstall(el) == noErr );
  163.       wait_for_completion(el);
  164.       dispose_element(el);
  165. }
  166.  
  167.                                     // Asynchronous notification
  168. void notify(const char * messg,...)
  169. {
  170.       va_list args;
  171.       char buffer[300];
  172.     register NMRecPtr el;
  173.  
  174.       va_start(args,messg);            // Init 'args' to the beginning of
  175.                                     // the variable length list of args
  176.     assert(strlen(messg) < sizeof(buffer)-100);
  177.       vsprintf(buffer,messg,args);
  178.       
  179.       check_queue();
  180.       el = new_element(buffer);
  181.       assert( NMInstall(el) == noErr );
  182.       while( !enqueue(el) )                    // If there are too many outstanding
  183.       {                                        // elements, wait until some are posted
  184.           wait_for_completion(get_head());
  185.           check_queue();
  186.       } 
  187. }
  188.  
  189.