2 Copyright © 2007, The AROS Development Team. All rights reserved.
5 DepthMenu commodity -- shows list of window/screens in popupmenu.
8 /******************************************************************************
20 Workbench:Tools/Commodities
24 Shows popup menu with list of screens and windows after user clicks on
25 depth gadget of screen or window.
29 CX_PRIORITY -- The priority of the commodity
43 ******************************************************************************/
45 #include <aros/symbolsets.h>
46 #include <intuition/intuition.h>
47 #include <intuition/intuitionbase.h>
48 #include <libraries/commodities.h>
49 #include <libraries/locale.h>
50 #include <proto/exec.h>
51 #include <proto/dos.h>
52 #include <proto/intuition.h>
53 #include <proto/graphics.h>
54 #include <proto/layers.h>
55 #include <proto/commodities.h>
56 #include <proto/input.h>
57 #include <proto/alib.h>
58 #include <proto/locale.h>
64 #include <aros/debug.h>
69 #define CATALOG_NAME "System/Tools/Commodities.catalog"
70 #define CATALOG_VERSION 2
73 /***************************************************************************/
75 UBYTE version
[] = "$VER: DepthMenu 0.3 (30.05.2007)";
77 #define ARG_TEMPLATE "CX_PRIORITY=PRI/N/K"
85 #define DM_MAXENTRY 15
86 #define DM_MAXSTRLEN 30
88 #define DM_BORDERWIDTH 4
90 #define SYSGADTYPE(gad) ((gad)->GadgetType & GTYP_SYSTYPEMASK)
92 struct Device
*InputBase
= NULL
;
93 struct Catalog
*catalog
;
94 struct IOStdReq
*inputIO
;
97 /* The Depth broker */
98 static struct NewBroker nb
=
104 NBU_NOTIFY
| NBU_UNIQUE
,
112 typedef struct _DMState
115 struct MsgPort
*cs_msgPort
;
119 typedef struct _DMData
121 struct Window
*popupwindow
;
124 void *address
[DM_MAXENTRY
]; // struct Window * or struct Screen *
125 char title
[DM_MAXENTRY
][DM_MAXSTRLEN
];
128 WORD selected
; // -1 means no entry selected
129 struct DrawInfo
*drawinfo
;
137 static DMData dmdata
;
139 /************************************************************************************/
141 static void freeResources(DMState
*cs
);
142 static BOOL
initiate(int argc
, char **argv
, DMState
*cs
);
143 static void depthMenu(CxMsg
*msg
, CxObj
*co
);
144 static void handleMenuUp(CxMsg
*cxm
);
145 static void handleMenuDown(CxMsg
*cxm
);
146 static void handleMouseMove(CxMsg
*cxm
);
147 static void showPopup(WORD mode
, struct Screen
*screen
, WORD xpos
, WORD ypos
);
148 static void lockIBaseSave(void);
149 static void unlockIBaseSave(void);
150 static CONST_STRPTR
_(ULONG id
);
151 static BOOL
Locale_Initialize(VOID
);
152 static VOID
Locale_Deinitialize(VOID
);
153 static void showSimpleMessage(CONST_STRPTR msgString
);
154 static void drawEntry(LONG entry
, BOOL selstate
);
155 static BOOL
depthGadHit(struct Window
*window
, WORD mousex
, WORD mousey
);
157 /************************************************************************************/
159 static CONST_STRPTR
_(ULONG id
)
161 if (LocaleBase
!= NULL
&& catalog
!= NULL
)
163 return GetCatalogStr(catalog
, id
, CatCompArray
[id
].cca_Str
);
167 return CatCompArray
[id
].cca_Str
;
171 /************************************************************************************/
173 static BOOL
Locale_Initialize(VOID
)
175 if (LocaleBase
!= NULL
)
177 catalog
= OpenCatalog
179 NULL
, CATALOG_NAME
, OC_Version
, CATALOG_VERSION
, TAG_DONE
190 /************************************************************************************/
192 static VOID
Locale_Deinitialize(VOID
)
194 if(LocaleBase
!= NULL
&& catalog
!= NULL
) CloseCatalog(catalog
);
197 /************************************************************************************/
199 static void showSimpleMessage(CONST_STRPTR msgString
)
201 struct EasyStruct easyStruct
;
203 easyStruct
.es_StructSize
= sizeof(easyStruct
);
204 easyStruct
.es_Flags
= 0;
205 easyStruct
.es_Title
= _(MSG_DEPTHMENU_CXNAME
);
206 easyStruct
.es_TextFormat
= msgString
;
207 easyStruct
.es_GadgetFormat
= _(MSG_OK
);
209 if (IntuitionBase
!= NULL
&& !Cli() )
211 EasyRequestArgs(NULL
, &easyStruct
, NULL
, NULL
);
219 /************************************************************************************/
221 static BOOL
initiate(int argc
, char **argv
, DMState
*cs
)
225 memset(cs
, 0, sizeof(DMState
));
230 IPTR args
[] = { (IPTR
) NULL
, (IPTR
) NULL
, FALSE
};
232 rda
= ReadArgs(ARG_TEMPLATE
, args
, NULL
);
235 if (args
[ARG_PRI
] != (IPTR
) NULL
)
237 nb
.nb_Pri
= *(LONG
*)args
[ARG_PRI
];
244 UBYTE
**array
= ArgArrayInit(argc
, (UBYTE
**)argv
);
245 nb
.nb_Pri
= ArgInt(array
, "CX_PRIORITY", 0);
249 nb
.nb_Name
= _(MSG_DEPTHMENU_CXNAME
);
250 nb
.nb_Title
= _(MSG_DEPTHMENU_CXTITLE
);
251 nb
.nb_Descr
= _(MSG_DEPTHMENU_CXDESCR
);
253 cs
->cs_msgPort
= CreateMsgPort();
254 if (cs
->cs_msgPort
== NULL
)
256 showSimpleMessage(_(MSG_CANT_CREATE_MSGPORT
));
260 nb
.nb_Port
= cs
->cs_msgPort
;
261 cs
->cs_broker
= CxBroker(&nb
, 0);
262 if (cs
->cs_broker
== NULL
)
267 customObj
= CxCustom(depthMenu
, 0);
268 if (customObj
== NULL
)
270 showSimpleMessage(_(MSG_CANT_CREATE_MSGPORT
));
274 AttachCxObj(cs
->cs_broker
, customObj
);
275 ActivateCxObj(cs
->cs_broker
, TRUE
);
277 inputIO
= (struct IOStdReq
*)CreateIORequest(cs
->cs_msgPort
,
278 sizeof(struct IOStdReq
));
282 showSimpleMessage(_(MSG_CANT_ALLOCATE_MEM
));
286 if ((OpenDevice("input.device", 0, (struct IORequest
*)inputIO
, 0)) != 0)
288 showSimpleMessage(_(MSG_CANT_OPEN_INPUTDEVICE
));
292 InputBase
= (struct Device
*)inputIO
->io_Device
;
297 /************************************************************************************/
299 static void freeResources(DMState
*cs
)
303 if (cs
->cs_broker
!= NULL
)
305 DeleteCxObjAll(cs
->cs_broker
);
308 if (cs
->cs_msgPort
!= NULL
)
310 while ((cxm
= GetMsg(cs
->cs_msgPort
)))
314 DeleteMsgPort(cs
->cs_msgPort
);
319 CloseDevice((struct IORequest
*)inputIO
);
320 DeleteIORequest((struct IORequest
*)inputIO
);
324 /************************************************************************************/
326 static void depthMenu(CxMsg
*cxm
, CxObj
*co
)
328 struct InputEvent
*ie
= (struct InputEvent
*)CxMsgData(cxm
);
329 if (ie
->ie_Class
== IECLASS_RAWMOUSE
)
339 case IECODE_NOBUTTON
:
340 handleMouseMove(cxm
);
346 /************************************************************************************/
348 static void handleMenuDown(CxMsg
*cxm
)
350 struct Screen
*screen
;
352 struct Window
*window
;
354 dmdata
.selected
= -1;
356 screen
= IntuitionBase
->FirstScreen
; // frontmost screen
357 layer
= WhichLayer(&screen
->LayerInfo
, screen
->MouseX
, screen
->MouseY
);
361 if (layer
== screen
->BarLayer
) // Title bar of screen
363 D(bug("DepthMenu: BarLayer\n"));
366 && (screen
->MouseX
> screen
->Width
- 25) // FIXME real width/pos. of depth gadget
367 && (screen
->MouseX
< screen
->Width
)
368 && (screen
->MouseY
> 0)
369 && (screen
->MouseY
< screen
->BarHeight
)
372 showPopup(DM_SCREEN
, screen
, screen
->MouseX
, screen
->MouseY
);
378 D(bug("DepthMenu: other Layer\n"));
379 window
= layer
->Window
;
382 && depthGadHit(window
, screen
->MouseX
, screen
->MouseY
)
385 showPopup(DM_WINDOW
, screen
, screen
->MouseX
, screen
->MouseY
);
393 /************************************************************************************/
395 static void handleMenuUp(CxMsg
*cxm
)
397 if (dmdata
.popupwindow
)
399 struct Screen
*screen
= dmdata
.popupwindow
->WScreen
;
401 LONG entry
= dmdata
.selected
;
403 FreeScreenDrawInfo(screen
, dmdata
.drawinfo
);
404 dmdata
.drawinfo
= NULL
;
406 CloseWindow(dmdata
.popupwindow
);
407 dmdata
.popupwindow
= NULL
;
409 D(bug("DepthMenu: selected entry %d\n", entry
));
412 if (dmdata
.mode
== DM_WINDOW
)
414 // does selected window still exist?
416 struct Window
*checkwin
= screen
->FirstWindow
;
419 if (checkwin
== dmdata
.address
[entry
])
422 WindowToFront(dmdata
.address
[entry
]);
423 ActivateWindow(dmdata
.address
[entry
]);
426 checkwin
= checkwin
->NextWindow
;
431 // does selected screen still exist?
433 struct Screen
*checkscreen
= IntuitionBase
->FirstScreen
;
436 if (checkscreen
== dmdata
.address
[entry
])
439 ScreenToFront(dmdata
.address
[entry
]);
442 checkscreen
= checkscreen
->NextScreen
;
447 // when we release mouse outside window it's still open
448 if (dmdata
.popupwindow
)
450 FreeScreenDrawInfo(screen
, dmdata
.drawinfo
);
451 dmdata
.drawinfo
= NULL
;
452 CloseWindow(dmdata
.popupwindow
);
453 dmdata
.popupwindow
= NULL
;
459 /************************************************************************************/
461 static void handleMouseMove(CxMsg
*cxm
)
463 if ( ! dmdata
.popupwindow
) return;
465 struct Screen
*screen
= dmdata
.popupwindow
->WScreen
;
468 // are we within popupwindow?
470 (screen
->MouseX
> dmdata
.popupwindow
->LeftEdge
)
471 && (screen
->MouseX
< dmdata
.popupwindow
->LeftEdge
+ dmdata
.popupwindow
->Width
)
472 && (screen
->MouseY
> dmdata
.popupwindow
->TopEdge
)
473 && (screen
->MouseY
< dmdata
.popupwindow
->TopEdge
+ dmdata
.popupwindow
->Height
)
476 entry
= (screen
->MouseY
- dmdata
.popupwindow
->TopEdge
- DM_BORDERWIDTH
)
477 / dmdata
.popupwindow
->RPort
->TxHeight
;
478 if ((entry
< 0) || (entry
>= dmdata
.entries
)) entry
= -1;
480 if (entry
!= dmdata
.selected
)
483 if (dmdata
.selected
!= -1)
485 drawEntry(dmdata
.selected
, FALSE
);
491 drawEntry(entry
, TRUE
);
493 dmdata
.selected
= entry
;
497 /************************************************************************************/
499 static void showPopup(WORD mode
, struct Screen
*screen
, WORD xpos
, WORD ypos
)
503 // screen for popupmenu, check if it's a public screen
504 struct Screen
*popupscreen
= screen
;
505 if ((popupscreen
->Flags
& (PUBLICSCREEN
| WBENCHSCREEN
)) == 0)
507 bug("DepthMenu: Frontmost screen isn't a public screen\n");
511 if ( ! popupscreen
->RastPort
.Font
)
513 bug("DepthMenu: Frontmost screen doesn't have Font\n");
517 if (mode
== DM_WINDOW
)
519 D(bug("DepthMenu: window\n"));
520 struct Window
*window
= screen
->FirstWindow
;
522 while (window
&& (dmdata
.entries
< DM_MAXENTRY
))
524 if (window
->Title
&& (window
->WScreen
== screen
))
526 dmdata
.mode
= DM_WINDOW
;
527 dmdata
.address
[dmdata
.entries
] = window
;
528 strncpy(dmdata
.title
[dmdata
.entries
], window
->Title
, DM_MAXSTRLEN
);
529 dmdata
.title
[dmdata
.entries
][DM_MAXSTRLEN
- 1] = 0;
532 window
= window
->NextWindow
;
537 D(bug("DepthMenu: Screen\n"));
539 screen
= screen
->NextScreen
; // Don't add frontmost screen, start with second screen
540 while (screen
&& (dmdata
.entries
< DM_MAXENTRY
))
544 dmdata
.mode
= DM_SCREEN
;
545 dmdata
.address
[dmdata
.entries
] = screen
;
546 strncpy(dmdata
.title
[dmdata
.entries
], screen
->Title
, DM_MAXSTRLEN
);
547 dmdata
.title
[dmdata
.entries
][DM_MAXSTRLEN
- 1] = 0;
550 screen
= screen
->NextScreen
;
554 if (dmdata
.entries
> 0)
556 // calculate max. text length
557 LONG maxtextwidth
= 0;
560 for (i
=0 ; i
< dmdata
.entries
; i
++)
562 textwidth
= TextLength(&popupscreen
->RastPort
, dmdata
.title
[i
], strlen(dmdata
.title
[i
]));
563 if (textwidth
> maxtextwidth
) maxtextwidth
= textwidth
;
566 LONG width
= maxtextwidth
+ 2 * DM_BORDERWIDTH
;
567 LONG height
= dmdata
.entries
* popupscreen
->RastPort
.TxHeight
+ 2 * DM_BORDERWIDTH
;
568 LONG left
= xpos
- width
/ 2;
569 LONG top
= ypos
- height
/ 2;
570 if (left
< 0) left
= 0;
571 if (left
+ width
> popupscreen
->Width
) left
= popupscreen
->Width
- width
;
572 if (top
< 0) top
= 0;
573 if (top
+ height
> popupscreen
->Height
) top
= popupscreen
->Height
- height
;
577 dmdata
.popupwindow
= OpenWindowTags
582 WA_InnerWidth
, width
,
583 WA_InnerHeight
, height
,
586 WA_SmartRefresh
, TRUE
,
587 WA_PubScreen
, popupscreen
,
590 if (dmdata
.popupwindow
)
592 struct RastPort
*rp
= dmdata
.popupwindow
->RPort
;
593 SetFont(rp
, popupscreen
->RastPort
.Font
); // use the screen's font for the menu
594 // so we can calculate the window size with the screen font
595 SetDrMd(rp
, JAM1
); // for text rendering
597 dmdata
.drawinfo
= GetScreenDrawInfo(popupscreen
);
600 dmdata
.bgpen
= dmdata
.drawinfo
->dri_Pens
[BACKGROUNDPEN
];
601 dmdata
.txtpen
= dmdata
.drawinfo
->dri_Pens
[TEXTPEN
];
602 dmdata
.highpen
= dmdata
.drawinfo
->dri_Pens
[FILLPEN
];
603 dmdata
.shinepen
=dmdata
.drawinfo
->dri_Pens
[SHINEPEN
];
604 dmdata
.shadowpen
= dmdata
.drawinfo
->dri_Pens
[SHADOWPEN
];
608 bug("DepthMenu: GetScreenDrawInfo failed\n");
613 dmdata
.shadowpen
= 1;
616 SetAPen(rp
, dmdata
.shinepen
);
617 Move(rp
, width
-1, 0);
619 Draw(rp
, 0, height
-1);
620 SetAPen(rp
, dmdata
.shadowpen
);
621 Draw(rp
, width
-1, height
-1);
622 Draw(rp
, width
-1, 0);
625 for(i
=0; i
<dmdata
.entries
; i
++)
632 bug("DepthMenu: Can't open popup window\n");
637 /************************************************************************************/
639 static void drawEntry(LONG entry
, BOOL selstate
)
641 struct RastPort
*rp
= dmdata
.popupwindow
->RPort
;
645 SetAPen(rp
, dmdata
.highpen
);
649 SetAPen(rp
, dmdata
.bgpen
);
651 RectFill(rp
, DM_BORDERWIDTH
, entry
* rp
->TxHeight
+ DM_BORDERWIDTH
,
652 dmdata
.popupwindow
->Width
- DM_BORDERWIDTH
, (entry
+1) * rp
->TxHeight
+ DM_BORDERWIDTH
);
654 SetAPen(rp
, dmdata
.txtpen
);
655 Move(rp
, DM_BORDERWIDTH
, entry
* rp
->TxHeight
+ rp
->TxBaseline
+ DM_BORDERWIDTH
);
656 Text(rp
, dmdata
.title
[entry
], strlen(dmdata
.title
[entry
]));
659 /************************************************************************************/
661 static BOOL
depthGadHit(struct Window
*window
, WORD mousex
, WORD mousey
)
665 for(gad
= window
->FirstGadget
; gad
; gad
= gad
->NextGadget
)
667 if ( ! (gad
->Flags
& GFLG_DISABLED
))
669 WORD x
= window
->LeftEdge
+ gad
->LeftEdge
;
670 WORD y
= window
->TopEdge
+ gad
->TopEdge
;
672 WORD h
= gad
->Height
;
674 if (gad
->Flags
& GFLG_RELRIGHT
) x
+= window
->Width
- 1;
675 if (gad
->Flags
& GFLG_RELBOTTOM
) y
+= window
->Height
- 1;
676 if (gad
->Flags
& GFLG_RELWIDTH
) w
+= window
->Width
;
677 if (gad
->Flags
& GFLG_RELHEIGHT
) h
+= window
->Height
;
686 if (SYSGADTYPE(gad
) == GTYP_WDEPTH
)
697 /************************************************************************************/
699 static void lockIBaseSave(void)
701 if ( ! dmdata
.locked
)
703 dmdata
.ibaselock
= LockIBase(0);
704 dmdata
.locked
= TRUE
;
708 /************************************************************************************/
710 static void unlockIBaseSave(void)
714 UnlockIBase(dmdata
.ibaselock
);
715 dmdata
.locked
= FALSE
;
719 /************************************************************************************/
721 static void handleCx(DMState
*cs
)
729 signals
= Wait((1 << nb
.nb_Port
->mp_SigBit
) | SIGBREAKF_CTRL_C
);
731 if (signals
& (1 << nb
.nb_Port
->mp_SigBit
))
733 while ((msg
= (CxMsg
*)GetMsg(cs
->cs_msgPort
)))
735 switch (CxMsgType(msg
))
738 switch (CxMsgID(msg
))
741 ActivateCxObj(cs
->cs_broker
, FALSE
);
745 ActivateCxObj(cs
->cs_broker
, TRUE
);
749 /* Running the program twice is the same as shutting
750 down the existing program... */
757 } /* switch (CxMsgID(msg)) */
759 } /* switch (CxMsgType(msg))*/
761 ReplyMsg((struct Message
*)msg
);
763 } /* while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort))) */
766 if (signals
& SIGBREAKF_CTRL_C
)
774 /************************************************************************************/
776 int main(int argc
, char **argv
)
779 int error
= RETURN_OK
;
781 if (initiate(argc
, argv
, &cState
))
790 freeResources(&cState
);
795 /************************************************************************************/
797 ADD2INIT(Locale_Initialize
, 90);
798 ADD2EXIT(Locale_Deinitialize
, 90);