/* * WindowShuffle.c * * Commodity * * Author: Stefan Sticht * * Copyright: source is public domain, no copyright * * Version history: * * V1.00 initial release * V1.02 recompiled with main.c V1.02 * V1.03 completly rewritten; shared commodity code thrown away; smaller, uses less CPU time * V1.04 now refuses to activate windows specified with REFUSE * second pair of hotkeys for only Activate without WindowToFront() * changed Priority to 21 to block out intuition for safety reasons * V1.05 some really minor changes */ #define VERSION "V1.05" /******************************************************************** * interfacing * ********************************************************************/ /* * include files */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG #define printf KPrintF #include #endif /* * prototypes */ long request(char *title, char *gadgets, char *text, ...); struct Library *myopenlibrary(char *name, unsigned long version); struct Window *lastwindow(struct Window *win); struct Window *nextwindow(struct Window *win); struct Window *prevwindow(struct Window *win); void *retryallocmem(unsigned long size, long mode); void processmessages(void); /* * global data defined in other moduls * * libraries opened by startup code; basepointers needed by function pragmas */ extern struct Library *DOSBase; extern struct Library *SysBase; /* * Disable SAS/C CTRL/C handling */ void chkabort(void) {} /******************************************************************** * global data * ********************************************************************/ #define TT_PREVAC "PREV_ACTIVE" #define TT_NEXTAC "NEXT_ACTIVE" #define TT_PREVBO "PREV_BOTH" #define TT_NEXTBO "NEXT_BOTH" /* * definition of all messages (multi language support not completed yet) */ #ifdef GERMAN #define RETRY_GADGETS "Wiederholen|Abbrechen" #define RESUME_GADGETS "Weiter" #define MSG_OUTOFMEM "Leider ein Speicherblock von %ld bytes\nnicht alloziert werden!" #define MSG_LIBRARY_OPENERR "Die %s (V%ld+) kann nicht geöffnet werden!" #define COM_NAME "Fensterln" #define COM_DESCR "Nächstes/letztes Fenster aktivieren" #define TT_BACKDROP "BACKDROP" #define TT_NOWINTITLE "OHNETITEL" #define TT_REFUSE "DIESENICHT" #define MSG_REFUSE_TOO_COMPLEX "Leider muß " TT_REFUSE " ignoriert werden,\nda der Ausdruck zu komplex ist." #define NO "NEIN" #define YES "JA" #else #define RETRY_GADGETS "Retry|Cancel" #define RESUME_GADGETS "Resume" #define MSG_OUTOFMEM "Failure allocting %ld bytes of memory!" #define MSG_LIBRARY_OPENERR "%s (V%ld+) can't be opened!" #define COM_NAME "WindowShuffle" #define COM_DESCR "Activate next/previous window" #define TT_BACKDROP "BACKDROP" #define TT_NOWINTITLE "WITHOUTTITLE" #define TT_REFUSE "REFUSE" #define MSG_REFUSE_TOO_COMPLEX TT_REFUSE " will be ignored\nas the pattern is too complex!" #define YES "YES" #define NO "NO" #endif #define COM_TITLE COM_NAME " " VERSION #define CX_PRIORITY "CX_PRIORITY" #define DEF_CX_PRIORITY 0 #define DEF_TT_PREVAC "lcommand lshift j" #define DEF_TT_NEXTAC "lcommand lshift k" #define DEF_TT_PREVBO "lcommand j" #define DEF_TT_NEXTBO "lcommand k" #define DEF_TT_BACKDROP NO #define DEF_TT_NOWINTITLE NO #define DEF_TT_REFUSE "" /* * data for cback.o */ long _stack = 4096l; char *_procname = COM_NAME; long _priority = 21l; long _BackGroundIO = 1; extern BPTR _Backstdout; /* * library base pointers */ struct IntuitionBase *IntuitionBase; struct Library *CxBase; struct Library *IconBase; /* * message port */ struct MsgPort *cxport = NULL; /* * signal flag */ unsigned long cxsigflag = 0l; /* * programtitle and version for Version command */ char versionstring[] ="\0$VER: " COM_NAME " " VERSION; /* * helpstring */ #ifdef GERMAN char helpstring[] = "\033[1m" COM_NAME "\033[0m " VERSION " (Public Domain) von Stefan Sticht\n"\ "Aufruf: " COM_NAME " ["\ CX_PRIORITY "=] [" TT_NEXTAC "=] [" TT_PREVAC "=] ["\ TT_NEXTBO "=] [" TT_PREVBO "=] [" TT_BACKDROP "=" YES "|" NO "] ["\ TT_NOWINTITLE "=" YES "|" NO "] [" TT_REFUSE "=]\n"; #else char helpstring[] = "\033[1m" COM_NAME "\033[0m " VERSION " (Public Domain) by Stefan Sticht\n" "Usage: " COM_NAME " ["\ CX_PRIORITY "=] [" TT_NEXTAC "=] [" TT_PREVAC "=] ["\ TT_NEXTBO "=] [" TT_PREVBO "=] [" TT_BACKDROP "=" YES "|" NO "] ["\ TT_NOWINTITLE "=" YES "|" NO "] [" TT_REFUSE "=]\n"; #endif /* * the tooltypearray */ char **tooltypes; /* * our broker */ CxObj *broker = NULL; struct NewBroker newbroker = { NB_VERSION, /* BYTE nb_Version */ COM_NAME, /* BYTE *nb_Name */ COM_TITLE, /* BYTE *nb_Title */ COM_DESCR, /* BYTE *nb_Descr */ NBU_NOTIFY | NBU_UNIQUE, /* SHORT nb_Unique */ 0, /* SHORT nb_Flags */ 0, /* BYTE nb_Pri */ NULL, /* struct MsgPort nb_Port */ 0 /* WORD nb_ReservedChannel */ }; #define NEXTAC 1 #define PREVAC 2 #define NEXTBO 3 #define PREVBO 4 /* * pointer to refuse tokens */ char *refusetokens = NULL; /* * booleans for activation of backdrop windows and windows w/o title */ unsigned short backdrop; unsigned short nowintitle; /******************************************************************** * functions * ********************************************************************/ /* * request(): a glue routine to EasyRequest as simple as printf plus * titlestring, gadgettexts * * Input: char *title: pointer to the title of the requester * char *gadgets: pointer to gadgettext * char *text: text displayed in requester * * Result: same as EasyrequestArgs() * * !!! for more info see EasyRequestArgs() in Autodocs/intuition.doc !!! */ long request(char *title, char *gadgets, char *text, ...) { /* * structure textreq only needed in this function, so hide it here * must be static, in order to be initialized only once */ static struct EasyStruct textreq = { sizeof (struct EasyStruct), /* ULONG es_StructSize */ 0l, /* ULONG es_Flags */ NULL, /* UBYTE *es_Title */ NULL, /* UBYTE *es_TextFormat */ NULL, /* UBYTE *es_GadgetFormat */ }; va_list ap; long rc; /* * get start of variable arguments */ va_start(ap, text); /* * update textreq */ textreq.es_Title = (UBYTE *)title; textreq.es_TextFormat = (UBYTE *)text; textreq.es_GadgetFormat = (UBYTE *)gadgets; /* * win may be NULL */ rc = EasyRequestArgs(NULL, &textreq, NULL, ap); va_end(ap); return(rc); } /* * myopenlibrary(): same as OpenLibrary(), but opens a retry-requester * if OpenLibrary() fails, to give the user a chance to * copy the library to libs: and retry * requires request(), see above */ struct Library *myopenlibrary(char *name, unsigned long version) { static char errortext[] = MSG_LIBRARY_OPENERR; struct Library *libptr; long ok = TRUE; do { if (!(libptr = OpenLibrary((UBYTE *)name, version))) { if (IntuitionBase) { ok = request(COM_NAME ":", RETRY_GADGETS, errortext, name, version); } else ok = FALSE; } } while (!libptr && ok); #ifdef DEBUG printf("myopenlibrary(%s, %ld) = 0x%lx\n", name, version, libptr); #endif return(libptr); } void *retryallocmem(unsigned long size, long mode) { void *addr; do { if (!(addr = AllocMem(size, mode))) { if (!(request(COM_NAME ":", RETRY_GADGETS, MSG_OUTOFMEM, size))) return(NULL); } } while (!addr); return(addr); } void main(int argc, char *argv[]) { CxObj *nextacfilter = NULL; CxObj *prevacfilter = NULL; CxObj *nextbofilter = NULL; CxObj *prevbofilter = NULL; struct Message *msg; char *refuse; char *nextackey; char *prevackey; char *nextbokey; char *prevbokey; unsigned long size = 0l; if ((argc > 1) && (*argv[1] == '?')) { /* * display help string */ if (_Backstdout) { Write(_Backstdout, helpstring, sizeof(helpstring) - 1l); Close(_Backstdout); } return; } else if (argc && _Backstdout) Close(_Backstdout); /* * open required libraries first */ if (IntuitionBase = (struct IntuitionBase *)myopenlibrary("intuition.library", 37l)) { if (CxBase = myopenlibrary("commodities.library", 37l)) { if (IconBase = myopenlibrary("icon.library", 37l)) { /* * create tooltypes array (requires icon.library open!!!) */ tooltypes = (char **)ArgArrayInit(argc, argv); /* * create our message port */ if (cxport = CreateMsgPort()) { cxsigflag = 1l << cxport->mp_SigBit; /* * set up some broker data */ newbroker.nb_Pri = ArgInt(tooltypes, CX_PRIORITY, DEF_CX_PRIORITY); newbroker.nb_Port = cxport; if (broker = CxBroker(&newbroker, NULL)) { if ((nextackey = ArgString(tooltypes, TT_NEXTAC, DEF_TT_NEXTAC)) && *nextackey) { if (nextacfilter = HotKey(nextackey, cxport, NEXTAC)) AttachCxObj(broker, nextacfilter); } /* if nextackey */ if ((prevackey = ArgString(tooltypes, TT_PREVAC, DEF_TT_PREVAC)) && *prevackey) { if (prevacfilter = HotKey(prevackey, cxport, PREVAC)) AttachCxObj(broker, prevacfilter); } /* if prevackey */ if ((nextbokey = ArgString(tooltypes, TT_NEXTBO, DEF_TT_NEXTBO)) && *nextbokey) { if (nextbofilter = HotKey(nextbokey, cxport, NEXTBO)) AttachCxObj(broker, nextbofilter); } /* if nextbokey */ if ((prevbokey = ArgString(tooltypes, TT_PREVBO, DEF_TT_PREVBO)) && *prevbokey) { if (prevbofilter = HotKey(prevbokey, cxport, PREVBO)) AttachCxObj(broker, prevbofilter); } /* if prevbokey */ backdrop = (strcmpi((char *)ArgString(tooltypes, TT_BACKDROP, DEF_TT_BACKDROP), YES)) ? FALSE : TRUE; nowintitle = (strcmpi((char *)ArgString(tooltypes, TT_NOWINTITLE, DEF_TT_NOWINTITLE), YES)) ? FALSE : TRUE; refuse = (char *)ArgString(tooltypes, TT_REFUSE, DEF_TT_REFUSE); #ifdef DEBUG if (refuse) printf("WindowShuffle: refuse = %s\n", refuse); #endif if (*refuse && (size = (strlen(refuse) << 1)) && (refusetokens = retryallocmem(size, 0l))) { #ifdef DEBUG printf("WindowShuffle: size = %ld, refusetokens = 0x%lx\n", size, refusetokens); #endif if (ParsePattern(refuse, refusetokens, size) == -1l) request(COM_NAME ":", RESUME_GADGETS, MSG_REFUSE_TOO_COMPLEX); #ifdef DEBUG printf("WindowShuffle: refusetokens = %s\n", refusetokens); #endif } if ((nextacfilter && !CxObjError(nextacfilter)) || (prevacfilter && !CxObjError(prevacfilter)) || (nextbofilter && !CxObjError(nextbofilter)) || (prevbofilter && !CxObjError(prevbofilter))) { /* * activate our commodity */ ActivateCxObj(broker, 1l); /* * now watch our numerous ports */ processmessages(); } /* if !CxObjError() */ DeleteCxObjAll(broker); if (refusetokens) FreeMem(refusetokens, size); } /* if broker */ #ifdef DEBUG else printf("main(): CxBroker() failed!\n"); #endif /* * delete our message port after replying all pending messages */ while (msg = GetMsg(cxport)) ReplyMsg(msg); DeleteMsgPort(cxport); } /* if cxport */ #ifdef DEBUG else printf("main(): CraeteMsgPort() failed!\n"); #endif ArgArrayDone(); CloseLibrary(IconBase); } /* if IconBase */ CloseLibrary(CxBase); } /* if CxBase */ CloseLibrary((struct Library *)IntuitionBase); } /* if IntuitionBase */ } /* main() */ #define PREV 1 #define TOF 2 #define AC 4 #define BO 6 void processmessages(void) { struct Window *win; struct Message *msg; unsigned long sigreceived; unsigned long msgtype; unsigned long msgid; unsigned long lock; unsigned short quit = FALSE; unsigned char mode; while (!quit) { sigreceived = Wait(SIGBREAKF_CTRL_C | cxsigflag); #ifdef DEBUG printf("processmessages(): signal received\n"); #endif if (sigreceived & SIGBREAKF_CTRL_C) quit = TRUE; if (sigreceived & cxsigflag) { while (msg = (struct Message *)GetMsg(cxport)) { msgid = CxMsgID((CxMsg *)msg); msgtype = CxMsgType((CxMsg *)msg); ReplyMsg(msg); switch (msgtype) { case CXM_IEVENT: mode = 0; switch (msgid) { case PREVAC: mode = PREV; case NEXTAC: mode |= AC; break; case PREVBO: mode = PREV; case NEXTBO: mode |= BO; break; } /* switch msgid */ lock = LockIBase(0l); if (mode & PREV) { /* * get previous window */ if (!(win = prevwindow(IntuitionBase->ActiveWindow))) { /* * no prev window; get last window; * if last window = backdrop || nowintitle || * refusewindow get predecessor of lastwindow */ if ((win = lastwindow(IntuitionBase->ActiveWindow)) && ((!backdrop && (win->Flags & WFLG_BACKDROP)) || (!nowintitle && !win->Title)) || (refusetokens && win->Title && MatchPattern(refusetokens, win->Title))) win = prevwindow(win); } } else { /* * get next window */ if (!(win = nextwindow(IntuitionBase->ActiveWindow))) { /* * no next window; get first window; * if first window = backdrop || nowintitle || * refusewindow get first window->NextWindow */ if ((win = IntuitionBase->ActiveScreen->FirstWindow) && ((!backdrop && (win->Flags & WFLG_BACKDROP)) || (!nowintitle && !win->Title)) || (refusetokens && win->Title && MatchPattern(refusetokens, win->Title))) win = nextwindow(win); } } UnlockIBase(lock); /* * now activate and windowtofront the window if (win != NULL) */ if (win) { if ((mode & AC) && (win != IntuitionBase->ActiveWindow)) ActivateWindow(win); if ((mode & TOF) && (!(win->Flags & WFLG_BACKDROP))) WindowToFront(win); } break; case CXM_COMMAND: switch (msgid) { case CXCMD_UNIQUE: case CXCMD_KILL: quit = TRUE; break; case CXCMD_DISABLE: ActivateCxObj(broker, 0l); break; case CXCMD_ENABLE: ActivateCxObj(broker, 1l); break; } break; } /* switch msgtype */ } /* while CxMsg */ } /* if (sigreceived & cxsigflag) */ } /* while !quit */ ActivateCxObj(broker, 0l); } /* * commodity functions */ /* * get next window */ struct Window *nextwindow(register struct Window *win) { register struct Window *w = NULL; if (win) { while (!w && win->NextWindow) { w = win = win->NextWindow; if ((!backdrop && (w->Flags & WFLG_BACKDROP)) || (!nowintitle && !w->Title) || (refusetokens && w->Title && MatchPattern(refusetokens, w->Title))) w = NULL; } /* while !w */ } /* if win */ return(w); } /* * get previous window */ struct Window *prevwindow(register struct Window *win) { register struct Window *w = NULL; if (win) { while (!w && (win != win->WScreen->FirstWindow)) { for (w = win->WScreen->FirstWindow; w->NextWindow != win; w = w->NextWindow); if ((!backdrop && (w->Flags & WFLG_BACKDROP)) || (!nowintitle && !w->Title) || (refusetokens && w->Title && MatchPattern(refusetokens, w->Title))) { win = w; w = NULL; } } /* while !w */ } /* if win */ return(w); } /* * get last window */ struct Window *lastwindow(register struct Window *win) { if (win) { while (win->NextWindow) win = win->NextWindow; } /* if win */ return(win); }