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 2
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.5 (15.04.2006)";
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 dimention 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
= WhichLayer(&scr
->LayerInfo
, scr
->MouseX
, scr
->MouseY
);
432 struct Window
*win
= NULL
;
434 if (lay
) win
= (struct Window
*)lay
->Window
;
436 if (win
&& !(ie
->ie_Qualifier
& (IEQUALIFIER_LCOMMAND
| IEQUALIFIER_RCOMMAND
)))
439 struct Window
*newwin
= NULL
;
441 for(gad
= win
->FirstGadget
; gad
; gad
= gad
->NextGadget
)
443 /* FIXME: does not handle app made dragging/resize gadgets in
444 GZZ innerlayer or boopsi gadgets with special GM_HITTEST
447 if (!(gad
->Flags
& GFLG_DISABLED
))
449 WORD x
= gad
->LeftEdge
;
450 WORD y
= gad
->TopEdge
;
452 WORD h
= gad
->Height
;
453 gadgetLeft
= gad
->LeftEdge
;
454 gadgetTop
= gad
->TopEdge
;
455 gadgetWidth
= gad
->Width
;
456 gadgetHeight
= gad
->Height
;
458 if (gad
->Flags
& GFLG_RELRIGHT
) x
+= win
->Width
- 1;
459 if (gad
->Flags
& GFLG_RELBOTTOM
) y
+= win
->Height
- 1;
460 if (gad
->Flags
& GFLG_RELWIDTH
) w
+= win
->Width
;
461 if (gad
->Flags
& GFLG_RELHEIGHT
) h
+= win
->Height
;
463 if ((win
->MouseX
>= x
) &&
464 (win
->MouseY
>= y
) &&
465 (win
->MouseX
< x
+ w
) &&
466 (win
->MouseY
< y
+ h
))
468 if ((SYSGADTYPE(gad
) == GTYP_WDRAGGING
) || (SYSGADTYPE(gad
) == GTYP_SIZING
))
470 /* found dragging or resize gadget */
472 actiontype
= (SYSGADTYPE(gad
) == GTYP_WDRAGGING
) ? ACTIONTYPE_DRAGGING
:
479 } /* for(gad = win->FirstGadget; gad; gad = gad->NextGadget) */
483 } /* if (win && !(ie->ie_Qualifier & (IEQUALIFIER_LCOMMAND | IEQUALIFIER_RCOMMAND))) */
487 opaque_active
= TRUE
;
488 if (IntuitionBase
->ActiveWindow
!= win
) ActivateWindow(win
);
490 winoffx
= win
->WScreen
->MouseX
- win
->LeftEdge
;
491 winoffy
= win
->WScreen
->MouseY
- win
->TopEdge
;
492 winwidth
= win
->Width
;
493 winheight
= win
->Height
;
494 #if !USE_CHANGEWINDOWBOX
495 actionstart_winx
= win
->LeftEdge
;
496 actionstart_winy
= win
->TopEdge
;
499 /* reset mouse bounds */
500 SetMouseBounds(actionwin
);
501 if (!offScreenLayersFlag
) SetPointerBounds(actionwin
->WScreen
, &mousebounds
, 0, NULL
);
503 //Signal(maintask, icontrolmask);
506 } /* if (!opaque_active && scr) */
512 opaque_active
= FALSE
;
513 if (!offScreenLayersFlag
) SetPointerBounds(actionwin
->WScreen
, NULL
, 0, NULL
);
518 case IECODE_NOBUTTON
:
521 if (!offScreenLayersFlag
) SetPointerBounds(actionwin
->WScreen
, &mousebounds
, 0, NULL
);
523 #if CALL_WINDOWFUNCS_IN_INPUTHANDLER
526 Signal(maintask
, actionmask
);
531 } /* switch(ie->ie_Code) */
533 } /* if (ie->ie_Class == IECLASS_RAWMOUSE) */
534 else if (ie
->ie_Class
== IECLASS_TIMER
)
536 if (opaque_active
&& !offScreenLayersFlag
)
538 SetPointerBounds(actionwin
->WScreen
, &mousebounds
, 0, NULL
);
543 /************************************************************************************/
545 static void InitCX(void)
547 if (!(cxport
= CreateMsgPort()))
549 Cleanup(_(MSG_CANT_CREATE_MSGPORT
));
554 cxmask
= 1L << cxport
->mp_SigBit
;
556 if (!(cxbroker
= CxBroker(&nb
, 0)))
558 Cleanup(_(MSG_CANT_CREATE_BROKER
));
561 if (!(cxcust
= CxCustom(OpaqueAction
, 0)))
563 Cleanup(_(MSG_CANT_CREATE_CUSTOM
));
566 AttachCxObj(cxbroker
, cxcust
);
567 ActivateCxObj(cxbroker
, 1);
571 /************************************************************************************/
573 /* Handle the case where the IControl Prefs have changed */
574 static void HandleIControl(void)
576 D(bug("[Opaque] notified of icontrol.prefs change\n"));
577 offScreenLayersFlag
= GetOFFSCREENLAYERSPref();
581 /************************************************************************************/
583 /* Move window to absolute position newWindowX, newWindowY */
584 static void HandleAction(void)
586 if (actiontype
== ACTIONTYPE_DRAGGING
)
588 WORD newx
= actionwin
->WScreen
->MouseX
- winoffx
;
589 WORD newy
= actionwin
->WScreen
->MouseY
- winoffy
;
591 /* MoveWindow(actionwin, newx - actionwin->LeftEdge, newy - actionwin->TopEdge); */
592 #if USE_CHANGEWINDOWBOX
593 ChangeWindowBox(actionwin
, newx
, newy
, actionwin
->Width
, actionwin
->Height
);
595 MoveWindow(actionwin
, newx
- actionstart_winx
, newy
- actionstart_winy
);
596 actionstart_winx
= newx
;
597 actionstart_winy
= newy
;
602 LONG neww
= winwidth
+ actionwin
->WScreen
->MouseX
- actionwin
->LeftEdge
- winoffx
;
603 LONG newh
= winheight
+ actionwin
->WScreen
->MouseY
- actionwin
->TopEdge
- winoffy
;
605 if ((neww
!= actionwin
->Width
) || (newh
!= actionwin
->Height
))
607 /* SizeWindow(actionwin, neww - actionwin->Width, newh - actionwin->Height); */
608 ChangeWindowBox(actionwin
, actionwin
->LeftEdge
, actionwin
->TopEdge
, neww
, newh
);
613 /************************************************************************************/
615 static void HandleCx(void)
618 while((msg
= (CxMsg
*)GetMsg(cxport
)))
620 switch(CxMsgType(msg
))
626 ActivateCxObj(cxbroker
,0L);
631 ActivateCxObj(cxbroker
,1L);
640 } /* switch(CxMsgID(msg)) */
643 } /* switch (CxMsgType(msg))*/
645 ReplyMsg((struct Message
*)msg
);
647 } /* while((msg = (CxMsg *)GetMsg(cxport))) */
650 /************************************************************************************/
652 static void HandleAll(void)
658 sigs
= Wait(cxmask
| actionmask
| icontrolmask
| SIGBREAKF_CTRL_C
);
660 if (sigs
& cxmask
) HandleCx();
661 if (sigs
& actionmask
) HandleAction(); /* "Action" == window moving or resizing */
662 if (sigs
& icontrolmask
) HandleIControl();
663 if (sigs
& SIGBREAKF_CTRL_C
) quitme
= TRUE
;
664 } /* while(!quitme) */
667 /************************************************************************************/
669 int main(int argc
, char **argv
)
673 nb
.nb_Name
= _(MSG_OPAQUE_CXNAME
);
674 nb
.nb_Title
= _(MSG_OPAQUE_CXTITLE
);
675 nb
.nb_Descr
= _(MSG_OPAQUE_CXDESCR
);
677 GetArguments(argc
, argv
);
684 /************************************************************************************/
686 ADD2INIT(Locale_Initialize
, 90);
687 ADD2EXIT(Locale_Deinitialize
, 90);