home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magazyn Amiga Shareware Floppies
/
ma15.dms
/
ma15.adf
/
Yak
/
Source
/
handler.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-17
|
13KB
|
502 lines
/*
* handler.c
*
* Routines to set up handler.
* Part of Yak.
*
* Martin W. Scott, 9/92.
*/
#include <exec/types.h>
#include <exec/exec.h>
#include <hardware/custom.h>
#include <hardware/dmabits.h>
#include <devices/console.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <libraries/commodities.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/displayinfo.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <clib/alib_protos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/layers.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/commodities.h>
#include <string.h>
#include "yak.h"
#include "beep.h"
static void __inline TurnMouseOn(void);
static void __inline TurnMouseOff(void);
static void __regargs IntuiOp(void (*routine)(APTR), APTR parameter);
static void __regargs PopToFront(struct Window *win);
static struct Window *WindowUnderMouse(void);
static BOOL __regargs StrGadgetActive(struct Window *w);
extern struct Custom __far custom;
#define TIMERCOUNT 2 /* how long mouse must stop before autopoint */
#define REBLANKCOUNT 10 /* how long to wait to reblank mouse */
void (*intui_routine)(APTR); /* for intui_op's */
APTR intui_parameter;
CxObj *clickobj;
ULONG clicksigflag, intuiopsigflag;
static BYTE clicksigbit, intuiopsigbit = -1;
static struct Task *thistask;
static BOOL misspop;
/* for screen click-to-back */
void __stdargs
MyScreenToBack(struct Screen *scr)
{
struct Layer *layer;
struct Screen *ns = scr->NextScreen;
struct Window *win;
if (!ns) ns = IntuitionBase->FirstScreen;
if (ns != scr)
{
ScreenToBack(scr);
if (scractivate && ns)
{
layer = WhichLayer(&ns->LayerInfo, ns->MouseX, ns->MouseY);
if (win = (layer ? layer->Window : NULL))
ActivateWindow(win);
else if (ns->FirstWindow)
ActivateWindow(ns->FirstWindow);
}
}
}
/* Stub for Intuition routines - passes request on to main task.
* DO NOT CALL WHILE FORBID()ING!
* Thanks to Eddy Carroll for this.
*/
#define WTB(win) IntuiOp(WindowToBack, win)
#define WTF(win) IntuiOp(WindowToFront, win)
#define WACT(win) IntuiOp((void (*)(APTR))ActivateWindow, win)
#define STB(scr) IntuiOp(MyScreenToBack, scr)
static void __regargs
IntuiOp(void (*routine)(APTR), APTR parameter)
{
BYTE oldpri = SetTaskPri(thistask, 21);
intui_routine = routine;
intui_parameter = parameter;
Signal(thistask, intuiopsigflag);
SetTaskPri(thistask, oldpri);
}
/* pattern-matching on screen/window titles */
#define IsXXXScreen(scr, pat) (scr && (!scr->Title || MatchPattern(pat, scr->Title)))
#define IsClickScreen(scr) IsXXXScreen(scr, clickscrpat)
#define IsAutoScreen(scr) IsXXXScreen(scr, autoscrpat)
#define IsXXXWindow(win, pat) (!win->Title || MatchPattern(pat, win->Title))
#define IsPopWindow(win) IsXXXWindow(win,popwinpat)
#define IsClickWindow(win) IsXXXWindow(win,clickwinpat)
#define INTERRUPT void __interrupt __saveds
/* when is a window safe to bring to front and not already at front? */
#define OkayToPop(win) (!win->ReqCount && !(win->Flags & (WFLG_MENUSTATE|WFLG_BACKDROP)) \
&& win->WLayer->ClipRect && win->WLayer->ClipRect->Next)
/* WindowToFront only if no requester, not backdrop, not already front... */
static void __regargs
PopToFront(struct Window *win)
{
/* want to avoid popping immediately after mousebutton/keyboard */
if (misspop)
misspop = FALSE;
else if (OkayToPop(win))
{
/* Does it pass pattern? */
if (IsPopWindow(win))
WTF(win);
}
}
/* modified from DMouse */
/* expects multitasking to be Forbid()en */
static struct Screen *mousescr; /* the screen under the mouse */
static struct Window *
WindowUnderMouse()
{
struct Layer *layer = NULL;
mousescr = IntuitionBase->FirstScreen;
for (; mousescr; mousescr = mousescr->NextScreen)
{
if (layer = WhichLayer(&mousescr->LayerInfo,
mousescr->MouseX, mousescr->MouseY))
break;
if (mousescr->MouseY >= mousescr->ViewPort.DyOffset)
break;
}
return (layer ? layer->Window : NULL);
}
/* does active window have an active string gadget? */
static BOOL __regargs
StrGadgetActive(struct Window * w)
{
struct Gadget *g = w->FirstGadget;
for (; g; g = g->NextGadget)
if ((g->GadgetType & STRGADGET) && (g->Flags & GFLG_SELECTED))
return TRUE;
return FALSE;
}
/* activate window under mouse */
/* context sensitive; why tells routine how to behave */
/* can be AUTO, KEY, SCREEN, RMBACT */
#define AW IntuitionBase->ActiveWindow
#define AWS IntuitionBase->ActiveWindow->WScreen
#define FS IntuitionBase->FirstScreen
#define FSW IntuitionBase->FirstScreen->FirstWindow
void __regargs
ActivateMouseWindow(BYTE why)
{
struct Window *win;
BOOL forbidden = TRUE;
Forbid();
if (win = WindowUnderMouse()) /* window exists to activate */
{
/* either window is not active or auto-activating - need to pop? */
if (win->Flags & WFLG_WINDOWACTIVE) /* already active - needs popped? */
{
if (why == AUTO && autopop && IsAutoScreen(win->WScreen))
{
Permit(), forbidden = FALSE;
PopToFront(win);
}
}
else if (why != AUTO || IsAutoScreen(win->WScreen))
{
/* window is not active, should we try to activate it? */
/* AW is IntuitionBase->ActiveWindow */
if (!AW ||
!(AW->Flags & WFLG_MENUSTATE) && /* not showing menus */
!(why == KEY && StrGadgetActive(AW))) /* no str gad active */
{
/* finally... */
Permit(), forbidden = FALSE;
/* do autopop? */
if (why == AUTO && autopop)
PopToFront(win);
if (why == KEY)
ActivateWindow(win); /* need this to avoid losing keys */
else
WACT(win); /* ...activate window */
}
}
}
else /* no window under mouse... */
{
if (mousescr && mousescr->FirstWindow &&
((why == SCREEN) || (why == RMBACT && AW && AWS != mousescr)))
{
Permit(), forbidden = FALSE;
WACT(mousescr->FirstWindow); /* ...activate window */
}
}
if (forbidden) Permit();
}
static UWORD __chip posctldata[4];
static struct SimpleSprite simplesprite = { posctldata, 0, 0, 0, 0 };
static BOOL mouseoff; /* is mouse off? (MB_SPRITES only) */
static void __inline
TurnMouseOn() /* restore mouse-pointer */
{
if (mouseblank == MB_SPRITES) /* really dirty blanking */
{ /* but guaranteed to work... */
if (mouseoff)
{
Forbid();
WaitTOF();
ON_SPRITE;
Permit();
}
}
/* else using FreeSprite solution - unblanks when needed */
mouseoff = FALSE;
}
static void __inline
TurnMouseOff() /* blank mouse-pointer */
{
if (!mouseoff) /* no point in turning it off twice... */
{
Forbid();
if (mouseblank == MB_SPRITES) {
WaitTOF();
OFF_SPRITE;
custom.spr[0].dataa = custom.spr[0].datab=0;
} else {
FreeSprite(0);
GetSprite(&simplesprite, 0);
}
Permit();
mouseoff = TRUE;
}
}
static BOOL blanked;
static struct Screen *blankscr;
/* blank display, by putting up a black screen */
/* this screen's displaymode is cloned from front screen */
void
BlankScreen()
{
ULONG modeid = INVALID_ID;
if (blankscr)
ScreenToFront(blankscr);
else
{
Forbid();
if (FS)
modeid = GetVPModeID(&(FS->ViewPort));
Permit();
if (modeid == INVALID_ID)
modeid = LORES_KEY;
if (blankscr = OpenScreenTags(NULL, SA_Depth, 1,
SA_Quiet, TRUE,
SA_Behind, TRUE,
SA_DisplayID, modeid,
TAG_DONE))
{
SetRGB4(&blankscr->ViewPort, 0, 0, 0, 0);
ScreenToFront(blankscr);
blanked = TRUE;
}
}
OFF_SPRITE; custom.spr[0].dataa = custom.spr[0].datab=0;
}
/* unblank display, i.e. close our screen */
void
UnBlankScreen()
{
if (blankscr)
CloseScreen(blankscr);
blankscr = NULL;
blanked = FALSE;
ON_SPRITE;
}
#define ALL_BUTTONS (IEQUALIFIER_LEFTBUTTON|IEQUALIFIER_RBUTTON|IEQUALIFIER_MIDBUTTON)
#define KEY_QUAL (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT \
|IEQUALIFIER_CONTROL \
|IEQUALIFIER_LALT|IEQUALIFIER_RALT \
|IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND)
#define ALL_QUALS (ALL_BUTTONS|KEY_QUAL)
/* the input handler itself */
INTERRUPT
Handler(CxMsg * CxMsg, CxObj * CO)
{
static struct timeval lastclick; /* last left-button click */
static WORD apcount; /* timer events since last mousemove */
struct InputEvent *ev;
ev = (struct InputEvent *) CxMsgData(CxMsg);
if (ev->ie_Class == IECLASS_TIMER)
{
/*** AUTO-ACTIVATE/POP, SCREENBLANK, MOUSEBLANK ***/
if (!(ev->ie_Qualifier & ALL_QUALS) && autopoint && !apcount--)
{
ActivateMouseWindow(AUTO);
}
if (blanktimeout && !--blankcount) /* blank screen? */
{
BlankScreen();
blankcount = blanktimeout; /* reset counter */
} /* in case sceen opens on top */
if (mouseblank && !--mblankcount) /* blank mouse? */
{
mouseoff = FALSE; /* force reblank */
TurnMouseOff();
/* in case someone else turns it on, reset counter */
mblankcount = REBLANKCOUNT;
}
}
else if ((ev->ie_Class == IECLASS_RAWKEY) && !(ev->ie_Code & IECODE_UP_PREFIX))
{
/*** MOUSEBLANK, KEYACTIVATE, KEYCLICK ***/
blankcount = blanktimeout; /* reset blanking countdown */
if (blanked) /* turn off screen-blanking */
UnBlankScreen();
if (mouseblank)
if (ev->ie_Qualifier & IEQUALIFIER_LCOMMAND)
{
/* this allows use of keyboard to move mouse */
mblankcount = mblanktimeout;
TurnMouseOn();
}
else TurnMouseOff(); /* blank the mouse */
if (click_volume)
Signal(thistask, clicksigflag);
if (keyactivate) /* perform key-activate */
ActivateMouseWindow(KEY);
}
else if (ev->ie_Class == IECLASS_RAWMOUSE)
{
/*** CLICKTOFRONT/BACK, AUTOACTIVATE ***/
/* restore screen/mouse pointer */
blankcount = blanktimeout; /* reset blanking countdowns */
mblankcount = mblanktimeout;
if (blanked) /* turn off screen-blanking */
UnBlankScreen();
if (mouseoff)
TurnMouseOn(); /* not needed for MB_COPPER */
/* window/screen cycling... */
/* maybe should check for depth gadgets? nah... */
if (!(ev->ie_Qualifier & KEY_QUAL))
{
if (!(ev->ie_Qualifier & ALL_BUTTONS))
{
apcount = TIMERCOUNT; /* reset auto-activate count */
}
else /* a button - check out clicktofront etc. */
{
/* mustn't be Forbid()en when calling window op */
BOOL forbidden = TRUE;
Forbid();
misspop = TRUE;
apcount = -1; /* button - wait for move */
if (clicktofront && ev->ie_Code == IECODE_LBUTTON)
{
if (DoubleClick(lastclick.tv_secs,
lastclick.tv_micro,
ev->ie_TimeStamp.tv_secs,
ev->ie_TimeStamp.tv_micro))
{
struct Window *win = WindowUnderMouse();
if (win && IsClickWindow(win) &&
IsClickScreen(win->WScreen) && OkayToPop(win))
{
Permit(), forbidden = FALSE;
WTF(win); /* musn't be Forbid()en here */
}
lastclick.tv_secs = 0;
lastclick.tv_micro = 0;
}
else
{
lastclick.tv_secs = ev->ie_TimeStamp.tv_secs;
lastclick.tv_micro = ev->ie_TimeStamp.tv_micro;
}
}
else if (ev->ie_Code == IECODE_RBUTTON && (ev->ie_Qualifier & IEQUALIFIER_LEFTBUTTON))
{
struct Window *win = WindowUnderMouse();
if (win && !(win->Flags & WFLG_BACKDROP) &&
(win->NextWindow || win->WScreen->FirstWindow != win))
{
if (clicktoback && IsClickScreen(win->WScreen))
{
Permit(), forbidden = FALSE;
WTB(win);
}
}
else if (screencycle)
{
Permit(), forbidden = FALSE;
ev->ie_Class = IECLASS_NULL;
STB(IntuitionBase->FirstScreen);
}
}
else if (rmbactivate && ev->ie_Code == IECODE_RBUTTON)
{
Permit(), forbidden = FALSE;
ActivateMouseWindow(RMBACT);
}
if (forbidden) Permit();
}
}
}
else if (ev->ie_Class == IECLASS_DISKINSERTED)
{
blankcount = blanktimeout; /* reset blanking countdown */
if (blanked) /* turn off screen-blanking */
UnBlankScreen();
}
}
/* close resources allocated for handler */
void
EndHandler()
{
if (clickobj) DeleteCxObj(clickobj);
FreeAudio();
if (intuiopsigbit != -1) FreeSignal(intuiopsigbit);
if (clicksigbit != -1) FreeSignal(clicksigbit);
UnBlankScreen();
TurnMouseOn();
}
/* open resources needed for handler */
BOOL
InitHandler()
{
if (((clicksigbit = AllocSignal(-1)) != -1) &&
((intuiopsigbit = AllocSignal(-1)) != -1) &&
AllocAudio())
{
thistask = FindTask(NULL); /* initialize liason structure */
clicksigflag = 1 << clicksigbit;
intuiopsigflag = 1 << intuiopsigbit;
clickobj = CxCustom(Handler, 0L);
AttachCxObj(broker, clickobj);
return TRUE;
}
EndHandler();
return FALSE;
}