2 Copyright © 1995-2006, 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, DOUBLE/S
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 double click (LEFT_ALT,
31 RIGHT_ALT, CTRL or NONE).
33 DOUBLE -- If specified, clicking means double-clicking.
47 ******************************************************************************/
49 #include <aros/symbolsets.h>
50 #include <intuition/intuition.h>
51 #include <intuition/intuitionbase.h>
52 #include <libraries/commodities.h>
53 #include <libraries/locale.h>
54 #include <proto/exec.h>
55 #include <proto/dos.h>
56 #include <proto/intuition.h>
57 #include <proto/layers.h>
58 #include <proto/commodities.h>
59 #include <proto/input.h>
60 #include <proto/alib.h>
61 #include <proto/locale.h>
67 #include <aros/debug.h>
72 #define CATALOG_NAME "System/Tools/Commodities.catalog"
73 #define CATALOG_VERSION 2
76 /***************************************************************************/
78 UBYTE version
[] = "$VER: ClickToFront 0.3 (15.04.2006)";
80 #define ARG_TEMPLATE "CX_PRIORITY=PRI/N/K,QUALIFIER/K,DOUBLE/S"
83 #define ARG_QUALIFIER 1
87 struct Device
*InputBase
= NULL
;
88 struct Catalog
*catalog
;
89 struct IOStdReq
*inputIO
;
92 /* The ClickToFront broker */
93 static struct NewBroker nb
=
99 NBU_NOTIFY
| NBU_UNIQUE
,
107 typedef struct _CFState
110 struct MsgPort
*cs_msgPort
;
116 struct Window
*ci_thisWindow
;
117 struct Window
*ci_lastWindow
;
118 UWORD ci_qualifiers
; /* Qualifiers that must match */
119 BOOL ci_mouseHasMoved
;
121 ULONG ci_lcSeconds
; /* Time stamp for the last click */
137 /************************************************************************************/
139 static void freeResources(CFState
*cs
);
140 static BOOL
initiate(int argc
, char **argv
, CFState
*cs
);
141 static void getQualifier(STRPTR qualString
);
142 static void clicktoFront(CxMsg
*msg
, CxObj
*co
);
143 static CONST_STRPTR
_(ULONG id
);
144 static BOOL
Locale_Initialize(VOID
);
145 static VOID
Locale_Deinitialize(VOID
);
146 static void showSimpleMessage(CONST_STRPTR msgString
);
148 /************************************************************************************/
150 static CONST_STRPTR
_(ULONG id
)
152 if (LocaleBase
!= NULL
&& catalog
!= NULL
)
154 return GetCatalogStr(catalog
, id
, CatCompArray
[id
].cca_Str
);
158 return CatCompArray
[id
].cca_Str
;
162 /************************************************************************************/
164 static BOOL
Locale_Initialize(VOID
)
166 if (LocaleBase
!= NULL
)
168 catalog
= OpenCatalog
170 NULL
, CATALOG_NAME
, OC_Version
, CATALOG_VERSION
, TAG_DONE
181 /************************************************************************************/
183 static VOID
Locale_Deinitialize(VOID
)
185 if(LocaleBase
!= NULL
&& catalog
!= NULL
) CloseCatalog(catalog
);
188 /************************************************************************************/
190 static void showSimpleMessage(CONST_STRPTR msgString
)
192 struct EasyStruct easyStruct
;
194 easyStruct
.es_StructSize
= sizeof(easyStruct
);
195 easyStruct
.es_Flags
= 0;
196 easyStruct
.es_Title
= _(MSG_CLICK2FNT_CXNAME
);
197 easyStruct
.es_TextFormat
= msgString
;
198 easyStruct
.es_GadgetFormat
= _(MSG_OK
);
200 if (IntuitionBase
!= NULL
&& !Cli() )
202 EasyRequestArgs(NULL
, &easyStruct
, NULL
, NULL
);
210 /************************************************************************************/
212 static BOOL
initiate(int argc
, char **argv
, CFState
*cs
)
216 memset(cs
, 0, sizeof(CFState
));
221 IPTR args
[] = { (IPTR
) NULL
, (IPTR
) NULL
, FALSE
};
223 rda
= ReadArgs(ARG_TEMPLATE
, args
, NULL
);
227 if (args
[ARG_PRI
] != (IPTR
) NULL
)
229 nb
.nb_Pri
= *(LONG
*)args
[ARG_PRI
];
232 getQualifier((STRPTR
)args
[ARG_QUALIFIER
]);
234 cfInfo
.ci_doubleClick
= args
[ARG_DOUBLE
];
236 if (cfInfo
.ci_doubleClick
)
238 D(bug("Using the double clicking method.\n"));
246 UBYTE
**array
= ArgArrayInit(argc
, (UBYTE
**)argv
);
248 nb
.nb_Pri
= ArgInt(array
, "CX_PRIORITY", 0);
249 cfInfo
.ci_doubleClick
= ArgString(array
, "DOUBLE", NULL
) != NULL
;
251 getQualifier(ArgString(array
, "QUALIFIER", NULL
));
256 nb
.nb_Name
= _(MSG_CLICK2FNT_CXNAME
);
257 nb
.nb_Title
= _(MSG_CLICK2FNT_CXTITLE
);
258 nb
.nb_Descr
= _(MSG_CLICK2FNT_CXDESCR
);
260 cs
->cs_msgPort
= CreateMsgPort();
262 if (cs
->cs_msgPort
== NULL
)
264 showSimpleMessage(_(MSG_CANT_CREATE_MSGPORT
));
269 nb
.nb_Port
= cs
->cs_msgPort
;
271 cs
->cs_broker
= CxBroker(&nb
, 0);
273 if (cs
->cs_broker
== NULL
)
278 customObj
= CxCustom(clicktoFront
, 0);
280 if (customObj
== NULL
)
282 showSimpleMessage(_(MSG_CANT_CREATE_MSGPORT
));
287 AttachCxObj(cs
->cs_broker
, customObj
);
288 ActivateCxObj(cs
->cs_broker
, TRUE
);
290 cfInfo
.ci_thisWindow
= IntuitionBase
->ActiveWindow
;
292 inputIO
= (struct IOStdReq
*)CreateIORequest(cs
->cs_msgPort
,
293 sizeof(struct IOStdReq
));
297 showSimpleMessage(_(MSG_CANT_ALLOCATE_MEM
));
302 if ((OpenDevice("input.device", 0, (struct IORequest
*)inputIO
, 0)) != 0)
304 showSimpleMessage(_(MSG_CANT_OPEN_INPUTDEVICE
));
309 InputBase
= (struct Device
*)inputIO
->io_Device
;
314 /************************************************************************************/
316 static void getQualifier(STRPTR qualString
)
318 if (qualString
== NULL
)
323 if (strcmp("CTRL", qualString
) == 0)
325 cfInfo
.ci_qualifiers
= IEQUALIFIER_CONTROL
;
328 if (strcmp("LEFT_ALT", qualString
) == 0)
330 cfInfo
.ci_qualifiers
= IEQUALIFIER_LALT
;
333 if (strcmp("RIGHT_ALT", qualString
) == 0)
335 cfInfo
.ci_qualifiers
= IEQUALIFIER_RALT
;
338 /* Default is NONE */
341 /************************************************************************************/
343 static void freeResources(CFState
*cs
)
347 if (cs
->cs_broker
!= NULL
)
349 DeleteCxObjAll(cs
->cs_broker
);
352 if (cs
->cs_msgPort
!= NULL
)
354 while ((cxm
= GetMsg(cs
->cs_msgPort
)))
359 DeleteMsgPort(cs
->cs_msgPort
);
364 CloseDevice((struct IORequest
*)inputIO
);
365 DeleteIORequest((struct IORequest
*)inputIO
);
369 /************************************************************************************/
371 /* Currently we use single click, not double click... */
372 static void clicktoFront(CxMsg
*cxm
, CxObj
*co
)
374 /* NOTE! Should use arbitration for IntuitionBase... */
376 struct InputEvent
*ie
= (struct InputEvent
*)CxMsgData(cxm
);
378 if (ie
->ie_Class
== IECLASS_RAWMOUSE
)
380 if (ie
->ie_Code
== SELECTDOWN
)
382 struct Screen
*screen
;
385 /* Mask relvant qualifiers (key qualifiers) */
386 if ((PeekQualifier() & 0xff) != cfInfo
.ci_qualifiers
)
388 D(bug("Qualifiers: %i, Wanted qualifiers: %i\n",
389 (int)PeekQualifier(),
390 (int)cfInfo
.ci_qualifiers
| IEQUALIFIER_LEFTBUTTON
));
395 cfInfo
.ci_lastWindow
= cfInfo
.ci_thisWindow
;
397 if (IntuitionBase
->ActiveWindow
!= NULL
)
399 screen
= IntuitionBase
->ActiveWindow
->WScreen
;
403 screen
= IntuitionBase
->ActiveScreen
;
406 layer
= WhichLayer(&screen
->LayerInfo
,
407 screen
->MouseX
, screen
->MouseY
);
414 cfInfo
.ci_thisWindow
= (layer
!= NULL
) ?
415 (struct Window
*)layer
->Window
: NULL
;
417 /* Error: IB->ActiveWindow is non-NULL even if there is no
419 if (layer
->front
!= NULL
)
421 if (cfInfo
.ci_doubleClick
)
423 if (!DoubleClick(cfInfo
.ci_lcSeconds
, cfInfo
.ci_lcMicros
,
424 ie
->ie_TimeStamp
.tv_secs
,
425 ie
->ie_TimeStamp
.tv_micro
))
427 cfInfo
.ci_lcSeconds
= ie
->ie_TimeStamp
.tv_secs
;
428 cfInfo
.ci_lcMicros
= ie
->ie_TimeStamp
.tv_micro
;
433 D(bug("Time %i %i, last time %i %i\n",
434 ie
->ie_TimeStamp
.tv_secs
,
435 ie
->ie_TimeStamp
.tv_micro
,
437 cfInfo
.ci_lcMicros
));
439 cfInfo
.ci_lcSeconds
= ie
->ie_TimeStamp
.tv_secs
;
440 cfInfo
.ci_lcMicros
= ie
->ie_TimeStamp
.tv_micro
;
442 /* Both clicks better have been in the same window */
443 if (cfInfo
.ci_lastWindow
!= cfInfo
.ci_thisWindow
)
449 WindowToFront(cfInfo
.ci_thisWindow
);
451 if (cfInfo
.ci_thisWindow
!= IntuitionBase
->ActiveWindow
)
453 ActivateWindow(cfInfo
.ci_thisWindow
);
458 D(bug("Put window %s to front.\n",
459 cfInfo
.ci_thisWindow
->Title
));
463 D(bug("New: %p Old: %p\n", cfInfo
.ci_thisWindow
,
464 IntuitionBase
->ActiveWindow
));
470 /************************************************************************************/
472 static void handleCx(CFState
*cs
)
480 signals
= Wait((1 << nb
.nb_Port
->mp_SigBit
) | SIGBREAKF_CTRL_C
);
482 if (signals
& (1 << nb
.nb_Port
->mp_SigBit
))
484 while ((msg
= (CxMsg
*)GetMsg(cs
->cs_msgPort
)))
486 switch (CxMsgType(msg
))
489 switch (CxMsgID(msg
))
492 ActivateCxObj(cs
->cs_broker
, FALSE
);
496 ActivateCxObj(cs
->cs_broker
, TRUE
);
500 /* Running the program twice is the same as shutting
501 down the existing program... */
508 } /* switch (CxMsgID(msg)) */
510 } /* switch (CxMsgType(msg))*/
512 ReplyMsg((struct Message
*)msg
);
514 } /* while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort))) */
517 if (signals
& SIGBREAKF_CTRL_C
)
525 /************************************************************************************/
527 int main(int argc
, char **argv
)
530 int error
= RETURN_OK
;
532 if (initiate(argc
, argv
, &cState
))
541 freeResources(&cState
);
546 /************************************************************************************/
548 ADD2INIT(Locale_Initialize
, 90);
549 ADD2EXIT(Locale_Deinitialize
, 90);