revert between 56095 -> 55830 in arch
[AROS.git] / workbench / tools / commodities / Opaque.c
blob836aaddff8412b14e9fae1a664d4553f5596589f
1 /*
2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
3 $Id$
4 */
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>
26 #define DEBUG 0
27 #include <aros/debug.h>
29 #include <stdio.h>
30 #include <stdlib.h>
32 #define CATCOMP_ARRAY
33 #include "strings.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"
58 #define ARG_PRI 0
59 #define NUM_ARGS 1
61 #define ACTIONTYPE_DRAGGING 1
62 #define ACTIONTYPE_RESIZING 2
64 #define SYSGADTYPE(gad) ((gad)->GadgetType & GTYP_SYSTYPEMASK)
67 static struct NewBroker nb =
69 NB_VERSION,
70 NULL,
71 NULL,
72 NULL,
73 NBU_NOTIFY | NBU_UNIQUE,
75 -120,
76 NULL,
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;
91 #endif
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];
102 static char s[256];
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];
120 UBYTE ic_TimeOut[2];
121 UBYTE ic_MetaDrag[2];
122 UBYTE ic_Flags[4];
123 UBYTE ic_WBtoFront;
124 UBYTE ic_FrontToBack;
125 UBYTE ic_ReqTrue;
126 UBYTE ic_ReqFalse;
128 /************************************************************************************/
130 static CONST_STRPTR _(ULONG id)
132 if (LocaleBase != NULL && catalog != NULL)
134 return GetCatalogStr(catalog, id, CatCompArray[id].cca_Str);
136 else
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
153 else
155 catalog = NULL;
158 return TRUE;
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);
184 else
186 PutStr(msgString);
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;
204 if (win) {
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 */
213 mouseLeft = winoffx;
214 mouseTop = winoffy;
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;
258 BOOL retval = TRUE;
260 if ((iff = AllocIFF()))
262 if ((iff->iff_Stream = (IPTR)Open(CONFIGNAME_ENV, MODE_OLDFILE)))
264 InitIFFasDOS(iff);
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)) */
288 CloseIFF(iff);
290 } /* if (!OpenIFF(iff, IFFF_READ)) */
292 Close((BPTR)iff->iff_Stream);
294 } /* if ((iff->iff_Stream = (IPTR)Open(CONFIGNAME_ENV, MODE_OLDFILE))) */
296 FreeIFF(iff);
298 } /* if ((iff = AllocIFF())) */
300 return retval;
303 /************************************************************************************/
305 static void Cleanup(CONST_STRPTR msg)
307 struct Message *cxmsg;
309 if (msg)
311 showSimpleMessage(msg);
314 if(CxBase)
316 if (cxbroker) DeleteCxObjAll(cxbroker);
317 if (cxport)
319 while((cxmsg = GetMsg(cxport)))
321 ReplyMsg(cxmsg);
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));
338 exit(0);
341 /************************************************************************************/
343 static void DosError(void)
345 Fault(IoErr(),0,s,255);
346 Cleanup(s);
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();
375 } else {
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)
391 if (argc == 0)
393 UBYTE **array = ArgArrayInit(argc, (UBYTE**)argv);
394 nb.nb_Pri = ArgInt(array, "CX_PRIORITY", 0);
395 ArgArrayDone();
397 else
399 if (!(myargs = ReadArgs(ARG_TEMPLATE, args, 0)))
401 DosError();
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);
415 struct Screen *scr;
417 if (ie->ie_Class == IECLASS_RAWMOUSE)
419 switch(ie->ie_Code)
421 case SELECTDOWN:
422 if (IntuitionBase->ActiveWindow)
424 scr = IntuitionBase->ActiveWindow->WScreen;
425 } else {
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)))
442 struct Gadget *gad;
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
449 method correctly! */
451 if (!(gad->Flags & GFLG_DISABLED))
453 WORD x = gad->LeftEdge;
454 WORD y = gad->TopEdge;
455 WORD w = gad->Width;
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 */
475 newwin = win;
476 actiontype = (SYSGADTYPE(gad) == GTYP_WDRAGGING) ? ACTIONTYPE_DRAGGING :
477 ACTIONTYPE_RESIZING;
479 break;
483 } /* for(gad = win->FirstGadget; gad; gad = gad->NextGadget) */
485 win = newwin;
487 } /* if (win && !(ie->ie_Qualifier & (IEQUALIFIER_LCOMMAND | IEQUALIFIER_RCOMMAND))) */
489 if (win)
491 opaque_active = TRUE;
492 if (IntuitionBase->ActiveWindow != win) ActivateWindow(win);
493 actionwin = 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;
501 #endif
502 DisposeCxMsg(msg);
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) */
511 break;
513 case SELECTUP:
514 if (opaque_active)
516 opaque_active = FALSE;
517 if (!offScreenLayersFlag) SetPointerBounds(actionwin->WScreen, NULL, 0, NULL);
518 DisposeCxMsg(msg);
520 break;
522 case IECODE_NOBUTTON:
523 if (opaque_active)
525 if (!offScreenLayersFlag) SetPointerBounds(actionwin->WScreen, &mousebounds, 0, NULL);
527 #if CALL_WINDOWFUNCS_IN_INPUTHANDLER
528 HandleAction();
529 #else
530 Signal(maintask, actionmask);
531 #endif
533 break;
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));
556 nb.nb_Port = cxport;
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();
583 //SetMouseBounds();
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);
599 #else
600 MoveWindow(actionwin, newx - actionstart_winx, newy - actionstart_winy);
601 actionstart_winx = newx;
602 actionstart_winy = newy;
603 #endif
605 else
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)
622 CxMsg *msg;
623 while((msg = (CxMsg *)GetMsg(cxport)))
625 switch(CxMsgType(msg))
627 case CXM_COMMAND:
628 switch(CxMsgID(msg))
630 case CXCMD_DISABLE:
631 ActivateCxObj(cxbroker,0L);
632 disabled = TRUE;
633 break;
635 case CXCMD_ENABLE:
636 ActivateCxObj(cxbroker,1L);
637 disabled = FALSE;
638 break;
640 case CXCMD_UNIQUE:
641 case CXCMD_KILL:
642 quitme = TRUE;
643 break;
645 } /* switch(CxMsgID(msg)) */
646 break;
648 } /* switch (CxMsgType(msg))*/
650 ReplyMsg((struct Message *)msg);
652 } /* while((msg = (CxMsg *)GetMsg(cxport))) */
655 /************************************************************************************/
657 static void HandleAll(void)
659 ULONG sigs;
661 while(!quitme)
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)
676 Init();
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);
683 InitCX();
684 HandleAll();
685 Cleanup(NULL);
686 return 0;
689 /************************************************************************************/
691 ADD2INIT(Locale_Initialize, 90);
692 ADD2EXIT(Locale_Deinitialize, 90);