home *** CD-ROM | disk | FTP | other *** search
- /*
- * WICONIFY A utility that allows you to iconify any Intuition window
- * on any screen, and to open WB windows on any screen.
- *
- * wIcon.c Handles most aspects of icon creation and maintenance
- *
- * Copyright 1990 by Davide P. Cervone, all rights reserved.
- * You may use this code, provided this copyright notice is kept intact.
- */
-
- #define INTUITION_PREFERENCES_H /* don't need 'em */
- #include <intuition/intuitionbase.h>
- #include "wHandler.h"
-
- struct Window *WindowToActivate; /* Activate this window on SELECTUP */
- static WSCREEN *Refresh; /* List of screens to be refreshed */
-
- #define ICONDELAY 2L /* For window to come forward for CHANGEREFRESH */
- #define MAXWAIT 10 /* Number of attempts if it hasn't come forward */
- #define MOVE_DY 2048L /* Distance to move screen when iconified */
-
- #define WINDOW(layer) ((struct Window *)((layer)->Window))
- #define LAYERREFRESHBITS (LAYERSIMPLE | LAYERSMART)
- #define ICONSCREEN ((WSCREEN *)theIcon->Window->UserData)
-
-
-
- /*
- * SetRefresh()
- *
- * Lock the layers of the window's screen
- * Change the window's refresh status
- * Get the window's layer
- * Change the layer's refresh status
- * Unlock the screen's layers
- */
-
- static void SetRefresh(theWindow,WindowBits)
- struct Window *theWindow;
- ULONG WindowBits;
- {
- struct Layer *theLayer;
- UWORD LayerBits = (WindowBits == SMART_REFRESH)? LAYERSMART: LAYERSIMPLE;
-
- Forbid();
- LockLayerInfo(&theWindow->WScreen->LayerInfo);
- theWindow->Flags = (theWindow->Flags & ~REFRESHBITS) | WindowBits;
- theLayer = theWindow->WLayer;
- theLayer->Flags = (theLayer->Flags & ~LAYERREFRESHBITS) | LayerBits;
- UnlockLayerInfo(&theWindow->WScreen->LayerInfo);
- Permit();
- }
-
-
- /*
- * SetBackdrop()
- *
- * Lock the screen's layers
- * Add or remove the BACKDROP flag appropriately
- * Get the window's first layer (GZZ and requesters may give it more)
- * While there are more layers for this window (we assume they are sequential)
- * Set the backdrop status of the layer
- * Go on to the next layer
- * Start over again with the first layer behind the window
- * For any layers nbelowing to this window
- * Set the backdrop status of the layer
- * Move on to the previous layer
- * Unlock the layers
- */
-
- static void SetBackdrop(theWindow,Backdrop)
- struct Window *theWindow;
- int Backdrop;
- {
- struct Layer *theLayer;
-
- Forbid();
- LockLayerInfo(&theWindow->WScreen->LayerInfo);
- if (Backdrop)
- theWindow->Flags |= BACKDROP;
- else
- theWindow->Flags &= ~BACKDROP;
-
- theLayer = theWindow->WLayer;
- while (theLayer && theLayer->Window == (APTR)theWindow)
- {
- if (Backdrop)
- theLayer->Flags |= LAYERBACKDROP;
- else
- theLayer->Flags &= ~LAYERBACKDROP;
- theLayer = theLayer->front;
- }
-
- theLayer = theWindow->WLayer->back;
- while (theLayer && theLayer->Window == (APTR)theWindow)
- {
- if (Backdrop)
- theLayer->Flags |= LAYERBACKDROP;
- else
- theLayer->Flags &= ~LAYERBACKDROP;
- theLayer = theLayer->back;
- }
- UnlockLayerInfo(&theWindow->WScreen->LayerInfo);
- Permit();
- }
-
-
- /*
- * TopWindow()
- *
- * Lock the screen's layers so they don't change while we look
- * Start with the top-most layer
- * Look through the layer list for the first one with a window pointer
- * Get the layer's window pointer
- * Unlock the layers
- * Return the window.
- */
-
- static struct Window *TopWindow(theScreen)
- struct Screen *theScreen;
- {
- struct Window *theWindow = NULL;
- struct Layer_Info *theLayerInfo = &(theScreen->LayerInfo);
- struct Layer *theLayer;
-
- LockLayers(theLayerInfo);
- theLayer = theLayerInfo->top_layer;
- while (theLayer && WINDOW(theLayer) == NULL) theLayer = theLayer->back;
- if (theLayer) theWindow = WINDOW(theLayer);
- UnlockLayers(theLayerInfo);
- return(theWindow);
- }
-
-
- /*
- * HideWindow()
- *
- * If the icon is a screen icon (not a window icon)
- * If the screen is the active one, activate the WB Iconify window
- * Send the screen to the back
- * Move the screen off the bottom of the display
- * Link the screen's icon into the WB screen list
- * Otherwise
- * If the icon is supposed to have its refresh status changed
- * If the window is a SMART_REFRESH one
- * Bring the window to the front
- * Wait for the window to come to the front (timeout after MAXWAIT)
- * (we must have the window completely uncovered before we change
- * the refresh status, otherwise the refresh regions get completely
- * messed up!)
- * Set the refresh type to SIMPLE_REFRESH
- * Mark the icon as changed
- * If the window is not already a backdrop window
- * Mark it as a backdrop window
- * Record the change so we can undo it later
- * If the window is getting refresh messages
- * Turn them off (dont update while we can't see it!)
- * Record the change
- * Finally, send the window to the back (behind the wIconify backdrop)
- */
-
- static void HideWindow(theIcon,Flags)
- WICONREF *theIcon;
- UWORD Flags;
- {
- struct Window *theWindow = theIcon->Window;
- short i = MAXWAIT;
-
- if (theIcon->Icon.Flags & WI_SCREENICON)
- {
- Forbid();
- if (IntuitionBase->ActiveScreen == ICONSCREEN->Screen)
- ActivateWindow(RealWB->BackDrop);
- Permit();
- ScreenToBack(ICONSCREEN->Screen);
- MoveScreen(ICONSCREEN->Screen,0L,MOVE_DY);
- LinkIcon(theIcon,RealWB);
- } else {
- if ((theIcon->Icon.Flags & WI_CHANGEREFRESH) || (Flags & WI_CHANGE))
- {
- if ((theWindow->Flags & REFRESHBITS) == SMART_REFRESH)
- {
- WindowToFront(theWindow);
- while (theWindow != TopWindow(theIcon->Screen->Screen) && --i)
- Delay(ICONDELAY);
- SetRefresh(theWindow,SIMPLE_REFRESH);
- theIcon->Icon.Flags |= WI_REFRESHCHANGE;
- }
- }
- if ((theWindow->Flags & BACKDROP) == FALSE)
- {
- SetBackdrop(theWindow,TRUE);
- theIcon->Icon.Flags |= WI_BACKDROPCHANGE;
- }
- if ((theWindow->Flags & NOCAREREFRESH) == FALSE)
- {
- theWindow->Flags |= NOCAREREFRESH;
- theIcon->Icon.Flags |= WI_NOCARECHANGE;
- }
- WindowToBack(theWindow);
- }
- }
-
-
- /*
- * ShowWindow()
- *
- * If the icon is a screen icon
- * Move the screen back to its previous location
- * Bring it to the front
- * Otherwise
- * If the window was not a BACKDROP one before, fix its layers
- * If we changes the refresh report flag, reset it
- * Bring the window to the front
- * If we changed the refresh type of the window
- * Wait for the window to appear at the front (timeout after MAXWAIT)
- * Set the refresh type to SMART_REFRESH
- * Remove the flags that say what changes were made
- */
-
- static void ShowWindow(theIcon)
- WICONREF *theIcon;
- {
- struct Window *theWindow = theIcon->Window;
- short i = MAXWAIT;
-
- if (theIcon->Icon.Flags & WI_SCREENICON)
- {
- MoveScreen(ICONSCREEN->Screen,0L,-MOVE_DY);
- ScreenToFront(ICONSCREEN->Screen);
- } else {
- if (theIcon->Icon.Flags & WI_BACKDROPCHANGE)
- SetBackdrop(theWindow,FALSE);
- if (theIcon->Icon.Flags & WI_NOCARECHANGE)
- theWindow->Flags &= ~NOCAREREFRESH;
- WindowToFront(theWindow);
- if (theIcon->Icon.Flags & WI_REFRESHCHANGE)
- {
- while (theWindow != TopWindow(theIcon->Screen->Screen) && --i)
- Delay(ICONDELAY);
- SetRefresh(theWindow,SMART_REFRESH);
- }
- theIcon->Icon.Flags &= ~WI_CHANGEBITS;
- }
- }
-
-
- /*
- * RefreshIcons()
- *
- * If there is a screen to refresh
- * If we are supposed to clear the screen, mark it to be cleared
- * If the screen is not already in the list
- * Link it into the list and mark it as in the list
- * (The refreshing is delayed until after all the messages are processed
- * so we don't refresh the same screen multiple times)
- */
-
- void RefreshIcons(theScreen,ClearIt)
- WSCREEN *theScreen;
- int ClearIt;
- {
- Forbid();
- if (theScreen)
- {
- if (ClearIt) theScreen->Flags |= WI_CLEARIT;
- if ((theScreen->Flags & WI_REFRESH) == FALSE)
- {
- theScreen->Flags |= WI_REFRESH;
- theScreen->NextRefresh = Refresh;
- Refresh = theScreen;
- }
- }
- Permit();
- }
-
-
- /*
- * DrawGadgets()
- *
- * Get the first gadget on the screen
- * While there are more gadgets
- * Temporarily use the MutualExclude flag as a backward pointer
- * Save the pointer to the last gadget seen
- * Go on to the next one
- * Start at the end of the list
- * While there are more gadgets to draw
- * Get the next gadget from MutualExclude (where we stored it above)
- * Reset MutualExclude to zero
- * Draw the given gadget
- * (The gadgets are drawn in reverse order to make them overlap correctly.
- * One could replace this routine by RefreshGadgets if desired. There are
- * two reason's not to, however; RefreshGadgets draws all the gadgets first
- * then goes back and adds any select imagery or complements. This causes
- * undue flickering of the icons if there are many of them selected. Also,
- * if any selected ones overlap, the complementation cancels out on the
- * overlapped region)
- */
-
- static void DrawGadgets(theScreen)
- WSCREEN *theScreen;
- {
- struct Gadget *theGadget = theScreen->BackDrop->FirstGadget;
- struct Gadget *IconGadget = NULL;
-
- while (theGadget)
- {
- theGadget->MutualExclude = (LONG) IconGadget;
- IconGadget = theGadget;
- theGadget = theGadget->NextGadget;
- }
- while (IconGadget)
- {
- theGadget = IconGadget;
- IconGadget = (struct Gadget *) theGadget->MutualExclude;
- theGadget->MutualExclude = 0L;
- RefreshGList(theGadget,theScreen->BackDrop,NULL,ONE);
- }
- }
-
-
- /*
- * RefreshScreens()
- *
- * For each screen in the list
- * If it still has a backdrop window (ie, the screen is not closing)
- * If we are supposed to clear the screen, do so
- * If the screen has gadgets, draw them
- * Clear the screen's refresh bits
- * Move on to the next screen
- */
-
- void RefreshScreens()
- {
- Forbid();
- while (Refresh)
- {
- if (Refresh->BackDrop)
- {
- if (Refresh->Flags & WI_CLEARIT) SetRast(Refresh->BackDrop->RPort,0L);
- if (Refresh->BackDrop->FirstGadget) DrawGadgets(Refresh);
- }
- Refresh->Flags &= ~(WI_REFRESH| WI_CLEARIT);
- Refresh = Refresh->NextRefresh;
- }
- Permit();
- }
-
-
- /*
- * UnLinkRefresh()
- *
- * Find the given screen in the refresh list and remove it.
- */
-
- void UnLinkRefresh(theScreen)
- WSCREEN *theScreen;
- {
- WSCREEN **ScreenPtr;
-
- Forbid();
- ScreenPtr = &Refresh;
- while (*ScreenPtr && *ScreenPtr != theScreen)
- ScreenPtr = &((*ScreenPtr)->NextRefresh);
- if (*ScreenPtr) *ScreenPtr = theScreen->NextRefresh;
- Permit();
- }
-
-
- /*
- * RemoveIcon()
- *
- * If the icon has a gadget
- * If the icon is selected
- * Unlink the gadget from the selection list
- * If this was the last icon on the screen update the menus
- * Mark the icon as not selected
- * If the screen still has a backdrop window
- * Remove the gadget from the window
- * Free the icon's gadget structure
- * Clear and refresh the screen's icons
- */
-
- void RemoveIcon(theIcon)
- WICONREF *theIcon;
- {
- if (theIcon->Gadget)
- {
- if (theIcon->Icon.Flags & WI_SELECTED)
- {
- UnLinkGadget(theIcon->Gadget);
- if (theIcon->Screen->Selected == NULL) UpdateActiveMenu();
- theIcon->Icon.Flags &= ~WI_SELECTED;
- }
- if (theIcon->Screen->BackDrop)
- RemoveGadget(theIcon->Screen->BackDrop,theIcon->Gadget);
- FREESTRUCT(wGadget,theIcon->Gadget); theIcon->Gadget = NULL;
- RefreshIcons(theIcon->Screen,TRUE);
- }
- }
-
-
- /*
- * DeleteIcon()
- *
- * Unlink the icon from the screen's list
- * Remove the icon gadget from the screen
- * If the screen has no more icons
- * If the screen has a task waiting to close it
- * Signal that task that it is now OK to close the screen
- * If Iconify is waiting to end, signal that it can try again
- * Update the menus (deactivate OPENALL, etc)
- * If the icon is not a screen icon (which is part of the scren structure)
- * Free the icon's memory
- */
-
- void DeleteIcon(theIcon)
- WICONREF *theIcon;
- {
- UnLinkIcon(theIcon);
- RemoveIcon(theIcon);
- if (theIcon->Screen->IconRef == NULL)
- {
- if (theIcon->Screen->CloseTask)
- Signal(theIcon->Screen->CloseTask,theIcon->Screen->CloseSignal);
- if (EndSignal) Signal(IconTask,EndSignal);
- UpdateActiveMenu();
- }
- if ((theIcon->Icon.Flags & WI_SCREENICON) == FALSE)
- FREESTRUCT(wIconRef,theIcon);
- }
-
-
- /*
- * CloseIcon()
- *
- * If the icon is allowed to be closed
- * If the icon wants to receive close messages, send one
- * Otherwise if the icon's window currently has a requester up, no nothing
- * Otherwise send the CLOSEWINDOW message to simulate pressing the
- * close gadget of the window
- */
-
- void CloseIcon(theIcon)
- WICONREF *theIcon;
- {
- if ((theIcon->Icon.Flags & WI_NOCLOSE) == FALSE)
- {
- if (theIcon->Icon.Report & WI_REPORTCLOSE)
- ReportEvent(WI_REPORTCLOSE,theIcon);
- else if (theIcon->Window && theIcon->Window->FirstRequest) /* nothing */;
- else SendIntuiMessage(CLOSEWINDOW,theIcon->Window);
- }
- }
-
-
- /*
- * Iconify()
- *
- * If we have an icon
- * If the icon is not already iconified, and it is allowed to be, and there
- * is somewhere to put the icon
- * If the icon is for a window or (if it IS a screen icon) if the
- * real WB screen is open and is not the screen whose icon this is
- * Find out it the icon's window is the active one
- * If so, activate the screen's backdrop window
- * Get a new gadget for the icon
- * If one was able to be allocated
- * Mark the icon as iconified
- * If the icon has an associated window
- * If it has no close gadget, mark the icon as not closable
- * Hide the window behind the wIconify backdrop window
- * Set up the gadget for the icon
- * Add the gadget to the backdrop window
- * Refresh the screen
- * If the icon wants iconification reports, send one
- * If the icon's window was the active one, activate its icon
- */
-
- void Iconify(theIcon,Flags)
- WICONREF *theIcon;
- UWORD Flags;
- {
- int isActive;
-
- if (theIcon)
- {
- if ((theIcon->Icon.Flags & (WI_ICONIFIED| WI_NOICONIFY)) == FALSE &&
- theIcon->Screen->BackDrop)
- {
- if ((theIcon->Icon.Flags & WI_SCREENICON) == FALSE ||
- (RealWB && ICONSCREEN != RealWB))
- {
- isActive = (theIcon->Window == IntuitionBase->ActiveWindow);
- if (isActive) ActivateWindow(theIcon->Screen->BackDrop), Delay(1L);
- if (NEWSTRUCT(wGadget,theIcon->Gadget))
- {
- theIcon->Icon.Flags |= WI_ICONIFIED;
- if (theIcon->Window)
- {
- if ((theIcon->Window->IDCMPFlags & CLOSEWINDOW) == FALSE)
- theIcon->Icon.Flags |= WI_NOCLOSE;
- HideWindow(theIcon,Flags);
- }
- SetupGadget(theIcon);
- AddGadget(theIcon->Screen->BackDrop,theIcon->Gadget,0);
- RefreshIcons(theIcon->Screen,TRUE);
- Forbid();
- if (theIcon->Icon.Report & WI_REPORTICONIFIED)
- ReportEvent(WI_REPORTICONIFIED,theIcon);
- if (isActive) SelectIcon(theIcon,FALSE);
- Permit();
- }
- }
- }
- }
- }
-
-
- /*
- * Restore()
- *
- * If we have an icon to restore
- * If it is iconified
- * If the icon wants restores reported, report it
- * Otherwise
- * If the icon has a window
- * Bring it out from behind the backdrop window
- * If we are to activate the window right away, do so
- * Otherwise record it for later activation
- * If we are not saving the icon's position, clear its position
- * Otherwise save the icon's position
- * If we are reporting restoration events, do so
- * If the icon is a screen icon
- * Remove the icon from the WB screen and reset its screen pointer
- * Otherwise if the icon has a window remove the icon from the screen
- * (don't remove icons with no windows - they must call DeleteIcon)
- */
-
- void Restore(theIcon,ActivateNow)
- WICONREF *theIcon;
- int ActivateNow;
- {
- if (theIcon)
- {
- if (theIcon->Icon.Flags & WI_ICONIFIED)
- {
- if (theIcon->Icon.Report & WI_REPORTOPEN)
- {
- ReportEvent(WI_REPORTOPEN,theIcon);
- } else {
- if (theIcon->Window)
- {
- ShowWindow(theIcon);
- if (ActivateNow) ActivateWindow(theIcon->Window);
- else WindowToActivate = theIcon->Window;
- theIcon->Icon.Flags &= ~WI_ICONIFIED;
- }
- if (theIcon->Icon.Flags & WI_NOSAVEPOS)
- {
- theIcon->Icon.x = theIcon->Icon.y = 0;
- } else {
- theIcon->Icon.x = theIcon->Gadget->Gadget.LeftEdge;
- theIcon->Icon.y = theIcon->Gadget->Gadget.TopEdge;
- }
- if (theIcon->Icon.Report & WI_REPORTRESTORE)
- ReportEvent(WI_REPORTRESTORE,theIcon);
- if (theIcon->Icon.Flags & WI_SCREENICON)
- {
- DeleteIcon(theIcon);
- theIcon->Screen = ICONSCREEN;
- } else if (theIcon->Window) RemoveIcon(theIcon);
- }
- }
- }
- }
-
-
- /*
- * OpenAllIcons()
- *
- * If a screen was specified
- * Get the first icon on the screen
- * While there are more icons to handle
- * Restore the icon and go on
- * (we save the pointer to the next icon first since Restore may
- * free the icon's memory and invalidate the pointer)
- */
-
- void OpenAllIcons(theScreen)
- WSCREEN *theScreen;
- {
- WICONREF *theIcon,*nextIcon;
-
- if (theScreen)
- {
- theIcon = theScreen->IconRef;
- while (theIcon)
- {
- nextIcon = theIcon->Next;
- Restore(theIcon,TRUE);
- theIcon = nextIcon;
- }
- }
- }
-
-
- /*
- * OpenSelected()
- *
- * If there is a screen to work with
- * Get the first gadget selected on the screen
- * While there are more gadgets to handle
- * Restore the window associated with gadget
- * Go on to the next one
- * (we save the pointer to the next gadget before restoring since
- * Restore() will remove the gadget before it returns)
- */
-
- void OpenSelected(theScreen,Activate)
- WSCREEN *theScreen;
- int Activate;
- {
- struct wGadget *theGadget,*nextGadget;
-
- if (theScreen)
- {
- theGadget = theScreen->Selected;
- while (theGadget)
- {
- nextGadget = theGadget->NextSelect;
- Restore(theGadget->Gadget.UserData,Activate);
- theGadget = nextGadget;
- }
- }
- }
-
-
- /*
- * CloseSelected()
- *
- * Start with the first selected gadget on the screen
- * While there are more gadgets to handle
- * Close the icon associated with the gadget
- * Go on to the next gadget
- */
-
- void CloseSelected(theScreen)
- WSCREEN *theScreen;
- {
- struct wGadget *theGadget = theScreen->Selected;
- struct wGadget *nextGadget;
-
- Forbid();
- while (theGadget)
- {
- nextGadget = theGadget->NextSelect;
- CloseIcon(GADGETICON);
- theGadget = nextGadget;
- }
- Permit();
- }
-
-
- /*
- * LockSelected()
- *
- * Start with the first selected gadget on the screen
- * Look through the list to see if any are locked
- * (if they are all locked, LockIt will remain FALSE, else it will be TRUE)
- * For each selected gadget on the screen
- * Set the LOCKED flag appropriately
- */
-
- void LockSelected(theScreen)
- WSCREEN *theScreen;
- {
- struct wGadget *theGadget = theScreen->Selected;
- int LockIt = FALSE;
-
- Forbid();
- while (theGadget && !LockIt)
- {
- LockIt = ((GADGETICON->Icon.Flags & WI_LOCKED) == FALSE);
- theGadget=theGadget->NextSelect;
- }
-
- for (theGadget = theScreen->Selected; theGadget;
- theGadget = theGadget->NextSelect)
- {
- if (LockIt)
- GADGETICON->Icon.Flags |= WI_LOCKED;
- else
- GADGETICON->Icon.Flags &= ~WI_LOCKED;
- }
- Permit();
- }
-