2 Copyright © 2007, The AROS Development Team. All rights reserved.
5 DepthMenu commodity -- shows list of window/screens in popupmenu.
8 /******************************************************************************
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 3
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 LockLayerInfo(&screen
->LayerInfo
);
358 layer
= WhichLayer(&screen
->LayerInfo
, screen
->MouseX
, screen
->MouseY
);
359 UnlockLayerInfo(&screen
->LayerInfo
);
363 if (layer
== screen
->BarLayer
) // Title bar of screen
365 D(bug("DepthMenu: BarLayer\n"));
368 && (screen
->MouseX
> screen
->Width
- 25) // FIXME real width/pos. of depth gadget
369 && (screen
->MouseX
< screen
->Width
)
370 && (screen
->MouseY
> 0)
371 && (screen
->MouseY
< screen
->BarHeight
)
374 showPopup(DM_SCREEN
, screen
, screen
->MouseX
, screen
->MouseY
);
380 D(bug("DepthMenu: other Layer\n"));
381 window
= layer
->Window
;
384 && depthGadHit(window
, screen
->MouseX
, screen
->MouseY
)
387 showPopup(DM_WINDOW
, screen
, screen
->MouseX
, screen
->MouseY
);
395 /************************************************************************************/
397 static void handleMenuUp(CxMsg
*cxm
)
399 if (dmdata
.popupwindow
)
401 struct Screen
*screen
= dmdata
.popupwindow
->WScreen
;
403 LONG entry
= dmdata
.selected
;
405 FreeScreenDrawInfo(screen
, dmdata
.drawinfo
);
406 dmdata
.drawinfo
= NULL
;
408 CloseWindow(dmdata
.popupwindow
);
409 dmdata
.popupwindow
= NULL
;
411 D(bug("DepthMenu: selected entry %d\n", entry
));
414 if (dmdata
.mode
== DM_WINDOW
)
416 // does selected window still exist?
418 struct Window
*checkwin
= screen
->FirstWindow
;
421 if (checkwin
== dmdata
.address
[entry
])
424 WindowToFront(dmdata
.address
[entry
]);
425 ActivateWindow(dmdata
.address
[entry
]);
428 checkwin
= checkwin
->NextWindow
;
433 // does selected screen still exist?
435 struct Screen
*checkscreen
= IntuitionBase
->FirstScreen
;
438 if (checkscreen
== dmdata
.address
[entry
])
441 ScreenToFront(dmdata
.address
[entry
]);
444 checkscreen
= checkscreen
->NextScreen
;
449 // when we release mouse outside window it's still open
450 if (dmdata
.popupwindow
)
452 FreeScreenDrawInfo(screen
, dmdata
.drawinfo
);
453 dmdata
.drawinfo
= NULL
;
454 CloseWindow(dmdata
.popupwindow
);
455 dmdata
.popupwindow
= NULL
;
461 /************************************************************************************/
463 static void handleMouseMove(CxMsg
*cxm
)
465 if ( ! dmdata
.popupwindow
) return;
467 struct Screen
*screen
= dmdata
.popupwindow
->WScreen
;
470 // are we within popupwindow?
472 (screen
->MouseX
> dmdata
.popupwindow
->LeftEdge
)
473 && (screen
->MouseX
< dmdata
.popupwindow
->LeftEdge
+ dmdata
.popupwindow
->Width
)
474 && (screen
->MouseY
> dmdata
.popupwindow
->TopEdge
)
475 && (screen
->MouseY
< dmdata
.popupwindow
->TopEdge
+ dmdata
.popupwindow
->Height
)
478 entry
= (screen
->MouseY
- dmdata
.popupwindow
->TopEdge
- DM_BORDERWIDTH
)
479 / dmdata
.popupwindow
->RPort
->TxHeight
;
480 if ((entry
< 0) || (entry
>= dmdata
.entries
)) entry
= -1;
482 if (entry
!= dmdata
.selected
)
485 if (dmdata
.selected
!= -1)
487 drawEntry(dmdata
.selected
, FALSE
);
493 drawEntry(entry
, TRUE
);
495 dmdata
.selected
= entry
;
499 /************************************************************************************/
501 static void showPopup(WORD mode
, struct Screen
*screen
, WORD xpos
, WORD ypos
)
505 // screen for popupmenu, check if it's a public screen
506 struct Screen
*popupscreen
= screen
;
507 if ((popupscreen
->Flags
& (PUBLICSCREEN
| WBENCHSCREEN
)) == 0)
509 bug("DepthMenu: Frontmost screen isn't a public screen\n");
513 if ( ! popupscreen
->RastPort
.Font
)
515 bug("DepthMenu: Frontmost screen doesn't have Font\n");
519 if (mode
== DM_WINDOW
)
521 D(bug("DepthMenu: window\n"));
522 struct Window
*window
= screen
->FirstWindow
;
524 while (window
&& (dmdata
.entries
< DM_MAXENTRY
))
526 if (window
->Title
&& (window
->WScreen
== screen
))
528 dmdata
.mode
= DM_WINDOW
;
529 dmdata
.address
[dmdata
.entries
] = window
;
530 strncpy(dmdata
.title
[dmdata
.entries
], window
->Title
, DM_MAXSTRLEN
);
531 dmdata
.title
[dmdata
.entries
][DM_MAXSTRLEN
- 1] = 0;
534 window
= window
->NextWindow
;
539 D(bug("DepthMenu: Screen\n"));
541 screen
= screen
->NextScreen
; // Don't add frontmost screen, start with second screen
542 while (screen
&& (dmdata
.entries
< DM_MAXENTRY
))
546 dmdata
.mode
= DM_SCREEN
;
547 dmdata
.address
[dmdata
.entries
] = screen
;
548 strncpy(dmdata
.title
[dmdata
.entries
], screen
->Title
, DM_MAXSTRLEN
);
549 dmdata
.title
[dmdata
.entries
][DM_MAXSTRLEN
- 1] = 0;
552 screen
= screen
->NextScreen
;
556 if (dmdata
.entries
> 0)
558 // calculate max. text length
559 LONG maxtextwidth
= 0;
562 for (i
=0 ; i
< dmdata
.entries
; i
++)
564 textwidth
= TextLength(&popupscreen
->RastPort
, dmdata
.title
[i
], strlen(dmdata
.title
[i
]));
565 if (textwidth
> maxtextwidth
) maxtextwidth
= textwidth
;
568 LONG width
= maxtextwidth
+ 2 * DM_BORDERWIDTH
;
569 LONG height
= dmdata
.entries
* popupscreen
->RastPort
.TxHeight
+ 2 * DM_BORDERWIDTH
;
570 LONG left
= xpos
- width
/ 2;
571 LONG top
= ypos
- height
/ 2;
572 if (left
< 0) left
= 0;
573 if (left
+ width
> popupscreen
->Width
) left
= popupscreen
->Width
- width
;
574 if (top
< 0) top
= 0;
575 if (top
+ height
> popupscreen
->Height
) top
= popupscreen
->Height
- height
;
579 dmdata
.popupwindow
= OpenWindowTags
584 WA_InnerWidth
, width
,
585 WA_InnerHeight
, height
,
588 WA_SmartRefresh
, TRUE
,
589 WA_PubScreen
, popupscreen
,
592 if (dmdata
.popupwindow
)
594 struct RastPort
*rp
= dmdata
.popupwindow
->RPort
;
595 SetFont(rp
, popupscreen
->RastPort
.Font
); // use the screen's font for the menu
596 // so we can calculate the window size with the screen font
597 SetDrMd(rp
, JAM1
); // for text rendering
599 dmdata
.drawinfo
= GetScreenDrawInfo(popupscreen
);
602 dmdata
.bgpen
= dmdata
.drawinfo
->dri_Pens
[BACKGROUNDPEN
];
603 dmdata
.txtpen
= dmdata
.drawinfo
->dri_Pens
[TEXTPEN
];
604 dmdata
.highpen
= dmdata
.drawinfo
->dri_Pens
[FILLPEN
];
605 dmdata
.shinepen
=dmdata
.drawinfo
->dri_Pens
[SHINEPEN
];
606 dmdata
.shadowpen
= dmdata
.drawinfo
->dri_Pens
[SHADOWPEN
];
610 bug("DepthMenu: GetScreenDrawInfo failed\n");
615 dmdata
.shadowpen
= 1;
618 SetAPen(rp
, dmdata
.shinepen
);
619 Move(rp
, width
-1, 0);
621 Draw(rp
, 0, height
-1);
622 SetAPen(rp
, dmdata
.shadowpen
);
623 Draw(rp
, width
-1, height
-1);
624 Draw(rp
, width
-1, 0);
627 for(i
=0; i
<dmdata
.entries
; i
++)
634 bug("DepthMenu: Can't open popup window\n");
639 /************************************************************************************/
641 static void drawEntry(LONG entry
, BOOL selstate
)
643 struct RastPort
*rp
= dmdata
.popupwindow
->RPort
;
647 SetAPen(rp
, dmdata
.highpen
);
651 SetAPen(rp
, dmdata
.bgpen
);
653 RectFill(rp
, DM_BORDERWIDTH
, entry
* rp
->TxHeight
+ DM_BORDERWIDTH
,
654 dmdata
.popupwindow
->Width
- DM_BORDERWIDTH
, (entry
+1) * rp
->TxHeight
+ DM_BORDERWIDTH
);
656 SetAPen(rp
, dmdata
.txtpen
);
657 Move(rp
, DM_BORDERWIDTH
, entry
* rp
->TxHeight
+ rp
->TxBaseline
+ DM_BORDERWIDTH
);
658 Text(rp
, dmdata
.title
[entry
], strlen(dmdata
.title
[entry
]));
661 /************************************************************************************/
663 static BOOL
depthGadHit(struct Window
*window
, WORD mousex
, WORD mousey
)
667 for(gad
= window
->FirstGadget
; gad
; gad
= gad
->NextGadget
)
669 if ( ! (gad
->Flags
& GFLG_DISABLED
))
671 WORD x
= window
->LeftEdge
+ gad
->LeftEdge
;
672 WORD y
= window
->TopEdge
+ gad
->TopEdge
;
674 WORD h
= gad
->Height
;
676 if (gad
->Flags
& GFLG_RELRIGHT
) x
+= window
->Width
- 1;
677 if (gad
->Flags
& GFLG_RELBOTTOM
) y
+= window
->Height
- 1;
678 if (gad
->Flags
& GFLG_RELWIDTH
) w
+= window
->Width
;
679 if (gad
->Flags
& GFLG_RELHEIGHT
) h
+= window
->Height
;
688 if (SYSGADTYPE(gad
) == GTYP_WDEPTH
)
699 /************************************************************************************/
701 static void lockIBaseSave(void)
703 if ( ! dmdata
.locked
)
705 dmdata
.ibaselock
= LockIBase(0);
706 dmdata
.locked
= TRUE
;
710 /************************************************************************************/
712 static void unlockIBaseSave(void)
716 UnlockIBase(dmdata
.ibaselock
);
717 dmdata
.locked
= FALSE
;
721 /************************************************************************************/
723 static void handleCx(DMState
*cs
)
731 signals
= Wait((1 << nb
.nb_Port
->mp_SigBit
) | SIGBREAKF_CTRL_C
);
733 if (signals
& (1 << nb
.nb_Port
->mp_SigBit
))
735 while ((msg
= (CxMsg
*)GetMsg(cs
->cs_msgPort
)))
737 switch (CxMsgType(msg
))
740 switch (CxMsgID(msg
))
743 ActivateCxObj(cs
->cs_broker
, FALSE
);
747 ActivateCxObj(cs
->cs_broker
, TRUE
);
751 /* Running the program twice is the same as shutting
752 down the existing program... */
759 } /* switch (CxMsgID(msg)) */
761 } /* switch (CxMsgType(msg))*/
763 ReplyMsg((struct Message
*)msg
);
765 } /* while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort))) */
768 if (signals
& SIGBREAKF_CTRL_C
)
776 /************************************************************************************/
778 int main(int argc
, char **argv
)
781 int error
= RETURN_OK
;
783 if (initiate(argc
, argv
, &cState
))
792 freeResources(&cState
);
797 /************************************************************************************/
799 ADD2INIT(Locale_Initialize
, 90);
800 ADD2EXIT(Locale_Deinitialize
, 90);