2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
6 #include <aros/symbolsets.h>
7 #include <workbench/startup.h>
8 #include <intuition/intuition.h>
9 #include <intuition/intuitionbase.h>
10 #include <graphics/gfx.h>
11 #include <graphics/gfxbase.h>
12 #include <libraries/commodities.h>
13 #include <libraries/locale.h>
14 #include <proto/exec.h>
15 #include <proto/dos.h>
16 #include <proto/intuition.h>
17 #include <proto/layers.h>
18 #include <proto/commodities.h>
19 #include <proto/locale.h>
20 #include <proto/alib.h>
21 #include <proto/iffparse.h>
22 #include <proto/icon.h>
23 #include <prefs/prefhdr.h>
24 #include <prefs/icontrol.h>
27 #include <aros/debug.h>
35 #define CATALOG_NAME "System/Tools/Commodities.catalog"
36 #define CATALOG_VERSION 3
39 #define ACCELERATOR_THRESH 2
40 #define ACCELERATOR_MULTI 2
42 /************************************************************************************/
44 /* Using ChangeWindowBox has the advantage, that one can specify absolute window
45 coords, instead of relative ones as in case of MoveWindow. OTOH it has the
46 disadvantage that it also generates IDCMP_NEWSIZE IntuiMessages. */
48 #define USE_CHANGEWINDOWBOX 0
50 #define CALL_WINDOWFUNCS_IN_INPUTHANDLER 0
52 /************************************************************************************/
54 UBYTE version
[] = "$VER: Opaque 0.6 (25.5.2010)";
56 #define ARG_TEMPLATE "CX_PRIORITY=PRI/N/K"
61 #define ACTIONTYPE_DRAGGING 1
62 #define ACTIONTYPE_RESIZING 2
64 #define SYSGADTYPE(gad) ((gad)->GadgetType & GTYP_SYSTYPEMASK)
67 static struct NewBroker nb
=
73 NBU_NOTIFY
| NBU_UNIQUE
,
80 static struct Catalog
*catalog
;
81 static struct MsgPort
*cxport
;
82 static struct Window
*actionwin
;
83 static struct Task
*maintask
;
85 static struct RDArgs
*myargs
;
86 static CxObj
*cxbroker
, *cxcust
;
87 static ULONG cxmask
, actionmask
, icontrolmask
;
88 static WORD winoffx
, winoffy
, winwidth
, winheight
;
89 #if !USE_CHANGEWINDOWBOX
90 static WORD actionstart_winx
, actionstart_winy
;
92 static struct Rectangle mousebounds
;
93 static LONG gadgetLeft
, gadgetTop
;
94 static LONG gadgetWidth
, gadgetHeight
;
95 static BYTE actionsig
, icontrolsig
;
96 static UBYTE actiontype
;
97 static BOOL quitme
, disabled
;
98 static BOOL offScreenLayersFlag
;
99 static struct NotifyRequest
*IControlChangeNR
;
101 static IPTR args
[NUM_ARGS
];
104 static void HandleAction(void);
105 static void HandleIControl(void);
107 /**********************************************************************************************/
109 #define ARRAY_TO_LONG(x) ( ((x)[0] << 24UL) + ((x)[1] << 16UL) + ((x)[2] << 8UL) + ((x)[3]) )
110 #define ARRAY_TO_WORD(x) ( ((x)[0] << 8UL) + ((x)[1]) )
112 #define CONFIGNAME_ENV "ENV:Sys/icontrol.prefs"
114 struct FileIControlPrefs
116 UBYTE ic_Reserved0
[4];
117 UBYTE ic_Reserved1
[4];
118 UBYTE ic_Reserved2
[4];
119 UBYTE ic_Reserved3
[4];
121 UBYTE ic_MetaDrag
[2];
124 UBYTE ic_FrontToBack
;
128 /************************************************************************************/
130 static CONST_STRPTR
_(ULONG id
)
132 if (LocaleBase
!= NULL
&& catalog
!= NULL
)
134 return GetCatalogStr(catalog
, id
, CatCompArray
[id
].cca_Str
);
138 return CatCompArray
[id
].cca_Str
;
142 /************************************************************************************/
144 static BOOL
Locale_Initialize(VOID
)
146 if (LocaleBase
!= NULL
)
148 catalog
= OpenCatalog
150 NULL
, CATALOG_NAME
, OC_Version
, CATALOG_VERSION
, TAG_DONE
161 /************************************************************************************/
163 static VOID
Locale_Deinitialize(VOID
)
165 if(LocaleBase
!= NULL
&& catalog
!= NULL
) CloseCatalog(catalog
);
168 /************************************************************************************/
170 static void showSimpleMessage(CONST_STRPTR msgString
)
172 struct EasyStruct easyStruct
;
174 easyStruct
.es_StructSize
= sizeof(easyStruct
);
175 easyStruct
.es_Flags
= 0;
176 easyStruct
.es_Title
= _(MSG_OPAQUE_CXNAME
);
177 easyStruct
.es_TextFormat
= msgString
;
178 easyStruct
.es_GadgetFormat
= _(MSG_OK
);
180 if (IntuitionBase
!= NULL
&& !Cli() )
182 EasyRequestArgs(NULL
, &easyStruct
, NULL
, NULL
);
190 /************************************************************************************/
192 #define MINWINDOWWIDTH (5)
193 #define MINWINDOWHEIGHT (5)
195 #define mouseLeft mousebounds.MinX
196 #define mouseTop mousebounds.MinY
197 #define mouseRight mousebounds.MaxX
198 #define mouseBottom mousebounds.MaxY
200 void SetMouseBounds(struct Window
*win
)
202 WORD minheight
, minwidth
, maxheight
, maxwidth
;
205 if (actiontype
== ACTIONTYPE_DRAGGING
) {
206 if (offScreenLayersFlag
) {
207 mouseLeft
= 0; /* as left as you want */
208 mouseTop
= winoffy
; /* keep the titlebar visible */
209 mouseRight
= win
->WScreen
->Width
; /* as far right as you want */
210 mouseBottom
= win
->WScreen
->Height
- (gadgetHeight
- (winoffy
+ 1));
212 else { /* bounds such that the window never goes offscreen */
215 mouseRight
= (win
->WScreen
->Width
- winwidth
) + winoffx
;
216 mouseBottom
= (win
->WScreen
->Height
- winheight
) + winoffy
;
219 else { /* actiontype == ACTIONTYPE_RESIZING) */
220 /* force legal min/max values */
221 minwidth
= win
->MinWidth
;
222 maxwidth
= win
->MaxWidth
;
223 minheight
= win
->MinHeight
;
224 maxheight
= win
->MaxHeight
;
226 if (maxwidth
<= 0) maxwidth
= win
->WScreen
->Width
;
227 if (maxheight
<= 0) maxheight
= win
->WScreen
->Height
;
229 if ((minwidth
< MINWINDOWWIDTH
) || (minheight
< MINWINDOWHEIGHT
) || /* if any dimension too small, or */
230 (minwidth
> maxwidth
) || (minheight
> maxheight
) || /* either min/max value pairs are inverted, or */
231 (minwidth
> win
->Width
) || (minheight
> win
->Height
) || /* the window is already smaller than minwidth/height, or */
232 (maxwidth
< win
->Width
) || (maxheight
< win
->Height
)) { /* the window is already bigger than maxwidth/height */
233 minwidth
= MINWINDOWWIDTH
; /* then put sane values in */
234 minheight
= MINWINDOWHEIGHT
;
235 maxwidth
= win
->WScreen
->Width
;
236 maxheight
= win
->WScreen
->Height
;
239 /* set new mouse bounds */
240 mouseLeft
= win
->LeftEdge
+ minwidth
- (win
->Width
- winoffx
);
241 mouseTop
= win
->TopEdge
+ minheight
- (win
->Height
- winoffy
);
242 mouseRight
= (win
->LeftEdge
+ maxwidth
) - (win
->Width
- winoffx
);
243 mouseBottom
= (win
->TopEdge
+ maxheight
) - (win
->Height
- winoffy
);
244 if ((win
->WScreen
->Width
- (win
->Width
- winoffx
)) < mouseRight
)
245 mouseRight
= (win
->WScreen
->Width
- (win
->Width
- winoffx
));
246 if ((win
->WScreen
->Height
- (win
->Height
- winoffy
)) < mouseBottom
)
247 mouseBottom
= (win
->WScreen
->Height
- (win
->Height
- winoffy
));
252 /************************************************************************************/
254 BOOL
GetOFFSCREENLAYERSPref()
256 static struct FileIControlPrefs loadprefs
;
257 struct IFFHandle
*iff
;
260 if ((iff
= AllocIFF()))
262 if ((iff
->iff_Stream
= (IPTR
)Open(CONFIGNAME_ENV
, MODE_OLDFILE
)))
266 if (!OpenIFF(iff
, IFFF_READ
))
268 if (!StopChunk(iff
, ID_PREF
, ID_ICTL
))
270 if (!ParseIFF(iff
, IFFPARSE_SCAN
))
272 struct ContextNode
*cn
;
274 cn
= CurrentChunk(iff
);
276 if (cn
->cn_Size
>= sizeof(loadprefs
))
278 if (ReadChunkBytes(iff
, &loadprefs
, sizeof(loadprefs
)) == sizeof(loadprefs
))
280 if ( ! (ARRAY_TO_LONG(loadprefs
.ic_Flags
) & ICF_OFFSCREENLAYERS
) ) retval
= FALSE
;
284 } /* if (!ParseIFF(iff, IFFPARSE_SCAN)) */
286 } /* if (!StopChunk(iff, ID_PREF, ID_INPT)) */
290 } /* if (!OpenIFF(iff, IFFF_READ)) */
292 Close((BPTR
)iff
->iff_Stream
);
294 } /* if ((iff->iff_Stream = (IPTR)Open(CONFIGNAME_ENV, MODE_OLDFILE))) */
298 } /* if ((iff = AllocIFF())) */
303 /************************************************************************************/
305 static void Cleanup(CONST_STRPTR msg
)
307 struct Message
*cxmsg
;
311 showSimpleMessage(msg
);
316 if (cxbroker
) DeleteCxObjAll(cxbroker
);
319 while((cxmsg
= GetMsg(cxport
)))
324 DeleteMsgPort(cxport
);
328 if (myargs
) FreeArgs(myargs
);
330 if (actionsig
) FreeSignal(actionsig
);
331 if (icontrolsig
) FreeSignal(icontrolsig
);
333 if (IControlChangeNR
!= NULL
) {
334 EndNotify(IControlChangeNR
);
335 FreeMem(IControlChangeNR
, sizeof(struct NotifyRequest
));
341 /************************************************************************************/
343 static void DosError(void)
345 Fault(IoErr(),0,s
,255);
349 /************************************************************************************/
351 static void Init(void)
354 /* create "action" signal, to handle window dragging and resize events */
355 maintask
= FindTask(0);
356 if((actionsig
= AllocSignal(-1L)) != -1)
358 actionmask
= 1L << actionsig
;
360 /* create "IControl pref changes" signal */
361 if((icontrolsig
= AllocSignal(-1L)) != -1)
363 icontrolmask
= 1L << icontrolsig
;
364 if ((IControlChangeNR
= AllocMem(sizeof(struct NotifyRequest
), MEMF_CLEAR
)))
366 IControlChangeNR
->nr_Name
= CONFIGNAME_ENV
;
367 IControlChangeNR
->nr_Flags
= NRF_SEND_SIGNAL
;
368 IControlChangeNR
->nr_stuff
.nr_Signal
.nr_Task
= maintask
;
369 IControlChangeNR
->nr_stuff
.nr_Signal
.nr_SignalNum
= icontrolsig
;
371 StartNotify(IControlChangeNR
);
373 /* set inital value for offscreenlayers */
374 offScreenLayersFlag
= GetOFFSCREENLAYERSPref();
376 showSimpleMessage(_(MSG_CANT_ALLOCATE_MEM
));
383 #define ABS(x) (((x)<0)?(-(x)):(x))
384 inline WORD
WITHACCEL(WORD raw
) { if (ABS(raw
) > ACCELERATOR_THRESH
) return(raw
<< 2); else return(raw
<< 1);}
385 inline WORD
WITHOUTACCEL(WORD raw
) { if (ABS(raw
) > ACCELERATOR_THRESH
) return(raw
>> 2); else return(raw
>> 1);}
387 /************************************************************************************/
389 static void GetArguments(int argc
, char **argv
)
393 UBYTE
**array
= ArgArrayInit(argc
, (UBYTE
**)argv
);
394 nb
.nb_Pri
= ArgInt(array
, "CX_PRIORITY", 0);
399 if (!(myargs
= ReadArgs(ARG_TEMPLATE
, args
, 0)))
404 if (args
[ARG_PRI
]) nb
.nb_Pri
= *(LONG
*)args
[ARG_PRI
];
408 /************************************************************************************/
410 static void OpaqueAction(CxMsg
*msg
,CxObj
*obj
)
412 static BOOL opaque_active
= FALSE
;
414 struct InputEvent
*ie
= (struct InputEvent
*)CxMsgData(msg
);
417 if (ie
->ie_Class
== IECLASS_RAWMOUSE
)
422 if (IntuitionBase
->ActiveWindow
)
424 scr
= IntuitionBase
->ActiveWindow
->WScreen
;
426 scr
= IntuitionBase
->ActiveScreen
;
429 if (!opaque_active
&& scr
)
431 struct Layer
*lay
= NULL
;
432 struct Window
*win
= NULL
;
434 LockLayerInfo(&scr
->LayerInfo
);
435 lay
= WhichLayer(&scr
->LayerInfo
, scr
->MouseX
, scr
->MouseY
);
436 UnlockLayerInfo(&scr
->LayerInfo
);
438 if (lay
) win
= (struct Window
*)lay
->Window
;
440 if (win
&& !(ie
->ie_Qualifier
& (IEQUALIFIER_LCOMMAND
| IEQUALIFIER_RCOMMAND
)))
443 struct Window
*newwin
= NULL
;
445 for(gad
= win
->FirstGadget
; gad
; gad
= gad
->NextGadget
)
447 /* FIXME: does not handle app made dragging/resize gadgets in
448 GZZ innerlayer or boopsi gadgets with special GM_HITTEST
451 if (!(gad
->Flags
& GFLG_DISABLED
))
453 WORD x
= gad
->LeftEdge
;
454 WORD y
= gad
->TopEdge
;
456 WORD h
= gad
->Height
;
457 gadgetLeft
= gad
->LeftEdge
;
458 gadgetTop
= gad
->TopEdge
;
459 gadgetWidth
= gad
->Width
;
460 gadgetHeight
= gad
->Height
;
462 if (gad
->Flags
& GFLG_RELRIGHT
) x
+= win
->Width
- 1;
463 if (gad
->Flags
& GFLG_RELBOTTOM
) y
+= win
->Height
- 1;
464 if (gad
->Flags
& GFLG_RELWIDTH
) w
+= win
->Width
;
465 if (gad
->Flags
& GFLG_RELHEIGHT
) h
+= win
->Height
;
467 if ((win
->MouseX
>= x
) &&
468 (win
->MouseY
>= y
) &&
469 (win
->MouseX
< x
+ w
) &&
470 (win
->MouseY
< y
+ h
))
472 if ((SYSGADTYPE(gad
) == GTYP_WDRAGGING
) || (SYSGADTYPE(gad
) == GTYP_SIZING
))
474 /* found dragging or resize gadget */
476 actiontype
= (SYSGADTYPE(gad
) == GTYP_WDRAGGING
) ? ACTIONTYPE_DRAGGING
:
483 } /* for(gad = win->FirstGadget; gad; gad = gad->NextGadget) */
487 } /* if (win && !(ie->ie_Qualifier & (IEQUALIFIER_LCOMMAND | IEQUALIFIER_RCOMMAND))) */
491 opaque_active
= TRUE
;
492 if (IntuitionBase
->ActiveWindow
!= win
) ActivateWindow(win
);
494 winoffx
= win
->WScreen
->MouseX
- win
->LeftEdge
;
495 winoffy
= win
->WScreen
->MouseY
- win
->TopEdge
;
496 winwidth
= win
->Width
;
497 winheight
= win
->Height
;
498 #if !USE_CHANGEWINDOWBOX
499 actionstart_winx
= win
->LeftEdge
;
500 actionstart_winy
= win
->TopEdge
;
503 /* reset mouse bounds */
504 SetMouseBounds(actionwin
);
505 if (!offScreenLayersFlag
) SetPointerBounds(actionwin
->WScreen
, &mousebounds
, 0, NULL
);
507 //Signal(maintask, icontrolmask);
510 } /* if (!opaque_active && scr) */
516 opaque_active
= FALSE
;
517 if (!offScreenLayersFlag
) SetPointerBounds(actionwin
->WScreen
, NULL
, 0, NULL
);
522 case IECODE_NOBUTTON
:
525 if (!offScreenLayersFlag
) SetPointerBounds(actionwin
->WScreen
, &mousebounds
, 0, NULL
);
527 #if CALL_WINDOWFUNCS_IN_INPUTHANDLER
530 Signal(maintask
, actionmask
);
535 } /* switch(ie->ie_Code) */
537 } /* if (ie->ie_Class == IECLASS_RAWMOUSE) */
538 else if (ie
->ie_Class
== IECLASS_TIMER
)
540 if (opaque_active
&& !offScreenLayersFlag
)
542 SetPointerBounds(actionwin
->WScreen
, &mousebounds
, 0, NULL
);
547 /************************************************************************************/
549 static void InitCX(void)
551 if (!(cxport
= CreateMsgPort()))
553 Cleanup(_(MSG_CANT_CREATE_MSGPORT
));
558 cxmask
= 1L << cxport
->mp_SigBit
;
560 if (!(cxbroker
= CxBroker(&nb
, 0)))
562 //Cleanup(_(MSG_CANT_CREATE_BROKER));
563 Cleanup(NULL
); // TO DO: show error if commodity wasn't running
566 if (!(cxcust
= CxCustom(OpaqueAction
, 0)))
568 Cleanup(_(MSG_CANT_CREATE_CUSTOM
));
571 AttachCxObj(cxbroker
, cxcust
);
572 ActivateCxObj(cxbroker
, 1);
576 /************************************************************************************/
578 /* Handle the case where the IControl Prefs have changed */
579 static void HandleIControl(void)
581 D(bug("[Opaque] notified of icontrol.prefs change\n"));
582 offScreenLayersFlag
= GetOFFSCREENLAYERSPref();
586 /************************************************************************************/
588 /* Move window to absolute position newWindowX, newWindowY */
589 static void HandleAction(void)
591 if (actiontype
== ACTIONTYPE_DRAGGING
)
593 WORD newx
= actionwin
->WScreen
->MouseX
- winoffx
;
594 WORD newy
= actionwin
->WScreen
->MouseY
- winoffy
;
596 /* MoveWindow(actionwin, newx - actionwin->LeftEdge, newy - actionwin->TopEdge); */
597 #if USE_CHANGEWINDOWBOX
598 ChangeWindowBox(actionwin
, newx
, newy
, actionwin
->Width
, actionwin
->Height
);
600 MoveWindow(actionwin
, newx
- actionstart_winx
, newy
- actionstart_winy
);
601 actionstart_winx
= newx
;
602 actionstart_winy
= newy
;
607 LONG neww
= winwidth
+ actionwin
->WScreen
->MouseX
- actionwin
->LeftEdge
- winoffx
;
608 LONG newh
= winheight
+ actionwin
->WScreen
->MouseY
- actionwin
->TopEdge
- winoffy
;
610 if ((neww
!= actionwin
->Width
) || (newh
!= actionwin
->Height
))
612 /* SizeWindow(actionwin, neww - actionwin->Width, newh - actionwin->Height); */
613 ChangeWindowBox(actionwin
, actionwin
->LeftEdge
, actionwin
->TopEdge
, neww
, newh
);
618 /************************************************************************************/
620 static void HandleCx(void)
623 while((msg
= (CxMsg
*)GetMsg(cxport
)))
625 switch(CxMsgType(msg
))
631 ActivateCxObj(cxbroker
,0L);
636 ActivateCxObj(cxbroker
,1L);
645 } /* switch(CxMsgID(msg)) */
648 } /* switch (CxMsgType(msg))*/
650 ReplyMsg((struct Message
*)msg
);
652 } /* while((msg = (CxMsg *)GetMsg(cxport))) */
655 /************************************************************************************/
657 static void HandleAll(void)
663 sigs
= Wait(cxmask
| actionmask
| icontrolmask
| SIGBREAKF_CTRL_C
);
665 if (sigs
& cxmask
) HandleCx();
666 if (sigs
& actionmask
) HandleAction(); /* "Action" == window moving or resizing */
667 if (sigs
& icontrolmask
) HandleIControl();
668 if (sigs
& SIGBREAKF_CTRL_C
) quitme
= TRUE
;
669 } /* while(!quitme) */
672 /************************************************************************************/
674 int main(int argc
, char **argv
)
678 nb
.nb_Name
= _(MSG_OPAQUE_CXNAME
);
679 nb
.nb_Title
= _(MSG_OPAQUE_CXTITLE
);
680 nb
.nb_Descr
= _(MSG_OPAQUE_CXDESCR
);
682 GetArguments(argc
, argv
);
689 /************************************************************************************/
691 ADD2INIT(Locale_Initialize
, 90);
692 ADD2EXIT(Locale_Deinitialize
, 90);