home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 530b.lha / AMenu_v1.3 / Mon.c < prev    next >
C/C++ Source or Header  |  1991-07-03  |  7KB  |  220 lines

  1. /*********************************************************************\
  2. **                               ________________________________    **
  3. **    A n t h o n y             |________    __    __    ________|   **
  4. **                                       |  |o_|  |o_|  |            **
  5. **            T h y s s e n            __|   __    __   |__          **
  6. **                                  __|   __|  |  |  |__   |__       **
  7. **   `` Dragon Computing ! ''    __|   __|     |  |     |__   |__    **
  8. **                              |_____|        |__|        |_____|   **
  9. **                                                                   **
  10. \*********************************************************************/
  11. /*  This file has routines to allow us to 'monitor' an Intuition port
  12. **
  13. **    What happens, is that we create a port, `OurPort', and set things
  14. **  up so that GetMsg() works normally for OurPort, and the original
  15. **  port, WBPort.  However, PutMsg() to OurPort will put the new message
  16. **  on WBPort, and vice-versa.  Basically, the heads of both message
  17. **  lists are normal, but the two tails have been swapped.  Since
  18. **  GetMsg() uses the head of the list, it acts normally.  PutMsg() uses
  19. **  the tail of the list, so it acts differently.  (the sigBit and
  20. **  sigTasks have also been swapped)
  21. **
  22. **    What this means, is that anything PutMsg()'ed to the WBPort (an
  23. **  intuiMessage for the Workbench), will signal us, and we can then
  24. **  GetMsg() it.  When we are finished looking at that message, we can
  25. **  give it to WBPort by a PutMsg() to OurPort.
  26. */
  27.  
  28. #include "AMenu.h"
  29.  
  30. extern struct MsgPort   *WBReplyPort;
  31. extern int               WBMenus, WBProcesses;
  32. extern BOOL   AddMenuStrip();
  33. extern void   DelMenuStrip(), WBFree(), RunItem();
  34.  
  35. static struct MsgPort  *WBPort;
  36. static struct List     *WBMsgList;
  37. static LONG             WBSignal, OurSignal;
  38. static BYTE             OrigPri;
  39.  
  40.  
  41. /* our port */
  42. static struct MsgPort OurPort = {
  43.      {NULL, NULL, NT_MSGPORT, 0, NULL},
  44.      PA_SIGNAL, 0, NULL,
  45.      {NULL, NULL, NULL, NT_MESSAGE, 0}
  46.   };
  47.  
  48. static struct List *OurMsgList = &(OurPort.mp_MsgList);
  49.  
  50. /*-----------------------------------------------------*/
  51.  
  52. void
  53. AttachMsgPort()
  54. /* fiddle with the two ports, setting things up */
  55. {
  56.   Forbid();
  57.  
  58.     /* get the info we need */
  59.   WBPort    = M->WBWindow->UserPort;
  60.   WBMsgList = &(WBPort->mp_MsgList);
  61.   WBSignal  = WBPort->mp_SigBit;
  62.  
  63.     /* setup our port */
  64.   OurPort.mp_SigBit    = WBSignal;
  65.   OurPort.mp_SigTask   = WBPort->mp_SigTask;
  66.  
  67.     /* flip things around */
  68.   WBPort->mp_SigTask = M->Handler;
  69.   OurMsgList->lh_Head = (struct Node *)&(WBMsgList->lh_Tail);
  70.   OurMsgList->lh_TailPred = WBMsgList->lh_TailPred;
  71.   WBMsgList->lh_TailPred = (struct Node *)&(OurMsgList->lh_Head);
  72.   OurMsgList->lh_TailPred->ln_Succ = (struct Node *)&(OurMsgList->lh_Tail);
  73.  
  74.   Permit();
  75.  
  76.     /* prevent deadlocks - adjust our Prioity above that of Workbench */
  77.   OrigPri = SetTaskPri(M->Handler, OurPort.mp_SigTask->tc_Node.ln_Pri+1);
  78. }
  79.  
  80.  
  81. void
  82. DeleteMsgPort()
  83. /* Restore things the way they were before make_MsgPort()
  84. ** Note that we don't refer to winPort.  This is because we
  85. ** may have had someone else 'monitor' this port (such as MonIDCMP)
  86. ** besides us, since we attached to it.
  87. */
  88. {
  89.   register struct Message *TmpMsg;
  90.   register struct MsgPort *TmpPort;
  91.  
  92.   Forbid();
  93.     /* clean out our list */
  94.   while ((TmpMsg = GetMsg(&OurPort)) != NULL) PutMsg(&OurPort, TmpMsg);
  95.  
  96.      /* find MsgPort that OurMsgList->lh_Head belongs to */
  97.      /*      (the port we've been PutMsg'ing to)         */
  98.   TmpPort = (struct MsgPort *) (
  99.     (UBYTE*) &OurPort - (UBYTE*) &(OurPort.mp_MsgList.lh_Tail)
  100.     + (UBYTE*)OurMsgList->lh_Head);
  101.  
  102.     /* restore things */
  103.   OurMsgList->lh_Head->ln_Pred = OurMsgList->lh_TailPred;
  104.   OurMsgList->lh_TailPred->ln_Succ = OurMsgList->lh_Head;
  105.   TmpPort->mp_SigTask = OurPort.mp_SigTask;
  106.   Permit();
  107.  
  108.   SetTaskPri(M->Handler, OrigPri);    /* return prioity to normal */
  109. }
  110.  
  111.  
  112. void
  113. FinishMonitor()
  114.   /* clean up everything */
  115. {
  116.   DeleteMsgPort();
  117.   FreeSignal(OurSignal);
  118. }
  119.  
  120.  
  121. BOOL
  122. StartMonitor()
  123.   /* do all appropriate initialization of monitor */
  124. {
  125.   AttachMsgPort();
  126.     /* we need to allocate the same signal, so that it doesn't get
  127.        allocated to something else, messing us up */
  128.   OurSignal = AllocSignal(WBSignal);
  129.   if (OurSignal != WBSignal) {
  130.     FinishMonitor();
  131.     return FALSE;
  132.   }
  133.   return TRUE;
  134. }
  135.  
  136.  
  137. /* Check if Menu code is from our menu items */
  138. struct ExtMenuItem *
  139. MatchItem(Code)
  140.   USHORT Code;
  141. {
  142.   if( MENUNUM( Code ) < WBMenus )
  143.     return NULL;                 /* a workbench menu */
  144.   return (struct ExtMenuItem *) ItemAddress(M->WBWindow->MenuStrip, Code);
  145. }
  146.  
  147.  
  148. /* The actual monitor.  Just keep waiting for messages, and acting on them
  149.  * Note that if we don't use a certain IDCMP message, we PutMsg it to get
  150.  * it back to the window it was meant for.
  151.  */
  152. #define CtrlC     SIGBREAKF_CTRL_C   /* Exit   Signal */
  153. #define CtrlD     SIGBREAKF_CTRL_D   /* Update Signal */
  154. #define CtrlMask  (CtrlC|CtrlD)
  155.  
  156. void
  157. Monitor()
  158. {
  159.   register struct IntuiMessage  *Msg;
  160.   register struct ExtMenuItem   *EItem;
  161.   register ULONG                 RetMask, WaitMask, WBReplyMask;
  162.  
  163.   WBReplyMask = 1L << WBReplyPort->mp_SigBit;
  164.  
  165.   WaitMask = (1L << WBSignal) | WBReplyMask | CtrlMask;
  166.  
  167.   while( TRUE ) {
  168.     RetMask = Wait(WaitMask);
  169.  
  170.     if( RetMask & CtrlC )       /* ^C - RemoveHandler in progress */
  171.       break;
  172.  
  173.     if( RetMask & CtrlD ) {     /* ^D - Update menus */
  174.       DB( FPrintf(DBWindow, "AMenu Update\n"); )
  175.       DelMenuStrip();
  176.       DB( FPrintf(DBWindow, "  Signaling Parent ready to update\n"); )
  177.       Signal(M->Parent, (1 << M->ParentSig));
  178.       if( Wait(CtrlMask) & CtrlC )
  179.         break;     /* if ^C - RemoveHandler in progress - else continue */
  180.       DB( FPrintf(DBWindow, "  Parent Signals Update complete\n"); )
  181.       AddMenuStrip();     /* ignore return - it always does it */
  182.       continue;
  183.     }
  184.  
  185.     if( RetMask & WBReplyMask ) {     /* a WB program Replied */
  186.       register struct Message *WBMsg;
  187.       DB( FPrintf(DBWindow, "WB Program Exited -- Freeing Message\n"); )
  188.       while ((WBMsg = GetMsg(WBReplyPort)) != NULL)
  189.         WBFree(WBMsg);
  190.       continue;
  191.     }
  192.                                          /* Intercepted a WB IDCMP message */
  193.     while( Msg = (struct IntuiMessage *)GetMsg(&OurPort) ) {
  194.       switch( Msg->Class ) {
  195.       case MENUPICK:
  196.         if( EItem = MatchItem(Msg->Code) ) {
  197.             /* Found one of our menu selections */
  198.           ReplyMsg((struct Message *)Msg);   /* reply directly */
  199.           DB( FPrintf(DBWindow, "Menu selection `%s'\n",
  200.                 ((struct IntuiText *)EItem->MenuItem.ItemFill)->IText); )
  201.           RunItem(EItem);                    /* run the indicated program */
  202.         } else
  203.           PutMsg(&OurPort, (struct Message *)Msg);   /* pass on to WB */
  204.         break;
  205.       case NEWPREFS:
  206.         DB( FPrintf(DBWindow, "NewPrefs recieved - reattaching\n"); )
  207.         PutMsg(&OurPort, (struct Message *)Msg);   /* pass on to WB */
  208.          /* loop until menus detached by WB and then we reattach them */
  209.         while( !AddMenuStrip() )
  210.           Delay(30);
  211.         DB( FPrintf(DBWindow, "-- DONE\n"); )
  212.         break;
  213.       default:
  214.         PutMsg(&OurPort, (struct Message *)Msg);   /* pass on to WB */
  215.       }
  216.     }
  217.   }
  218. }
  219.  
  220.