/*
 *  Click-Handler.c     Input Handler for ClickUpFront, which brings a
 *                      window to the front when you double-click in it.
 *
 *              Copyright (c) 1987 by Davide P. Cervone
 *  You may use this code provided this copyright notice is left intact.
 */

#include <exec/types.h>
#include <devices/inputevent.h>
#include <intuition/intuitionbase.h>

static char *version = "Click-Handler v1.0 (July 1987)";
static char *author  = "Copyright (c) 1987 by Davide P. Cervone";

extern struct Layer *WhichLayer();
extern void myHandlerStub();

#define WINDOW(layer)   ((struct Window *)((layer)->Window))
#define SCREENTOP\
   (theScreen->TopEdge << ((theScreen->ViewPort.Modes & LACE)? 0: 1))
#define ie_Secs         ie_TimeStamp.tv_secs
#define ie_Mics         ie_TimeStamp.tv_micro

long LastSecs = 0;      /* seconds field from last mouse click */
long LastMics = 0;      /* micros  field from last mouse click */
long StayMask;          /* qualifier keys that allow you to double click */
                        /* a window without bringing it to the front */


struct IntuitionBase *IntuitionBase = NULL;
struct LayersBase    *LayersBase    = NULL;
struct SysBase       *SysBase       = NULL;

/*
 *  Setup()
 *
 *  ClickUpFront calls LoadSeg() to get this handler into memory.  The segment
 *  that it gets points to this routine.  ClickUpFront calls Setup() and 
 *  passes the IntuitionBase, LayersBase and SysBase pointers that it
 *  has initialized (with OpenLibrary()).  Setup returns a pointer to
 *  the actual input handler, which ClickUpFront installs.
 */

long Setup(Ibase,Lbase,Sbase,flags)
struct IntuitionBase *Ibase;
struct LayersBase *Lbase;
struct SysBase *Sbase;
long flags;
{
   IntuitionBase = Ibase;
   LayersBase = Lbase;
   SysBase = Sbase;
   StayMask = flags;
   return((long) &myHandlerStub);
}


/*
 *  myHandler()
 *
 *  This is the input handler.  For each event in the event list:
 *  If it is a raw mouse event:
 *    if it is a left button click, then
 *      if the mouse has not moved since the last click and the user is
 *          not holding down the keys that allow windows to stay put, then
 *        if the time since the last click was less than the double click time,
 *          Find the screen where the mouse is pointing.
 *          Find the top window on the that screen.
 *          If there is one, then
 *            find the Layer in which the click occured.
 *            if that Layer's window is not already at the top,
 *              bring it to the top.
 *      Set the time since the last click to the current time.
 *    Otherwise, it was not a left button click, so
 *      ignore lift button up messages, but set the times to zero (a long time
 *         ago) if the mouse moved or the right button was clicked.
 *  If the event was a keyboard event, then set the times to zero.
 *  Ignore all other event types (timer, disk).
 *
 *  Finally, return the event list so that Intuition can do its thing.
 *
 */

struct InputEvent *myHandler(EventList,data)
struct InputEvent *EventList;
APTR data;
{
   register struct InputEvent *theEvent = EventList;
   register struct Layer  *theLayer, *topLayer;
   register struct Screen *theScreen;

   Forbid();
   while(theEvent)
   {
      switch(theEvent->ie_Class)
      {
         case IECLASS_RAWMOUSE:
            if (theEvent->ie_Code == SELECTDOWN)
            {
               if (theEvent->ie_X == 0 && theEvent->ie_Y == 0 &&
                  (theEvent->ie_Qualifier & StayMask) == 0)
               {
                  if (DoubleClick(LastSecs,LastMics,
                      theEvent->ie_Secs,theEvent->ie_Mics))
                  {
                     theScreen = IntuitionBase->FirstScreen;
                     while (theScreen && IntuitionBase->MouseY < SCREENTOP)
                        theScreen = theScreen->NextScreen;
                     if (theScreen == NULL)
                        theScreen = IntuitionBase->ActiveScreen;
                     if (theScreen != IntuitionBase->FirstScreen)
                        ScreenToFront(theScreen);

                     topLayer = theScreen->LayerInfo.top_layer;
                     while (topLayer && WINDOW(topLayer) == NULL)
                        topLayer = topLayer->back;
                     if (topLayer)
                     {
                        theLayer = WhichLayer(&(theScreen->LayerInfo),
                                   theScreen->MouseX,theScreen->MouseY);
                        if (theLayer && WINDOW(theLayer) != WINDOW(topLayer))
                           WindowToFront(WINDOW(theLayer));
                     }
                  }
               }
               LastSecs = theEvent->ie_Secs;
               LastMics = theEvent->ie_Mics;
            } else {
               if (theEvent->ie_Code != SELECTUP)
                  LastSecs = LastMics = 0;
            }
            break;

         case IECLASS_RAWKEY:
            LastSecs = LastMics = 0;
            break;
      }
      theEvent = theEvent->ie_NextEvent;
   }
   Permit();
   return(EventList);
}
