Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (02/12/90)
Submitted-by: micke@slaka.sirius.se (Mikael Karlsson) Posting-number: Volume 90, Issue 069 Archive-name: util/snap-1.4/part03 #!/bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 3 (of 4)." # Contents: source/handler.s source/minrexx.c source/snapchars.c # Wrapped by tadguy@xanth on Sun Feb 11 17:48:46 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'source/handler.s' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'source/handler.s'\" else echo shar: Extracting \"'source/handler.s'\" \(17796 characters\) sed "s/^X//" >'source/handler.s' <<'END_OF_FILE' X include "exec/types.i" X include "exec/lists.i" X include "devices/inputevent.i" X Xwaiting equ 0 Xselregion equ 1 Xwaitext equ 2 Xselgfx equ 3 Xwaitgfx equ 4 Xinserting equ 5 Xpendsnap equ 6 Xkillbutt equ 7 X Xnoaction equ 0 Xsnapgfx equ 1 Xsnaptext equ 2 Xsnapinit equ 3 Xinsert equ 4 Xcancel equ 5 X XLMB equ IECODE_LBUTTON XLMB_UP equ IECODE_UP_PREFIX+IECODE_LBUTTON XRMB equ IECODE_RBUTTON XRMB_UP equ IECODE_UP_PREFIX+IECODE_RBUTTON XNO_BUTT equ IECODE_NOBUTTON XLCOM equ IEQUALIFIER_LCOMMAND XSHIFT equ IEQUALIFIER_LSHIFT+IEQUALIFIER_RSHIFT X X X XDEF _myhandler X XREF _geta4 X XREF _LVOSignal X XREF _SysBase X XREF _MyTask X XREF _action X XREF _state X XREF _modinsert X XREF _startsignal X XREF _insertsignal X XREF _cancelsignal X XREF _donesignal X XREF _movesignal X XREF _clicksignal X XREF _timersignal X XREF _initsignal X XREF _cwsignal X XREF _textqual ; qualifier for snapping text X XREF _gfxqual ; -"- -"- -"- gfx X XREF _insertkey X XREF _cwkey X X SECTION CODE X X_myhandler: X X; On entry: a0 : Pointer to event list X; a1 : Pointer to data X X; In loop: a1 : Pointer to event X; d0 : scratch X X; Result: d0 : New event list X X movem.l a4,-(sp) X X jsr _geta4 ; Get offset base a4 X X move.l a0,a1 ; a1 = Event list = a0 X X.nextevent X cmpa.l #0,a1 ; Check for end of list X beq .done X X cmp.w #noaction,_action ; forced noaction - cancel X bne .notcanceled ; no, we're in action X move.w #waiting,_state ; no action -> wait state X bra .dostate X.notcanceled X cmp.w #insert,_action ; forced insert - cancel X bne .dostate ; no X move.w #inserting,_state ; set correct state X X.dostate X move.w _state,d0 X asl.w #1,d0 X move.w JumpTable(pc,d0.w),d0 XOrigin X jmp 0(pc,d0.w) XJumpTable X dc.w .Waiting-Origin-2 X dc.w .SelRegion-Origin-2 X dc.w .WaitExt-Origin-2 X dc.w .SelGfx-Origin-2 X dc.w .WaitGfx-Origin-2 X dc.w .Insert-Origin-2 X dc.w .PendSnap-Origin-2 X dc.w .CancelTxt-Origin-2 X X; ******************************************************** X; State: Waiting ~TQ X; Actions New state Signal X; TQ PendSnap init X; LMB+GQ SelGfx init+start X; LCOM+IKEY Inserting insert X X.Waiting X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; Is it RAWKEY? X bne .wait_RAWMOUSE X X move.w ie_Qualifier(a1),d0 X and.w _textqual,d0 ; TQ? X bne .signalinit ; Yes -- init X X move.w ie_Qualifier(a1),d0 X and.w #LCOM,d0 ; LCOM? X beq .EventHandled ; No X X move.w _cwkey,d0 ; Control window key X cmp.w ie_Code(a1),d0 X beq .signalcw X X move.w _insertkey,d0 X beq .EventHandled ; Key = 0 -- disabled X X cmp.w ie_Code(a1),d0 ; The insert key? X bne .EventHandled ; No, pass it on X bra .signalinsert ; Tell'em to insert X X.wait_RAWMOUSE X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE? X bne .EventHandled ; Nope, pass it on X X move.w ie_Qualifier(a1),d0 X and.w _textqual,d0 ; TQ? X bne .signalinit ; Yes X X cmp.w #LMB,ie_Code(a1) ; OK, is it SELECTDOWN? X bne .EventHandled ; Too bad X X move.w ie_Qualifier(a1),d0 X and.w _gfxqual,d0 ; GQ? X beq .EventHandled ; No, not interested X X; Handle event LMB+GQ X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.w #snapgfx,_action ; action snapgfx; X move.w #selgfx,_state ; state selgfx X move.l _initsignal,d0 ; Signal init and X or.l _startsignal,d0 ; start X bra SignalTask X X.signalinit X move.w #pendsnap,_state X move.w #snapinit,_action X move.l _initsignal,d0 ; Signal start X bsr Signal X bra .PendSnap X X X; ******************************************************* X; State: PendSnap TQ X; Actions New state Signal X; ~TQ Waiting cancel X; LCOM+IKEY Inserting insert X; LMB SelRegion start X; RMB Inserting insert X X.PendSnap X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; RAWKEY? X bne .ps_RAWMOUSE X move.w ie_Qualifier(a1),d0 X and.w _textqual,d0 ; TQ? X bne .ps_IKEY ; Still down, continue X X;Handle event ~TQ X.ps_TQ X move.w #noaction,_action ; no action X move.w #waiting,_state ; state waiting X move.l _cancelsignal,d0 ; snap cancelled X bra SignalTask X X.ps_IKEY X move.w ie_Qualifier(a1),d0 X and.w #LCOM,d0 ; LCOM? X beq .EventHandled ; No X X move.w _cwkey,d0 ; Control window key X cmp.w ie_Code(a1),d0 X beq .signalcw X X move.w _insertkey,d0 X beq .EventHandled ; Key = 0 -- disabled X X cmp.w ie_Code(a1),d0 ; The insert key? X bne .EventHandled ; No, pass it on X bra .signalinsert ; Tell'em to insert X X.ps_RAWMOUSE X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE? X bne .EventHandled ; Nope, pass it on X X move.w ie_Qualifier(a1),d0 ; Might be TQ going up. X and.w _textqual,d0 ; TQ? X beq .ps_TQ X X cmp.w #LMB,ie_Code(a1) ; OK, is it SELECTDOWN? X bne .ps_RMB ; Too bad X X; Handle event LMB+TQ X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.w #snaptext,_action ; action snaptext X move.w #selregion,_state ; state selregion X move.l _startsignal,d0 ; start X bra SignalTask X X.ps_RMB X cmp.w #RMB,ie_Code(a1) ; MENUDOWN X bne .EventHandled X X; Handle event RMB+TQ X.signalinsert X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X X move.w #0,_modinsert X move.w ie_Qualifier(a1),d0 X and.w #SHIFT,d0 ; SHIFT? X beq .NonModified ; No X move.w #1,_modinsert X.NonModified X move.w #insert,_action X move.w #inserting,_state X move.l _insertsignal,d0 ; and insert X bra SignalTask X X.signalcw X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.w #noaction,_action X move.w #waiting,_state X move.l _cancelsignal,d0 ; Exit pending snap X or.l _cwsignal,d0 ; and tell'em to open window X bra SignalTask X X X; ******************************************************* X; State: SelRegion LMB+TQ X; Actions New state Signal X; ~TQ Waiting cancel X; ~LMB WaitExt X; MOVE SelRegion move X; RMB SelRegion click X; ~RMB SelRegion Needs no action X; TIMER SelRegion timer X X.SelRegion X cmp.b #IECLASS_TIMER,ie_Class(a1) ; Timer event? X bne .sr_RAWKEY X X;Handle timer event X move.l _timersignal,d0 X bra SignalTask X X.sr_RAWKEY X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; RAWKEY? X bne .sr_LMB_UP X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.w ie_Qualifier(a1),d0 X and.w _textqual,d0 ; TQ? X bne .EventHandled ; Still down, continue X X;Handle event ~TQ X.sr_TQ X move.w #cancel,_action ; no action X move.w #killbutt,_state ; state waiting X move.l _cancelsignal,d0 ; snap cancelled X bra SignalTask X X.sr_LMB_UP X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE? X bne .EventHandled ; Nope, pass it on X X move.w ie_Qualifier(a1),d0 ; Might be TQ going up. X and.w _textqual,d0 ; TQ? X beq .sr_TQ X X cmp.w #LMB_UP,ie_Code(a1) ; SELECTUP X bne .sr_MOVE ; no, check for move X X; Handle event ~LMB X move.w #waitext,_state ; state waitext X bra KillEvent X X.sr_MOVE X cmp.w #NO_BUTT,ie_Code(a1) ; MOVE X bne .sr_RMB ; No, check for RMB X move.w ie_Qualifier(a1),d0 X and.w #IEQUALIFIER_RELATIVEMOUSE,d0 ; RELATIVEMOUSE X beq .sr_RMB X X; Handle event MOVE X move.l _movesignal,d0 X bra SignalTask X X.sr_RMB X cmp.w #RMB,ie_Code(a1) ; MENUDOWN X bne .EventHandled ; No, not interested X X; Handle event RMB X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.l _clicksignal,d0 X bra SignalTask X X; *************************************************** X; State WaitExt TQ X; Actions New state Signal X; ~TQ Waiting done X; LMB SelRegion click X; MOVE WaitExt No action needed. X; RMB Inserting done & insert X; TIMER WaitExt timer X X.WaitExt X cmp.b #IECLASS_TIMER,ie_Class(a1) ; Timer event? X bne .we_RAWKEY X X;Handle timer event X move.l _timersignal,d0 X bra SignalTask X X.we_RAWKEY X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; RAWKEY? X bne .we_LMB X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.w ie_Qualifier(a1),d0 X and.w _textqual,d0 ; TQ? X bne .EventHandled ; Still down, continue X X;Handle event ~TQ X.we_TQ X move.w #noaction,_action ; no action X move.w #waiting,_state ; state waiting X move.l _donesignal,d0 ; snap finished X bra SignalTask X X.we_LMB X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE? X bne .EventHandled ; Nope, pass it on X X move.w ie_Qualifier(a1),d0 ; Might be TQ going up. X and.w _textqual,d0 ; TQ? X beq .we_TQ ; No. X X cmp.w #LMB,ie_Code(a1) ; SELECTDOWN X bne .we_RMB ; no, check for RMB X X; Handle event LMB X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.w #selregion,_state ; state waitext X move.l _clicksignal,d0 ; Extend selection X bra SignalTask X X.we_RMB X cmp.w #RMB,ie_Code(a1) ; MENUDOWN X bne .EventHandled ; No, not interested X X; Handle event RMB X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.w #insert,_action X move.w #inserting,_state X move.l _donesignal,d0 X or.l _insertsignal,d0 X bra SignalTask X X; ******************************************************* X; State: SelGfx LMB+GQ X; Actions New state Signal X; ~GQ Waiting cancel X; ~LMB WaitGfx X; MOVE SelGfx move X; TIMER SelGfx timer X; RMB SelGfx removed X X.SelGfx X cmp.b #IECLASS_TIMER,ie_Class(a1) ; Timer event? X bne .sg_RAWKEY X X;Handle timer event X move.l _timersignal,d0 X bra SignalTask X X.sg_RAWKEY X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; RAWKEY? X bne .sg_LMB_UP X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.w ie_Qualifier(a1),d0 X and.w _gfxqual,d0 ; GQ? X bne .EventHandled ; Still down, continue X X;Handle event ~GQ X.sg_GQ X move.w #cancel,_action ; cancelling snap X move.w #killbutt,_state ; Kill obsolete button X move.l _cancelsignal,d0 ; snap cancelled X bra SignalTask X X.sg_LMB_UP X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE? X bne .EventHandled ; Nope, pass it on X X move.w ie_Qualifier(a1),d0 ; Might be GQ going up. X and.w _gfxqual,d0 ; GQ? X beq .sg_GQ X X cmp.w #LMB_UP,ie_Code(a1) ; SELECTUP X bne .sg_MOVE ; no, check for move X X; Handle event ~LMB X move.w #waitgfx,_state ; state waitext X bra KillEvent X X.sg_MOVE X cmp.w #NO_BUTT,ie_Code(a1) ; MOVE X bne .EventHandled ; No, check for RMB X move.w ie_Qualifier(a1),d0 X and.w #IEQUALIFIER_RELATIVEMOUSE,d0 ; RELATIVEMOUSE X beq .EventHandled X X; Handle event MOVE X move.l _movesignal,d0 X bra SignalTask X X.sg_RMB X bra KillEvent X X; *************************************************** X; State WaitGfx GQ X; Actions New state Signal X; ~GQ Waiting done X; LMB SelGfx click X; MOVE WaitGfx No action needed. X; TIMER WaitGfx timer X; RMB WaitGfx -- remove event X X.WaitGfx X cmp.b #IECLASS_TIMER,ie_Class(a1) ; Timer event? X bne .wg_RAWKEY X X;Handle timer event X move.l _timersignal,d0 X bra SignalTask X X.wg_RAWKEY X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; RAWKEY? X bne .wg_LMB X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.w ie_Qualifier(a1),d0 X and.w _gfxqual,d0 ; GQ? X bne .EventHandled ; Still down, continue X X;Handle event ~GQ X.wg_GQ X move.w #noaction,_action ; no action X move.w #waiting,_state ; state waiting X move.l _donesignal,d0 ; snap finished X bra SignalTask X X.wg_LMB X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE? X bne .EventHandled ; Nope, pass it on X X move.w ie_Qualifier(a1),d0 ; Might be GQ going up X and.w _gfxqual,d0 ; GQ? X beq .wg_GQ X X cmp.w #LMB,ie_Code(a1) ; SELECTDOWN X bne .wg_RMB ; no -- finished X X; Handle event LMB X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X move.w #selgfx,_state ; state waitext X move.l _clicksignal,d0 ; Extend selection X bra SignalTask X X.wg_RMB X cmp.w #NO_BUTT,ie_Code(a1) ; Any button? X beq .EventHandled ; No, moves are ok X X bra KillEvent X X X; *************************************************** X; State CancelTxt X; Make sure that the Button Up event that we've got X; hanging around doesn't get through. X X.CancelTxt X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE? X bne .EventHandled ; Nope, just pass it on X X cmp.w #LMB_UP,ie_Code(a1) ; The button? X bne .EventHandled ; No X X move.w #noaction,_action X move.w #waiting,_state X bra KillEvent X X; *************************************************** X; State Insert X; Snap actions are removed, the rest are passed along. X X.Insert X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE? X bne .EventHandled ; Nope, pass it on X X cmp.w #LMB,ie_Code(a1) ; Left mouse button X bne .insert_TQ ; No -- just kill X X move.w #noaction,_action ; Cancel paste X X.insert_TQ X move.w ie_Qualifier(a1),d0 X and.w _textqual,d0 ; TQ? X beq .EventHandled ; no X X cmp.w #NO_BUTT,ie_Code(a1) ; Any button? X beq .EventHandled ; No, moves are ok X XKillEvent: X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event X bra .EventHandled X XSignalTask: X bsr Signal X X.EventHandled X move.l ie_NextEvent(a1),a1 ; Get next event X bra .nextevent X X.done X movem.l (sp)+,a4 X move.l a0,d0 X rts X XSignal: X movem.l a0-a2/a6,-(sp) X move.l _MyTask,a1 X move.l _SysBase,a6 ; Get ExecBase for Signal X jsr _LVOSignal(a6) X movem.l (sp)+,a0-a2/a6 X rts X X end END_OF_FILE if test 17796 -ne `wc -c <'source/handler.s'`; then echo shar: \"'source/handler.s'\" unpacked with wrong size! fi # end of 'source/handler.s' fi if test -f 'source/minrexx.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'source/minrexx.c'\" else echo shar: Extracting \"'source/minrexx.c'\" \(15411 characters\) sed "s/^X//" >'source/minrexx.c' <<'END_OF_FILE' X#ifdef SNAPREXX X/* X * This is an example of how REXX messages might be handled. This is X * a `minimum' example that both accepts asynchronous REXX messages and X * can request REXX service. X * X * Read this entire file! It's short enough. X * X * It is written in such a fashion that it can be attached to a program X * with a minimum of fuss. The only external symbols it makes available X * are the seven functions and RexxSysBase. X * X * This code is by Radical Eye Software, but it is put in the public X * domain. I would appreciate it if the following string was left in X * both as a version check and as thanks from you for the use of this X * code. X * X * If you modify this file for your own use, don't bump the version X * number; add a suffix, such as 1.0a or 1.0.3 or something, so we X * don't have fake `versions' floating around. X */ Xstatic char *blurb = "Radical Eye MinRexx 0.4" ; X/* X * We read in our own personal little include. X */ X#include "minrexx.h" X/* X * All of our local globals, hidden from sight. X */ Xstatic struct MsgPort *rexxPort ; /* this is *our* rexx port */ Xstatic int bringerdown ; /* are we trying to shut down? */ Xstatic struct rexxCommandList *globalrcl ; /* our command association list */ Xstatic long stillNeedReplies ; /* how many replies are pending? */ Xstatic long rexxPortBit ; /* what bit to wait on for Rexx? */ Xstatic char *extension ; /* the extension for macros */ Xstatic int (*userdisp)() ; /* the user's dispatch function */ Xstatic struct RexxMsg *oRexxMsg ; /* the outstanding Rexx message */ X/* X * Our library base. Don't you dare close this! X */ Xstruct RxsLib *RexxSysBase ; X/* X * This is the main entry point into this code. X */ Xlong upRexxPort(s, rcl, exten, uf) X/* X * The first argument is the name of your port to be registered; X * this will be used, for instance, with the `address' command of ARexx. X */ Xchar *s ; X/* X * The second argument is an association list of command-name/user-data X * pairs. It's an array of struct rexxCommandList, terminated by a X * structure with a NULL in the name field. The commands are case X * sensitive. The user-data field can contain anything appropriate, X * perhaps a function to call or some other data. X */ Xstruct rexxCommandList *rcl ; X/* X * The third argument is the file extension for ARexx macros invoked X * by this program. If you supply this argument, any `primitive' not X * in the association list rcl will be sent out to ARexx for X * interpretation, thus allowing macro programs to work just like X * primitives. If you do not want this behavior, supply a `NULL' X * here, and those commands not understood will be replied with an X * error value of RXERRORNOCMD. X */ Xchar *exten ; X/* X * The fourth argument is the user dispatch function. This function X * will *only* be called from rexxDisp(), either from the user calling X * this function directly, or from dnRexxPort(). Anytime a command X * match is found in the association list, this user-supplied function X * will be called with two arguments---the Rexx message that was X * received, and a pointer to the association pair. This function X * should return a `1' if the message was replied to by the function X * and a `0' if the default success code of (0, 0) should be returned. X * Note that the user function should never ReplyMsg() the message; X * instead he should indicate the return values with replyRexxCmd(); X * otherwise we lose track of the messages that still lack replies. X */ Xint (*uf)() ; X/* X * upRexxPort() returns the signal bit to wait on for Rexx messages. X * If something goes wrong, it simply returns a `0'. Note that this X * function is safe to call multiple times because we check to make X * sure we haven't opened already. It's also a quick way to change X * the association list or dispatch function. X */ X{ X struct MsgPort *FindPort() ; X struct MsgPort *CreatePort() ; X X/* X * Some basic error checking. X */ X if (rcl == NULL || uf == NULL) X return(0L) ; X/* X * If we aren't open, we make sure no one else has opened a port with X * this name already. If that works, and the createport succeeds, we X * fill rexxPortBit with the value to return. X * X * Note that rexxPortBit will be 0 iff rexxPort is NULL, so the check X * for rexxPort == NULL also insures that our rexxPortBit is 0. X */ X if (rexxPort == NULL) { X Forbid() ; X if (FindPort(s)==NULL) X rexxPort = CreatePort(s, 0L) ; X Permit() ; X if (rexxPort != NULL) X rexxPortBit = 1L << rexxPort->mp_SigBit ; X } X/* X * Squirrel away these values for our own internal access, and return X * the wait bit. X */ X globalrcl = rcl ; X extension = exten ; X userdisp = uf ; X return(rexxPortBit) ; X} X/* X * This function closes the rexx library, but only if it is open X * and we aren't expecting further replies from REXX. It's X * *private*, but it doesn't have to be; it's pretty safe to X * call anytime. X */ Xstatic void closeRexxLib() { X if (stillNeedReplies == 0 && RexxSysBase) { X CloseLibrary(RexxSysBase) ; X RexxSysBase = NULL ; X } X} X/* X * This function closes down the Rexx port. It is always safe to X * call, and should *definitely* be made a part of your cleanup X * routine. No arguments and no return. It removes the Rexx port, X * replies to all of the messages and insures that we get replies X * to all the ones we sent out, closes the Rexx library, deletes the X * port, clears a few flags, and leaves. X */ Xvoid dnRexxPort() { X if (rexxPort) { X RemPort(rexxPort) ; X bringerdown = 1 ; X/* X * A message still hanging around? We kill it off. X */ X if (oRexxMsg) { X oRexxMsg->rm_Result1 = RXERRORIMGONE ; X ReplyMsg(oRexxMsg) ; X oRexxMsg = NULL ; X } X while (stillNeedReplies) { X WaitPort(rexxPort) ; X dispRexxPort() ; X } X closeRexxLib() ; X DeletePort(rexxPort) ; X rexxPort = NULL ; X } X rexxPortBit = 0 ; X} X/* X * Here we dispatch any REXX messages that might be outstanding. X * This is the main routine for handling Rexx messages. X * This function is fast if no messages are outstanding, so it's X * pretty safe to call fairly often. X * X * If we are bring the system down and flushing messages, we reply X * with a pretty serious return code RXERRORIMGONE. X * X * No arguments, no returns. X */ Xvoid dispRexxPort() { X register struct RexxMsg *RexxMsg ; X int cmdcmp() ; X register struct rexxCommandList *rcl ; X register char *p ; X register int dontreply ; X X/* X * If there's no rexx port, we're out of here. X */ X if (rexxPort == NULL) X return ; X/* X * Otherwise we have our normal loop on messages. X */ X while (RexxMsg = (struct RexxMsg *)GetMsg(rexxPort)) { X/* X * If we have a reply to a message we sent, we look at the second X * argument. If it's set, it's a function we are supposed to call X * so we call it. Then, we kill the argstring and the message X * itself, decrement the outstanding count, and attempt to close X * down the Rexx library. Note that this call only succeeds if X * there are no outstanding messages. Also, it's pretty quick, so X * don't talk to me about efficiency. X */ X if (RexxMsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) { X if (RexxMsg->rm_Args[1]) { X ((int (*)())(RexxMsg->rm_Args[1]))(RexxMsg) ; X } X DeleteArgstring(RexxMsg->rm_Args[0]) ; X DeleteRexxMsg(RexxMsg) ; X stillNeedReplies-- ; X closeRexxLib() ; X/* X * The default case is we got a message and we need to check it for X * primitives. We skip past any initial tabs or spaces and initialize X * the return code fields. X */ X } else { X p = (char *)RexxMsg->rm_Args[0] ; X while (*p > 0 && *p <= ' ') X p++ ; X RexxMsg->rm_Result1 = 0 ; X RexxMsg->rm_Result2 = 0 ; X/* X * If somehow the reply is already done or postponed, `dontreply' is X * set. X */ X dontreply = 0 ; X/* X * If the sky is falling, we just blow up and replymsg. X */ X if (bringerdown) { X RexxMsg->rm_Result1 = RXERRORIMGONE ; X/* X * Otherwise we cdr down our association list, comparing commands, X * until we get a match. If we get a match, we call the dispatch X * function with the appropriate arguments, and break out. X */ X } else { X oRexxMsg = RexxMsg ; X for (rcl = globalrcl; rcl->name; rcl++) { X if (cmdcmp(rcl->name, p) == 0) { X userdisp(RexxMsg, rcl, p+strlen(rcl->name)) ; X break ; X } X } X/* X * If we broke out, rcl will point to the command we executed; if we X * are at the end of the list, we didn't understand the command. In X * this case, if we were supplied an extension in upRexxPort, we know X * that we should send the command out, so we do so, synchronously. X * The synchronous send takes care of our reply. If we were given a X * NULL extension, we bitch that the command didn't make sense to us. X */ X if (rcl->name == NULL) { X if (extension) { X syncRexxCmd(RexxMsg->rm_Args[0], RexxMsg) ; X dontreply = 1 ; X } else { X RexxMsg->rm_Result1 = RXERRORNOCMD ; X } X } X } X/* X * Finally, reply if appropriate. X */ X oRexxMsg = NULL ; X if (! dontreply) X ReplyMsg(RexxMsg) ; X } X } X} X/* X * This is the function we use to see if the command matches X * the command string. Not case sensitive, and the real command only X * need be a prefix of the command string. Make sure all commands X * are given in lower case! X */ Xstatic int cmdcmp(c, m) Xregister char *c, *m ; X{ X while (*c && ((*c == *m) || (*c == *m + 32 && ('a' <= *c && *c <= 'z')))) { X c++ ; X m++ ; X } X return(*c) ; X} X/* X * Opens the Rexx library if unopened. Returns success (1) or X * failure (0). This is another function that is *private* but X * that doesn't have to be. X */ Xstatic int openRexxLib() { X if (RexxSysBase) X return(1) ; X return((RexxSysBase = (struct RxsLib *)OpenLibrary(RXSNAME, 0L)) != NULL) ; X} X/* X * This is the general ARexx command interface, but is not the one X * you will use most of the time; ones defined later are easier to X * understand and use. But they all go through here. X */ Xstruct RexxMsg *sendRexxCmd(s, f, p1, p2, p3) Xchar *s ; X/* X * The first parameter is the command to send to Rexx. X */ Xint (*f)() ; X/* X * The second parameter is either NULL, indicating that the command X * should execute asynchronously, or a function to be called when the X * message we build up and send out here finally returns. Please note X * that the function supplied here could be called during cleanup after X * a fatal error, so make sure it is `safe'. This function always is X * passed one argument, the RexxMsg that is being replied. X */ XSTRPTR p1, p2, p3 ; X/* X * These are up to three arguments to be stuffed into the RexxMsg we X * are building up, making the values available when the message is X * finally replied to. The values are stuffed into Args[2]..Args[4]. X */ X{ X struct RexxMsg *CreateRexxMsg() ; X STRPTR CreateArgstring() ; X register struct MsgPort *rexxport ; X register struct RexxMsg *RexxMsg ; X X/* X * If we have too many replies out there, we just return failure. X * Note that you should check the return code to make sure your X * message got out! Then, we forbid, and make sure that: X * - we have a rexx port open X * - Rexx is out there X * - the library is open X * - we can create a message X * - we can create an argstring X * X * If all of these succeed, we stuff a few values and send the X * message, permit, and return. X */ X if (rexxPort == NULL || stillNeedReplies > MAXRXOUTSTANDING-1) X return(NULL) ; X RexxMsg = NULL ; X if (openRexxLib() && (RexxMsg = X CreateRexxMsg(rexxPort, extension, rexxPort->mp_Node.ln_Name)) && X (RexxMsg->rm_Args[0] = CreateArgstring(s, (long)strlen(s)))) { X RexxMsg->rm_Action = RXCOMM ; X RexxMsg->rm_Args[1] = (STRPTR)f ; X RexxMsg->rm_Args[2] = p1 ; X RexxMsg->rm_Args[3] = p2 ; X RexxMsg->rm_Args[4] = p3 ; X RexxMsg->rm_Node.mn_Node.ln_Name = RXSDIR ; X Forbid() ; X if (rexxport = FindPort(RXSDIR)) X PutMsg(rexxport, RexxMsg) ; X Permit() ; X if (rexxport) { X stillNeedReplies++ ; X return(RexxMsg) ; X } else X DeleteArgstring(RexxMsg->rm_Args[0]) ; X } X if (RexxMsg) X DeleteRexxMsg(RexxMsg) ; X closeRexxLib() ; X return(NULL) ; X} X/* X * This function is used to send out an ARexx message and return X * immediately. Its single parameter is the command to send. X */ Xstruct RexxMsg *asyncRexxCmd(s) Xchar *s ; X{ X return(sendRexxCmd(s, NULL, NULL, NULL, NULL)) ; X} X/* X * This function sets things up to reply to the message that caused X * it when we get a reply to the message we are sending out here. X * But first the function we pass in, which actually handles the reply. X * Note how we get the message from the Args[2]; Args[0] is the command, X * Args[1] is this function, and Args[2]..Args[4] are any parameters X * passed to sendRexxCmd() as p1..p3. We pass the result codes right X * along. X */ Xstatic void replytoit(msg) Xregister struct RexxMsg *msg ; X{ X register struct RexxMsg *omsg ; X X omsg = (struct RexxMsg *)(msg->rm_Args[2]) ; X replyRexxCmd(omsg, msg->rm_Result1, msg->rm_Result2, NULL) ; X ReplyMsg(omsg) ; X} X/* X * This function makes use of everything we've put together so far, X * and functions as a synchronous Rexx call; as soon as the macro X * invoked here returns, we reply to `msg', passing the return codes X * back. X */ Xstruct RexxMsg *syncRexxCmd(s, msg) Xchar *s ; Xstruct RexxMsg *msg ; X{ X return(sendRexxCmd(s, (APTR)&replytoit, msg, NULL, NULL)) ; X} X/* X * There are times when you want to pass back return codes or a X * return string; call this function when you want to do that, X * and return `1' from the user dispatch function so the main X * event loop doesn't reply (because we reply here.) This function X * always returns 1. X */ Xvoid replyRexxCmd(msg, primary, secondary, string) X/* X * The first parameter is the message we are replying to. X */ Xregister struct RexxMsg *msg ; X/* X * The next two parameters are the primary and secondary return X * codes. X */ Xregister long primary, secondary ; X/* X * The final parameter is a return string. This string is only X * returned if the primary return code is 0, and a string was X * requested. X * X * We also note that we have replied to the message that came in. X */ Xregister char *string ; X{ X STRPTR CreateArgstring() ; X X/* X * Note how we make sure the Rexx Library is open before calling X * CreateArgstring . . . and we close it down at the end, if possible. X */ X if (primary == 0 && (msg->rm_Action & (1L << RXFB_RESULT))) { X if (string && openRexxLib()) X secondary = (long)CreateArgstring(string, (long)strlen(string)) ; X else X secondary = 0L ; X } X msg->rm_Result1 = primary ; X msg->rm_Result2 = secondary ; X closeRexxLib() ; X} X#endif END_OF_FILE if test 15411 -ne `wc -c <'source/minrexx.c'`; then echo shar: \"'source/minrexx.c'\" unpacked with wrong size! fi # end of 'source/minrexx.c' fi if test -f 'source/snapchars.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'source/snapchars.c'\" else echo shar: Extracting \"'source/snapchars.c'\" \(21526 characters\) sed "s/^X//" >'source/snapchars.c' <<'END_OF_FILE' X/* Auto: make X*/ X XIMPORT struct SnapRsrc *SnapRsrc; X X#define COPY 0xC0L X#define INVCOPY 0x30L X#define CopyChar(_x, _y, _m) \ X BltBitMap(&MyBM, (LONG)_x, (LONG)_y, \ X &TempBM, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, \ X _m, -1L, NULL); \ X WaitBlit() X XWORD Unit; XWORD Pattern[5] = { X 0, X 0x0c3f, /* Frame ....oo....oooooo */ X 0x3333, /* Char ..oo..oo..oo..oo */ X 0x1f1f, /* Word ...ooooo...ooooo */ X 0xffff /* Line oooooooooooooooo */ X}; X XIMPORT LONG xl; /* leftmost x position */ XIMPORT LONG xr; /* rightmost x position */ XIMPORT LONG yt; /* topmost y position */ XIMPORT LONG yb; /* bottommost y position */ XLONG minx; /* left limit */ XLONG maxx; /* right limit */ XLONG maxy; /* bottom limit */ XLONG tl, tr; /* used by findword - left and right edge of word */ XWORD fw, fh; /* Font width and height used when drawing the frame */ XWORD GZZ; XWORD SBM; X XIMPORT LONG mx, my; /* Mouse position in character steps */ X#define closetop 0 X#define closebottom 1 XWORD closey; X#define closeleft 0 X#define closeright 1 XWORD closex; X X Xstruct Window *window; /* The window we're snapping from */ X X/* Data for font being snapped */ XUWORD FontHeight; XUWORD FontWidth; XUWORD Underscore; XUBYTE FontType; XUBYTE LoChar; XUBYTE HiChar; XUWORD Modulo; XUWORD *CharLoc; XUWORD NoOfChars; XUBYTE *SrcData; XIMPORT UBYTE *CharData; XUBYTE IFlags; X XIMPORT struct RastPort TempRp, MyRP; XIMPORT struct BitMap TempBM, MyBM; X XIMPORT UWORD *TempRaster; /* Used for character recognition */ X XIMPORT struct Screen *theScreen; XIMPORT struct RastPort rp; Xstruct Layer *LockedLayer; X XIMPORT LONGBITS cancelsignal, donesignal, movesignal, clicksignal, timersignal; XIMPORT WORD action; X XWORD starting; X X/* Init vars with font data. X*/ X XVOID SetSnapFont(font) Xstruct TextFont *font; X{ X if (!font) { X FontWidth = -1; X return; X } X FontHeight = font->tf_YSize; X Underscore = font->tf_Baseline + 1; X FontType = font->tf_Flags; X FontWidth = (FontType & FPF_PROPORTIONAL ? -1 : font->tf_XSize); X if (FontWidth == -1) { X return; X } X LoChar = font->tf_LoChar; X HiChar = font->tf_HiChar; X Modulo = font->tf_Modulo; X CharLoc = (UWORD *)font->tf_CharLoc; X NoOfChars = HiChar - LoChar + 1; X Modulo = font->tf_Modulo; X SrcData = (UBYTE *)font->tf_CharData; X BltClear(CharData, 256L * 32, 0L); X WaitBlit(); X CopyFont(); X} X X/* Check if the character at x, y is a space X*/ X XWORD IsSpace(x, y) XLONG x, y; X{ X REGISTER WORD i = FontHeight - 1; X REGISTER UWORD *data = &TempRaster[i]; X X /* Copy character at x, y */ X BltClear((char *)TempRaster, 32L, 0L); X ClipBlit(&rp, x, y, X &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY); X WaitBlit(); X X if (*data) { /* Try inverted copy */ X ClipBlit(&rp, x, y, X &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, INVCOPY); X WaitBlit(); X } X while (i--) { X if (*data--) { X return 0; X } X } X return 1; X} X X#define ShortFrame 4L /* Square frame - columnar select */ X#define LongFrame 8L /* Strange frame - char or word select */ XIMPORT LONG OFType; /* Old frame type: ShortFrame/LongFrame */ XIMPORT UWORD Ptrn; XIMPORT Point OldFrame[]; XIMPORT Point NewFrame[]; X X X/* update_frame calculates the new frame, X** erases the old frame and draws the new one. X** It's all pretty obvious if you take it slowly. X*/ XVOID update_frame() X{ X LONG ft; X switch (Unit) { X case UNIT_FRAME: { X /*********\ X * * X * * X \*********/ X NewFrame[0].x = xl - 1; NewFrame[0].y = yt - 1; X NewFrame[1].x = xr + fw; NewFrame[1].y = yt - 1; X NewFrame[2].x = xr + fw; NewFrame[2].y = yb + fh; X NewFrame[3].x = xl - 1; NewFrame[3].y = yb + fh; X NewFrame[4].x = xl - 1; NewFrame[4].y = yt - 1; X ft = ShortFrame; X break; X } X case UNIT_CHAR: X case UNIT_WORD: { X if (yt == yb) { /* On the same line - same as UNIT_FRAME */ X NewFrame[0].x = xl - 1; NewFrame[0].y = yt - 1; X NewFrame[1].x = xr + fw; NewFrame[1].y = yt - 1; X NewFrame[2].x = xr + fw; NewFrame[2].y = yb + fh; X NewFrame[3].x = xl - 1; NewFrame[3].y = yb + fh; X NewFrame[4].x = xl - 1; NewFrame[4].y = yt - 1; X ft = ShortFrame; X } else { X /*****\ X ****** * X * * X * ***** X *******/ X NewFrame[0].x = xl - 1; NewFrame[0].y = yt - 1; X NewFrame[1].x = maxx + fw; NewFrame[1].y = yt - 1; X NewFrame[2].x = maxx + fw; NewFrame[2].y = yb; X NewFrame[3].x = xr + fw; NewFrame[3].y = yb; X NewFrame[4].x = xr + fw; NewFrame[4].y = yb + fh; X NewFrame[5].x = minx - 1; NewFrame[5].y = yb + fh; X NewFrame[6].x = minx - 1; NewFrame[6].y = yt + fh; X NewFrame[7].x = xl - 1; NewFrame[7].y = yt + fh; X NewFrame[8].x = xl - 1; NewFrame[8].y = yt - 1; X ft = LongFrame; X } X break; X } X case UNIT_LINE: { X NewFrame[0].x = minx - 1; NewFrame[0].y = yt - 1; X NewFrame[1].x = maxx + fw; NewFrame[1].y = yt - 1; X NewFrame[2].x = maxx + fw; NewFrame[2].y = yb + fh; X NewFrame[3].x = minx - 1; NewFrame[3].y = yb + fh; X NewFrame[4].x = minx - 1; NewFrame[4].y = yt - 1; X ft = ShortFrame; X break; X } X default: { X break; X } X } X draw_frame(ft); X} X XVOID FindWord() X{ X /* Must remove frame to be able to search for spaces */ X WaitTOF(); X erase_frame(); X tl = mx; X /* Find a space to the left... */ X while (!IsSpace(tl, my)) { X tl -= fw; X if (tl < minx) { X break; X } X } X tl += fw; X tr = mx; X /* ...and to the right */ X while (!IsSpace(tr, my)) { X tr += fw; X if (tr + fw > maxx) { X break; X } X } X tr -= fw; X if (tr < tl) { X tl = xl; X tr = xr; X } X} X X/* ChangeUnit cycles the unit of selection. The differents units X are: character, word and line. X*/ X XVOID ChangeUnit() X{ X X switch (Unit) { X case UNIT_FRAME: { X Unit = UNIT_CHAR; X break; X } X case UNIT_CHAR: { X Unit = UNIT_WORD; X FindWord(); X xl = tl; X xr = tr; X break; X } X case UNIT_WORD: { X Unit = UNIT_LINE; X xl = minx; X xr = maxx; X break; X } X case UNIT_LINE: { X Unit = UNIT_FRAME; X xl = xr = mx; X break; X } X } X if (SnapRsrc->CrawlPtrn == 0) { X Ptrn = Pattern[Unit]; X } X} X X/* ExtendSelection extends the current selection according to X the mouse position and the selected unit. X Note that ExtendSelection doesn't optimize moves that don't X make any difference. FIXME X*/ X XVOID ExtendSelection() X{ X /* Fix which row we're talking about */ X if (closey == closetop) { /* Find closest row */ X yt = my; /* change top row */ X } else { X yb = my; /* change bottom row */ X } X X /* Take care of left and right character pos */ X switch (Unit) { X case UNIT_FRAME: { X if (closex == closeleft) { X xl = mx; X } else { X xr = mx; X } X break; X } X case UNIT_CHAR: { X if (yt == yb) { /* One line */ X if (closex == closeleft) { X xl = mx; X } else { X xr = mx; X } X } else { /* Multiple lines */ X if (yt == my) { X xl = mx; /* At top - set left */ X } else { X xr = mx; /* At bottom - set right */ X } X } X break; X } X case UNIT_WORD: { X FindWord(); /* Find the word */ X if (yt == yb) { /* One line */ X if (closex == closeleft) { /* Find closest char pos */ X xl = tl; X } else { X xr = tr; X } X } else { /* Multiple lines */ X if (yt == my) { /* Where am I */ X xl = tl; /* At top - set left */ X } else { X xr = tr; /* At bottom - set right */ X } X } X break; X } X case UNIT_LINE: { /* Always full width */ X break; X } X } X if (yt - fh == yb) { X yb += fh; X } X if (yt == yb && xl - fw == xr) { X xr += fw; X } X if (xr > maxx) { /* Check for window bounds */ X xr = maxx; X } X if (xl < minx) { /* Check for window bounds */ X xl = minx; X } X if (yb > maxy) { /* Check for window bounds */ X yb = maxy; X } X} X X/* The actual character snapper. It actually works. :-) */ X XWORD SnapChars() X{ X LONG width; X LONG height; X UBYTE *SnapSpace; X ULONG SnapSize; X ULONG counter; X REGISTER LONG x, y; X X /* Check coordinates */ X if (yt - fh == yb) { /* No rows, shouldn't happen */ X return 0; X } X if (yt == yb && xl - fw == xr) { /* Nothing at all */ X return 0; X } X X /* Calculate stuff */ X width = maxx - (minx + 1) + fw + fw; /* Add one for a LF */ X height = yb - yt + fh; X SnapSize = ((width / fw) + 1) * (height / fh); X counter = 0; X X /* Initialize things */ X InitRastPort(&MyRP); X InitBitMap(&MyBM, 1L, width, height); X MyRP.BitMap = &MyBM; X SnapSpace = AllocMem(SnapSize, MEMF_PUBLIC|MEMF_CLEAR); X /* Please insert more memory */ X if (!SnapSpace) { X return 0; X } X MyBM.Planes[0] = AllocRaster(width, height); X if (!MyBM.Planes[0]) { X FreeMem(SnapSpace, SnapSize); X return 0; X } X IFlags = 0; X /* Make a local copy of the snapped chars */ X ClipBlit(&rp, minx, yt, &MyRP, 0L, 0L, width, height, COPY); X X /* Ok, now we've got a copy of the character data */ X /* Now it's ok to mess with the layers again */ X UnlockLayer(LockedLayer); X X /* Clear our work area */ X BltClear((char *)TempRaster, 32L, 0L); X X /* Calculate bounds */ X xl -= minx; X xr -= minx; X maxx -= minx; X minx = 0; X yb -= yt; X yt = 0; X X /* Single line - needs to be handled separately */ X if (yt == yb) { /* Ok, we've got one */ X X /* Read from left to right */ X for (x = xl; x <= xr; x += fw, counter++) { X CopyChar(x, yt, COPY); X if ((SnapSpace[counter] = interpret(TempRaster)) == 255) { X SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */ X } X } X if (Unit == UNIT_LINE) { X while (counter && SnapSpace[counter-1] == ' ') { X counter--; X } X } X } else { /* Multiple lines */ X X if (Unit == UNIT_FRAME) { X minx = xl; X maxx = xr; X } X X /* Read first line */ X for (x = xl; x <= maxx; x += fw, counter++) { X CopyChar(x, yt, COPY); X if ((SnapSpace[counter] = interpret(TempRaster)) == 255) { X SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */ X } X } X if (Unit == UNIT_FRAME) { X SnapSpace[counter++] = 10; X } else { X SHORT endspace = (SnapSpace[counter-1] == ' '); X /* Remove trailing blanks */ X while (counter && SnapSpace[counter-1] == ' ') { X counter--; X } X if (endspace || !(SnapRsrc->flags & JOINLONG)) { X SnapSpace[counter++] = 10; X } X } X X /* If more than two rows - read full middle rows */ X if (yt + fh != yb) { X for (y = yt + fh; y < yb; y += fh) { X for (x = minx; x <= maxx; x += fw, counter++) { X CopyChar(x, y, COPY); X if ((SnapSpace[counter] = interpret(TempRaster)) == 255) { X SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */ X } X } X if (Unit == UNIT_FRAME) { X SnapSpace[counter++] = 10; X } else { X SHORT endspace = (SnapSpace[counter-1] == ' '); X /* Remove trailing blanks */ X while (counter && SnapSpace[counter-1] == ' ') { X counter--; X } X if (endspace || !(SnapRsrc->flags & JOINLONG)) { X SnapSpace[counter++] = 10; X } X } X } X } X X /* Read last line */ X for (x = minx; x <= xr; x += fw, counter++) { X CopyChar(x, yb, COPY); X if ((SnapSpace[counter] = interpret(TempRaster)) == 255) { X SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */ X } X } X /* Remove trailing blanks */ X while (counter && SnapSpace[counter-1] == ' ') { X counter--; X } X } X FreeRaster(MyBM.Planes[0], width, height); X SaveClip(SnapSpace, counter); X FreeMem(SnapSpace, SnapSize); X return 1; X} X X X/* HandleChars is the part of the Snap state machine that handles X snapping of characters. The selection is done in different X units: char, word, line. X*/ X XWORD HandleChars() X{ X LONG xoff, yoff; X LONG ox, oy; X X /* Find out which screen we're working on */ X theScreen = WhichScreen(); X X /* Oops, no screen? */ X if (!theScreen) { X action = noaction; X return 0; X } X X /* Ok, what window? */ X window = WhichWindow(theScreen); X X /* Oh dear, no window. */ X if (!window) { X action = noaction; X return 0; X } X X /* No messing with the layers while I think */ X LockedLayer = window->WLayer; X LockLayer(0L, LockedLayer); X X /* Don't want to wreck somebody's rastport */ X CopyMem((char *)window->RPort, (char *)&rp, (LONG)sizeof(struct RastPort)); X X /* Or his picture */ X SetDrMd(&rp, COMPLEMENT); X rp.Mask = SnapRsrc->FrameMask; X X /* Find out what we're trying to read */ X SetSnapFont(rp.Font); X if (FontWidth == -1) { X UnlockLayer(LockedLayer); X action = noaction; X return 0; X } X X if (window->Flags & GIMMEZEROZERO) { X GZZ = 1; X } else { X GZZ = 0; X } X if (window->Flags & SUPER_BITMAP) { X SBM = 1; X } else { X SBM = 0; X } X X /* Find a position */ X xl = (GZZ ? window->GZZMouseX : window->MouseX) X + window->RPort->Layer->Scroll_X; X yt = (GZZ ? window->GZZMouseY : window->MouseY) X + window->RPort->Layer->Scroll_Y; X X if (xl < 0) { X xl = 0; X } X if (yt < 0) { X yt = 0; X } X X /* Check your position */ X if (xl > (GZZ ? window->GZZWidth : window->Width) || X yt > (GZZ ? window->GZZHeight : window->Height)) { X UnlockLayer(LockedLayer); X action = noaction; X return 0; X } X IFlags = 0; X X /* Find out the offset for the clicked character, if any. X ** This is the part that makes it special. Simple, isn't it. Hah! X */ X { X REGISTER struct CacheWindow *cw = GetCachedWindow(theScreen, window); X X if (cw) { X xoff = - ((xl - cw->xoff) % cw->fw); X yoff = - ((yt - cw->yoff) % cw->fh); X BltClear((char *)TempRaster, 32L, 0L); X ClipBlit(&rp, xl + xoff, yt + yoff, X &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY); X WaitBlit(); X if (interpret(TempRaster) != 255) { X goto found; X } X } X /* No cache or cache didn't match */ X xl -= 7; X yt -= 7; X BltClear((char *)TempRaster, 32L, 0L); X xoff = 0; X while (xoff < (16 - FontWidth)) { X ClipBlit(&rp, xl + xoff, yt, X &TempRp, 0L, 0L, (LONG)FontWidth, 16L, COPY); X WaitBlit(); X yoff = 0; X while (yoff < (16 - FontHeight)) { X if (interpret(&TempRaster[yoff]) != 255) { X goto found; X } X ++yoff; X } X ++xoff; X } X X /* No character found. Back off */ X UnlockLayer(LockedLayer); X action = noaction; X return 0; X Xfound: X /* Ok, now we know where to look for chars. X ** xoff and yoff is character position within our 16x16 bitmap. X */ X xl = xl + xoff; /* Adjust x */ X yt = yt + yoff; /* Adjust y */ X X fw = FontWidth; X fh = FontHeight; X X { X SHORT temp = fh; X while (temp <= fh + 1) { /* Check for extra pixel row */ X BltClear((char *)TempRaster, 32L, 0L); X ClipBlit(&rp, xl, yt + temp, X &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY); X WaitBlit(); X if (interpret(TempRaster) != 255) { X fh = temp; X break; X } X ++temp; X } X } X X /* Find out offsets within the window */ X xoff = xl % fw; X yoff = yt % fh; X X if (cw) { X cw->xoff = xoff; X cw->yoff = yoff; X cw->fw = fw; X cw->fh = fh; X } else { X CacheWindow(window, xoff, yoff, fw, fh); X } X } X X /* Set bounds */ X minx = xoff; X maxx = minx + X (((GZZ ? X window->GZZWidth : X window->Width - window->BorderRight X /* Hack for borderless conman windows */ X + (window->Flags & BORDERLESS && window->Flags & WINDOWSIZING ? 14 : 0)) X - minx - fw) / fw) * fw; X maxy = ((GZZ ? window->GZZHeight : window->Height) / fh) * fh; X X /* Check bounds */ X if (xl > maxx) { X UnlockLayer(LockedLayer); X action = noaction; X return 0; X } X /* Set box dimensions */ X xr = xl; X yb = yt; X ox = xr; X oy = yt; X X /* Select unit while starting */ X starting = 1; X X /* Starting unit is character or frame */ X Unit = SnapRsrc->StartUnit; X Ptrn = (SnapRsrc->CrawlPtrn ? SnapRsrc->CrawlPtrn : Pattern[Unit]); X OFType = 0L; X update_frame(); X X /* Get the state machine running */ X FOREVER { X /* Wait for something to happen */ X REGISTER LONGBITS sig = X Wait(movesignal|cancelsignal|donesignal|clicksignal|timersignal); X X if ((sig & timersignal) && (SnapRsrc->CrawlPtrn != 0xffff)) { X crawl_frame(0L); X } X X mx = (LONG)(GZZ ? window->GZZMouseX : window->MouseX) X + window->RPort->Layer->Scroll_X; X if (mx < 0) { X mx = 0; X } X /* Calculate which edge is closest */ X if ((mx - xl) < (xr - mx)) { X closex = closeleft; X } else { X closex = closeright; X } X /* Only interested in real char pos */ X mx = mx - ((mx - xoff) % fw); X X my = (LONG)(GZZ ? window->GZZMouseY : window->MouseY) X + window->RPort->Layer->Scroll_Y; X if (my < 0) { X my = 0; X } X /* Calculate which row is closest */ X if ((my - yt) < (yb - my)) { X closey = closetop; X } else { X closey = closebottom; X } X my = my - ((my - yoff) % fh); X X /* Hey, it moves! It's alive!! */ X if ((sig & movesignal) && (action == snaptext)) { X if (mx != ox || my != oy) { /* Something's happened */ X ExtendSelection(); X update_frame(); X starting = 0; X ox = mx; X oy = my; X sig &= ~clicksignal; X } X } X X /* Ok, forget it... */ X if (sig & cancelsignal) { X erase_frame(); X UnlockLayer(LockedLayer); X return 0; X } X X /* Click */ X if ((sig & clicksignal) && (action == snaptext)) { X /* Selecting unit */ X if (starting) { X if (mx == ox && my == oy) { X ChangeUnit(); X if (Unit == UNIT_CHAR) { X ChangeUnit(); X } X update_frame(); X } else if (Unit == UNIT_FRAME) { X ChangeUnit(); X update_frame(); X } X } X if (mx != ox || my != oy) { /* Click in a new place */ X ExtendSelection(); X update_frame(); X starting = 0; X ox = mx; X oy = my; X } X } X X /* Finished */ X if (sig & donesignal) { X erase_frame(); X return SnapChars(); X } X } X} X END_OF_FILE if test 21526 -ne `wc -c <'source/snapchars.c'`; then echo shar: \"'source/snapchars.c'\" unpacked with wrong size! fi # end of 'source/snapchars.c' fi echo shar: End of archive 3 \(of 4\). cp /dev/null ark3isdone MISSING="" for I in 1 2 3 4 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 4 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Mail submissions (sources or binaries) to <amiga@cs.odu.edu>. Mail comments to the moderator at <amiga-request@cs.odu.edu>. Post requests for sources, and general dicussion to comp.sys.amiga.