home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / commodities / yak / source / handler.c < prev    next >
C/C++ Source or Header  |  1993-04-22  |  13KB  |  504 lines

  1. /*
  2.  * handler.c
  3.  *
  4.  * Routines to set up handler.
  5.  * Part of Yak.
  6.  *
  7.  * Martin W. Scott, 9/92.
  8.  */
  9. #include <exec/types.h>
  10. #include <exec/exec.h>
  11. #include <hardware/custom.h>
  12. #include <hardware/dmabits.h>
  13. #include <devices/console.h>
  14. #include <devices/input.h>
  15. #include <devices/inputevent.h>
  16. #include <libraries/commodities.h>
  17. #include <graphics/gfxbase.h>
  18. #include <graphics/gfxmacros.h>
  19. #include <graphics/displayinfo.h>
  20. #include <intuition/intuition.h>
  21. #include <intuition/intuitionbase.h>
  22. #include <clib/alib_protos.h>
  23. #include <proto/exec.h>
  24. #include <proto/dos.h>
  25. #include <proto/layers.h>
  26. #include <proto/graphics.h>
  27. #include <proto/intuition.h>
  28. #include <proto/commodities.h>
  29. #include <string.h>
  30.  
  31. #include "yak.h"
  32. #include "beep.h"
  33.  
  34. static void __inline TurnMouseOn(void);
  35. static void __inline TurnMouseOff(void);
  36. static void __regargs IntuiOp(void (*routine)(APTR), APTR parameter);
  37. static void __regargs PopToFront(struct Window *win);
  38. static struct Window *WindowUnderMouse(void);
  39. static BOOL __regargs StrGadgetActive(struct Window *w);
  40.  
  41. extern struct Custom __far custom;
  42.  
  43. #define TIMERCOUNT    2    /* how long mouse must stop before autopoint */
  44. #define REBLANKCOUNT    20    /* how long to wait to reblank mouse */
  45.  
  46. void (*intui_routine)(APTR);    /* for intui_op's */
  47. APTR intui_parameter;
  48. CxObj *clickobj;
  49. ULONG clicksigflag, intuiopsigflag;
  50. static BYTE clicksigbit, intuiopsigbit = -1;
  51. static struct Task *thistask;
  52. static BOOL misspop;
  53.  
  54.  
  55. /* Stub for Intuition routines - passes request on to main task.
  56.  * DO NOT CALL WHILE FORBID()ING!
  57.  * Thanks to Eddy Carroll for this.
  58.  */
  59.  
  60. /* for screen click-to-back */
  61. void __stdargs
  62. MyScreenToBack(struct Screen *scr)
  63. {
  64.     struct Layer *layer;
  65.     struct Screen *ns = scr->NextScreen;
  66.     struct Window *win;
  67.  
  68.     if (!ns) ns = IntuitionBase->FirstScreen;
  69.     if (ns != scr)
  70.     {
  71.         ScreenToBack(scr);
  72.  
  73.         if (scractivate && ns)
  74.         {
  75.             layer = WhichLayer(&ns->LayerInfo, ns->MouseX, ns->MouseY);
  76.             if (win = (layer ? layer->Window : NULL))
  77.                 ActivateWindow(win);
  78.             else if (ns->FirstWindow)
  79.                 ActivateWindow(ns->FirstWindow);
  80.         }
  81.     }
  82. }
  83.  
  84. #define WTB(win)    IntuiOp(WindowToBack, win)
  85. #define WTF(win)    IntuiOp(WindowToFront, win)
  86. #define WACT(win)    IntuiOp((void (*)(APTR))ActivateWindow, win)
  87. #define STB(scr)    IntuiOp(MyScreenToBack, scr)
  88.  
  89. static void __regargs
  90. IntuiOp(void (*routine)(APTR), APTR parameter)
  91. {
  92.     BYTE oldpri = SetTaskPri(thistask, 21);
  93.  
  94.     intui_routine = routine;
  95.     intui_parameter = parameter;
  96.     Signal(thistask, intuiopsigflag);
  97.     SetTaskPri(thistask, oldpri);
  98. }
  99.  
  100. /* pattern-matching on screen/window titles */
  101. #define IsXXXScreen(scr, pat)    (scr && (!scr->Title || MatchPattern(pat, scr->Title)))
  102. #define IsClickScreen(scr)    IsXXXScreen(scr, clickscrpat)
  103. #define IsAutoScreen(scr)    IsXXXScreen(scr, autoscrpat)
  104. #define IsXXXWindow(win, pat)    (!win->Title || MatchPattern(pat, win->Title))
  105. #define IsPopWindow(win)    IsXXXWindow(win,popwinpat)
  106. #define IsClickWindow(win)    IsXXXWindow(win,clickwinpat)
  107.  
  108. #define INTERRUPT void __interrupt __saveds
  109.  
  110. /* when is a window safe to bring to front and not already at front? */
  111. #define OkayToPop(win)    (!win->ReqCount && !(win->Flags & (WFLG_MENUSTATE|WFLG_BACKDROP)) \
  112.              && win->WLayer->ClipRect && win->WLayer->ClipRect->Next)
  113.  
  114. /* WindowToFront only if no requester, not backdrop, not already front... */
  115. static void __regargs
  116. PopToFront(struct Window *win)
  117. {
  118.     /* want to avoid popping immediately after mousebutton/keyboard */
  119.     if (misspop)
  120.     misspop = FALSE;
  121.     else if (OkayToPop(win))
  122.     {
  123.     /* Does it pass pattern? */
  124.     if (IsPopWindow(win))
  125.         WTF(win);
  126.     }
  127. }
  128.  
  129. /* modified from DMouse */
  130. /* expects multitasking to be Forbid()en */
  131.  
  132. static struct Screen *mousescr;        /* the screen under the mouse */
  133.  
  134. static struct Window *
  135. WindowUnderMouse()
  136. {
  137.     struct Layer *layer = NULL;
  138.  
  139.     mousescr = IntuitionBase->FirstScreen;
  140.     for (; mousescr; mousescr = mousescr->NextScreen)
  141.     {
  142.     if (layer = WhichLayer(&mousescr->LayerInfo,
  143.                    mousescr->MouseX, mousescr->MouseY))
  144.         break;
  145.     if (mousescr->MouseY >= mousescr->ViewPort.DyOffset)
  146.         break;
  147.     }
  148.  
  149.     return (layer ? layer->Window : NULL);
  150. }
  151.  
  152. /* does active window have an active string gadget? */
  153. static BOOL __regargs
  154. StrGadgetActive(struct Window * w)
  155. {
  156.     struct Gadget *g = w->FirstGadget;
  157.  
  158.     for (; g; g = g->NextGadget)
  159.     if ((g->GadgetType & STRGADGET) && (g->Flags & GFLG_SELECTED))
  160.         return TRUE;
  161.     return FALSE;
  162. }
  163.  
  164. /* activate window under mouse */
  165. /* context sensitive; why tells routine how to behave */
  166. /* can be AUTO, KEY, SCREEN, RMBACT */
  167. #define AW    IntuitionBase->ActiveWindow
  168. #define AWS    IntuitionBase->ActiveWindow->WScreen
  169. #define FS    IntuitionBase->FirstScreen
  170. #define FSW    IntuitionBase->FirstScreen->FirstWindow
  171. void __regargs
  172. ActivateMouseWindow(BYTE why)
  173. {
  174.     struct Window *win;
  175.     BOOL forbidden = TRUE;
  176.  
  177.     Forbid();
  178.  
  179.     if (win = WindowUnderMouse())    /* window exists to activate */
  180.     {
  181.     /* either window is not active or auto-activating - need to pop? */
  182.  
  183.     if (win->Flags & WFLG_WINDOWACTIVE)    /* already active - needs popped? */
  184.     {
  185.         if (why == AUTO && autopop && IsAutoScreen(win->WScreen))
  186.         {
  187.                 Permit(), forbidden = FALSE;
  188.             PopToFront(win);
  189.         }
  190.     }
  191.     else if (why != AUTO || IsAutoScreen(win->WScreen))
  192.     {
  193.         /* window is not active, should we try to activate it? */
  194.  
  195.         /* AW is IntuitionBase->ActiveWindow */
  196.         if (!AW ||
  197.             !(AW->Flags & WFLG_MENUSTATE) &&        /* not showing menus */
  198.             !(why == KEY && StrGadgetActive(AW)))    /* no str gad active */
  199.         {
  200.             /* finally... */
  201.             Permit(), forbidden = FALSE;
  202.  
  203.             /* do autopop? */
  204.             if (why == AUTO && autopop)
  205.             PopToFront(win);
  206.  
  207.             if (why == KEY)        
  208.             ActivateWindow(win);    /* need this to avoid losing keys */
  209.             else
  210.             WACT(win);        /* ...activate window */
  211.         }
  212.     }
  213.     }
  214.     else /* no window under mouse... */
  215.     {
  216.     if (mousescr && mousescr->FirstWindow &&
  217.         ((why == SCREEN) || (why == RMBACT && AW && AWS != mousescr)))
  218.     {
  219.         Permit(), forbidden = FALSE;
  220.         WACT(mousescr->FirstWindow);    /* ...activate window */
  221.     }
  222.     }
  223.     if (forbidden) Permit();
  224. }
  225.  
  226.  
  227. static UWORD __chip posctldata[4];
  228. static struct SimpleSprite simplesprite = { posctldata, 0, 0, 0, 0 };
  229. static BOOL mouseoff;    /* is mouse off? (MB_SPRITES only) */
  230.  
  231. static void __inline
  232. TurnMouseOn()    /* restore mouse-pointer */
  233. {
  234.     if (mouseblank == MB_SPRITES)        /* really dirty blanking */
  235.     {                    /* but guaranteed to work... */
  236.         if (mouseoff)
  237.         {
  238.             Forbid();
  239.               WaitTOF();
  240.               ON_SPRITE;
  241.             Permit();
  242.         }
  243.     }
  244.     /* else using FreeSprite solution - unblanks when needed */
  245.     mouseoff = FALSE;
  246. }
  247.  
  248. static void __inline
  249. TurnMouseOff()        /* blank mouse-pointer */
  250. {
  251.     if (!mouseoff)    /* no point in turning it off twice... */
  252.     {
  253.         Forbid();
  254.  
  255.         if (mouseblank == MB_SPRITES) {
  256.             WaitTOF();
  257.             OFF_SPRITE;
  258.             custom.spr[0].dataa = custom.spr[0].datab=0;
  259.         } else {
  260.             FreeSprite(0);
  261.             GetSprite(&simplesprite, 0);
  262.         }
  263.         
  264.         Permit();
  265.  
  266.         mouseoff = TRUE;
  267.     }
  268. }
  269.  
  270.  
  271. static BOOL blanked;
  272. static struct Screen *blankscr;
  273.  
  274. /* blank display, by putting up a black screen */
  275. /* this screen's displaymode is cloned from front screen */
  276. void
  277. BlankScreen()
  278. {
  279.     ULONG modeid = INVALID_ID;
  280.  
  281.     if (blankscr)
  282.     ScreenToFront(blankscr);
  283.     else
  284.     {
  285.     Forbid();
  286.     if (FS)
  287.         modeid = GetVPModeID(&(FS->ViewPort));
  288.     Permit();
  289.     if (modeid == INVALID_ID)
  290.         modeid = LORES_KEY;
  291.  
  292.         if (blankscr = OpenScreenTags(NULL, SA_Depth, 1,
  293.                        SA_Quiet, TRUE,
  294.                        SA_Behind, TRUE,
  295.                        SA_DisplayID, modeid,
  296.                        TAG_DONE))
  297.     {
  298.         SetRGB4(&blankscr->ViewPort, 0, 0, 0, 0);
  299.         ScreenToFront(blankscr);
  300.         blanked = TRUE;
  301.     }
  302.     }
  303.     OFF_SPRITE; custom.spr[0].dataa = custom.spr[0].datab=0;
  304. }
  305.  
  306. /* unblank display, i.e. close our screen */
  307. void
  308. UnBlankScreen()
  309. {
  310.     if (blankscr)
  311.     CloseScreen(blankscr);
  312.     blankscr = NULL;
  313.     blanked = FALSE;
  314.     ON_SPRITE;
  315. }
  316.  
  317.  
  318. #define ALL_BUTTONS    (IEQUALIFIER_LEFTBUTTON|IEQUALIFIER_RBUTTON|IEQUALIFIER_MIDBUTTON)
  319. #define KEY_QUAL    (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT \
  320.             |IEQUALIFIER_CONTROL \
  321.             |IEQUALIFIER_LALT|IEQUALIFIER_RALT \
  322.             |IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND)
  323. #define ALL_QUALS    (ALL_BUTTONS|KEY_QUAL)
  324.  
  325. #define sqr(x) ((x)*(x))
  326.  
  327. /* the input handler itself */
  328. INTERRUPT
  329. Handler(CxMsg * CxMsg, CxObj * CO)
  330. {
  331.     static struct timeval lastclick;    /* last left-button click */
  332.     static WORD apcount;        /* timer events since last mousemove */
  333.     struct InputEvent *ev;
  334.  
  335.  
  336.     ev = (struct InputEvent *) CxMsgData(CxMsg);
  337.  
  338.     if (ev->ie_Class == IECLASS_TIMER)
  339.     {
  340.     /*** AUTO-ACTIVATE/POP, SCREENBLANK, MOUSEBLANK ***/
  341.     if (!(ev->ie_Qualifier & ALL_QUALS) && autopoint && !apcount--)
  342.     {
  343.         ActivateMouseWindow(AUTO);
  344.     }
  345.  
  346.     if (blanktimeout && !--blankcount)    /* blank screen? */
  347.     {
  348.         BlankScreen();
  349.         blankcount = blanktimeout;    /* reset counter */
  350.     }            /* in case sceen opens on top */
  351.  
  352.     if (mouseblank && !--mblankcount)    /* blank mouse? */
  353.     {
  354.         mouseoff = FALSE;        /* force reblank */
  355.         TurnMouseOff();
  356.         /* in case someone else turns it on, reset counter */
  357.         mblankcount = REBLANKCOUNT;
  358.     }
  359.     }
  360.     else if ((ev->ie_Class == IECLASS_RAWKEY) && !(ev->ie_Code & IECODE_UP_PREFIX))
  361.     {
  362.     /*** MOUSEBLANK, KEYACTIVATE, KEYCLICK ***/
  363.  
  364.     blankcount = blanktimeout;    /* reset blanking countdown */
  365.     if (blanked)            /* turn off screen-blanking */
  366.         UnBlankScreen();
  367.  
  368.     if (mouseblank)
  369.         if (ev->ie_Qualifier & IEQUALIFIER_LCOMMAND)
  370.         {
  371.         /* this allows use of keyboard to move mouse */
  372.         mblankcount = mblanktimeout;
  373.             TurnMouseOn();
  374.         }
  375.         else TurnMouseOff();    /* blank the mouse */
  376.  
  377.     if (click_volume)
  378.         Signal(thistask, clicksigflag);
  379.  
  380.     if (keyactivate)            /* perform key-activate */
  381.         ActivateMouseWindow(KEY);
  382.     }
  383.     else if (ev->ie_Class == IECLASS_RAWMOUSE)
  384.     {
  385.     /*** CLICKTOFRONT/BACK, AUTOACTIVATE ***/
  386.  
  387.     /* restore screen/mouse pointer */
  388.     blankcount = blanktimeout;    /* reset blanking countdowns */
  389.     mblankcount = mblanktimeout;
  390.     if (blanked)        /* turn off screen-blanking */
  391.         UnBlankScreen();
  392.     if (mouseoff)
  393.         TurnMouseOn(); /* not needed for MB_COPPER */
  394.  
  395.     /* window/screen cycling... */
  396.     /* maybe should check for depth gadgets? nah... */
  397.     if (!(ev->ie_Qualifier & KEY_QUAL))
  398.     {
  399.         if (!(ev->ie_Qualifier & ALL_BUTTONS))
  400.         {
  401.         apcount = TIMERCOUNT;    /* reset auto-activate count */
  402.         }
  403.         else    /* a button - check out clicktofront etc. */
  404.         {
  405.         /* mustn't be Forbid()en when calling window op */
  406.         BOOL forbidden = TRUE;
  407.         Forbid();
  408.  
  409.         misspop = TRUE;
  410.         apcount = -1;    /* button - wait for move */
  411.  
  412.         if (clicktofront && ev->ie_Code == IECODE_LBUTTON)
  413.         {
  414.             if (DoubleClick(lastclick.tv_secs,
  415.                     lastclick.tv_micro,
  416.                     ev->ie_TimeStamp.tv_secs,
  417.                     ev->ie_TimeStamp.tv_micro))
  418.             {
  419.             struct Window *win = WindowUnderMouse();
  420.  
  421.             if (win && IsClickWindow(win) &&
  422.                 IsClickScreen(win->WScreen) && OkayToPop(win))
  423.             {
  424.                 Permit(), forbidden = FALSE;
  425.                 WTF(win);    /* musn't be Forbid()en here */
  426.             }
  427.             lastclick.tv_secs = 0;
  428.             lastclick.tv_micro = 0;
  429.             }
  430.             else
  431.             {
  432.             lastclick.tv_secs = ev->ie_TimeStamp.tv_secs;
  433.             lastclick.tv_micro = ev->ie_TimeStamp.tv_micro;
  434.             }
  435.         }
  436.         else if (ev->ie_Code == IECODE_RBUTTON && (ev->ie_Qualifier & IEQUALIFIER_LEFTBUTTON))
  437.         {
  438.             struct Window *win = WindowUnderMouse();
  439.  
  440.             if (win && !(win->Flags & WFLG_BACKDROP) &&
  441.             (win->NextWindow || win->WScreen->FirstWindow != win))
  442.             {
  443.             if (clicktoback && IsClickScreen(win->WScreen) /*&& IsClickWindow(win)*/)
  444.             {
  445.                 Permit(), forbidden = FALSE;
  446.                 WTB(win);
  447.             }
  448.             }
  449.             else if (screencycle)
  450.             {
  451.             Permit(), forbidden = FALSE;
  452.             ev->ie_Class = IECLASS_NULL;
  453.             STB(IntuitionBase->FirstScreen);
  454.             }
  455.         }
  456.         else if (rmbactivate && ev->ie_Code == IECODE_RBUTTON)
  457.         {
  458.             Permit(), forbidden = FALSE;
  459.             ActivateMouseWindow(RMBACT);
  460.         }
  461.         if (forbidden) Permit();
  462.         }
  463.     }
  464.     }
  465.     else if (ev->ie_Class == IECLASS_DISKINSERTED)
  466.     {
  467.     blankcount = blanktimeout;    /* reset blanking countdown */
  468.     if (blanked)            /* turn off screen-blanking */
  469.         UnBlankScreen();
  470.     }
  471. }
  472.  
  473. /* close resources allocated for handler */
  474. void
  475. EndHandler()
  476. {
  477.     if (clickobj) DeleteCxObj(clickobj);
  478.     FreeAudio();
  479.     if (intuiopsigbit != -1) FreeSignal(intuiopsigbit);
  480.     if (clicksigbit != -1) FreeSignal(clicksigbit);
  481.     UnBlankScreen();
  482.     TurnMouseOn();
  483. }
  484.  
  485. /* open resources needed for handler */
  486. BOOL
  487. InitHandler()
  488. {
  489.     if (((clicksigbit = AllocSignal(-1)) != -1) &&
  490.         ((intuiopsigbit = AllocSignal(-1)) != -1) &&
  491.     AllocAudio())
  492.     {
  493.     thistask = FindTask(NULL);    /* initialize liason structure */
  494.     clicksigflag = 1 << clicksigbit;
  495.     intuiopsigflag = 1 << intuiopsigbit;
  496.  
  497.     clickobj = CxCustom(Handler, 0L);
  498.     AttachCxObj(broker, clickobj);
  499.     return TRUE;
  500.     }
  501.     EndHandler();
  502.     return FALSE;
  503. }
  504.