2 Copyright © 1995-2008, 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
20 Workbench:Tools/Commodities
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 2
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 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
));
402 cfInfo
.ci_lastWindow
= cfInfo
.ci_thisWindow
;
404 if (IntuitionBase
->ActiveWindow
!= NULL
)
406 screen
= IntuitionBase
->ActiveWindow
->WScreen
;
410 screen
= IntuitionBase
->ActiveScreen
;
413 layer
= WhichLayer(&screen
->LayerInfo
,
422 cfInfo
.ci_thisWindow
= (layer
!= NULL
) ?
423 (struct Window
*)layer
->Window
: NULL
;
426 Error: IB->ActiveWindow is non-NULL even if there is no
429 if (layer
->front
!= NULL
)
432 Counting clicks is only meaningfull if cfInfo.ci_clicksToDo
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
,
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
));
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
,
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
)
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
));
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
));
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
)
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
))
532 switch (CxMsgID(msg
))
535 ActivateCxObj(cs
->cs_broker
, FALSE
);
539 ActivateCxObj(cs
->cs_broker
, TRUE
);
543 /* Running the program twice is the same as shutting
544 down the existing program... */
551 } /* switch (CxMsgID(msg)) */
553 } /* switch (CxMsgType(msg))*/
555 ReplyMsg((struct Message
*)msg
);
557 } /* while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort))) */
560 if (signals
& SIGBREAKF_CTRL_C
)
568 /************************************************************************************/
570 int main(int argc
, char **argv
)
573 int error
= RETURN_OK
;
575 D((argc
== 0) ? bug("argc == 0\n") : bug("argc != 0\n") );
577 if (initiate(argc
, argv
, &cState
))
586 freeResources(&cState
);
591 /************************************************************************************/
593 ADD2INIT(Locale_Initialize
, 90);
594 ADD2EXIT(Locale_Deinitialize
, 90);