2 ** $Id: PIPWin.c,v 1.2 2000/01/12 21:01:01 bernie Exp $
4 ** Use 4 chars wide TABs to read this file.
10 ** This program opens a window showing the contents of a user selected
11 ** public screen. The PIP view can be scrolled around by dragging it
12 ** with mouse or using the cursor keys.
14 ** The source code shows how to create a resizable window with sliders
15 ** and how to write a custom `boopsi' class on top of the gadgetclass.
21 ** PipWin SCREEN,PUB/K,DELAY/K,LEFT/K,TOP/K,WIDTH/K,HEIGHT/K
24 ** the name of the public screen to monitorize
27 ** name of the public screen where the window should open
30 ** delay between window refreshes, in tenth of seconds (default: 20)
32 ** LEFT, TOP, WIDTH, HEIGHT
33 ** window geometry (in pixels)
39 ** This project can be compiled with:
40 ** - SAS/C (version 6.58 or newer)
41 ** - gcc (version 2.7.2.1 or newer) and egcs (version 1.1b or newer)
42 ** - StormC (version 2.00.14 or newer)
44 ** You get the smallest executable with SAS/C. gcc will give you
45 ** quite a lot of warnings with the tag calls. Don't worry about them.
51 ** 1.0 (3.12.95) -- First version by Alfonso Caschili
53 ** 1.1 (27.3.96) -- Major revamp by Bernardo Innocenti
55 ** - Source cleaned up, re-indented and commented the way I like it :)
57 ** - Fixed a bug with CTRL-C handling
59 ** - Does not keep a lock on the screen where the window opens for all the time
61 ** - Argument parsing improved a bit
63 ** - Does not need C startup code anymore (saves some KB)
65 ** - Window positioning and sizing is a bit smarter
67 ** - Does not refresh the window twice on startup
70 ** 2.0 (14.4.96) -- Rewritten using a `boopsi' class by Bernardo Innocenti
72 ** - Created the PIP 'boopsi' class
74 ** - Added sliders and buttons in window borders
76 ** - Added no-op backfilling hook (makes resizing and depth arragnging
77 ** much faster and less flickering
82 ** - Fixed window positioning bug. Window was being positioned just below
83 ** the screen title bar, but it was looking on the titlebar height of
84 ** the screen being captured instead of the screen when the window was
87 ** - Changed PATTA_#? attributes to PIPA_#? attributes in the boopsi
88 ** interconnection diagram. PATTA_ is the attribute prefix for the
89 ** pattedit.gadget, another boopsi class written by me
91 ** - Changed to always keep a lock on the screen where the window opens.
92 ** This is needed because we are trying to free the associated DrawInfo
93 ** strucure *after* closing the window. Without a proper lock, our host
94 ** screen could close just after we closed our window, which would make
95 ** the parameter we pass to FreeScreenDrawInfo() an invalid pointer
97 ** - Fixed a bug that caused a call to still BltBitMapRastPort() with a
98 ** NULL BitMap pointer when the PIPA_BitMap attribute was set to NULL
100 ** - Added error report for bad arguments
105 ** - Added gcc compiler support (untested)
107 ** - Now uses a custom DoMethod() stub (faster than calling amiga.lib one)
109 ** - Fixed the arrow buttons positioning when their width/height is
110 ** not the same of the size gadget
114 ** - Fixed LEFT, TOP, WIDTH & HEIGHT command line arguments. The
115 ** OpenPIPWin() function was passing the *pointers* to the LONG
116 ** values to OpenWindowTags(). (Riccardo Torrini)
118 ** - Dragging the view to the extreme left or top does no longer send
119 ** negative numbers when notifying the sliders.
121 ** - Removed test to check if GetScreenDrawInfo() fails because this
122 ** function is always successful
127 ** - Added StormC compiler support
129 ** - gcc support tested: works fine with latest GeekGadgets snapshot
134 ** - Compiled with SAS/C 6.58
136 ** - Improved SMakefile, now PIPWin is not need to be linked with
137 ** any static libraries
139 ** - Size reduced even more!
143 ** - Fixed scroll bars positioning with non standard window
146 ** - gcc version can now be built without linking with libnix
148 ** - Replaced call to RefreshGList() with the new PIPM_Refresh
149 ** class method, which in turn calls GM_RENDER with mode GREDRAW_UPDATE.
155 ** - Add a requester to select a public screen to snoop
157 ** - Allow opening more than one window
159 ** - Workbench startup and ToolTypes parsing
161 ** - Allow zooming into the bitmap
163 ** - Make the pipclass update its imagery automatically at given
164 ** time intervals. This would require creating a Process for each
165 ** istance the class, or perhaps one single Process for all objects.
166 ** Unfortunately, most gadgetclass methods can not be called by
167 ** soft interrupts, so it seems we really need a process :-(
169 ** - This one is very ambitious: it should be possible to forward mouse
170 ** and keyboard input to the screen being displayed. This would allow
171 ** the user to actually USE programs without bringing their screens
174 ** - Optimize display scrolling in some special cases. When the bitmap
175 ** of the screen being displayed is not the same format of the bitmap
176 ** where the PIP gadget renders (i.e.: they arn't `friend bitmaps'),
177 ** some kind of conversion (e.g.: planar to chunky) will be done
178 ** transparently by CopyBitMapRastPort(). This operation might be
179 ** very slow, making more convenient to ScrollRaster() the existing
180 ** image and copy just the part that gets revealed by the scrolling
182 ** - Change the mouse pointer to a grabbing hand while user is dragging
189 ** Copyright © 1995 by Alfonso Caschili <valdus@mbox.vol.it>.
190 ** Freely Distributable.
192 ** Copyright © 1996,97 by Bernardo Innocenti <bernie@cosmos.it>.
193 ** Freely Distributable, as long as source code, documentation and
194 ** executable are kept together. Permission is granted to release
195 ** modified versions of this program as long as all existing copyright
196 ** notices are left intact.
201 #define INTUI_V36_NAMES_ONLY
202 #define __USE_SYSBASE
203 #define CLIB_ALIB_PROTOS_H /* Avoid including this header file because of
204 * conflicting definitions in BoopsiStubs.h
206 #include <exec/types.h>
207 #include <exec/memory.h>
208 #include <exec/execbase.h>
209 #include <dos/rdargs.h>
210 #include <intuition/intuition.h>
211 #include <intuition/intuitionbase.h>
212 #include <intuition/screens.h>
213 #include <intuition/classes.h>
214 #include <intuition/classusr.h>
215 #include <intuition/gadgetclass.h>
216 #include <intuition/imageclass.h>
217 #include <intuition/icclass.h>
218 #include <devices/timer.h>
220 #include <proto/exec.h>
221 #include <proto/intuition.h>
222 #include <proto/dos.h>
223 #include <proto/utility.h>
225 #include <CompilerSpecific.h>
226 #include <DebugMacros.h>
227 #include <BoopsiStubs.h>
229 #include "PIPClass.h"
233 /* Local function prototypes */
234 LONG SAVEDS _main (void);
235 static struct PIPHandle *OpenPIPWin (UBYTE *spyscreen, UBYTE *pubscreen,
236 ULONG *left, ULONG *top, ULONG *width, ULONG *height);
237 static void ClosePIPWin (struct PIPHandle *piphandle);
238 static struct Gadget *CreateGadgets (struct PIPHandle *piphandle);
239 static void DisposeGadgets (struct PIPHandle *piphandle);
240 static void CreateImages (struct DrawInfo *dri);
241 static void FreeImages (void);
242 static Class * MakeScrollButtonClass (void);
243 static BOOL FreeScrollButtonClass (Class *cl);
244 static ULONG HOOKCALL ScrollButtonDispatcher (
246 REG(a2, struct Gadget *g),
247 REG(a1, struct gpInput *gpi));
251 /* Definitions for argument parsing */
253 #define ARGS_TEMPLATE "SCREEN,PUBSCREEN/K,DELAY/K/N," \
254 "LEFT/K/N,TOP/K/N,WIDTH/K/N,HEIGHT/K/N"
258 ARG_SCREEN, ARG_PUBSCREEN, ARG_DELAY,
259 ARG_LEFT, ARG_TOP, ARG_WIDTH, ARG_HEIGHT, ARG_COUNT
267 GAD_PIP, GAD_VSLIDER, GAD_HSLIDER,
268 GAD_UPBUTTON, GAD_DOWNBUTTON, GAD_LEFTBUTTON, GAD_RIGHTBUTTON,
277 IMG_UP, IMG_DOWN, IMG_LEFT, IMG_RIGHT, IMG_COUNT
282 /* This structure describes an open PIP window */
288 struct DrawInfo *DrawInfo;
289 struct Screen *SpyScr;
290 struct Gadget *Gad[GAD_COUNT];
298 static const UBYTE versiontag[] = "$VER: PIPWin 2.6 (13.10.97) by Bernardo Innocenti & Alfonso Caschili";
299 static const UBYTE PrgName[] = "PIPWin";
303 /* Workaround a bug in StormC header file <proto/utility.h> */
306 #define UTILITYBASETYPE struct Library
308 #define UTILITYBASETYPE struct UtilityBase
314 struct ExecBase *SysBase;
315 struct DosLibrary *DOSBase;
316 struct IntuitionBase *IntuitionBase;
317 struct GfxBase *GfxBase;
318 UTILITYBASETYPE *UtilityBase;
322 /* Our private `boopsi' classes */
324 static Class *PIPClass;
325 static Class *ScrollButtonClass;
329 /* 'boopsi' images for all our windows
331 * These variables must be NULL at startup time. We are not
332 * going to explicitly initialize them because otherwise
333 * Storm C 2.0 would generate a constructor to do it :-)
334 * LoasSeg() will clear the BSS data section for us, so
335 * these variables are guaranteed to be NULL anyway.
337 static struct Image *Img[IMG_COUNT];
338 static ULONG ImgWidth[IMG_COUNT];
339 static ULONG ImgHeight[IMG_COUNT];
343 /* Attribute translations for object interconnections */
345 static const ULONG MapPIPToHSlider[] =
348 PIPA_Width, PGA_Total,
349 PIPA_DisplayWidth, PGA_Visible,
353 static const ULONG MapHSliderToPIP[] =
359 static const ULONG MapPIPToVSlider[] =
362 PIPA_Height, PGA_Total,
363 PIPA_DisplayHeight, PGA_Visible,
368 static const ULONG MapVSliderToPIP[] =
374 static const ULONG MapUpButtonToPIP[] =
380 static const ULONG MapDownButtonToPIP[] =
382 GA_ID, PIPA_MoveDown,
386 static const ULONG MapLeftButtonToPIP[] =
388 GA_ID, PIPA_MoveLeft,
392 static const ULONG MapRightButtonToPIP[] =
394 GA_ID, PIPA_MoveRight,
400 LONG SAVEDS _main(void)
402 /* Main program entry point. When linking without startup code, this
403 * must be the first function in the first object module listed on the
404 * linker command line. We also need to initialize SysBase and open
405 * all needed libraries manually.
408 struct PIPHandle *piphandle;
409 struct RDArgs *rdargs;
410 struct MsgPort *TimerMsgPort;
411 struct timerequest *TimerIO;
412 LONG args[ARG_COUNT] = { 0 };
413 LONG sigwait, sigrcvd;
415 LONG retval = RETURN_FAIL;
419 /* Initialize SysBase */
420 SysBase = *((struct ExecBase **)4UL);
422 if (DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L))
424 if (UtilityBase = (UTILITYBASETYPE *) OpenLibrary("utility.library", 37L))
426 /* Parse shell arguments */
427 if (rdargs = ReadArgs(ARGS_TEMPLATE, args, NULL))
431 /* We use utility.library math because it works for 68000 too */
432 secs = UDivMod32(*((LONG *)args[ARG_DELAY]), 10);
433 micros = UMult32((*((LONG *)args[ARG_DELAY]) - UMult32 (secs, 10)), 100000);
441 if (IntuitionBase = (struct IntuitionBase *)
442 OpenLibrary("intuition.library", 39))
444 if (GfxBase = (struct GfxBase *)
445 OpenLibrary("graphics.library", 39))
447 if (TimerMsgPort = CreateMsgPort())
449 if (TimerIO = (struct timerequest *) CreateIORequest(TimerMsgPort, sizeof (struct timerequest)))
451 if (!OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)TimerIO, 0))
453 if (PIPClass = MakePIPClass())
455 if (ScrollButtonClass = MakeScrollButtonClass())
457 if (piphandle = OpenPIPWin((UBYTE *)args[ARG_SCREEN], (UBYTE *)args[ARG_PUBSCREEN],
458 (ULONG *)args[ARG_LEFT], (ULONG *)args[ARG_TOP],
459 (ULONG *)args[ARG_WIDTH], (ULONG *)args[ARG_HEIGHT]))
461 /* Pre-calculate the signal mask for Wait() */
462 sigwait = (1 << TimerMsgPort->mp_SigBit) |
463 (1 << piphandle->Win->UserPort->mp_SigBit) |
466 /* Send our first IORequest to timer.device */
467 TimerIO->tr_node.io_Command = TR_ADDREQUEST;
468 TimerIO->tr_time.tv_secs = secs;
469 TimerIO->tr_time.tv_micro = micros;
470 SendIO ((struct IORequest *)TimerIO);
472 /* Now for the main loop. As you can see, it is really
473 * very compact. That's the magic of boopsi! :-)
477 /* Sleep until something interesting occurs */
478 sigrcvd = Wait(sigwait);
480 /* Now handle received signals */
483 if (sigrcvd & SIGBREAKF_CTRL_C)
487 if (sigrcvd & (1 << TimerMsgPort->mp_SigBit))
489 /* Update the PIP gadget and send another
490 * request to the timer.device
492 DoGadgetMethod(piphandle->Gad[GAD_PIP], piphandle->Win, NULL,
495 TimerIO->tr_node.io_Command = TR_ADDREQUEST;
496 TimerIO->tr_time.tv_secs = secs;
497 TimerIO->tr_time.tv_micro = micros;
498 SendIO((struct IORequest *)TimerIO);
502 if (sigrcvd & (1 << piphandle->Win->UserPort->mp_SigBit))
504 struct IntuiMessage *msg;
506 while (msg = (struct IntuiMessage *) GetMsg(piphandle->Win->UserPort))
510 case IDCMP_CLOSEWINDOW:
517 ReplyMsg ((struct Message *) msg);
520 } /* End while (!quit) */
524 /* Abort the IORequest sent to the timer.device */
525 AbortIO((struct IORequest *)TimerIO);
526 WaitIO((struct IORequest *)TimerIO);
528 ClosePIPWin(piphandle);
532 /* This one cannot fail */
533 FreeScrollButtonClass(ScrollButtonClass);
535 /* This one cannot fail */
536 FreePIPClass(PIPClass);
538 CloseDevice((struct IORequest *)TimerIO);
540 DeleteIORequest((struct IORequest *)TimerIO);
542 DeleteMsgPort(TimerMsgPort);
544 CloseLibrary((struct Library *)GfxBase);
546 CloseLibrary((struct Library *)IntuitionBase);
550 else PrintFault(IoErr(), (STRPTR)PrgName);
552 CloseLibrary((struct Library *)UtilityBase);
554 CloseLibrary((struct Library *)DOSBase);
562 static struct PIPHandle *OpenPIPWin(UBYTE *screen, UBYTE *pubscreen,
563 ULONG *left, ULONG *top, ULONG *width, ULONG *height)
565 struct PIPHandle *piphandle;
566 struct Gadget *glist;
569 if (piphandle = AllocMem(sizeof (struct PIPHandle), MEMF_ANY | MEMF_CLEAR))
571 if (piphandle->SpyScr = LockPubScreen(screen))
573 if (piphandle->Scr = LockPubScreen(pubscreen))
575 if (glist = CreateGadgets(piphandle))
578 PIPA_Screen, piphandle->SpyScr,
581 if (piphandle->Win = OpenWindowTags(NULL,
582 WA_Left, left ? *left : 0,
583 WA_Top, top ? *top : piphandle->Scr->BarHeight + 1,
584 WA_InnerWidth, width ? *width : piphandle->SpyScr->Width,
585 WA_InnerHeight, height ? *height : piphandle->SpyScr->Height,
588 WA_MaxWidth, piphandle->SpyScr->Width,
589 WA_MaxHeight, piphandle->SpyScr->Height,
590 WA_PubScreen, piphandle->Scr,
591 WA_PubScreenFallBack, TRUE,
593 WA_IDCMP, IDCMP_CLOSEWINDOW,
594 WA_Flags, WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET |
595 WFLG_SIZEGADGET | WFLG_SIZEBRIGHT | WFLG_SIZEBBOTTOM |
596 WFLG_SIMPLE_REFRESH | WFLG_NOCAREREFRESH,
598 WA_BackFill, LAYERS_NOBACKFILL,
599 WA_Title, piphandle->SpyScr->DefaultTitle,
600 WA_ScreenTitle, versiontag + 6,
603 /* We need to keep our screen locked all the time
604 * because we want to free the associated DrawInfo
605 * *after* the window has been closed and
606 * FreeScreenDrawInfo() wants a pointer to a *valid*
610 DisposeGadgets(piphandle);
612 UnlockPubScreen(NULL, piphandle->Scr);
614 UnlockPubScreen(NULL, piphandle->SpyScr);
616 FreeMem(piphandle, sizeof (struct PIPHandle));
623 static void ClosePIPWin(struct PIPHandle *piphandle)
625 /* Close our window. No need to reply queued messages,
626 * Intuition is clever enough to care about this for us.
628 CloseWindow(piphandle->Win);
629 DisposeGadgets(piphandle);
630 UnlockPubScreen(NULL, piphandle->Scr);
631 UnlockPubScreen(NULL, piphandle->SpyScr);
632 FreeMem(piphandle, sizeof (struct PIPHandle));
638 * Diagram of object interconnections
639 * ==================================
642 * ScrollButtonClass objects
643 * +----------+ +------------+ +------------+ +-------------+
644 * | UpButton | | DownButton | | LeftButton | | RightButton |
645 * +----------+ +------------+ +------------+ +-------------+
646 * | GA_ID = | GA_ID = | GA_ID = | GA_ID =
647 * | PIPA_MoveUp | PIPA_MoveDown | PIPA_MoveLeft | PIPA_MoveRight
650 * | | +-----------------------+ |
651 * | | | +------------------------------------+
652 * | | | | propgclass object icclass object
653 * | | | | +-----------+ +--------------+
654 * | | | | | HSlider |<-----| PIPToHSlider |
655 * | | | | +-----------+ +--------------+
656 * | | | | PGA_Top = | ^ PIPA_OffX = PGA_Top
657 * | | | | PIPA_OffX | | PIPA_Width = PGA_Visible
658 * | | | | | | PIPA_DisplayWidth =
659 * V V V V V | PGA_Total
660 * +-----------+ *********** |
661 * | |-------->* *------------+
663 * | |<--------* *------------+
664 * +-----------+ *********** |
667 * PIPA_OffY | V icclass object
668 * +-----------+ +--------------+
669 * | VSlider |<-----| PIPToVSlider |
670 * +-----------+ +--------------+
671 * propgclass object PIPA_OffY = PGA_Top
672 * PIPA_Height = PGA_Visible
673 * PIPA_DisplayHeight = PGA_Total
676 static struct Gadget *CreateGadgets(struct PIPHandle *piphandle)
678 struct DrawInfo *dri;
679 struct Screen *scr = piphandle->Scr;
680 struct Image *SizeImage;
681 ULONG SizeWidth = 18, SizeHeight = 11; /* Default values */
683 /* GetScreenDrawInfo() never fails */
684 dri = piphandle->DrawInfo = GetScreenDrawInfo (scr);
686 /* Create a new size image to get its size */
687 if (SizeImage = NewObject(NULL, SYSICLASS,
688 SYSIA_Which, SIZEIMAGE,
692 /* Get size gadget geometry */
693 GetAttr(IA_Width, SizeImage, &SizeWidth);
694 GetAttr(IA_Height, SizeImage, &SizeHeight);
696 /* And then get rid of it... */
697 DisposeObject(SizeImage);
700 /* No need to check this: in case of failure we would just
701 * get no images in the scroll buttons, but we can still try
702 * to open our window.
706 if (piphandle->Model = NewObjectA(NULL, MODELCLASS, NULL))
707 if (piphandle->Gad[GAD_PIP] = NewObject (PIPClass, NULL,
709 GA_Left, scr->WBorLeft,
710 GA_Top, scr->WBorTop + scr->Font->ta_YSize + 1,
711 GA_RelWidth, - SizeWidth - scr->WBorLeft,
712 GA_RelHeight, - (scr->WBorTop + scr->Font->ta_YSize + SizeHeight + 1),
714 ICA_TARGET, piphandle->Model,
716 if (piphandle->Gad[GAD_VSLIDER] = NewObject(NULL, PROPGCLASS,
718 GA_Previous, piphandle->Gad[GAD_PIP],
719 GA_RelRight, - SizeWidth + 5,
720 GA_Top, scr->WBorTop + scr->Font->ta_YSize + 2,
721 GA_Width, SizeWidth - 8,
722 GA_RelHeight, - (scr->WBorTop + scr->Font->ta_YSize +
723 SizeHeight + ImgHeight[IMG_DOWN] + ImgHeight[IMG_UP] + 4),
724 GA_RightBorder, TRUE,
726 PGA_Freedom, FREEVERT,
727 PGA_Borderless, ((dri->dri_Flags & DRIF_NEWLOOK) && (dri->dri_Depth != 1)),
729 ICA_TARGET, piphandle->Model,
730 ICA_MAP, MapVSliderToPIP,
732 if (piphandle->Gad[GAD_HSLIDER] = NewObject(NULL, PROPGCLASS,
734 GA_Previous, piphandle->Gad[GAD_VSLIDER],
735 GA_RelBottom, - SizeHeight + ((SizeHeight > 15) ? 4 : 3),
736 GA_Left, scr->WBorLeft,
737 GA_Height, SizeHeight - ((SizeHeight > 15) ? 6 : 4),
738 GA_RelWidth, - (SizeWidth + ImgWidth[IMG_RIGHT] + ImgWidth[IMG_LEFT] + scr->WBorLeft + 2),
739 GA_BottomBorder,TRUE,
741 PGA_Freedom, FREEHORIZ,
742 PGA_Borderless, ((dri->dri_Flags & DRIF_NEWLOOK) && (dri->dri_Depth != 1)),
744 ICA_TARGET, piphandle->Model,
745 ICA_MAP, MapHSliderToPIP,
747 if (piphandle->Gad[GAD_UPBUTTON] = NewObject(ScrollButtonClass, NULL,
749 GA_Previous, piphandle->Gad[GAD_HSLIDER],
750 GA_RelBottom, - SizeHeight - ImgHeight[IMG_DOWN] - ImgHeight[IMG_UP] + 1,
751 GA_RelRight, - ImgWidth[IMG_DOWN] + 1,
752 GA_RightBorder, TRUE,
754 GA_Image, Img[IMG_UP],
755 ICA_TARGET, piphandle->Gad[GAD_PIP],
756 ICA_MAP, MapUpButtonToPIP,
758 if (piphandle->Gad[GAD_DOWNBUTTON] = NewObject(ScrollButtonClass, NULL,
759 GA_ID, GAD_DOWNBUTTON,
760 GA_Previous, piphandle->Gad[GAD_UPBUTTON],
761 GA_RelBottom, - SizeHeight - ImgHeight[IMG_DOWN] + 1,
762 GA_RelRight, - ImgWidth[IMG_DOWN] + 1,
763 GA_RightBorder, TRUE,
765 GA_Image, Img[IMG_DOWN],
766 ICA_TARGET, piphandle->Gad[GAD_PIP],
767 ICA_MAP, MapDownButtonToPIP,
769 if (piphandle->Gad[GAD_LEFTBUTTON] = NewObject(ScrollButtonClass, NULL,
770 GA_ID, GAD_LEFTBUTTON,
771 GA_Previous, piphandle->Gad[GAD_DOWNBUTTON],
772 GA_RelBottom, - ImgHeight[IMG_LEFT] + 1,
773 GA_RelRight, - SizeWidth - ImgWidth[IMG_RIGHT] - ImgWidth[IMG_LEFT] + 1,
774 GA_BottomBorder,TRUE,
776 GA_Image, Img[IMG_LEFT],
777 ICA_TARGET, piphandle->Gad[GAD_PIP],
778 ICA_MAP, MapLeftButtonToPIP,
780 if (piphandle->Gad[GAD_RIGHTBUTTON] = NewObject(ScrollButtonClass, NULL,
781 GA_ID, GAD_RIGHTBUTTON,
782 GA_Previous, piphandle->Gad[GAD_LEFTBUTTON],
783 GA_RelBottom, - ImgHeight[IMG_RIGHT] + 1,
784 GA_RelRight, - SizeWidth - ImgWidth[IMG_RIGHT] + 1,
785 GA_BottomBorder,TRUE,
787 GA_Image, Img[IMG_RIGHT],
788 ICA_TARGET, piphandle->Gad[GAD_PIP],
789 ICA_MAP, MapRightButtonToPIP,
794 /* Connect VSlider to Model */
796 if (icobject = NewObject(NULL, ICCLASS,
797 ICA_TARGET, piphandle->Gad[GAD_VSLIDER],
798 ICA_MAP, MapPIPToVSlider,
800 if (!DoMethod (piphandle->Model, OM_ADDMEMBER, icobject))
801 DisposeObject (icobject);
803 /* Connect HSlider to Model */
805 if (icobject = NewObject(NULL, ICCLASS,
806 ICA_TARGET, piphandle->Gad[GAD_HSLIDER],
807 ICA_MAP, MapPIPToHSlider,
809 if (!DoMethod (piphandle->Model, OM_ADDMEMBER, icobject))
810 DisposeObject (icobject);
812 /* Connect Model to PIP */
814 SetAttrs(piphandle->Model,
815 ICA_TARGET, piphandle->Gad[GAD_PIP],
818 return piphandle->Gad[GAD_PIP];
820 DisposeGadgets(piphandle);
827 static void DisposeGadgets(struct PIPHandle *piphandle)
831 for (i = 0; i < GAD_COUNT; i++)
833 DisposeObject(piphandle->Gad[i]);
834 /* piphandle->Gad[i] = NULL; */
837 /* Freeing the Model will also free its two targets */
838 DisposeObject(piphandle->Model);
839 /* piphandle->Model = NULL */
841 FreeScreenDrawInfo(piphandle->Scr, piphandle->DrawInfo);
842 /* piphandle->DrawInfo = NULL */
847 static void CreateImages(struct DrawInfo *dri)
849 /* Create 4 arrow images for the window scrolling buttons.
851 * Why bother checking for failure? The arrow images are not
852 * life critical in our program...
855 static ULONG imagetypes[IMG_COUNT] = { UPIMAGE, DOWNIMAGE, LEFTIMAGE, RIGHTIMAGE };
858 for (i = 0; i < IMG_COUNT; i++)
860 if (Img[i] = (struct Image *)NewObject(NULL, SYSICLASS,
861 SYSIA_Which, imagetypes[i],
865 /* Ask image width and height */
866 GetAttr(IA_Width, Img[i], &ImgWidth[i]);
867 GetAttr(IA_Height, Img[i], &ImgHeight[i]);
873 static void FreeImages(void)
877 for (i = 0; i < IMG_COUNT; i++)
878 DisposeObject((APTR)Img[i]); /* DisposeObject(NULL) is safe */
886 ** This code has been taken from ScrollerWindow 0.3
887 ** Copyright © 1994 Christoph Feck, TowerSystems.
889 ** Subclass of buttongclass. The ROM class has two problems, which make
890 ** it not quite usable for scrollarrows. The first problem is the missing
891 ** delay. Once the next INTUITICK gets send by input.device, the ROM
892 ** class already sends a notification. The other problem is that it also
893 ** notifies us, when the button finally gets released (which is necessary
894 ** for command buttons).
896 ** We define a new class with the GM_GOACTIVE and GM_HANDLEINPUT method
897 ** overloaded to work around these problems.
902 /* Function prototypes */
904 static ULONG HOOKCALL ScrollButtonDispatcher(
906 REG(a2, struct Gadget *g),
907 REG(a1, struct gpInput *gpi));
910 /* Per object instance data */
911 struct ScrollButtonData
913 /* The number of ticks we still have to wait
914 * before sending any notification.
921 static ULONG HOOKCALL ScrollButtonDispatcher(
923 REG(a2, struct Gadget *g),
924 REG(a1, struct gpInput *gpi))
926 /* ScrollButton Class Dispatcher entrypoint.
927 * Handle BOOPSI messages.
930 struct ScrollButtonData *bd = (struct ScrollButtonData *) INST_DATA(cl, g);
932 switch (gpi->MethodID)
935 /* May define an attribute to make delay configurable */
938 /* Notify our target that we have initially hit. */
939 NotifyAttrs((Object *)g, gpi->gpi_GInfo, 0,
943 /* Send more input */
948 ULONG retval = GMR_MEACTIVE;
951 /* This also works with classic (non-boopsi) images. */
952 if (PointInImage((gpi->gpi_Mouse.X << 16) + (gpi->gpi_Mouse.Y), g->GadgetRender))
955 selected = GFLG_SELECTED;
958 if (gpi->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE && gpi->gpi_IEvent->ie_Code == SELECTUP)
960 /* Gadgetup, time to go */
961 retval = GMR_NOREUSE;
962 /* Unselect the gadget on our way out... */
965 else if (gpi->gpi_IEvent->ie_Class == IECLASS_TIMER)
967 /* We got a tick: decrement counter, and if 0, send notify. */
969 if (bd->TickCounter) bd->TickCounter--;
971 /* Notify our target that we are still being hit */
972 NotifyAttrs((Object *)g, gpi->gpi_GInfo, 0,
977 if ((g->Flags & GFLG_SELECTED) != selected)
981 /* Update changes in gadget render */
982 g->Flags ^= GFLG_SELECTED;
983 if (rp = ObtainGIRPort(gpi->gpi_GInfo))
985 DoMethod((Object *) g, GM_RENDER, gpi->gpi_GInfo, rp, GREDRAW_UPDATE);
993 /* Super class handles everything else */
994 return (DoSuperMethodA(cl, (Object *)g, (Msg) gpi));
1000 static Class *MakeScrollButtonClass(void)
1004 if (class = MakeClass(NULL, BUTTONGCLASS, NULL, sizeof(struct ScrollButtonData), 0))
1005 class->cl_Dispatcher.h_Entry = (ULONG (*)()) ScrollButtonDispatcher;
1012 static BOOL FreeScrollButtonClass(Class *cl)
1014 return (FreeClass(cl));