afb@j.cc.purdue.edu (Matthew Bradburn) (12/07/87)
This is an update to the ClickToFront utility by Davide P. Cervone,
which brings a window or screen to the front or pushes it to the
back when the user double clicks in that window or screen. Docs
in comp.binaries.amiga.
The author:
Davide P. Cervone
dpvc@tut.cc.rochester.edu
dpvc@ur-tut.UUCP
DPVC@UORDBV.BITNET
The poster:
Matthew Bradburn
ARPA: afb@j.cc.purdue.edu
UUCP: j.cc.purdue.edu!afb
BITNET: bradburn@purccvm.bitnet
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# Click-Handler.c
# ClickUpFront.c
# Click-Handler.lnk
# ClickUpFront.lnk
# HandlerStub.a
# This archive created: Sun Dec 6 20:50:52 1987
# By: Matthew Bradburn (Purdue University)
echo shar: extracting Click-Handler.c '(7244 characters)'
cat << \SHAR_EOF > Click-Handler.c
/*
* 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 v2.1 (October 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 TOPLAYER(screen) ((screen)->LayerInfo.top_layer)
#define ie_Secs ie_TimeStamp.tv_secs
#define ie_Mics ie_TimeStamp.tv_micro
static UBYTE LastCode = 0; /* the last ie_Code for a button event */
static long LastSecs = 0; /* seconds field from last mouse click */
static long LastMics = 0; /* micros field from last mouse click */
static long StayMask; /* qualifier keys that allow you to 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.
*/
static 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:
* Ignore button-up events,
* For button down events, if it is the same as the last button, and
* the mouse has not moved, and the button was a double click, then
* Find the active window and screen (where the button press occured)
* for SELECTDOWN buttons:
* If the screen is not the first one, then bring it to the front.
* If a window is selected, then find the top layer with a window.
* If the window where the click ocurred is not the top, and
* the stay-put qualifier key is not pressed, then
* bring the window to the front.
* for MENUDOWN buttons:
* If a window is selected, and the window is not the bottom window
* already, and the window below it is not a backdrop window, then
* if the selected window has no double-menu requester and
* the stay-put qualifier is not present (if there IS a
* DM request and the stay-put qualifier IS present), then
* send the window to the back.
* change the event into a mouse move with zero offsets
* (that is, remove one of the right button clicks).
* otherwise (there is no window, or it is already at the bottom,
* or the one below is a backdrop), then
* find the first window on the next screen and activate it.
* Send the active screen to the back.
* Otherwise (the mouse was moved, or it was not a double click, etc.)
* record this click and the time it ocurred.
* For mouse moves, clear the last code (ie, don't match a double click)
* 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 Window *theWindow;
register struct Screen *theScreen;
register struct Layer *topLayer;
Forbid();
while(theEvent)
{
switch(theEvent->ie_Class)
{
case IECLASS_RAWMOUSE:
if ((theEvent->ie_Code & IECODE_UP_PREFIX) == 0)
{
if (theEvent->ie_Code == LastCode &&
theEvent->ie_X == 0 && theEvent->ie_Y == 0 &&
DoubleClick(LastSecs,LastMics,
theEvent->ie_Secs,theEvent->ie_Mics))
{
theWindow = IntuitionBase->ActiveWindow;
theScreen = IntuitionBase->ActiveScreen;
switch(LastCode)
{
case SELECTDOWN:
if (theScreen != IntuitionBase->FirstScreen)
ScreenToFront(theScreen);
if (theWindow)
{
topLayer = TOPLAYER(theScreen);
while (topLayer && WINDOW(topLayer) == NULL)
topLayer = topLayer->back;
if (theWindow != WINDOW(topLayer) &&
(theEvent->ie_Qualifier & StayMask) == 0)
WindowToFront(theWindow);
}
break;
case MENUDOWN:
if (theWindow && theWindow->WLayer->back &&
(theWindow->Flags & BACKDROP) == 0 &&
(theWindow->WLayer->back->Flags &
LAYERBACKDROP) == 0)
{
if (theWindow && (theWindow->DMRequest == NULL) ==
((theEvent->ie_Qualifier & StayMask) == 0))
{
WindowToBack(theWindow);
theEvent->ie_Code = IECODE_NOBUTTON;
theEvent->ie_X = theEvent->ie_Y = 0;
}
} else {
if (theScreen->NextScreen)
{
topLayer = TOPLAYER(theScreen->NextScreen);
while (topLayer && WINDOW(topLayer) == NULL)
topLayer = topLayer->back;
if (topLayer && WINDOW(topLayer))
ActivateWindow(WINDOW(topLayer));
ScreenToBack(theScreen);
}
}
break;
}
LastCode = 0;
} else {
LastCode = theEvent->ie_Code;
LastSecs = theEvent->ie_Secs;
LastMics = theEvent->ie_Mics;
}
} else {
if (theEvent->ie_Code == IECODE_NOBUTTON) LastCode = 0;
}
break;
case IECLASS_RAWKEY:
LastSecs = LastMics = 0;
break;
}
theEvent = theEvent->ie_NextEvent;
}
Permit();
return(EventList);
}
SHAR_EOF
if test 7244 -ne "`wc -c Click-Handler.c`"
then
echo shar: error transmitting Click-Handler.c '(should have been 7244 characters)'
fi
echo shar: extracting ClickUpFront.c '(9317 characters)'
cat << \SHAR_EOF > ClickUpFront.c
/*
* ClickUpFront.c Brings a window to the front when you double-click
* in it (unless specified qualifier keys are also pressed).
*
* Copyright (c) 1987 by Davide P. Cervone
* You may use this code provided this copyright notice is left intact.
*/
#include <exec/types.h>
#include <libraries/dos.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <devices/input.h>
#include <devices/inputevent.h>
static char *program = "ClickUpFront";
static char *version = "v1.0";
static char *date = "July 1987";
static char *author = "Copyright (c) 1987 by Davide P. Cervone";
static char *PortName = "ClickUpFrontPort";
static char *handler = "L:Click-Handler"; /* the handler file */
#define HANDLER &(handler[2]) /* without the "L:" */
#define STAYMASK (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)
/*
* This is the structure that holds the handler information between calls
* to ClickUpFront. We create a named, public message-port that points to
* an instance of this structure so that we can find this information
* when we are asked to remove the handler. The PortName is stored here
* (NamedPort->mp_Node.ln_Name uses this area for it's name). The other
* data are what we need in order to remove the handler and clean up properly.
*/
struct HandlerBlock
{
char *PortName; /* name of the public, named message-port */
struct Interrupt Handler; /* the handler added to the handler chain */
struct IntuitionBase *Ibase; /* library base used by the handler */
struct LayersBase *Lbase; /* library base used by the handler */
long Segment; /* pointer from LoadSeg() */
};
#define HANDLERINFOSIZE sizeof(struct HandlerBlock)
#define NAMESIZE (strlen(PortName)+1)
extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStdIO();
extern struct MsgPort *FindPort(), *CreatePort();
extern APTR AllocMem();
extern long LoadSeg();
#define INTUITION_REV 0L
#define LAYERS_REV 0L
struct IntuitionBase *IntuitionBase = NULL;
struct LayersBase *LayersBase = NULL;
extern struct SysBase *SysBase;
struct MsgPort *InputPort = NULL; /* Port used to talk to Input.Device */
struct IOStdReq *InputBlock = NULL; /* request block used with Input.Device */
LONG InputDevice = 0; /* flag whether Input.Device is open */
struct MsgPort *NamedPort = NULL; /* holds info needed to remove handler */
struct HandlerBlock *HandlerInfo = NULL; /* holds info stored in NamedPort */
/*
* DoExit()
*
* General purpose exit routine. If 's' is not NULL, then print an
* error message with up to three parameters. Free any memory, close
* any open device, delete any ports, close any libraries, etc.
*/
void DoExit(s,x1,x2,x3)
char *s, *x1, *x2, *x3;
{
long status = RETURN_OK;
if (s != NULL)
{
printf(s,x1,x2,x3);
printf("\n");
status = RETURN_ERROR;
}
if (InputDevice) CloseDevice(InputBlock);
if (InputBlock) DeleteStdIO(InputBlock);
if (InputPort) DeletePort(InputPort);
if (NamedPort) DeletePort(NamedPort);
if (HandlerInfo)
{
if (HandlerInfo->PortName) FreeMem(HandlerInfo->PortName,NAMESIZE);
FreeMem(HandlerInfo,HANDLERINFOSIZE);
}
if (IntuitionBase) CloseLibrary(IntuitionBase);
if (LayersBase) CloseLibrary(LayersBase);
exit(status);
}
/*
* CheckLibOpen()
*
* General library open routine. It opens a library and sets a pointer
* to it. It checks that the library was openned successfully.
*/
void CheckLibOpen(lib,name,rev)
APTR *lib;
char *name;
int rev;
{
extern APTR OpenLibrary();
if ((*lib = OpenLibrary(name,(LONG)rev)) == NULL)
DoExit("Can't open '%s'\n",name);
}
/*
* Macros that make memory allocation easier.
*/
#define NEW(s,var) (var = (struct s *)New("var",sizeof(struct s)))
#define NEWCHAR(var,s) (var = (char *)New("var",s))
/*
* New()
*
* Allocate public memory of a given size and set it to all zeros. If there
* is not enough memory, then exit with an error, otherwise return the
* pointer to the newly allocated memory.
*/
APTR New(name,size)
char *name;
int size;
{
APTR ptr;
if ((ptr = AllocMem(size,MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
DoExit("Can't Get Memory for '%s'");
return(ptr);
}
/*
* TellInputDevice()
*
* Create a port and I/O block, and open the input device. Set up the
* I/O block to add or remove the input handler, and send the request
* to the input device. Finally, close the device and delete the
* I/O block and port.
*/
void TellInputDevice(function)
int function;
{
long status;
if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port");
if ((InputBlock = CreateStdIO(InputPort)) == NULL)
DoExit("Can't Create Standard IO Block");
InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
if (InputDevice == FALSE) DoExit("Can't Open 'input.device'");
InputBlock->io_Command = (long) function;
InputBlock->io_Data = (APTR) &(HandlerInfo->Handler);
if (status = DoIO(InputBlock)) DoExit("Error from DoIO: %ld",status);
CloseDevice(InputBlock);
DeleteStdIO(InputBlock);
DeletePort(InputPort);
}
/*
* CreateHandler()
*
* Open the libraries needed by the input handler and store their locations
* in the HandlerInfo structure (so we can close them later). Try to
* LoadSeg() the handler. If it is not in the current directory, try the
* L: directory. Exit with an error if the handler can't be found.
* Convert the segment pointer into a pointer to the Setup routine (the
* first routine in the handler executable). Call Setup() and pass it
* the pointers to the libraries that it will need to use. Setup() returns
* a pointer to the actual handler routine that should be added into the
* input handler chain. Store this in the HandlerInfo structure so we
* can use it to remove the handler later. Set the handler priority to
* 51 so that it is ahead of Intuition.
*
* Finally, add the handler in the chain and tell the user that the
* handler has been installed.
*/
void CreateHandler(argc,argv)
int argc;
char **argv;
{
long (*Setup)();
long flags = STAYMASK;
CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV);
if (argc > 1) sscanf(argv[1],"%lx",&flags);
HandlerInfo->Ibase = IntuitionBase;
HandlerInfo->Lbase = LayersBase;
if ((HandlerInfo->Segment = LoadSeg(HANDLER)) == NULL)
if ((HandlerInfo->Segment = LoadSeg(handler)) == NULL)
DoExit("Can't Load '%s'",handler);
Setup = (long (*)()) ((HandlerInfo->Segment << 2) + 4);
HandlerInfo->Handler.is_Code =
(void (*)()) ((*Setup)(IntuitionBase,LayersBase,SysBase,flags));
HandlerInfo->Handler.is_Node.ln_Pri = 51;
TellInputDevice(IND_ADDHANDLER);
printf("%s %s (%s) Installed\n",program,version,date);
}
/*
* Delete Handler()
*
* Retreive the library pointers fro mthe HandlerInfo structure, where
* we stored them when we originally installed the handler, then remove
* the handler from the input handler chain. Tell the user that the
* handler is gone, and then close the libraries that are no longer needed.
*/
void DeleteHandler()
{
IntuitionBase = HandlerInfo->Ibase;
LayersBase = HandlerInfo->Lbase;
TellInputDevice(IND_REMHANDLER);
UnLoadSeg(HandlerInfo->Segment);
printf("%s Removed\n",program);
CloseLibrary(IntuitionBase);
CloseLibrary(LayersBase);
}
/*
* main()
*
* Check if a message port with our name already exists.
* If not, then the handler is not already installed, so:
* Allocate a new HandlerInfo structure and initialize the port name.
* Create a public, named message-port (we will look for this the next
* time ClickUpFront is called).
* Make the message port point to the HandlerInfo structure so we
* can use it later when the user asks us to remove the handler.
* Note that the port is not actually used for putting and getting
* messages, so the Task field is never used, so we can take it for
* our own uses.
* Finally, add the input handler into the chain.
* Otherwise, the port exists, so ClickUpFront already is installed:
* Retreive the HandlerInfo poiner from the port, and remove the
* handler from the input handler chain.
* Free the memory used by the HandlerInfo, and delete the message port.
*/
void main(argc,argv)
int argc;
char **argv;
{
NamedPort = FindPort(PortName);
if (NamedPort == NULL)
{
NEW(HandlerBlock,HandlerInfo);
NEWCHAR(HandlerInfo->PortName,NAMESIZE);
strcpy(HandlerInfo->PortName,PortName);
if ((NamedPort = CreatePort(HandlerInfo->PortName,0)) == NULL)
DoExit("Can't Create Message Port '%s'",PortName);
NamedPort->mp_SigTask = (struct Task *)HandlerInfo;
CreateHandler(argc,argv);
} else {
HandlerInfo = (struct HandlerBlock *)(NamedPort->mp_SigTask);
DeleteHandler();
FreeMem(HandlerInfo->PortName,NAMESIZE);
FreeMem(HandlerInfo,HANDLERINFOSIZE);
DeletePort(NamedPort);
}
}
SHAR_EOF
if test 9317 -ne "`wc -c ClickUpFront.c`"
then
echo shar: error transmitting ClickUpFront.c '(should have been 9317 characters)'
fi
echo shar: extracting Click-Handler.lnk '(98 characters)'
cat << \SHAR_EOF > Click-Handler.lnk
FROM Click-Handler.o+handlerstub.o
TO Click-Handler
LIB LIB:amiga.lib
NODEBUG
SMALLDATA
SMALLCODE
SHAR_EOF
if test 98 -ne "`wc -c Click-Handler.lnk`"
then
echo shar: error transmitting Click-Handler.lnk '(should have been 98 characters)'
fi
echo shar: extracting ClickUpFront.lnk '(101 characters)'
cat << \SHAR_EOF > ClickUpFront.lnk
FROM LIB:c.o+ClickUpFront.o
TO ClickUpFront
LIB LIB:lc.lib+LIB:amiga.lib
NODEBUG
SMALLDATA
SMALLCODE
SHAR_EOF
if test 101 -ne "`wc -c ClickUpFront.lnk`"
then
echo shar: error transmitting ClickUpFront.lnk '(should have been 101 characters)'
fi
echo shar: extracting HandlerStub.a '(215 characters)'
cat << \SHAR_EOF > HandlerStub.a
CSECT text
XREF _myHandler
XDEF _myHandlerStub
_myHandlerStub:
MOVEM.L A0/A1,-(A7)
JSR _myHandler
ADDQ.L #8,A7
RTS
END
SHAR_EOF
if test 215 -ne "`wc -c HandlerStub.a`"
then
echo shar: error transmitting HandlerStub.a '(should have been 215 characters)'
fi
# End of shell archive
exit 0