home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
disks
/
disk437.lzh
/
Flip
/
flip2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-16
|
11KB
|
376 lines
/***************************************************************
* FLIP v2.0 02/25/90
* © Copyright 1990 by Timm Martin and Mike Monaco
* Based heavily on the Shuffle program written by Ray Lambert
* *** This program is FreeWare ***
*
* This program is the same as FLIP v1.0 except that it uses
* an assembler input handler, eliminating the need to compile
* it in large code/large data format. This also means that
* it's about 1K smaller than FLIP v1.0!
*
* You will get a ptr/ptr warning when you compile. You will
* also get a linker warning about replacing __main. These
* are OK and do not affect the program.
****************************************************************/
#include <stdio.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <exec/io.h>
#include <exec/interrupts.h>
#include <exec/ports.h>
#include <exec/tasks.h>
#include <graphics/layers.h>
#include <graphics/clip.h>
#include <graphics/text.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <devices/timer.h>
#include <libraries/dos.h>
#asm
InputEvent EQU 0
SOFFSET SET 0
ie_NextEvent EQU SOFFSET
SOFFSET SET SOFFSET+4
ie_Class EQU SOFFSET
SOFFSET SET SOFFSET+1
ie_SubClass EQU SOFFSET
SOFFSET SET SOFFSET+1
ie_Code EQU SOFFSET
SOFFSET SET SOFFSET+2
ie_Qualifier EQU SOFFSET
SOFFSET SET SOFFSET+2
xdef _LVOSignal
#endasm
/* name of the message port for input handler to reach this process */
char *port_name = "FlipPort";
/* signals and signal bits */
ULONG
window_signal,
screen_signal,
window_signal_bit = -1L,
screen_signal_bit = -1L,
all_signal_bits,
exit_bits;
/* needs to be declared globally for inline assembly */
struct InputEvent *ie;
/* flags */
UBYTE
input_opened = 0,
handler_active = 0;
/* global variables */
struct Interrupt *handler = NULL;
struct Task *my_task;
struct IOStdReq *io_req = NULL;
struct MsgPort *message_port = NULL;
struct IntuitionBase *IntuitionBase = NULL;
#define IO_REQ_SIZE (long)sizeof(struct IOStdReq)
/***************
* END PROGRAM
****************/
void end_program()
{
if (handler_active)
{
io_req->io_Command = IND_REMHANDLER;
io_req->io_Data = (APTR)handler;
DoIO( io_req );
}
if (input_opened) CloseDevice( io_req );
if (io_req) FreeMem( io_req, IO_REQ_SIZE );
if (handler) FreeMem( handler, (LONG)sizeof(struct Interrupt) );
if (message_port) DeletePort( message_port );
if (screen_signal_bit != -1L) FreeSignal( screen_signal_bit );
if (window_signal_bit != -1L) FreeSignal( window_signal_bit );
if (IntuitionBase) CloseLibrary( IntuitionBase );
exit( 0 );
}
/***************
* KEY HANDLER
****************/
/*
This function is the input handler code used to monitor for left-Amiga-M and
left-Amiga-N key presses. It's not doing too much, so there shouldn't be any
noticable degradation in the input process. A pointer to the active input
even chain is passed to this function in register A0, hence the need for
inline assembler. Thanks to Mike Monaco (Dr. Assembler) for this tidbit!
Assembler Notes:
To allow for use with the small data and small code models, particularly
small data model, variables used in the handler had to be addressable such
that the assembler would not use the offset register associated with the
small data models. (For the MANX compiler/assembler that is A4) The reason
is that the handler is invoked as an interrupt and does not have the luxury
of having the registers in the same state as the task which installed it.
(ie. A4 would be garbage in relation to the handler code)
Also data created during startup and instalation must be available for
signaling the task into action. This data must be stored so it is addressable
in the small data model. The only way I could think of doing this was to
allocate storage space within the code and use (pc) addressing for the
constants. Orignally I also used the same method for saving the variable data
but wasn't sure if the handler could be invoked while it is was processing
other data, so is switched to using the stack for that. I didn't have any
problems the other way though.
Ok. I could have used the farcode and fardata directives, but that wouldn't
have been any fun.
--Mike Monaco
*/
struct InputEvent *key_handler()
{
;
#asm
move.l a0,-(sp) ; save beginning of event chain
Key_For_Loop:
move.l a0,d0 ; see if its NULL
beq.s Key_For_Exit ; yes - with event chain
move.b ie_Class(a0),d0 ; RAWKEY = $0001
subq.b #1,d0 ; is it a RAWKEY event
bne.s Key_Next ; no - get next event
move.w ie_Qualifier(a0),d0 ; IEQUALIFIER_LCOMMAND = $0040
and.w #$0040,d0 ; was Left Amiga pressed
beq.s Key_Next ; no - get next event
move.w ie_Code(a0),d0 ; looking for $36 for screen
; and $37 for window
Key_Check_Screen:
sub.b #$36,d0 ; is it screen
bne.s Key_Check_Window ; no - might be window
move.l _ss_(pc),d0 ; yes - user wants to flip screens
bra.s Key_Send_Signal
Key_Check_Window:
sub.b #$01,d0 ; is it window
bne.s Key_Next ; nope - we dont want this baby
move.l _ws_(pc),d0 ; yes - user wants to flip windows
Key_Send_Signal: ; signal task to perform flip
move.l a0,-(sp) ; save a0
move.l _mt_(pc),a1
move.l $4,a6 ;Signal( my_task, window_signal );
jsr _LVOSignal(a6) ; a1 d0
Key_Clear_Event: ; ready to remove event
move.l (sp)+,a0 ; restore a0
move.b #0,ie_Class(a0) ; remove event by clearing Class
Key_Next:
move.l ie_NextEvent(a0),a0 ; get next pointer in a0
bra.s Key_For_Loop
Key_For_Exit:
move.l (sp)+,d0 ; return beginning of event chain
; for other handlers to process
#endasm
;
return ();
}
#asm
cseg ; storage must be accessable but not
ds.l 0 ; restricted by the small data model
_ws_ dc.l 0 ; window signal created during startup
_ss_ dc.l 0 ; screen signal created during startup
_mt_ dc.l 0 ; task pointer found during starup
#endasm
/*******************
* INSTALL HANDLER
********************/
void install_handler()
{
/* try to allocate signal bits */
if ((screen_signal_bit = AllocSignal( -1L )) == -1L ||
(window_signal_bit = AllocSignal( -1L )) == -1L)
end_program();
/* calculate the bit masks */
screen_signal = 1L << screen_signal_bit;
window_signal = 1L << window_signal_bit;
/* get a pointer to this process for signalling purposes */
my_task = FindTask( NULL );
/* get a message port */
if (!(message_port = CreatePort( port_name, 0L )))
end_program();
/* Init Std IO structure */
if (!(io_req = (struct IOStdReq *)
AllocMem( IO_REQ_SIZE, MEMF_PUBLIC|MEMF_CLEAR )))
end_program();
io_req->io_Message.mn_Node.ln_Type = NT_MESSAGE;
io_req->io_Message.mn_Node.ln_Pri = 0;
io_req->io_Message.mn_ReplyPort = message_port;
/* open the input.device */
if (!(input_opened = (OpenDevice( "input.device", 0L, io_req, 0L ) == 0)))
end_program();
/* store required values in code segment of handler */
;
#asm
lea _ws_,a0
move.l _window_signal,(a0)
lea _ss_,a0
move.l _screen_signal,(a0)
lea _mt_,a0
move.l _my_task,(a0)
#endasm
;
if (!(handler = (struct Interrupt *)
AllocMem( (LONG)sizeof(struct Interrupt),
MEMF_PUBLIC|MEMF_CLEAR )))
end_program();
/* add the handler */
handler->is_Code = (void *)key_handler;
handler->is_Data = NULL;
handler->is_Node.ln_Pri = 51;
io_req->io_Command = IND_ADDHANDLER;
io_req->io_Data = (APTR)handler;
if (!(handler_active = (DoIO( io_req ) == 0) ))
end_program();
}
/******************
* SHUFFLE SCREEN
*******************/
/*
This procedure locks Intuition so nothing funny can happen in between the
test and the execution portions of the "if" statement (this is a multitasking
machine, you know). Then the procedure checks to see if there is another
screen in line. If so, the current screen is sent to the back, and the first
window (if any) on the new front screen is activated.
*/
void shuffle_screen()
{
register ULONG ilock;
register struct Screen *screen;
register struct Window *window;
ilock = LockIBase( NULL );
screen = IntuitionBase->FirstScreen;
if (screen->NextScreen)
{
while (screen->NextScreen) screen = screen->NextScreen;
ScreenToFront( screen );
if (window = screen->LayerInfo.top_layer->Window)
ActivateWindow( window );
}
UnlockIBase( ilock );
SetSignal( 0L, screen_signal );
}
/******************
* SHUFFLE WINDOW
*******************/
/*
This procedure again locks Intuition for reasons mentioned above. Then it
sends the current window to the background, and activates the new front
window.
*/
void shuffle_window()
{
register ULONG ilock;
register struct Layer *layer, *get_layer;
register struct Window *window;
ilock = LockIBase( NULL );
layer = IntuitionBase->FirstScreen->LayerInfo.top_layer;
get_layer = NULL;
while (layer->back)
{
if (layer->Window && !(layer->Flags & LAYERBACKDROP))
get_layer = layer;
layer = layer->back;
}
if (get_layer)
{
WindowToFront( window = get_layer->Window );
ActivateWindow( window );
}
UnlockIBase( ilock );
SetSignal( 0L, window_signal );
}
/*********
* _MAIN
**********/
/*
This replaces the _main defined in the standard c.lib library.
*/
void _main()
{
register ULONG signal;
/* if couldn't open Intuition (we're in trouble!) or if this is already
* running, end the program
*/
if (!(IntuitionBase = (struct IntuitionBase *)
OpenLibrary( "intuition.library", LIBRARY_VERSION ))
|| FindPort( port_name ))
end_program();
install_handler();
exit_bits = SIGBREAKF_CTRL_C |
SIGBREAKF_CTRL_D |
SIGBREAKF_CTRL_E |
SIGBREAKF_CTRL_F;
all_signal_bits = screen_signal | window_signal | exit_bits;
SetSignal( 0L, all_signal_bits );
for (;;)
{
signal = Wait( all_signal_bits );
if (signal & exit_bits) end_program();
if (signal & screen_signal) shuffle_screen();
if (signal & window_signal) shuffle_window();
}
}