home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga Shareware Floppies / ma15.dms / ma15.adf / Yak / Source / handler.c < prev    next >
C/C++ Source or Header  |  1993-05-17  |  13KB  |  502 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    10    /* 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. /* for screen click-to-back */
  56. void __stdargs
  57. MyScreenToBack(struct Screen *scr)
  58. {
  59.     struct Layer *layer;
  60.     struct Screen *ns = scr->NextScreen;
  61.     struct Window *win;
  62.  
  63.     if (!ns) ns = IntuitionBase->FirstScreen;
  64.     if (ns != scr)
  65.     {
  66.         ScreenToBack(scr);
  67.  
  68.         if (scractivate && ns)
  69.         {
  70.             layer = WhichLayer(&ns->LayerInfo, ns->MouseX, ns->MouseY);
  71.             if (win = (layer ? layer->Window : NULL))
  72.                 ActivateWindow(win);
  73.             else if (ns->FirstWindow)
  74.                 ActivateWindow(ns->FirstWindow);
  75.         }
  76.     }
  77. }
  78.  
  79. /* Stub for Intuition routines - passes request on to main task.
  80.  * DO NOT CALL WHILE FORBID()ING!
  81.  * Thanks to Eddy Carroll for this.
  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. /* the input handler itself */
  326. INTERRUPT
  327. Handler(CxMsg * CxMsg, CxObj * CO)
  328. {
  329.     static struct timeval lastclick;    /* last left-button click */
  330.     static WORD apcount;        /* timer events since last mousemove */
  331.     struct InputEvent *ev;
  332.  
  333.  
  334.     ev = (struct InputEvent *) CxMsgData(CxMsg);
  335.  
  336.     if (ev->ie_Class == IECLASS_TIMER)
  337.     {
  338.     /*** AUTO-ACTIVATE/POP, SCREENBLANK, MOUSEBLANK ***/
  339.     if (!(ev->ie_Qualifier & ALL_QUALS) && autopoint && !apcount--)
  340.     {
  341.         ActivateMouseWindow(AUTO);
  342.     }
  343.  
  344.     if (blanktimeout && !--blankcount)    /* blank screen? */
  345.     {
  346.         BlankScreen();
  347.         blankcount = blanktimeout;    /* reset counter */
  348.     }            /* in case sceen opens on top */
  349.  
  350.     if (mouseblank && !--mblankcount)    /* blank mouse? */
  351.     {
  352.         mouseoff = FALSE;        /* force reblank */
  353.         TurnMouseOff();
  354.         /* in case someone else turns it on, reset counter */
  355.         mblankcount = REBLANKCOUNT;
  356.     }
  357.     }
  358.     else if ((ev->ie_Class == IECLASS_RAWKEY) && !(ev->ie_Code & IECODE_UP_PREFIX))
  359.     {
  360.     /*** MOUSEBLANK, KEYACTIVATE, KEYCLICK ***/
  361.  
  362.     blankcount = blanktimeout;    /* reset blanking countdown */
  363.     if (blanked)            /* turn off screen-blanking */
  364.         UnBlankScreen();
  365.  
  366.     if (mouseblank)
  367.         if (ev->ie_Qualifier & IEQUALIFIER_LCOMMAND)
  368.         {
  369.         /* this allows use of keyboard to move mouse */
  370.         mblankcount = mblanktimeout;
  371.             TurnMouseOn();
  372.         }
  373.         else TurnMouseOff();    /* blank the mouse */
  374.  
  375.     if (click_volume)
  376.         Signal(thistask, clicksigflag);
  377.  
  378.     if (keyactivate)            /* perform key-activate */
  379.         ActivateMouseWindow(KEY);
  380.     }
  381.     else if (ev->ie_Class == IECLASS_RAWMOUSE)
  382.     {
  383.     /*** CLICKTOFRONT/BACK, AUTOACTIVATE ***/
  384.  
  385.     /* restore screen/mouse pointer */
  386.     blankcount = blanktimeout;    /* reset blanking countdowns */
  387.     mblankcount = mblanktimeout;
  388.     if (blanked)        /* turn off screen-blanking */
  389.         UnBlankScreen();
  390.     if (mouseoff)
  391.         TurnMouseOn(); /* not needed for MB_COPPER */
  392.  
  393.     /* window/screen cycling... */
  394.     /* maybe should check for depth gadgets? nah... */
  395.     if (!(ev->ie_Qualifier & KEY_QUAL))
  396.     {
  397.         if (!(ev->ie_Qualifier & ALL_BUTTONS))
  398.         {
  399.         apcount = TIMERCOUNT;    /* reset auto-activate count */
  400.         }
  401.         else    /* a button - check out clicktofront etc. */
  402.         {
  403.         /* mustn't be Forbid()en when calling window op */
  404.         BOOL forbidden = TRUE;
  405.         Forbid();
  406.  
  407.         misspop = TRUE;
  408.         apcount = -1;    /* button - wait for move */
  409.  
  410.         if (clicktofront && ev->ie_Code == IECODE_LBUTTON)
  411.         {
  412.             if (DoubleClick(lastclick.tv_secs,
  413.                     lastclick.tv_micro,
  414.                     ev->ie_TimeStamp.tv_secs,
  415.                     ev->ie_TimeStamp.tv_micro))
  416.             {
  417.             struct Window *win = WindowUnderMouse();
  418.  
  419.             if (win && IsClickWindow(win) &&
  420.                 IsClickScreen(win->WScreen) && OkayToPop(win))
  421.             {
  422.                 Permit(), forbidden = FALSE;
  423.                 WTF(win);    /* musn't be Forbid()en here */
  424.             }
  425.             lastclick.tv_secs = 0;
  426.             lastclick.tv_micro = 0;
  427.             }
  428.             else
  429.             {
  430.             lastclick.tv_secs = ev->ie_TimeStamp.tv_secs;
  431.             lastclick.tv_micro = ev->ie_TimeStamp.tv_micro;
  432.             }
  433.         }
  434.         else if (ev->ie_Code == IECODE_RBUTTON && (ev->ie_Qualifier & IEQUALIFIER_LEFTBUTTON))
  435.         {
  436.             struct Window *win = WindowUnderMouse();
  437.  
  438.             if (win && !(win->Flags & WFLG_BACKDROP) &&
  439.             (win->NextWindow || win->WScreen->FirstWindow != win))
  440.             {
  441.             if (clicktoback && IsClickScreen(win->WScreen))
  442.             {
  443.                 Permit(), forbidden = FALSE;
  444.                 WTB(win);
  445.             }
  446.             }
  447.             else if (screencycle)
  448.             {
  449.             Permit(), forbidden = FALSE;
  450.             ev->ie_Class = IECLASS_NULL;
  451.             STB(IntuitionBase->FirstScreen);
  452.             }
  453.         }
  454.         else if (rmbactivate && ev->ie_Code == IECODE_RBUTTON)
  455.         {
  456.             Permit(), forbidden = FALSE;
  457.             ActivateMouseWindow(RMBACT);
  458.         }
  459.         if (forbidden) Permit();
  460.         }
  461.     }
  462.     }
  463.     else if (ev->ie_Class == IECLASS_DISKINSERTED)
  464.     {
  465.     blankcount = blanktimeout;    /* reset blanking countdown */
  466.     if (blanked)            /* turn off screen-blanking */
  467.         UnBlankScreen();
  468.     }
  469. }
  470.  
  471. /* close resources allocated for handler */
  472. void
  473. EndHandler()
  474. {
  475.     if (clickobj) DeleteCxObj(clickobj);
  476.     FreeAudio();
  477.     if (intuiopsigbit != -1) FreeSignal(intuiopsigbit);
  478.     if (clicksigbit != -1) FreeSignal(clicksigbit);
  479.     UnBlankScreen();
  480.     TurnMouseOn();
  481. }
  482.  
  483. /* open resources needed for handler */
  484. BOOL
  485. InitHandler()
  486. {
  487.     if (((clicksigbit = AllocSignal(-1)) != -1) &&
  488.         ((intuiopsigbit = AllocSignal(-1)) != -1) &&
  489.     AllocAudio())
  490.     {
  491.     thistask = FindTask(NULL);    /* initialize liason structure */
  492.     clicksigflag = 1 << clicksigbit;
  493.     intuiopsigflag = 1 << intuiopsigbit;
  494.  
  495.     clickobj = CxCustom(Handler, 0L);
  496.     AttachCxObj(broker, clickobj);
  497.     return TRUE;
  498.     }
  499.     EndHandler();
  500.     return FALSE;
  501. }
  502.