/* * HOTKEY.C vi:ts=4 * * Copyright (c) Eddy Carroll, September 1994. * * Controls the management of the commodities hotkey for SnoopDos, * along with other related stuff (Workbench AppIcon/Tools Menu support). */ #include "system.h" #include "snoopdos.h" #include "snooptext.h" #include "icon.h" extern char CommodityTitle[]; /* From SNOOPDOS.C */ struct NewBroker MyBroker = { NB_VERSION, "SnoopDos", CommodityTitle, NULL, /* Description, filled in at run time */ NBU_UNIQUE | NBU_NOTIFY, COF_SHOW_HIDE, 0, 0, 0 }; struct MsgPort *BrokerMP; /* Message port used for msgs from CX */ CxObj *Broker; /* CX handle for the broker we created */ CxObj *Filter; /* Filter to filter CX messages */ struct MsgPort *WorkbenchPort; /* Port for AppIcon/AppMenu messages */ struct DiskObject *ProgramIcon; /* Handle on our program's icon data */ struct AppMenuItem *MyAppMenu; /* Current AppMenuItem, if any */ struct AppIcon *MyAppIcon; /* Current AppMenuItem, if any */ struct DiskObject *AppIconObj; /* Current object for AppMenuItem */ struct DiskObject *DefIconObj; /* A temporary default icon we use */ /* * InstallHotKey(char *hotkey) * * Initialises commodity support and sets things up so that the * key sequence specified by "hotkey" will send a CTRL-F activation * signal to SnoopDos. We can also get various messages from the * commodities exchange to show/hide the interface etc -- these * will be indicated using CommodityMask. * * To see whether a hotkey is currently available or not, simply * check the HotKeyActive flag. (This is used for disabling window * gadgets etc.) * * Returns true for success, false for failure. */ int InstallHotKey(char *hotkey) { CxObj *newobj; HotKeyActive = 0; /* Assume commodity is not currently active */ if (CurSettings.Setup.HideMethod == HIDE_NONE || !CxBase) { /* * Don't install a commodity at all if we have no hide * method. */ return (0); } if (!BrokerMP) { BrokerMP = CreateMsgPort(); if (!BrokerMP) return (0); CommodityMask = (1L << BrokerMP->mp_SigBit); } if (Broker && MyBroker.nb_Pri != CommodityPriority) { /* * The commodity priority has changed, so * remove the current broker to force a new * one to be created at the correct priority. */ DeleteCxObjAll(Broker); Broker = NULL; Filter = NULL; } if (!Broker) { /* * Attempt to create a new broker */ MyBroker.nb_Descr = MSG(MSG_COMMODITY_DESC); MyBroker.nb_Port = BrokerMP; MyBroker.nb_Pri = CommodityPriority; Broker = CxBroker(&MyBroker, NULL); if (!Broker) return (0); ActivateCxObj(Broker, 1); } /* * Okay, now we create a new filter object to handle the * commodity string we were passed */ if (Filter) DeleteCxObjAll(Filter); Filter = CxFilter(hotkey); if (!Filter) { /* * Couldn't create the filter (probably out of memory -- * specifying an illegal hotkey doesn't cause this to * fail, but instead produces an accumulated error later). * * We still leave the broker itself installed, since it can * be used to allow the CX to send us Enable/Disable/Show/ * Hide/Quit messages. */ return (0); } /* * Now add our various translation bits and pieces to the filter */ newobj = CxSignal(SysBase->ThisTask, SIGBREAKB_CTRL_F); if (!newobj) goto filter_error; AttachCxObj(Filter, newobj); newobj = CxTranslate(NULL); if (!newobj) goto filter_error; AttachCxObj(Filter, newobj); if (CxObjError(Filter)) goto filter_error; AttachCxObj(Broker, Filter); HotKeyActive = 1; /* Everything went okay so show we're active */ return (1); filter_error: DeleteCxObjAll(Filter); Filter = NULL; return (NULL); } /* * HandleHotKey() * * Handles any incoming messages on the commodities exchange port. * Should be called whenever a CommodityMask signal is received. */ void HandleHotKeyMsgs(void) { CxMsg *msg; if (!BrokerMP) return; while ((msg = (CxMsg *)GetMsg(BrokerMP)) != NULL) { ULONG msgid = CxMsgID(msg); ULONG msgtype = CxMsgType(msg); ReplyMsg((void *)msg); if (msgtype == CXM_COMMAND) { switch (msgid) { case CXCMD_DISABLE: SetMonitorMode(MONITOR_DISABLED); break; case CXCMD_ENABLE: if (Disabled) /* Don't want to enable if Paused */ SetMonitorMode(MONITOR_NORMAL); break; case CXCMD_KILL: QuitFlag = 1; break; case CXCMD_APPEAR: case CXCMD_UNIQUE: ShowSnoopDos(); break; case CXCMD_DISAPPEAR: HideSnoopDos(); break; } } } } /* * CleanupHotKey() * * Frees any resources used by the commodities module */ void CleanupHotKey(void) { if (Broker) { DeleteCxObjAll(Broker); Broker = NULL; Filter = NULL; } if (BrokerMP) { struct Message *msg; while ((msg = GetMsg(BrokerMP)) != NULL) ReplyMsg(msg); DeleteMsgPort(BrokerMP); BrokerMP = NULL; CommodityMask = 0; } HotKeyActive = 0; } /* * GetCommandName() * * Returns a pointer to a static string containing the name of * this program. The pointer remains valid until the next call * to this function. */ char *GetCommandName(void) { static char name[200]; struct Process *pr = (struct Process *)SysBase->ThisTask; struct CommandLineInterface *cli = BTOC(pr->pr_CLI); char *cmdname = (char *)BTOC(cli->cli_CommandName); if (WBenchMsg) return (WBenchMsg->sm_ArgList->wa_Name); memcpy(name, cmdname+1, *cmdname); name[*cmdname] = '\0'; return (name); } /* * GetProgramIcon() * * Returns a pointer to an icon structure containing a program * icon for SnoopDos, as follows: * * If SnoopDos was run from Workbench, we have a lock on it * If SnoopDos was run from CLI, we look in the directory * the program was run from. If we can't find it there, then * we give up and use the default SnoopDos icon image. * * Regardless, you should call CleanupIcons() before exiting, * to free up any loose icon images that may have been allocated. * * Warning: icon.library must be open when you call this function. */ struct DiskObject *GetProgramIcon(void) { if (ProgramIcon) return (ProgramIcon); if (WBenchMsg) { /* * Running from Workbench, so try and get the program icon * indicated in the lock */ struct WBArg *wbarg = WBenchMsg->sm_ArgList; BPTR lk; lk = CurrentDir(wbarg->wa_Lock); ProgramIcon = GetDiskObject(wbarg->wa_Name); CurrentDir(lk); } else { /* * Running from CLI so try and get icon associated with executable */ struct Process *pr = (struct Process *)SysBase->ThisTask; BPTR lk; if (pr->pr_HomeDir) lk = CurrentDir(pr->pr_HomeDir); ProgramIcon = GetDiskObject(GetCommandName()); if (pr->pr_HomeDir) CurrentDir(lk); } if (ProgramIcon) return (ProgramIcon); /* * Okay, unfortunately we couldn't locate the program icon, so * instead, let's just fall back to the default icon. */ DefSnoopDosIcon.do_StackSize = MINSTACKSIZE; /* Fix this up here */ return (&DefSnoopDosIcon); } /* * CleanupIcons() * * Frees any icon-related resources that were allocated */ void CleanupIcons(void) { RemoveProgramFromWorkbench(); if (ProgramIcon) { FreeDiskObject(ProgramIcon); ProgramIcon = NULL; } if (DefIconObj) { FreeDiskObject(DefIconObj); DefIconObj = NULL; AppIconObj = NULL; } if (WorkbenchPort) { struct Message *msg; while ((msg = GetMsg(WorkbenchPort)) != NULL) ReplyMsg(msg); DeleteMsgPort(WorkbenchPort), WorkbenchPort = NULL; WorkbenchMask = 0; } if (WorkbenchBase) { CloseLibrary(WorkbenchBase); WorkbenchBase = NULL; } } /* * WriteIcon(filename) * * Writes a SnoopDos project icon to the associated filename. If an * icon already exists for the filename, then that icon is left alone. * * If no icon exists, then we create one using a copy of what we think * is the icon SnoopDos was started from (or the default). */ void WriteIcon(char *filename) { struct DiskObject newobj; struct DiskObject *dobj; if (!IconBase) return; dobj = GetDiskObject(filename); if (dobj) { FreeDiskObject(dobj); return; } dobj = GetProgramIcon(); /* * We can create a copy of our tool icon and change * it to a project icon. */ newobj = *dobj; newobj.do_CurrentX = NO_ICON_POSITION; newobj.do_CurrentY = NO_ICON_POSITION; newobj.do_ToolTypes = DefToolTypes; newobj.do_Type = WBPROJECT; if (WBenchMsg) newobj.do_DefaultTool = WBenchMsg->sm_ArgList->wa_Name; else newobj.do_DefaultTool = GetCommandName(); PutDiskObject(filename, &newobj); } /* * AddProgramToWorkbench(hidetype) * * Creates an AppIcon or AppMenuItem which can be used to re-active * SnoopDos, and attaches it to Workbench. Normally used when * SnoopDos goes into a HIDE state. * * Hidetype is HIDE_ICON or HIDE_TOOLS, depending on which type of * hide method is required. * * Initialises WorkbenchMask accordingly. * * Call RemoveProgramFromWorkbench() to remove the item later on. * * Returns TRUE for success, FALSE for failure. */ int AddProgramToWorkbench(int hidetype) { if (!IconBase) return (FALSE); if (!WorkbenchBase) { WorkbenchBase = OpenLibrary("workbench.library", 37); if (!WorkbenchBase) return (FALSE); } if (!WorkbenchPort) { WorkbenchPort = CreateMsgPort(); if (!WorkbenchPort) return (FALSE); WorkbenchMask = (1 << WorkbenchPort->mp_SigBit); } if (hidetype == HIDE_TOOLS && !MyAppMenu) { /* * Adding an item to the Workbench tools menu */ MyAppMenu = AddAppMenuItem(0, 0, MSG(MSG_APPMENU_NAME), WorkbenchPort, NULL); if (!MyAppMenu) return (FALSE); } if (hidetype == HIDE_ICON && !MyAppIcon) { /* * Adding an AppIcon to the Workbench. We make a copy * of the current program icon to use as our appicon. */ struct DiskObject *dobj; if (!AppIconObj) { /* * We need a temporary icon to play around with. * We allocate a new default disk object, copy * it, and modify our copy to give us an icon * we can use as an AppIcon. We need to remember * to free the original icon before we exit. */ static struct DiskObject defobj; DefIconObj = GetDefDiskObject(WBTOOL); if (!DefIconObj) return (FALSE); defobj = *DefIconObj; AppIconObj = &defobj; dobj = GetProgramIcon(); AppIconObj->do_Gadget.Width = dobj->do_Gadget.Width; AppIconObj->do_Gadget.Height = dobj->do_Gadget.Height; AppIconObj->do_Gadget.Flags = dobj->do_Gadget.Flags; AppIconObj->do_Gadget.GadgetRender = dobj->do_Gadget.GadgetRender; AppIconObj->do_Gadget.SelectRender = dobj->do_Gadget.SelectRender; AppIconObj->do_Type = 0; } AppIconObj->do_CurrentX = CurSettings.IconPosLeft != -1 ? CurSettings.IconPosLeft : NO_ICON_POSITION; AppIconObj->do_CurrentY = CurSettings.IconPosTop != -1 ? CurSettings.IconPosTop : NO_ICON_POSITION; MyAppIcon = AddAppIcon(0, 0, APPICON_NAME, WorkbenchPort, NULL, AppIconObj, TAG_DONE); if (!MyAppIcon) return (FALSE); } return (TRUE); } /* * RemoveProgramFromWorkbench() * * Removes any AppIcon or AppMenuItem item that is currently installed * on Workbench. Usually called when the SnoopDos window is about * about to reappear. */ void RemoveProgramFromWorkbench(void) { if (MyAppMenu) RemoveAppMenuItem(MyAppMenu), MyAppMenu = NULL; if (MyAppIcon) RemoveAppIcon(MyAppIcon), MyAppIcon = NULL; } /* * HandleWorkbenchMsgs() * * Handles any outstanding messages at the Workbench message port */ void HandleWorkbenchMsgs(void) { struct AppMessage *msg; int show = 0; if (!WorkbenchPort) return; while ((msg = (void *)GetMsg(WorkbenchPort)) != NULL) { show = 1; ReplyMsg(msg); } if (show) ShowSnoopDos(); }