;ClickToFront V1.1 Copyright 1987 Bryce Nesbitt. Unlimited, revokable, free, ;non-exclusive licence hereby granted to any sentient being to use or abuse ;this code in any way whatsoever provided that this and any other copyright ;notices remain fully attached and are reproduced in any simultaneously ;distributed printed matter and with the exception that, without prior ;written permission, it not be utilized by any entity that has been commonly ;referred to as Robert W. Skyles, Skyles Electric Works, Jim Drew, Regie ;Warren or any organization founded by, controlled, employing or profiting ;any such entity, it's offspring or spouses. FISH use ok. Author ;correspondence, bug or stupidity reports may be directed to: ; 1712 Marin Ave. ; Berkeley, Ca 94707-2902 ; bryce@cogsci.berkeley.EDU -or- ucbvax!cogsci!bryce ;"(almost) as seen in Transactor magazine". ; ;USAGE ; CLI - ClickToFront ; WB - Brings up requester, choose Install or Cancel ; ; A click into any part of any window works as normal. ; A double click brings it to the front. How handy! ; ; !!! In order to prevent false activation, lower the !!! ; !!! double-click sensitvity from preferences. !!! ; ;BUGS ; No provisions for un-install. The only way I can think to do this would ;be to add a handler at priority 52, then search the chain downward for a ;handler with name ClickToFront. This seems like a kludge. ; This program is NOT Intuition. This makes certain things more difficult. ;A test should be made that both clicks are over the same window. If some, ;kind Intuition() hacker has a way... ; No longer brings screens to the front. ; Proper size when assembled with Metacomco and Blink'ed with NODEBUG ; is 956 bytes. ; ************** NOLIST INCLUDE 'exec/types.i' INCLUDE 'exec/memory.i' INCLUDE 'exec/interrupts.i' INCLUDE 'exec/io.i' ; INCLUDE 'exec/tasks.i' ThisTask EQU $114 INCLUDE 'libraries/dosextens.i' INCLUDE 'devices/inputevent.i' INCLUDE 'devices/input.i' ; INCLUDE 'intuition/intuitionbase.i' ib_ActiveWindow EQU $34 ib_ActiveScreen EQU $38 ib_FirstScreen EQU $3C ; ;What follows is a non-standard extension that eliminates the need to link ;with the HUGE amiga.lib file. ; ;INCLUDE 'lib/exec_lib.i' ;INCLUDE 'lib/intuition_lib.i' LIST jsrlib macro xref _LVO\1 jsr _LVO\1(a6) endm jmplib macro xref _LVO\1 jmp _LVO\1(a6) endm ******************** CODE startup: move.l 4,a6 move.l ThisTask(a6),a5 moveq #0,d0 ;Set zero for later move.l pr_CLI(a5),d1 ;Pointer to CLI only structure bne.s fromCLI ;If not zero, then save a zero... ; ; If called from Workbench a message will be sent. This waits for it, ; and saves it's pointer to be returned to Workbench later. ; lea.l pr_MsgPort(a5),a0 jsrlib WaitPort lea.l pr_MsgPort(a5),a0 jsrlib GetMsg ;Message pointer in D0 fromCLI move.l d0,-(a7) ;Save message for later... ******************************** [A6=ExecBase][a5=this task] failcode equr d7 Ibase equr d6 portsave equr a5 IOReqsave equr a4 moveq #20,failcode ;Default code ;---Prepare StdIO--- bsr _CreatePortE ;[d0=Port] beq ExitToDOS move.l d0,portsave bsr _CreateStdIOE ;[a1=IoRequest] beq e_StdIO move.l a1,IOReqsave ;---Open input.device--- moveq #0,d0 ;Unit move.l d0,d1 ;Flags lea.l devname(pc),a0 ;[a1-IoRequest] jsrlib OpenDevice ;[d0=zero if ok] tst.l d0 bne e_Open ;---Open Intuition--- ;Intuition will be opened, and the pointer given to the interrupt code ; Since the interrupt will still be installed after this task exits, ; intuition will be left open. ; lea.l IntuiName(pc),a1 jsrlib OldOpenLibrary ;V1.0 Compatible :-) move.l d0,Ibase ;(d) beq e_Intui tst.l (a7) ;check CLI flag on stack beq.s DoIt ;always do it from CLI move.l Ibase,a6 suba.l a0,a0 lea.l IText1(pc),a1 lea.l IText2(pc),a2 lea.l IText3(pc),a3 moveq #0,d0 moveq #0,d1 move.l #560,d2 moveq #68,d3 jsrlib AutoRequest move.l 4,a6 tst.l d0 ;grumble, gritch, grrr... bne.s DoIt ;---User said no, so pack our bags and go home-- move.l Ibase,a1 jsrlib CloseLibrary bra.s Cancel ;---Copy Handler--- DoIt move.l #DownEnd-Start,d0 move.l #MEMF_PUBLIC+MEMF_CLEAR,d1 jsrlib AllocMem move.l d0,a2 ;location of block move.l d0,a1 tst.l d0 beq.s e_nomem lea.l Start(pc),a0 moveq #((DownEnd-Start)/4)-1,d1 ;Length in LONGS-1 copylp move.l (a0)+,(a1)+ ;Copy handler to Public Memory dbra d1,copylp ;68010 Loop mode! ;---Prepare IOReq with proper addresses--- lea.l Handlercode-Start(a2),a0 ;offset+memblock move.l a0,IS_DATA(a2) ;unused move.l a0,IS_CODE(a2) ;where code is lea.l PopName-Start(a2),a0 ;set ascii name move.l a0,LN_NAME(a2) move.l Ibase,IBASE1+2-Start(a2) ;modify code move.l Ibase,IBASE2+2-Start(a2) ;modify code ;---Send ADDHANDLER--- move.l IOReqsave,a1 move.w #IND_ADDHANDLER,IO_COMMAND(a1) move.l a2,IO_DATA(a1) ;(IOReq in a1) jsrlib DoIO ;d0=(IOReq-a0) tst.l d0 bne.s e_DoIO ;bad<>0. Forget the memory... Cancel moveq #0,d7 e_nomem e_DoIO e_Intui move.l IOReqsave,a1 jsrlib CloseDevice e_Open move.l IOReqsave,a1 bsr _DeleteStdIOE e_StdIO move.l portsave,a1 bsr _DeletePortE tst.l failcode beq.s ExitToDOS ;-- There can be only one reason why we failed (knock on formica) -- ;-- and that is lack of memory. Unless you have a better idea... -- move.l ThisTask(a6),a1 moveq #ERROR_NO_FREE_STORE,d0 move.l d0,pr_Result2(a1) ******************************* (a7)+=message d7=return code a6=exec ExitToDOS: move.l (a7)+,d2 beq.s NotWB ;If saved pointer is zero, exit to CLI... ; ; Return the startup message to the parent Workbench tool. The forbid ; is needed so workbench can't UnLoadSeg() the code too early. ; jsrlib Forbid move.l d2,a1 ;message pointer jsrlib ReplyMsg NotWB move.l failcode,d0 ;Set "failat" code rts ;**** exec_support/CreatePort *** ; ; port=_CreatePort() ; d0 ; ;FUNCTION: Create a nameless message port with a 0 priority. ; (exec/ports.i) ;RESULT: The port pointer or Z=1 if an error occured. ;REGISTERS: a6 is destroyed unless _CreatePortE is called, ; in which case a6 must contain ExecBase. ;EXAMPLE: ; moveq #3,d0 ;Set Priority ; jsr _CreatePort ; beq.s noport ;Not enough memory or signals ; ;xref _CreatePort ;xref _CreatePortE ;_CreatePort move.l 4,a6 _CreatePortE: move.l a2,-(a7) move.l #MEMF_PUBLIC+MEMF_CLEAR,d1 moveq #MP_SIZE,d0 jsrlib AllocMem move.l d0,a2 tst.l d0 beq.s cp_nomemory moveq #-1,d0 jsrlib AllocSignal ;d0=return moveq #-1,d1 cmp.l d0,d1 ;-1 indicates bad signal bne.s cp_sigok move.l a2,a1 moveq #MP_SIZE,d0 jsrlib FreeMem cp_nomemory moveq #0,d0 ;set z=1 bra.s cp_xit cp_sigok move.b d0,MP_SIGBIT(a2) move.b #PA_SIGNAL,MP_FLAGS(a2) move.b #NT_MSGPORT,LN_TYPE(a2) clr.b LN_PRI(a2) move.l ThisTask(a6),MP_SIGTASK(a2) lea.l MP_MSGLIST(a2),a0 ;Point to list header NEWLIST a0 ;Init new list macro move.l a2,d0 cp_xit move.l (a7)+,a2 ;cc's NOT affected rts ;**** exec_support/DeletePort *** ; ;_DeletePort(port) ; a1 ; ;FUNCTION: Deletes the port by first setting some ; fields to illegal values then calling FreeMem. ;RESULT: none ;REGISTERS: a6 is destroyed unless _DeleteStdIOE is called, ; in which case a6 must contain ExecBase. ; ;xref _DeletePort ;xref _DeletePortE ;_DeletePort move.l 4,a6 _DeletePortE: move.l a1,-(a7) moveq #-1,d0 move.b d0,LN_TYPE(a1) move.l d0,MP_MSGLIST+LH_HEAD(a1) moveq #0,d0 ;Clear upper 3/4 of d0 move.b MP_SIGBIT(a1),d0 jsrlib FreeSignal move.l (a7)+,a1 moveq #MP_SIZE,d0 jmplib FreeMem ; ;ioStdReq=CreateStdIO(ioReplyPort) ; a1 d0 ; ;Function: Allocate a IoRequest block of standard size. ;Example: move.l MyPort,d0 ; jsr _CreateStdIO ; beq.s badnews ; ;xref _CreateStdIOE ;xref _CreateStdIO ;_CreateStdIO move.l 4,a6 _CreateStdIOE: move.l d0,-(a7) moveq #IOSTD_SIZE,d0 move.l #MEMF_PUBLIC+MEMF_CLEAR,d1 jsrlib AllocMem move.l d0,a1 tst.l d0 beq.s nomem move.b #NT_MESSAGE,LN_TYPE(a1) move.l (a7)+,MN_REPLYPORT(a1) nomem rts ;*** exec_support/DeleteStdIO *** ; ;_DeleteStdIO(ioStdReq) ; a1 ; ;FUNCTION: Deletes an ioStdReq by setting some ; fields to illegal values then calling FreeMem. ;RESULT: none ;REGISTERS: a6 is destroyed unless _DeleteStdIOE is called, ; in which case a6 must contain ExecBase. ; ;xref _DeleteStdIO ;xref _DeleteStdIOE ;_DeleteStdIO move.l 4,a6 ;Get ExecBase _DeleteStdIOE: moveq #-1,d0 ;Set fields to illegal value move.b d0,LN_TYPE(a1) move.l d0,IO_DEVICE(a1) move.l d0,IO_UNIT(a1) moveq #IOSTD_SIZE,d0 jmplib FreeMem IText1: dc.b 0,1,1,0 ;pens, drawmode and filler dc.w 20,6 ;XY dc.l 0 ;NULL for default font dc.l ITextText1 ;pointer to text dc.l IText1b ;next IntuitText structure IText1b dc.b 0,1,1,0 dc.w 20,17 dc.l 0 dc.l ITextText1b dc.l 0 IText2: dc.b 0,1,1,0 dc.w 6,3 dc.l 0 dc.l ITextText2 dc.l 0 IText3: dc.b 0,1,1,0 dc.w 6,3 dc.l 0 dc.l ITextText3 dc.l 0 ITextText1: dc.b 'ClickToFront installer v1.1. ' dc.b $a9,'1987 Bryce Nesbitt',0 ITextText1b dc.b 'Double-clicking will bring ' ITextText1c dc.b 'any window to the front',0 ITextText2: dc.b 'Install',0 ITextText3: dc.b 'Cancel',0 IntuiName: dc.b 'intuition.library',0 devname: dc.b 'input.device',0 ;------------------------------- cnop 0,4 ;LONG word align Start: ints: ;This is an interrupt structure (exec/interrupts.i) ;since it will be referenced by an interrupt it MUST be ;copied into PUBLIC memory. (All memory that will be used ;by interrupts or other tasks must be PUBLIC.) dc.l 0 ;succ dc.l 0 ;pred dc.b 0 ;type dc.b 51 ;Priority (One step higher than Intuition) dc.l 0 ;Name dc.l 0 ;Data dc.l 0 ;Code inte ;When the handler is entered a0 will point to a linked list of input ; events of the type defined in the incude file (devices/inputevent.i) ; When done mangling the input stream it returns a new pointer in d0 ;Note: All references to (a0) below refer to ie_NextEvent(a0). The ; offeset equates to zero and was eliminated for effeciency. Handlercode: move.l a0,d0 ;Save pointer to start of chain cmpi.w #$0200,ie_Class(a0) ;Compare class AND subclass. $0200 is a combination of IECLASS_RAWMOUSE for ;ie_Class and IECLASS_NULL for ie_SubClass (it checks two BYTEs at once). beq.s hurdle1 move.l (a0),d1 ;Get {ie_NextEvent} pointer bne.s MoreEvents ;If any... rts ;exit (with no changes made) hurdle1 move.l ie_Code(a0),d1 ;Code & Qualifier. andi.w #%0011000000000000,d1 ; ;Mask off the bits of the qualifier field that we do not care about. In this ; case that's all but the RIGHT and MIDDLE buttons, which may not be down. cmpi.l #$00680000,d1 ; ;The upper word of this comparison ($0068) is the RAWMOUSE code for LBUTTON ; the lower is the match for the qualifier. beq.s CheckClick KeepLooking move.l (a0),d1 ;See above... bne.s MoreEvents ;See above... rts ;exit (no changes) ; ;MoreEvents handles the case where several events may be linked and ; can extract one of them from the middle. MoreEvents ;move.l a0,a1 ;Temporary for unlinking move.l d1,a0 ;Look here next... cmpi.w #$0200,ie_Class(a0) bne.s KeepLooking move.l ie_Code(a0),d1 andi.w #%0011000000000000,d1 cmpi.l #$00680000,d1 bne.s KeepLooking ; ;Don't unlink the event, that would cause problems. ; CheckClick movem.l a6/a1/d3/d2/d0,-(a7) move.l a0,-(a7) IBASE2 move.l #-1,a6 ;Self-modifying-> Intuitionbase move.l TimeSave+0(pc),d0 move.l TimeSave+4(pc),d1 move.l ie_TimeStamp+0(a0),d2 move.l ie_TimeStamp+4(a0),d3 jsrlib DoubleClick move.l (a7)+,a0 lea.l TimeSave+0(pc),a1 move.l ie_TimeStamp+0(a0),(a1)+ move.l ie_TimeStamp+4(a0),(a1)+ tst.l d0 movem.l (a7)+,d0/d2/d3/a1/a6 ;cc's not beq.s KeepLooking ;[d0-short input] ;The pointer to the currently active Screen and Windows are available at a ; positive offset from the Intuition base pointer. These will be brought ; to the front. Note that it may not be proper under the Amiga system to ; do this in the actual handler. It may be safer to have another task ; lying around in the background to do the actual work. The description ; of the Intuition WindowToFront commands indicates that it will not take ; effect until the NEXT input event, which (of course) will not happen ; until this one exits. Now, if Intuition was a device... ; tofront: movem.l a6/d0,-(a7) IBASE1 move.l #-1,a6 ;Self-modifying-> Intuitionbase moveq #0,d0 jsrlib LockIBase ;Lock before reading any private move.l d0,-(a7) ;Intuition structures ;move.l ib_ActiveScreen(a6),d0 ;Uncomment to bring screen ;beq.s iinoscreen ;to front also ;move.l d0,a0 ;jsrlib ScreenToFront ;move.l ib_ActiveScreen(a6),d0 ;Garbage, forget it ;beq.s inoscreen ;move.l d0,a0 ;lea.l MouseYX(pc),a1 ;move.l sc_MouseX(a0),d1 ;cmp.l d1,(a1) ;bne.s imousemoved ;The mouse moved!! Don't do it!! ;move.l d1,(a1) ;jsrlib ScreenToFront iinoscreen move.l ib_ActiveWindow(a6),d0 beq.s inowindow move.l d0,a0 jsrlib WindowToFront inowindow move.l (a7)+,a0 jsrlib UnlockIBase movem.l (a7)+,d0/a6 ;d0 contains output pointer rts imousemoved ;move.l d1,(a1) ;Set last position inoscreen ;move.l (a7)+,a0 ;jsrlib UnlockIBase ;movem.l (a7)+,d0/a6 ;rts ;don't bother with remaining chained events PopName: dc.b 'ClickToFront',0 cnop 0,4 ;Pad out to Longword boundary TimeSave: dc.l 0,0 ;longs on longs retain long ;MouseYX dc.l 0 DownEnd END