revert between 56095 -> 55830 in arch
[AROS.git] / workbench / tools / commodities / ClickToFront.c
blobb478fa563c8f7a96ad5208f91db3b9065610bec6
1 /*
2 Copyright © 1995-2013, 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 relevant 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 LockLayerInfo(&screen->LayerInfo);
414 layer = WhichLayer(&screen->LayerInfo,
415 screen->MouseX,
416 screen->MouseY);
417 UnlockLayerInfo(&screen->LayerInfo);
419 if (layer == NULL)
421 return;
424 cfInfo.ci_thisWindow = (layer != NULL) ?
425 (struct Window *)layer->Window : NULL;
428 Error: IB->ActiveWindow is non-NULL even if there is no
429 active window!
431 if (layer->front != NULL)
434 Counting clicks is only meaningful if cfInfo.ci_clicksToDo
435 is no less than 2
437 if (cfInfo.ci_clicksToDo > 1)
439 cfInfo.ci_clicksDone++;
441 D(bug("clicksDone = %i\n",cfInfo.ci_clicksDone));
444 Return if the delay between two clicks is longer than
445 Input-Preferences-set double-click delay
447 if (!DoubleClick(cfInfo.ci_lcSeconds,
448 cfInfo.ci_lcMicros,
449 ie->ie_TimeStamp.tv_secs,
450 ie->ie_TimeStamp.tv_micro))
452 cfInfo.ci_lcSeconds = ie->ie_TimeStamp.tv_secs;
453 cfInfo.ci_lcMicros = ie->ie_TimeStamp.tv_micro;
454 cfInfo.ci_clicksDone = 1L;
455 D(bug("DoubleClick is FALSE\nclicksDone = %i\n",
456 cfInfo.ci_clicksDone));
457 return;
460 D(bug("DoubleClick is TRUE\n"));
462 D(bug("Time %i %i, last time %i %i\n",
463 ie->ie_TimeStamp.tv_secs,
464 ie->ie_TimeStamp.tv_micro,
465 cfInfo.ci_lcSeconds,
466 cfInfo.ci_lcMicros));
468 cfInfo.ci_lcSeconds = ie->ie_TimeStamp.tv_secs;
469 cfInfo.ci_lcMicros = ie->ie_TimeStamp.tv_micro;
471 /* Return if the user didn't make enough clicks */
472 if (cfInfo.ci_clicksDone < cfInfo.ci_clicksToDo)
474 return;
477 /* Return if the clicks weren't made in the same window */
478 if (cfInfo.ci_lastWindow != cfInfo.ci_thisWindow)
480 cfInfo.ci_clicksDone = 1L;
481 D(bug("Window changed. clicksDone = %i\n",
482 cfInfo.ci_clicksDone));
483 return;
487 If we didn't return yet, that means that all conditions
488 are good to bring the window to front, and it will be
489 done now. We just reset cfInfo.ci_clicksDone to 0 in
490 order to be ready for another bring-to-front loop...
492 cfInfo.ci_clicksDone = 0L;
494 }/* if (cfInfo.ci_nbClicks) */
496 WindowToFront(cfInfo.ci_thisWindow);
498 if (cfInfo.ci_thisWindow != IntuitionBase->ActiveWindow)
500 ActivateWindow(cfInfo.ci_thisWindow);
503 D(bug("Window %s was put to front.\n",
504 cfInfo.ci_thisWindow->Title));
506 else
508 D(bug("New: %p Old: %p\n", cfInfo.ci_thisWindow,
509 IntuitionBase->ActiveWindow));
511 } /* if (ie->ie_Code == SELECTDOWN) */
512 } /* if (ie->ie_Class == IECLASS_RAWMOUSE) */
515 /************************************************************************************/
517 static void handleCx(CFState *cs)
519 CxMsg *msg;
520 BOOL quit = FALSE;
521 LONG signals;
523 while (!quit)
525 signals = Wait((1 << nb.nb_Port->mp_SigBit) | SIGBREAKF_CTRL_C);
527 if (signals & (1 << nb.nb_Port->mp_SigBit))
529 while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort)))
531 switch (CxMsgType(msg))
533 case CXM_COMMAND:
534 switch (CxMsgID(msg))
536 case CXCMD_DISABLE:
537 ActivateCxObj(cs->cs_broker, FALSE);
538 break;
540 case CXCMD_ENABLE:
541 ActivateCxObj(cs->cs_broker, TRUE);
542 break;
544 case CXCMD_UNIQUE:
545 /* Running the program twice is the same as shutting
546 down the existing program... */
547 /* Fall through */
549 case CXCMD_KILL:
550 quit = TRUE;
551 break;
553 } /* switch (CxMsgID(msg)) */
554 break;
555 } /* switch (CxMsgType(msg))*/
557 ReplyMsg((struct Message *)msg);
559 } /* while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort))) */
562 if (signals & SIGBREAKF_CTRL_C)
564 quit = TRUE;
567 } /* while(!quit) */
570 /************************************************************************************/
572 int main(int argc, char **argv)
574 CFState cState;
575 int error = RETURN_OK;
577 D((argc == 0) ? bug("argc == 0\n") : bug("argc != 0\n") );
579 if (initiate(argc, argv, &cState))
581 handleCx(&cState);
583 else
585 error = RETURN_FAIL;
588 freeResources(&cState);
590 return error;
593 /************************************************************************************/
595 ADD2INIT(Locale_Initialize, 90);
596 ADD2EXIT(Locale_Deinitialize, 90);