/* * ZOOM-DAEMON A program that implements Zoom gadgets for all Intuition * windows that are opened while it is running. * * Copyright 1989 by Davide P. Cervone. * You may use this code, provided this copyright notice is kept intact. */ #include "Zoom-Handler.h" static char *program = PROGRAM; static char *copyright = COPYRIGHT; struct ExtGadget *FirstZoom; /* Linked list of Zoom Gadgets */ /* * The Image structures for the HIRES and LOWRES Zoom Gadgets */ static struct Image ZoomImage = {-6,0, ZOOMWIDTH,ZOOMHEIGHT,ZOOMDEPTH, &ZoomData[0][0], 0x03,0x00, NULL}; static struct Image LR_ZoomImage = {-4,0, LRZOOMWIDTH,LRZOOMHEIGHT,LRZOOMDEPTH, &LR_ZoomData[0][0], 0x03,0x00,NULL}; /* * Templates for the HIRES and LOWRES Zoom Gadgets (copied when a new * instance of a Zoom Gadget is created). */ static struct ExtGadget ZoomGadget = { NULL,NULL, NULL, 0,0,0,0, 0, {NULL, 0,0, 21,10, GADGHCOMP | GADGIMAGE | GRELRIGHT, RELVERIFY | TOPBORDER, SYSGADGET | BOOLGADGET, (APTR)&ZoomImage, NULL, NULL, 0, NULL, ZOOMGADG, NULL} }; static struct ExtGadget LR_ZoomGadget = { NULL,NULL, NULL, 0,0,0,0, 0, {NULL, 0,0, 15,10, GADGHCOMP | GADGIMAGE | GRELRIGHT, RELVERIFY | TOPBORDER, SYSGADGET | BOOLGADGET, (APTR)&LR_ZoomImage, NULL, NULL, 0, NULL, ZOOMGADG, NULL} }; /* * PositionZoomGadget() * * Finds the position for the zoom gadget by checking for GRELRIGHT * gadgets in the window's gadget list. Gadgets in the TOPBORDER are * counted, but since the DEPTH gadgets are not listed with TOPBORDER * flags set, we also check for SYSGADGETs that are GRELGADGETs but not * GRELBOTTOM gadgets (the SIZING gadget is GRELRIGHT and GRELBOTTOM), * the DEPTH gadgets are just GRELRIGHT). The farthest left position is * recorded, and the Zoom Gadget is placed just to the left of that. */ static void PositionZoomGadget(zGadget,theWindow) struct Gadget *zGadget; struct Window *theWindow; { struct Gadget *theGadget = theWindow->FirstGadget; int FarthestLeft = 1; while (theGadget) { if ((theGadget->Flags & (GRELRIGHT|GRELBOTTOM)) == GRELRIGHT && theGadget->TopEdge <= zGadget->Height && theGadget->LeftEdge < FarthestLeft) FarthestLeft = theGadget->LeftEdge; theGadget = theGadget->NextGadget; } zGadget->LeftEdge = FarthestLeft - zGadget->Width; } /* * AddZoomGadget() * * Allocate a new Zoom Gadget structure, and initialize it for the proper * resolution of the window it is attached to. Set the position of the * gadget so that it is to the left of the depth gadgets. Then link it * into the linked list of zoom gadgets so that we can keep track of it * (Forbid() so that the linked list does not change while we are using it). * Add the new gadget into the window, and refresh it so that it is * displayed properly. Since the gadget is added to the beginning of the * list, it will lie on top of the drag bar (if any). */ static void AddZoomGadget(theWindow) struct Window *theWindow; { ULONG Resolution = theWindow->WScreen->ViewPort.Modes & HIRES; struct ExtGadget *theGadget; theGadget = AllocMem(EXTGADGETSIZE,MEMFLAGS); if (theGadget) { theGadget->Window = theWindow; theGadget->Flags = 0; if (Resolution == HIRES) theGadget->Gadget = ZoomGadget.Gadget; else theGadget->Gadget = LR_ZoomGadget.Gadget; PositionZoomGadget(&(theGadget->Gadget),theWindow); if (theWindow->Flags & GIMMEZEROZERO) theGadget->Gadget.GadgetType |= GZZGADGET; Forbid(); theGadget->Prev = NULL; theGadget->Next = FirstZoom; if (FirstZoom) FirstZoom->Prev = theGadget; FirstZoom = theGadget; Permit(); AddGadget(theWindow,&(theGadget->Gadget),0); RefreshGList(&(theGadget->Gadget),theWindow,NULL,1); } } /* * cOpenWindow() * * This is called after a window has been opened: theWindow is the * pointer to the opened window. * * If the window gets NEWSIZE IntuiMessages, or if it includes a SIZING * gadget, then add the Zoom Gadget. We assume that windows that do not * include one of these are not allowed to change size, so we don't add * Zoom Gadgets to them. */ struct Window *cOpenWindow(theWindow) struct Window *theWindow; { if (theWindow) { if ((theWindow->IDCMPFlags & NEWSIZE) || (theWindow->Flags & WINDOWSIZING)) AddZoomGadget(theWindow); } return(theWindow); } /* * FindZoomGadget() * * Look through the linked list for a gadget attached to this window * (alternatively, we could look through the window's gadget list for * one that has the ZOOMGADG Id, but this is probably safer). * Do this in Forbid() mode so that the list does not change while * we are looking at it. */ static struct ExtGadget *FindZoomGadget(theWindow) struct Window *theWindow; { struct ExtGadget *theGadget; Forbid(); theGadget = FirstZoom; while (theGadget && theGadget->Window != theWindow) theGadget = theGadget->Next; Permit(); return(theGadget); } /* * cCloseWindow() * * This is called before the window is closed. * * If a window is being closed, check to see if it has a Zoom Gadget. * If so, then remove the gadget from the window, unlink it from * the linked list of gadgets, and free its memory. This is done in * Forbid() mode so that the linked list of zoom gadgets does not change * while we are looking at it. */ void cCloseWindow(theWindow) struct Window *theWindow; { struct ExtGadget *theGadget; if (theWindow) { Forbid(); theGadget = FindZoomGadget(theWindow); if (theGadget) { RemoveGadget(theWindow,&(theGadget->Gadget)); if (theGadget->Next) theGadget->Next->Prev = theGadget->Prev; if (theGadget->Prev) theGadget->Prev->Next = theGadget->Next; if (theGadget == FirstZoom) FirstZoom = theGadget->Next; FreeMem(theGadget,EXTGADGETSIZE); } Permit(); } } /* * CheckZoomMove() * * Called when a new gadget is being added to a window, this checks to * see if it is first in the gadget list and that it is being added to * a window (not a screen or requester). If so, look for a zoom gadget * attached to this window. If one exists, then remove it temporarily, * reposition it in relation to other GRELRIGHT gadgets, and then add it * back at the front of the list (make sure it's displayed on top). * Ten refresh the display so that the old image is removed and the new * one is displayed. */ static void CheckZoomMove(theParent,theGadget,Position) struct Window *theParent; struct Gadget *theGadget; int Position; { struct ExtGadget *zGadget; if (Position == 0 && (theGadget->GadgetType & (SCRGADGET|REQGADGET)) == 0) { zGadget = FindZoomGadget(theParent); if (zGadget && theGadget != &(zGadget->Gadget)) { RemoveGadget(theParent,&(zGadget->Gadget)); PositionZoomGadget(&(zGadget->Gadget),theParent); aOldAddGadget(theParent,&(zGadget->Gadget),0); RefreshWindowFrame(theParent); } } } /* * cAddGadget() * * This is called before the gadget is added, and we are expected to call * aOldAddGadget somewhere in this routine. The return address is the * position of the new gadget in the list. * * First we add the new gadget into the list, then check the list for * Zoom Gadgets and reposition them as needed. */ int cAddGadget(theParent,theGadget,Position) struct Window *theParent; struct Gadget *theGadget; int Position; { Position = aOldAddGadget(theParent,theGadget,Position); CheckZoomMove(theParent,theGadget,Position); return(Position); } /* * cAddGList() * * This is called before the gadgets are added, and we are expected to call * aOldAddGList somewhere in this routine. The return address is the * position of the new gadgets in the list. * * First we add the new gadgets into the list, then check the list for * Zoom Gadgets and reposition them as needed. */ int cAddGList(theParent,theGadget,Position,Count,theRequest) struct Window *theParent; struct Gadget *theGadget; int Position; int Count; struct Requester *theRequest; { Position = aOldAddGList(theParent,theGadget,Position,Count,theRequest); CheckZoomMove(theParent,theGadget,Position); return(Position); } /* * ResizeWindow() * * This routine provides a safe way to resize and move a window (the size * and position may be changed in order to make the window fit the screen). * * Check to be sure the width and height are mot too big. * Check to be sure the position makes the whole window fit on the screen. * * Calculate the offsets needed to make the window the right size and place * If the new widths would take it off the screen, * Move the window to its new position, and set the offsets to zero. * Size the window to make it the new size. * Move the window to its new position. */ static void ResizeWindow(theWindow,x,y,w,h) struct Window *theWindow; int x,y,w,h; { struct Screen *theScreen = theWindow->WScreen; int dx,dy,dh,dw; if (w < 0) w = theScreen->Width; else if (w > theScreen->Width) w = theScreen->Width; if (h < 0) h = theScreen->Height; else if (h > theScreen->Height) h = theScreen->Height; if (x < 0) x = 0; else if (x + w > theScreen->Width) x = theScreen->Width - w; if (y < 0) y = 0; else if (y + h > theScreen->Height) y = theScreen->Height - h; dx = x - theWindow->LeftEdge; dy = y - theWindow->TopEdge; dw = w - theWindow->Width; dh = h - theWindow->Height; if (theWindow->LeftEdge + w > theScreen->Width || theWindow->TopEdge + h > theScreen->Height) { MoveWindow(theWindow,dx,dy); dx = dy = 0; } if (dw || dh) SizeWindow(theWindow,dw,dh); if (dx || dy) MoveWindow(theWindow,dx,dy); } /* * ZoomOutWindow() * * If the window has already been zoomed, * Resize the window to its original size. * Mark the window as not ZOOMED. * Otherwise the window should be sized to the full size of the screen. * If the window is not zoomed in then * Save the window's current position and size. * Zoom the window out to the size of the screen. * Mark the window as ZOOMED. */ static void ZoomOutWindow(theGadget) struct ExtGadget *theGadget; { struct Window *theWindow = theGadget->Window; if (theGadget->Flags & EG_ZOOMEDOUT) { ResizeWindow(theWindow,theGadget->x,theGadget->y, theGadget->w,theGadget->h); theGadget->Flags = 0; } else { if ((theGadget->Flags & EG_ZOOMED) == 0) { theGadget->x = theWindow->LeftEdge; theGadget->y = theWindow->TopEdge; theGadget->w = theWindow->Width; theGadget->h = theWindow->Height; } ResizeWindow(theWindow,0,0,theWindow->MaxWidth,theWindow->MaxHeight); theGadget->Flags = EG_ZOOMEDOUT; } } /* * ZoomInWindow() * * If the window has already been zoomed, * Resize the window to its original size. * Mark the window as not ZOOMED. * Otherwise the window should be sized to its minimum size. * If the window is not zoomed out then * Save the window's current position and size. * Zoom the window to its smallest size. * Mark the window as ZOOMED. */ static void ZoomInWindow(theGadget) struct ExtGadget *theGadget; { struct Window *theWindow = theGadget->Window; int w,h; if (theGadget->Flags & EG_ZOOMEDIN) { ResizeWindow(theWindow,theGadget->x,theGadget->y, theGadget->w,theGadget->h); theGadget->Flags = 0; } else { if ((theGadget->Flags & EG_ZOOMED) == 0) { theGadget->x = theWindow->LeftEdge; theGadget->y = theWindow->TopEdge; theGadget->w = theWindow->Width; theGadget->h = theWindow->Height; } w = MAX(theWindow->MinWidth,-theGadget->Gadget.LeftEdge); h = MAX(theWindow->MinHeight,theGadget->Gadget.Height); ResizeWindow(theWindow,theWindow->LeftEdge,theWindow->TopEdge,w,h); theGadget->Flags = EG_ZOOMEDIN; } } /* * PressedZoomGadget() * * Finds the Zoom Gadget that is currently selected (if any). * This is called from an Input Handler whenever a SELECTUP button * event is passed to Intuition. Intuition maintains the SELECTED flag * for the Zoom Gadgets and since the ZOOM gadgets are RELVERY BOOLGADGETs * they will be marked SELECTED whenever the mouse is pressed and held, and * as long as the mouse is over the gadget itself. Thus if we find a * selected Zoom Gadget when the left mouse button is being released, * we can be pretty sure that the user is letting go of the Zoom Gadget * while the mouse is still over it, and thus we should process the * gadget hit. This is done in Forbid() mode so that the linked list does * not change while we are looking at it. */ static struct ExtGadget *PressedZoomGadget() { struct ExtGadget *theGadget; Forbid(); theGadget = FirstZoom; while (theGadget && (theGadget->Gadget.Flags & SELECTED) == 0) theGadget = theGadget->Next; Permit(); return(theGadget); } /* * ZoomHandler() * * This is the Input Handler that checks for Zoom Gadget hits. As described * in PressedZoomGadget() above, every time the left or right mouse button is * released, we check to see if a Zoom Gadget is SELECTED, and assume that * that gadget is being released. If such a gadget is found, then the * window it is attached to is zoomed. The button event is still passed * to Intuition so that it will know that the mouse is no longer pressed, * and will deactivate the gadget. * * Since the Zoom Gadgets are marked as SYSGADGETs, Intuition will not * send any IntuiMessages to the application about the Zoom Gadget, but since * their types are none of the standard Intuition gadgets, Intuition * ignores them. This saves having to monitor each windows IDCMP port for * messages from these gadgets, which reduces the overhead both in time and * programming. */ struct InputEvent *ZoomHandler(EventList,data) struct InputEvent *EventList; APTR data; { struct InputEvent *theEvent = EventList; struct ExtGadget *theGadget; while (theEvent) { if (theEvent->ie_Class == IECLASS_RAWMOUSE && (theEvent->ie_Code == SELECTUP || theEvent->ie_Code == MENUDOWN)) { theGadget = PressedZoomGadget(); if (theGadget) if (theEvent->ie_Code == MENUDOWN) { ZoomInWindow(theGadget); theEvent->ie_Code = SELECTUP; } else { ZoomOutWindow(theGadget); } } theEvent = theEvent->ie_NextEvent; } return(EventList); }