Updated PCI IDs to latest snapshot.
[tangerine.git] / workbench / tools / commodities / DepthMenu.c
blob255d5850830a0118d2da7737139d9025a4785102
1 /*
2 Copyright © 2007, The AROS Development Team. All rights reserved.
3 $Id$
5 DepthMenu commodity -- shows list of window/screens in popupmenu.
6 */
8 /******************************************************************************
10 NAME
12 DepthMenu
14 SYNOPSIS
16 CX_PRIORITY/N/K
18 LOCATION
20 Workbench:Tools/Commodities
22 FUNCTION
24 Shows popup menu with list of screens and windows after user clicks on
25 depth gadget of screen or window.
27 INPUTS
29 CX_PRIORITY -- The priority of the commodity
31 RESULT
33 NOTES
35 EXAMPLE
37 BUGS
39 SEE ALSO
41 INTERNALS
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>
60 #include <stdio.h>
61 #include <string.h>
63 #define DEBUG 0
64 #include <aros/debug.h>
66 #define CATCOMP_ARRAY
67 #include "strings.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"
79 #define ARG_PRI 0
80 #define NUM_ARGS 1
82 #define DM_WINDOW 1
83 #define DM_SCREEN 2
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 =
100 NB_VERSION,
101 NULL,
102 NULL,
103 NULL,
104 NBU_NOTIFY | NBU_UNIQUE,
107 NULL,
112 typedef struct _DMState
114 CxObj *cs_broker;
115 struct MsgPort *cs_msgPort;
116 } DMState;
119 typedef struct _DMData
121 struct Window *popupwindow;
122 WORD entries;
123 WORD mode;
124 void *address[DM_MAXENTRY]; // struct Window * or struct Screen *
125 char title[DM_MAXENTRY][DM_MAXSTRLEN];
126 ULONG ibaselock;
127 BOOL locked;
128 WORD selected; // -1 means no entry selected
129 struct DrawInfo *drawinfo;
130 UBYTE bgpen;
131 UBYTE txtpen;
132 UBYTE highpen;
133 UBYTE shinepen;
134 UBYTE shadowpen;
135 } DMData;
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);
165 else
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
182 else
184 catalog = NULL;
187 return TRUE;
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);
213 else
215 PutStr(msgString);
219 /************************************************************************************/
221 static BOOL initiate(int argc, char **argv, DMState *cs)
223 CxObj *customObj;
225 memset(cs, 0, sizeof(DMState));
227 if (Cli() != NULL)
229 struct RDArgs *rda;
230 IPTR args[] = { (IPTR) NULL, (IPTR) NULL, FALSE };
232 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
233 if (rda != NULL)
235 if (args[ARG_PRI] != (IPTR) NULL)
237 nb.nb_Pri = *(LONG *)args[ARG_PRI];
240 FreeArgs(rda);
242 else
244 UBYTE **array = ArgArrayInit(argc, (UBYTE **)argv);
245 nb.nb_Pri = ArgInt(array, "CX_PRIORITY", 0);
246 ArgArrayDone();
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));
257 return FALSE;
260 nb.nb_Port = cs->cs_msgPort;
261 cs->cs_broker = CxBroker(&nb, 0);
262 if (cs->cs_broker == NULL)
264 return FALSE;
267 customObj = CxCustom(depthMenu, 0);
268 if (customObj == NULL)
270 showSimpleMessage(_(MSG_CANT_CREATE_MSGPORT));
271 return FALSE;
274 AttachCxObj(cs->cs_broker, customObj);
275 ActivateCxObj(cs->cs_broker, TRUE);
277 inputIO = (struct IOStdReq *)CreateIORequest(cs->cs_msgPort,
278 sizeof(struct IOStdReq));
280 if (inputIO == NULL)
282 showSimpleMessage(_(MSG_CANT_ALLOCATE_MEM));
283 return FALSE;
286 if ((OpenDevice("input.device", 0, (struct IORequest *)inputIO, 0)) != 0)
288 showSimpleMessage(_(MSG_CANT_OPEN_INPUTDEVICE));
289 return FALSE;
292 InputBase = (struct Device *)inputIO->io_Device;
294 return TRUE;
297 /************************************************************************************/
299 static void freeResources(DMState *cs)
301 struct Message *cxm;
303 if (cs->cs_broker != NULL)
305 DeleteCxObjAll(cs->cs_broker);
308 if (cs->cs_msgPort != NULL)
310 while ((cxm = GetMsg(cs->cs_msgPort)))
312 ReplyMsg(cxm);
314 DeleteMsgPort(cs->cs_msgPort);
317 if (inputIO != NULL)
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)
331 switch (ie->ie_Code)
333 case MENUDOWN:
334 handleMenuDown(cxm);
335 break;
336 case MENUUP:
337 handleMenuUp(cxm);
338 break;
339 case IECODE_NOBUTTON:
340 handleMouseMove(cxm);
341 break;
346 /************************************************************************************/
348 static void handleMenuDown(CxMsg *cxm)
350 struct Screen *screen;
351 struct Layer *layer;
352 struct Window *window;
354 dmdata.selected = -1;
355 lockIBaseSave();
356 screen = IntuitionBase->FirstScreen; // frontmost screen
357 layer = WhichLayer(&screen->LayerInfo, screen->MouseX, screen->MouseY);
359 if (layer)
361 if (layer == screen->BarLayer) // Title bar of screen
363 D(bug("DepthMenu: BarLayer\n"));
364 if (
365 screen->Title
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);
373 DisposeCxMsg(cxm);
376 else
378 D(bug("DepthMenu: other Layer\n"));
379 window = layer->Window;
380 if (
381 window
382 && depthGadHit(window, screen->MouseX, screen->MouseY)
385 showPopup(DM_WINDOW, screen, screen->MouseX, screen->MouseY);
386 DisposeCxMsg(cxm);
390 unlockIBaseSave();
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));
410 if (entry != -1)
412 if (dmdata.mode == DM_WINDOW)
414 // does selected window still exist?
415 lockIBaseSave();
416 struct Window *checkwin = screen->FirstWindow;
417 while (checkwin)
419 if (checkwin == dmdata.address[entry])
421 unlockIBaseSave();
422 WindowToFront(dmdata.address[entry]);
423 ActivateWindow(dmdata.address[entry]);
424 break;
426 checkwin = checkwin->NextWindow;
429 else
431 // does selected screen still exist?
432 lockIBaseSave();
433 struct Screen *checkscreen = IntuitionBase->FirstScreen;
434 while (checkscreen)
436 if (checkscreen == dmdata.address[entry])
438 unlockIBaseSave();
439 ScreenToFront(dmdata.address[entry]);
440 break;
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;
456 unlockIBaseSave();
459 /************************************************************************************/
461 static void handleMouseMove(CxMsg *cxm)
463 if ( ! dmdata.popupwindow) return;
465 struct Screen *screen = dmdata.popupwindow->WScreen;
466 LONG entry = -1;
468 // are we within popupwindow?
469 if (
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)
482 // undraw old entry
483 if (dmdata.selected != -1)
485 drawEntry(dmdata.selected, FALSE);
488 // draw selected
489 if (entry != -1)
491 drawEntry(entry, TRUE);
493 dmdata.selected = entry;
497 /************************************************************************************/
499 static void showPopup(WORD mode, struct Screen *screen, WORD xpos, WORD ypos)
501 lockIBaseSave();
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");
508 return;
511 if ( ! popupscreen->RastPort.Font)
513 bug("DepthMenu: Frontmost screen doesn't have Font\n");
514 return;
517 if (mode == DM_WINDOW)
519 D(bug("DepthMenu: window\n"));
520 struct Window *window = screen->FirstWindow;
521 dmdata.entries = 0;
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;
530 dmdata.entries++;
532 window = window->NextWindow;
535 else
537 D(bug("DepthMenu: Screen\n"));
538 dmdata.entries = 0;
539 screen = screen->NextScreen; // Don't add frontmost screen, start with second screen
540 while (screen && (dmdata.entries < DM_MAXENTRY))
542 if (screen->Title)
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;
548 dmdata.entries++;
550 screen = screen->NextScreen;
554 if (dmdata.entries > 0)
556 // calculate max. text length
557 LONG maxtextwidth = 0;
558 LONG textwidth;
559 int i;
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;
575 unlockIBaseSave();
577 dmdata.popupwindow = OpenWindowTags
579 NULL,
580 WA_Left, left,
581 WA_Top, top,
582 WA_InnerWidth, width,
583 WA_InnerHeight, height,
584 WA_Borderless, TRUE,
585 WA_Activate, TRUE,
586 WA_SmartRefresh, TRUE,
587 WA_PubScreen, popupscreen,
588 TAG_DONE
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);
598 if (dmdata.drawinfo)
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];
606 else
608 bug("DepthMenu: GetScreenDrawInfo failed\n");
609 dmdata.bgpen = 0;
610 dmdata.txtpen = 1;
611 dmdata.highpen = 3;
612 dmdata.shinepen = 1;
613 dmdata.shadowpen = 1;
616 SetAPen(rp, dmdata.shinepen);
617 Move(rp, width-1, 0);
618 Draw(rp, 0, 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);
624 int i;
625 for(i=0; i<dmdata.entries; i++)
627 drawEntry(i, FALSE);
630 else
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;
643 if (selstate)
645 SetAPen(rp, dmdata.highpen);
647 else
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)
663 struct Gadget *gad;
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;
671 WORD w = gad->Width;
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;
679 if (
680 (mousex >= x) &&
681 (mousey >= y) &&
682 (mousex < x + w) &&
683 (mousey < y + h)
686 if (SYSGADTYPE(gad) == GTYP_WDEPTH)
688 /* found depth */
689 return TRUE;
694 return FALSE;
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)
712 if (dmdata.locked)
714 UnlockIBase(dmdata.ibaselock);
715 dmdata.locked = FALSE;
719 /************************************************************************************/
721 static void handleCx(DMState *cs)
723 CxMsg *msg;
724 BOOL quit = FALSE;
725 LONG signals;
727 while (!quit)
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))
737 case CXM_COMMAND:
738 switch (CxMsgID(msg))
740 case CXCMD_DISABLE:
741 ActivateCxObj(cs->cs_broker, FALSE);
742 break;
744 case CXCMD_ENABLE:
745 ActivateCxObj(cs->cs_broker, TRUE);
746 break;
748 case CXCMD_UNIQUE:
749 /* Running the program twice is the same as shutting
750 down the existing program... */
751 /* Fall through */
753 case CXCMD_KILL:
754 quit = TRUE;
755 break;
757 } /* switch (CxMsgID(msg)) */
758 break;
759 } /* switch (CxMsgType(msg))*/
761 ReplyMsg((struct Message *)msg);
763 } /* while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort))) */
766 if (signals & SIGBREAKF_CTRL_C)
768 quit = TRUE;
771 } /* while(!quit) */
774 /************************************************************************************/
776 int main(int argc, char **argv)
778 DMState cState;
779 int error = RETURN_OK;
781 if (initiate(argc, argv, &cState))
783 handleCx(&cState);
785 else
787 error = RETURN_FAIL;
790 freeResources(&cState);
792 return error;
795 /************************************************************************************/
797 ADD2INIT(Locale_Initialize, 90);
798 ADD2EXIT(Locale_Deinitialize, 90);