Trust uboot's device list only if it does not look suspicious.
[AROS.git] / workbench / tools / commodities / ClickToFront.c
blob1d313b424f87f58c7815a4356102a51b43ce56cd
1 /*
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
5 ClickToFront commodity -- puts windows to front when clicked in.
6 */
8 /******************************************************************************
10 NAME
12 ClickToFront
14 SYNOPSIS
16 CX_PRIORITY/N/K, QUALIFIER/K, NUMCLICKS/N/K
18 LOCATION
20 SYS:Tools/Commodities
22 FUNCTION
24 Automatically raises and activates a window when clicking in it.
26 INPUTS
28 CX_PRIORITY -- The priority of the commodity
30 QUALIFIER -- Qualifier to match the clicks (LEFT_ALT, RIGHT_ALT,
31 CTRL or NONE).
33 NUMCLICKS -- Number of clicks to bring window to front. Value
34 must be greater than 0.
36 RESULT
38 NOTES
40 EXAMPLE
42 BUGS
44 SEE ALSO
46 INTERNALS
48 ******************************************************************************/
50 #include <aros/symbolsets.h>
51 #include <workbench/startup.h>
52 #include <intuition/intuition.h>
53 #include <intuition/intuitionbase.h>
54 #include <libraries/commodities.h>
55 #include <libraries/locale.h>
56 #include <proto/exec.h>
57 #include <proto/dos.h>
58 #include <proto/intuition.h>
59 #include <proto/layers.h>
60 #include <proto/commodities.h>
61 #include <proto/input.h>
62 #include <proto/alib.h>
63 #include <proto/locale.h>
64 #include <proto/icon.h>
66 #include <stdio.h>
68 #define DEBUG 0
69 #include <aros/debug.h>
71 #define CATCOMP_ARRAY
72 #include "strings.h"
74 #define CATALOG_NAME "System/Tools/Commodities.catalog"
75 #define CATALOG_VERSION 3
78 /***************************************************************************/
80 UBYTE version[] = "$VER: ClickToFront 0.4 (13.10.2008)";
82 #define ARG_TEMPLATE "CX_PRIORITY=PRI/N/K,QUALIFIER/K,NUMCLICKS=CLICKS/N/K"
84 #define ARG_PRI 0
85 #define ARG_QUALIFIER 1
86 #define ARG_CLICKS 2
87 #define NUM_ARGS 3
89 struct Device *InputBase = NULL;
90 struct Catalog *catalog;
91 struct IOStdReq *inputIO;
94 /* The ClickToFront broker */
95 static struct NewBroker nb =
97 NB_VERSION,
98 NULL,
99 NULL,
100 NULL,
101 NBU_NOTIFY | NBU_UNIQUE,
104 NULL,
109 typedef struct _CFState
111 CxObj *cs_broker;
112 struct MsgPort *cs_msgPort;
113 } CFState;
116 typedef struct CF
118 struct Window *ci_thisWindow;
119 struct Window *ci_lastWindow;
120 UWORD ci_qualifiers; /* Qualifiers that must match */
121 BOOL ci_mouseHasMoved;
122 ULONG ci_clicksToDo; /* Bring to front after how many clicks? */
123 ULONG ci_clicksDone; /* How many clicks are we already aware of? */
124 ULONG ci_lcSeconds; /* Time stamp for the last click */
125 ULONG ci_lcMicros;
126 } CF;
129 static CF cfInfo =
131 NULL,
132 NULL,
134 FALSE,
141 /************************************************************************************/
143 static void freeResources(CFState *cs);
144 static BOOL initiate(int argc, char **argv, CFState *cs);
145 static void getQualifier(STRPTR qualString);
146 static void clicktoFront(CxMsg *msg, CxObj *co);
147 static CONST_STRPTR _(ULONG id);
148 static BOOL Locale_Initialize(VOID);
149 static VOID Locale_Deinitialize(VOID);
150 static void showSimpleMessage(CONST_STRPTR msgString);
152 /************************************************************************************/
154 static CONST_STRPTR _(ULONG id)
156 if (LocaleBase != NULL && catalog != NULL)
158 return GetCatalogStr(catalog, id, CatCompArray[id].cca_Str);
160 else
162 return CatCompArray[id].cca_Str;
166 /************************************************************************************/
168 static BOOL Locale_Initialize(VOID)
170 if (LocaleBase != NULL)
172 catalog = OpenCatalog(NULL, CATALOG_NAME, OC_Version, CATALOG_VERSION,
173 TAG_DONE);
175 else
177 catalog = NULL;
180 return TRUE;
183 /************************************************************************************/
185 static VOID Locale_Deinitialize(VOID)
187 if(LocaleBase != NULL && catalog != NULL) CloseCatalog(catalog);
190 /************************************************************************************/
192 static void showSimpleMessage(CONST_STRPTR msgString)
194 struct EasyStruct easyStruct;
196 easyStruct.es_StructSize = sizeof(easyStruct);
197 easyStruct.es_Flags = 0;
198 easyStruct.es_Title = _(MSG_CLICK2FNT_CXNAME);
199 easyStruct.es_TextFormat = msgString;
200 easyStruct.es_GadgetFormat = _(MSG_OK);
202 if (IntuitionBase != NULL && !Cli() )
204 EasyRequestArgs(NULL, &easyStruct, NULL, NULL);
206 else
208 PutStr(msgString);
212 /************************************************************************************/
214 static BOOL initiate(int argc, char **argv, CFState *cs)
216 CxObj *customObj;
218 memset(cs, 0, sizeof(CFState));
220 if (argc != 0)
222 struct RDArgs *rda;
223 IPTR args[] = { (IPTR) NULL, (IPTR) NULL, FALSE };
225 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
227 if (rda != NULL)
229 if (args[ARG_PRI] != (IPTR) NULL)
231 nb.nb_Pri = *(LONG *)args[ARG_PRI];
234 getQualifier((STRPTR)args[ARG_QUALIFIER]);
236 if (args[ARG_CLICKS] != (IPTR) NULL)
238 cfInfo.ci_clicksToDo = *(LONG *)args[ARG_CLICKS];
243 FreeArgs(rda);
245 else
247 D(bug("Cli() == NULL\n"));
248 UBYTE **array = ArgArrayInit(argc, (UBYTE **)argv);
250 nb.nb_Pri = ArgInt(array, "CX_PRIORITY", 0);
252 cfInfo.ci_clicksToDo = ArgInt(array, "NUMCLICKS", 0);
253 D(bug("CLICKS in array from ArgArrayInit = %i\n",ArgInt(array,"NUMCLICKS", 0)));
255 getQualifier(ArgString(array, "QUALIFIER", NULL));
257 ArgArrayDone();
260 if (cfInfo.ci_clicksToDo == 0)
261 cfInfo.ci_clicksToDo = 2; /* Default value is 2 */
263 D(bug("CLICKS to do = %i\n",cfInfo.ci_clicksToDo));
264 nb.nb_Name = _(MSG_CLICK2FNT_CXNAME);
265 nb.nb_Title = _(MSG_CLICK2FNT_CXTITLE);
266 nb.nb_Descr = _(MSG_CLICK2FNT_CXDESCR);
268 cs->cs_msgPort = CreateMsgPort();
270 if (cs->cs_msgPort == NULL)
272 showSimpleMessage(_(MSG_CANT_CREATE_MSGPORT));
274 return FALSE;
277 nb.nb_Port = cs->cs_msgPort;
279 cs->cs_broker = CxBroker(&nb, 0);
281 if (cs->cs_broker == NULL)
283 return FALSE;
286 customObj = CxCustom(clicktoFront, 0);
288 if (customObj == NULL)
290 showSimpleMessage(_(MSG_CANT_CREATE_MSGPORT));
292 return FALSE;
295 AttachCxObj(cs->cs_broker, customObj);
296 ActivateCxObj(cs->cs_broker, TRUE);
298 cfInfo.ci_thisWindow = IntuitionBase->ActiveWindow;
300 inputIO = (struct IOStdReq *)CreateIORequest(cs->cs_msgPort,
301 sizeof(struct IOStdReq));
303 if (inputIO == NULL)
305 showSimpleMessage(_(MSG_CANT_ALLOCATE_MEM));
307 return FALSE;
310 if ((OpenDevice("input.device", 0, (struct IORequest *)inputIO, 0)) != 0)
312 showSimpleMessage(_(MSG_CANT_OPEN_INPUTDEVICE));
314 return FALSE;
317 InputBase = (struct Device *)inputIO->io_Device;
319 return TRUE;
322 /************************************************************************************/
324 static void getQualifier(STRPTR qualString)
326 if (qualString == NULL)
328 return;
331 if (strcmp("CTRL", qualString) == 0)
333 cfInfo.ci_qualifiers = IEQUALIFIER_CONTROL;
336 if (strcmp("LEFT_ALT", qualString) == 0)
338 cfInfo.ci_qualifiers = IEQUALIFIER_LALT;
341 if (strcmp("RIGHT_ALT", qualString) == 0)
343 cfInfo.ci_qualifiers = IEQUALIFIER_RALT;
346 /* Default is NONE */
349 /************************************************************************************/
351 static void freeResources(CFState *cs)
353 struct Message *cxm;
355 if (cs->cs_broker != NULL)
357 DeleteCxObjAll(cs->cs_broker);
360 if (cs->cs_msgPort != NULL)
362 while ((cxm = GetMsg(cs->cs_msgPort)))
364 ReplyMsg(cxm);
367 DeleteMsgPort(cs->cs_msgPort);
370 if (inputIO != NULL)
372 CloseDevice((struct IORequest *)inputIO);
373 DeleteIORequest((struct IORequest *)inputIO);
377 /************************************************************************************/
379 static void clicktoFront(CxMsg *cxm, CxObj *co)
381 /* NOTE! Should use arbitration for IntuitionBase... */
383 struct InputEvent *ie = (struct InputEvent *)CxMsgData(cxm);
385 if (ie->ie_Class == IECLASS_RAWMOUSE)
387 if (ie->ie_Code == SELECTDOWN)
389 struct Screen *screen;
390 struct Layer *layer;
392 /* Mask relvant qualifiers (key qualifiers) */
393 if ((PeekQualifier() & 0xff) != cfInfo.ci_qualifiers)
395 D(bug("Qualifiers: %i, Wanted qualifiers: %i\n",
396 (int)PeekQualifier(),
397 (int)cfInfo.ci_qualifiers | IEQUALIFIER_LEFTBUTTON));
399 return;
402 cfInfo.ci_lastWindow = cfInfo.ci_thisWindow;
404 if (IntuitionBase->ActiveWindow != NULL)
406 screen = IntuitionBase->ActiveWindow->WScreen;
408 else
410 screen = IntuitionBase->ActiveScreen;
413 layer = WhichLayer(&screen->LayerInfo,
414 screen->MouseX,
415 screen->MouseY);
417 if (layer == NULL)
419 return;
422 cfInfo.ci_thisWindow = (layer != NULL) ?
423 (struct Window *)layer->Window : NULL;
426 Error: IB->ActiveWindow is non-NULL even if there is no
427 active window!
429 if (layer->front != NULL)
432 Counting clicks is only meaningfull if cfInfo.ci_clicksToDo
433 is no less than 2
435 if (cfInfo.ci_clicksToDo > 1)
437 cfInfo.ci_clicksDone++;
439 D(bug("clicksDone = %i\n",cfInfo.ci_clicksDone));
442 Return if the delay between two clicks is longer than
443 Input-Preferences-set double-click delay
445 if (!DoubleClick(cfInfo.ci_lcSeconds,
446 cfInfo.ci_lcMicros,
447 ie->ie_TimeStamp.tv_secs,
448 ie->ie_TimeStamp.tv_micro))
450 cfInfo.ci_lcSeconds = ie->ie_TimeStamp.tv_secs;
451 cfInfo.ci_lcMicros = ie->ie_TimeStamp.tv_micro;
452 cfInfo.ci_clicksDone = 1L;
453 D(bug("DoubleClick is FALSE\nclicksDone = %i\n",
454 cfInfo.ci_clicksDone));
455 return;
458 D(bug("DoubleClick is TRUE\n"));
460 D(bug("Time %i %i, last time %i %i\n",
461 ie->ie_TimeStamp.tv_secs,
462 ie->ie_TimeStamp.tv_micro,
463 cfInfo.ci_lcSeconds,
464 cfInfo.ci_lcMicros));
466 cfInfo.ci_lcSeconds = ie->ie_TimeStamp.tv_secs;
467 cfInfo.ci_lcMicros = ie->ie_TimeStamp.tv_micro;
469 /* Return if the user didn't make enough clicks */
470 if (cfInfo.ci_clicksDone < cfInfo.ci_clicksToDo)
472 return;
475 /* Return if the clicks weren't made in the same window */
476 if (cfInfo.ci_lastWindow != cfInfo.ci_thisWindow)
478 cfInfo.ci_clicksDone = 1L;
479 D(bug("Window changed. clicksDone = %i\n",
480 cfInfo.ci_clicksDone));
481 return;
485 If we didn't return yet, that means that all conditions
486 are good to bring the window to front, and it will be
487 done now. We just reset cfInfo.ci_clicksDone to 0 in
488 order to be ready for another bring-to-front loop...
490 cfInfo.ci_clicksDone = 0L;
492 }/* if (cfInfo.ci_nbClicks) */
494 WindowToFront(cfInfo.ci_thisWindow);
496 if (cfInfo.ci_thisWindow != IntuitionBase->ActiveWindow)
498 ActivateWindow(cfInfo.ci_thisWindow);
501 D(bug("Window %s was put to front.\n",
502 cfInfo.ci_thisWindow->Title));
504 else
506 D(bug("New: %p Old: %p\n", cfInfo.ci_thisWindow,
507 IntuitionBase->ActiveWindow));
509 } /* if (ie->ie_Code == SELECTDOWN) */
510 } /* if (ie->ie_Class == IECLASS_RAWMOUSE) */
513 /************************************************************************************/
515 static void handleCx(CFState *cs)
517 CxMsg *msg;
518 BOOL quit = FALSE;
519 LONG signals;
521 while (!quit)
523 signals = Wait((1 << nb.nb_Port->mp_SigBit) | SIGBREAKF_CTRL_C);
525 if (signals & (1 << nb.nb_Port->mp_SigBit))
527 while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort)))
529 switch (CxMsgType(msg))
531 case CXM_COMMAND:
532 switch (CxMsgID(msg))
534 case CXCMD_DISABLE:
535 ActivateCxObj(cs->cs_broker, FALSE);
536 break;
538 case CXCMD_ENABLE:
539 ActivateCxObj(cs->cs_broker, TRUE);
540 break;
542 case CXCMD_UNIQUE:
543 /* Running the program twice is the same as shutting
544 down the existing program... */
545 /* Fall through */
547 case CXCMD_KILL:
548 quit = TRUE;
549 break;
551 } /* switch (CxMsgID(msg)) */
552 break;
553 } /* switch (CxMsgType(msg))*/
555 ReplyMsg((struct Message *)msg);
557 } /* while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort))) */
560 if (signals & SIGBREAKF_CTRL_C)
562 quit = TRUE;
565 } /* while(!quit) */
568 /************************************************************************************/
570 int main(int argc, char **argv)
572 CFState cState;
573 int error = RETURN_OK;
575 D((argc == 0) ? bug("argc == 0\n") : bug("argc != 0\n") );
577 if (initiate(argc, argv, &cState))
579 handleCx(&cState);
581 else
583 error = RETURN_FAIL;
586 freeResources(&cState);
588 return error;
591 /************************************************************************************/
593 ADD2INIT(Locale_Initialize, 90);
594 ADD2EXIT(Locale_Deinitialize, 90);