2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
5 ClickToFront commodity -- puts windows to front when clicked in.
8 /******************************************************************************
16 CX_PRIORITY/N/K, QUALIFIER/K, NUMCLICKS/N/K
24 Automatically raises and activates a window when clicking in it.
28 CX_PRIORITY -- The priority of the commodity
30 QUALIFIER -- Qualifier to match the clicks (LEFT_ALT, RIGHT_ALT,
33 NUMCLICKS -- Number of clicks to bring window to front. Value
34 must be greater than 0.
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>
69 #include <aros/debug.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"
85 #define ARG_QUALIFIER 1
89 struct Device
*InputBase
= NULL
;
90 struct Catalog
*catalog
;
91 struct IOStdReq
*inputIO
;
94 /* The ClickToFront broker */
95 static struct NewBroker nb
=
101 NBU_NOTIFY
| NBU_UNIQUE
,
109 typedef struct _CFState
112 struct MsgPort
*cs_msgPort
;
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 */
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
);
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
,
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
);
212 /************************************************************************************/
214 static BOOL
initiate(int argc
, char **argv
, CFState
*cs
)
218 memset(cs
, 0, sizeof(CFState
));
223 IPTR args
[] = { (IPTR
) NULL
, (IPTR
) NULL
, FALSE
};
225 rda
= ReadArgs(ARG_TEMPLATE
, args
, 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
];
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
));
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
));
277 nb
.nb_Port
= cs
->cs_msgPort
;
279 cs
->cs_broker
= CxBroker(&nb
, 0);
281 if (cs
->cs_broker
== NULL
)
286 customObj
= CxCustom(clicktoFront
, 0);
288 if (customObj
== NULL
)
290 showSimpleMessage(_(MSG_CANT_CREATE_MSGPORT
));
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
));
305 showSimpleMessage(_(MSG_CANT_ALLOCATE_MEM
));
310 if ((OpenDevice("input.device", 0, (struct IORequest
*)inputIO
, 0)) != 0)
312 showSimpleMessage(_(MSG_CANT_OPEN_INPUTDEVICE
));
317 InputBase
= (struct Device
*)inputIO
->io_Device
;
322 /************************************************************************************/
324 static void getQualifier(STRPTR qualString
)
326 if (qualString
== NULL
)
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
)
355 if (cs
->cs_broker
!= NULL
)
357 DeleteCxObjAll(cs
->cs_broker
);
360 if (cs
->cs_msgPort
!= NULL
)
362 while ((cxm
= GetMsg(cs
->cs_msgPort
)))
367 DeleteMsgPort(cs
->cs_msgPort
);
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
;
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
));
402 cfInfo
.ci_lastWindow
= cfInfo
.ci_thisWindow
;
404 if (IntuitionBase
->ActiveWindow
!= NULL
)
406 screen
= IntuitionBase
->ActiveWindow
->WScreen
;
410 screen
= IntuitionBase
->ActiveScreen
;
413 LockLayerInfo(&screen
->LayerInfo
);
414 layer
= WhichLayer(&screen
->LayerInfo
,
417 UnlockLayerInfo(&screen
->LayerInfo
);
424 cfInfo
.ci_thisWindow
= (layer
!= NULL
) ?
425 (struct Window
*)layer
->Window
: NULL
;
428 Error: IB->ActiveWindow is non-NULL even if there is no
431 if (layer
->front
!= NULL
)
434 Counting clicks is only meaningful if cfInfo.ci_clicksToDo
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
,
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
));
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
,
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
)
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
));
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
));
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
)
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
))
534 switch (CxMsgID(msg
))
537 ActivateCxObj(cs
->cs_broker
, FALSE
);
541 ActivateCxObj(cs
->cs_broker
, TRUE
);
545 /* Running the program twice is the same as shutting
546 down the existing program... */
553 } /* switch (CxMsgID(msg)) */
555 } /* switch (CxMsgType(msg))*/
557 ReplyMsg((struct Message
*)msg
);
559 } /* while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort))) */
562 if (signals
& SIGBREAKF_CTRL_C
)
570 /************************************************************************************/
572 int main(int argc
, char **argv
)
575 int error
= RETURN_OK
;
577 D((argc
== 0) ? bug("argc == 0\n") : bug("argc != 0\n") );
579 if (initiate(argc
, argv
, &cState
))
588 freeResources(&cState
);
593 /************************************************************************************/
595 ADD2INIT(Locale_Initialize
, 90);
596 ADD2EXIT(Locale_Deinitialize
, 90);