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.
- *
- * wMain.c The handler setup and main loop routines
- *
- * 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"
- #include "wSetup.h"
- #include "wMenu.h"
- #include <exec/interrupts.h>
- #include <devices/input.h>
- #include <libraries/dos.h>
-
- static int MessageCount; /* number of messages still not returned */
-
- extern void wHandlerStub();
- static struct Interrupt wIconInterrupt = /* the Interrupt needed to add a */
- { /* handler to the input chain */
- {NULL, NULL, 0, 51, NULL}, /* ln_Pri = 51 (before Intuition) */
- NULL,
- &wHandlerStub /* the handler to add */
- };
-
-
- extern struct wMenuItem OpenWindowMenu[];
- extern void cOpenScreen(),FreeAllLists();
-
- extern void aOpenWindow(),aCloseWindow();
- extern void aOpenScreen(),aCloseScreen();
- extern void aSetWindowTitles(),aWindowToFront(),aWindowToBack();
- extern void aActivateWindow();
- extern void aBuildSysRequest(),aFreeSysRequest(),aAutoRequest();
-
- /*
- * Storage for the old library vectors that are replaced by SetFunction
- */
- long OldOpenWindow,OldCloseWindow,OldOpenScreen,OldCloseScreen;
- long OldSetWindowTitles,OldWindowToFront,OldWindowToBack;
- long OldActivateWindow,OldBuildSysRequest,OldFreeSysRequest,OldAutoRequest;
-
- /*
- * The data needed by the loader to set up the handler
- */
- static struct HandlerData HandlerData =
- {
- MAJVERSION,MINVERSION,
- NULL, NULL,
- &IntuitionBase, &GfxBase, &LayersBase, &SysBase, &DOSBase,
- &wIconInterrupt,
- &wMenu[0],&OpenWindowMenu[0],
- &DefaultIcon, &DefaultScreenIcon,
- &HiResCLICommand, &LoResCLICommand, &StackSize,
- &DefaultImage, &DefaultSelect, &DefaultMask,
- &DefaultScreenImage, &DefaultScreenSelect, &DefaultScreenMask,
- &DefaultFlags,
- &DefaultScreenFlags,
- &IgnoreScreen,
- &IconifyKey,&ActivateKey,
- &IconifyQuals,&IconifyDisquals,&IconifyChange,
- &ActivateQuals,
- &Colors[0],
- &cOpenScreen,&FreeAllLists,
- &aOpenWindow,&OldOpenWindow,
- &aCloseWindow,&OldCloseWindow,
- &aOpenScreen,&OldOpenScreen,
- &aCloseScreen,&OldCloseScreen,
- &aSetWindowTitles,&OldSetWindowTitles,
- &aWindowToFront,&OldWindowToFront,
- &aWindowToBack,&OldWindowToBack,
- &aActivateWindow,&OldActivateWindow,
- &aBuildSysRequest,&OldBuildSysRequest,
- &aFreeSysRequest,&OldFreeSysRequest,
- &aAutoRequest,&OldAutoRequest
- };
-
-
- extern struct MsgPort *CreatePort();
- extern void DeletePort();
- extern void wMain();
- extern void ReplyMessages();
-
-
- /*
- * Setup()
- *
- * This routine MUST be linked into the handler as the first routine.
- * It is called by the loader to check version numbers, and to get
- * the handler data structure. It should compare the version number
- * and return NULL if a mismatch occurs or a pointer to HandlerData
- * if all is OK.
- *
- * Since the handler is started as a process, it will also be called
- * as the process first starts up. FirstCall is used to tell which
- * invocation this is.
- *
- * When it is called as part of the process starting up
- * Get our task pointer for use by the handler routines
- * Create a port for icon messages
- * And one for the window's common UserPort
- * Get a signal for when the last window on a screen is closed
- * If all of these were allocated
- * Clear the close signal
- * If the Real WB is open and we have a backdrop window on it
- * Set and clear the menu strip (to get the NL-Deamon to change
- * its pen number, in case it is going to)
- * Signal the loader that all is OK so far
- * Wait for the loader to finish setting up
- * If we were not cancelled, call the main loop routine
- * Get ready to singal OK
- * Otherwise (something could not be set up) Get ready to signal CANCEL
- * Reply to any messages in the UserPort or IconPort
- * Free the ports that were allocated
- * Signal the loader (either OK or CANCEL)
- */
-
- struct HandlerData *Setup(MajLoadVers,MinLoadVers)
- int MajLoadVers,MinLoadVers;
- {
- ULONG theSignal;
- static int FirstCall = TRUE;
- struct HandlerData *theData = &HandlerData;
-
- if (FirstCall)
- {
- if (MajLoadVers < MAJLOADVERS ||
- (MajLoadVers == MAJLOADVERS && MinLoadVers < MINLOADVERS))
- theData = NULL;
- FirstCall = FALSE;
- } else {
- theData = NULL;
- IconTask = FindTask(NULL);
- wIconPort = CreatePort(WICONPORT);
- wUserPort = CreatePort(NULL);
- CloseSigBit = AllocSignal(-ONE);
- if (wIconPort && wUserPort && CloseSigBit != -ONE)
- {
- CloseSignal = (ONE << CloseSigBit);
- SetSignal(CloseSignal,0L);
- if (RealWB && RealWB->BackDrop)
- {
- SetMenuStrip(RealWB->BackDrop,wMenu); /* for NL-Deamon */
- ClearMenuStrip(RealWB->BackDrop);
- }
- Signal(HandlerData.ParentTask,OKSIGNAL);
- theSignal = Wait(OKSIGNAL| CANCELSIGNAL);
- if ((theSignal & CANCELSIGNAL) == FALSE) wMain();
- theSignal = OKSIGNAL;
- } else theSignal = CANCELSIGNAL;
- Forbid();
- ReplyMessages();
- if (wIconPort) DeletePort(wIconPort);
- if (wUserPort) DeletePort(wUserPort);
- Signal(HandlerData.ParentTask,theSignal);
- }
- return(theData);
- }
-
-
- /*
- * CreatePort()
- *
- * Get a new port structure
- * Allocate a signal for it
- * If none could be allocated
- * Free the structure
- * Otherwise
- * Set the port's name and type
- * Set its signal type and signal task
- * Add it to the port list if it has a name, otheriwse
- * initialize its message list
- */
-
- struct MsgPort *CreatePort(theName)
- char *theName;
- {
- struct MsgPort *thePort;
-
- if (NEWSTRUCT(MsgPort,thePort))
- {
- thePort->mp_SigBit = AllocSignal(-ONE);
- if (thePort->mp_SigBit == -ONE)
- {
- FREESTRUCT(MsgPort,thePort);
- thePort = NULL;
- } else {
- thePort->mp_Node.ln_Name = theName;
- thePort->mp_Node.ln_Type = NT_MESSAGE;
- thePort->mp_Flags = PA_SIGNAL;
- thePort->mp_SigTask = (struct Task *)FindTask(NULL);
- if (theName) AddPort(thePort); else NewList(&(thePort->mp_MsgList));
- }
- }
- return(thePort);
- }
-
-
- /*
- * DeletePort()
- *
- * If the port exists
- * If it has a name, remove it frlom the system port list
- * Remove its type and message list
- * Free the port's signal
- * Free the ports memory
- */
-
- void DeletePort(thePort)
- struct MsgPort *thePort;
- {
- if (thePort)
- {
- if (thePort->mp_Node.ln_Name) RemPort(thePort);
- thePort->mp_Node.ln_Type = 0xFF;
- thePort->mp_MsgList.lh_Head = (struct Node *)-1L;
- FreeSignal(thePort->mp_SigBit);
- FREESTRUCT(MsgPort,thePort);
- }
- }
-
-
- /*
- * ReportEvent()
- *
- * If the icon has an IconPort to send messages to
- * Get a new message structure
- * Increment the number of messages yet to be replied
- * Set the message's Window, Icon, Action and Flags fields
- * Set up the data field for special cases
- * Set the reply port to the IconPort and send the message
- */
-
- void ReportEvent(theEvent,theIcon,theData)
- ULONG theEvent;
- WICONREF *theIcon;
- APTR theData;
- {
- struct wIconMessage *theMessage;
-
- if (theIcon->Icon.IconPort)
- {
- if (NEWSTRUCT(wIconMessage,theMessage))
- {
- MessageCount++;
- theMessage->Window = theIcon->Window;
- theMessage->Icon = theIcon;
- theMessage->Action = theEvent;
- theMessage->Flags = WI_ICONMESSAGE| WI_REPORT| WI_NOREPLY;
- switch(theEvent)
- {
- case WI_REPORTACTIVATE:
- case WI_REPORTINACTIVE:
- case WI_REPORTNEWSCREEN:
- case WI_REPORTSCREENCLOSE:
- case WI_REPORTICONEND:
- theMessage->Data.DataPtr = theData;
- break;
-
- case WI_REPORTICONVERIFY:
- theMessage->Flags &= ~WI_ICONMESSAGE;
- break;
-
- case WI_REPORTMOVED:
- theMessage->Data.Position.x = theIcon->Icon.x;
- theMessage->Data.Position.y = theIcon->Icon.y;
- break;
- }
- theMessage->Message.mn_ReplyPort = wIconPort;
- theMessage->Message.mn_Length = sizeof(struct wIconMessage);
- PutMsg(theIcon->Icon.IconPort,theMessage);
- }
- }
- }
-
-
- /*
- * ReportMulti()
- *
- * If a screen was specified, use it, otherwise start at the top of the list
- * While there are more screens to check
- * For each icon on the screen
- * If the icon wants to hear about this type of event, report it
- * If a screen was specified, we're done, otherwise go on to the next one
- */
-
- void ReportMulti(theEvent,theData,IconScreen)
- ULONG theEvent;
- APTR theData;
- WSCREEN *IconScreen;
- {
- WSCREEN *theScreen;
- WICONREF *theIcon,*nextIcon;
-
- Forbid();
- if (IconScreen) theScreen = IconScreen; else theScreen = FirstScreen;
- while (theScreen)
- {
- theIcon = theScreen->IconRef;
- while (theIcon)
- {
- nextIcon = theIcon->Next;
- if (theIcon->Icon.Report & theEvent)
- ReportEvent(theEvent,theIcon,theData);
- theIcon = nextIcon;
- }
- if (IconScreen) theScreen = NULL; else theScreen = theScreen->Next;
- }
- Permit();
- }
-
-
- /*
- * wMain()
- *
- * Set the Wait signal bits to CANCEL, close and the bits used by the ports
- * While there is more to do
- * Don't try to end wIconify yet
- * Wait for one of the signals we're interested in
- * While there are messages in the common wIconify window UserPort
- * If the message type is CLOSEWINDOW ro NEWSIZE (fake messages
- * sent to Intuition windows by wIconify), then just free the message
- * Otherwise
- * Make a copy of the message data and reply the original
- * Do the event, and record whether we are supposed to end wIconify
- * While ther are messages in the IconPort (from the handler or IconCalls)
- * If the message is not an IconMessage being returned to us
- * Do what the message wants, and record if we are supposed to end
- * If the message is not supposed to be replied (it came from us)
- * If the message is a REPORT message we generated, decrement the count
- * If we are trying to end and there are no more outstanding messages
- * that need to be returned, go ahead and try to end
- * Free the message
- * Otherwise reply to the message (it's from IconCalls)
- * If the last window on a screen was closed, update the menus
- * If the loader wants us to end, try to quit
- * Do any pending mouse moves (since we're about to Wait anyway)
- * Refresh the screens that need it
- * If we are supposed to end
- * Try to close all screens and windows
- * If all are closed, make sure there are no outstanding messages
- * that need to be replied first; if not, go ahead and quit
- */
-
- static void wMain()
- {
- int NotDone = TRUE;
- int EndItAll;
- ULONG WaitSignal = CANCELSIGNAL| CloseSignal;
- ULONG theSignal;
- struct IntuiMessage *inMessage,tmpMessage;
- struct wIconMessage *wiMessage;
- extern struct Node *GetMsg();
-
- if (wUserPort) WaitSignal |= (ONE << wUserPort->mp_SigBit);
- if (wIconPort) WaitSignal |= (ONE << wIconPort->mp_SigBit);
- while (NotDone)
- {
- EndItAll = FALSE;
- theSignal = Wait(WaitSignal | EndSignal);
- while (inMessage = (struct IntuiMessage *)GetMsg(wUserPort))
- {
- if (inMessage->Class & FREECLASS)
- {
- FREESTRUCT(IntuiMessage,inMessage);
- } else {
- tmpMessage = *inMessage; ReplyMsg(inMessage);
- EndItAll = DoEvent(&tmpMessage,EndItAll);
- }
- }
- while (wiMessage = (struct wIconMessage *)GetMsg(wIconPort))
- {
- if ((wiMessage->Flags & WI_ICONMESSAGE) == 0)
- EndItAll = DoIconEvent(wiMessage,EndItAll);
- if (wiMessage->Flags & WI_NOREPLY)
- {
- if (wiMessage->Flags & WI_REPORT) MessageCount--;
- if (EndSignal && MessageCount == 0) EndItAll = TRUE;
- FREESTRUCT(wIconMessage,wiMessage);
- } else {
- ReplyMsg(wiMessage);
- }
- }
- if (theSignal & CloseSignal) UpdateActiveMenu();
- if (theSignal & EndSignal) EndItAll = TRUE;
- DoMouseMove();
- RefreshScreens();
-
- if (EndItAll)
- if (AttemptQuit())
- if (MessageCount == 0) NotDone = FALSE;
- }
- }
-
-
- /*
- * ReplyMessages()
- *
- * While there are more IntuiMessages in the UserPort
- * If the message is to be freed, do so, otherwise reply to it
- * While there are more IconMessages in the IconPort
- * If the message is not to be replied, free it, otherwise reply to it
- */
-
- static void ReplyMessages()
- {
- struct IntuiMessage *inMessage;
- struct wIconMessage *wiMessage;
- extern struct Node *GetMsg();
-
- while (inMessage = (struct IntuiMessage *)GetMsg(wUserPort))
- {
- if (inMessage->Class & FREECLASS) FREESTRUCT(IntuiMessage,inMessage);
- else ReplyMsg(inMessage);
- }
- while (wiMessage = (struct wIconMessage *)GetMsg(wIconPort))
- {
- if (wiMessage->Flags & WI_NOREPLY) FREESTRUCT(wIconMessage,wiMessage);
- else wiMessage->Icon = NULL, ReplyMsg(wiMessage);
- }
- }
-
-
- /*
- * AttemptEnd()
- *
- * This routine is called when an ENDICONIFY message arrives.
- * Return a pointer to the HandlerData for use by the loader
- * Get the loader's task pointer from the message data pointer
- */
-
- void AttemptEnd(theMessage)
- struct wIconMessage *theMessage;
- {
- theMessage->Icon = (WICONREF *) &HandlerData;
- HandlerData.ParentTask = theMessage->Data.DataPtr;
- }
-