- added WMGetLabelText()
[wmaker-crm.git] / WINGs / wpopupbutton.c
blob8785134c06b05bdcd9dfdf96b51303121be19635
5 #include "WINGsP.h"
8 typedef struct W_PopUpButton {
9 W_Class widgetClass;
10 WMView *view;
12 void *clientData;
13 WMAction *action;
15 char *caption;
17 WMBag *items;
19 short selectedItemIndex;
21 short highlightedItem;
23 WMView *menuView; /* override redirect popup menu */
25 WMHandlerID timer; /* for autoscroll */
27 /**/
28 int scrollStartY; /* for autoscroll */
30 struct {
31 unsigned int pullsDown:1;
33 unsigned int configured:1;
35 unsigned int insideMenu:1;
37 unsigned int enabled:1;
39 } flags;
40 } PopUpButton;
43 #define MENU_BLINK_DELAY 60000
44 #define MENU_BLINK_COUNT 2
46 #define SCROLL_DELAY 10
49 #define DEFAULT_WIDTH 60
50 #define DEFAULT_HEIGHT 20
51 #define DEFAULT_CAPTION ""
54 static void destroyPopUpButton(PopUpButton *bPtr);
55 static void paintPopUpButton(PopUpButton *bPtr);
57 static void handleEvents(XEvent *event, void *data);
58 static void handleActionEvents(XEvent *event, void *data);
60 static void resizeMenu(PopUpButton *bPtr);
63 WMPopUpButton*
64 WMCreatePopUpButton(WMWidget *parent)
66 PopUpButton *bPtr;
67 W_Screen *scr = W_VIEW(parent)->screen;
70 bPtr = wmalloc(sizeof(PopUpButton));
71 memset(bPtr, 0, sizeof(PopUpButton));
73 bPtr->widgetClass = WC_PopUpButton;
75 bPtr->view = W_CreateView(W_VIEW(parent));
76 if (!bPtr->view) {
77 wfree(bPtr);
78 return NULL;
80 bPtr->view->self = bPtr;
82 WMCreateEventHandler(bPtr->view, ExposureMask|StructureNotifyMask
83 |ClientMessageMask, handleEvents, bPtr);
86 W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
87 bPtr->caption = wstrdup(DEFAULT_CAPTION);
89 WMCreateEventHandler(bPtr->view, ButtonPressMask|ButtonReleaseMask,
90 handleActionEvents, bPtr);
92 bPtr->flags.enabled = 1;
94 bPtr->items = WMCreateBag(4);
96 bPtr->selectedItemIndex = -1;
98 bPtr->menuView = W_CreateUnmanagedTopView(scr);
100 W_ResizeView(bPtr->menuView, bPtr->view->size.width, 1);
102 WMCreateEventHandler(bPtr->menuView, ButtonPressMask|ButtonReleaseMask
103 |EnterWindowMask|LeaveWindowMask|ButtonMotionMask
104 |ExposureMask, handleActionEvents, bPtr);
106 return bPtr;
110 void
111 WMSetPopUpButtonAction(WMPopUpButton *bPtr, WMAction *action, void *clientData)
113 CHECK_CLASS(bPtr, WC_PopUpButton);
115 bPtr->action = action;
117 bPtr->clientData = clientData;
121 WMMenuItem*
122 WMAddPopUpButtonItem(WMPopUpButton *bPtr, char *title)
124 WMMenuItem *item;
126 CHECK_CLASS(bPtr, WC_PopUpButton);
128 item = WMCreateMenuItem();
129 WMSetMenuItemTitle(item, title);
131 WMPutInBag(bPtr->items, item);
133 if (bPtr->menuView && bPtr->menuView->flags.realized)
134 resizeMenu(bPtr);
136 return item;
140 WMMenuItem*
141 WMInsertPopUpButtonItem(WMPopUpButton *bPtr, int index, char *title)
143 WMMenuItem *item;
145 CHECK_CLASS(bPtr, WC_PopUpButton);
147 item = WMCreateMenuItem();
148 WMSetMenuItemTitle(item, title);
150 WMInsertInBag(bPtr->items, index, item);
152 /* if there is an selected item, update it's index to match the new
153 * position */
154 if (index < bPtr->selectedItemIndex)
155 bPtr->selectedItemIndex++;
157 if (bPtr->menuView && bPtr->menuView->flags.realized)
158 resizeMenu(bPtr);
160 return item;
164 void
165 WMRemovePopUpButtonItem(WMPopUpButton *bPtr, int index)
167 WMMenuItem *item;
169 CHECK_CLASS(bPtr, WC_PopUpButton);
171 wassertr(index >= 0 && index < WMGetBagItemCount(bPtr->items));
174 item = WMGetFromBag(bPtr->items, index);
175 WMDeleteFromBag(bPtr->items, index);
177 WMDestroyMenuItem(item);
179 if (bPtr->selectedItemIndex >= 0 && !bPtr->flags.pullsDown) {
180 if (index < bPtr->selectedItemIndex)
181 bPtr->selectedItemIndex--;
182 else if (index == bPtr->selectedItemIndex) {
183 /* reselect first item if the removed item is the
184 * selected one */
185 bPtr->selectedItemIndex = 0;
186 if (bPtr->view->flags.mapped)
187 paintPopUpButton(bPtr);
191 if (bPtr->menuView && bPtr->menuView->flags.realized)
192 resizeMenu(bPtr);
196 void
197 WMSetPopUpButtonEnabled(WMPopUpButton *bPtr, Bool flag)
199 bPtr->flags.enabled = flag;
200 if (bPtr->view->flags.mapped)
201 paintPopUpButton(bPtr);
205 Bool
206 WMGetPopUpButtonEnabled(WMPopUpButton *bPtr)
208 return bPtr->flags.enabled;
212 void
213 WMSetPopUpButtonSelectedItem(WMPopUpButton *bPtr, int index)
216 wassertr(index < WMGetBagItemCount(bPtr->items));
218 /* if (index >= WMGetBagCount(bPtr->items))
219 index = -1;*/
221 bPtr->selectedItemIndex = index;
223 if (bPtr->view->flags.mapped)
224 paintPopUpButton(bPtr);
228 WMGetPopUpButtonSelectedItem(WMPopUpButton *bPtr)
230 if (!bPtr->flags.pullsDown && bPtr->selectedItemIndex < 0)
231 return -1;
232 else
233 return bPtr->selectedItemIndex;
237 void
238 WMSetPopUpButtonText(WMPopUpButton *bPtr, char *text)
240 if (bPtr->caption)
241 wfree(bPtr->caption);
242 if (text)
243 bPtr->caption = wstrdup(text);
244 else
245 bPtr->caption = NULL;
246 if (bPtr->view->flags.realized) {
247 if (bPtr->flags.pullsDown || bPtr->selectedItemIndex < 0) {
248 paintPopUpButton(bPtr);
255 void
256 WMSetPopUpButtonItemEnabled(WMPopUpButton *bPtr, int index, Bool flag)
258 WMMenuItem *item;
260 item = WMGetFromBag(bPtr->items, index);
261 wassertr(item != NULL);
263 WMSetMenuItemEnabled(item, flag);
267 Bool
268 WMGetPopUpButtonItemEnabled(WMPopUpButton *bPtr, int index)
270 WMMenuItem *item;
272 item = WMGetFromBag(bPtr->items, index);
273 wassertrv(item != NULL, False);
275 return WMGetMenuItemEnabled(item);
279 void
280 WMSetPopUpButtonPullsDown(WMPopUpButton *bPtr, Bool flag)
282 bPtr->flags.pullsDown = flag;
283 if (flag) {
284 bPtr->selectedItemIndex = -1;
287 if (bPtr->view->flags.mapped)
288 paintPopUpButton(bPtr);
293 WMGetPopUpButtonNumberOfItems(WMPopUpButton *bPtr)
295 return WMGetBagItemCount(bPtr->items);
299 char*
300 WMGetPopUpButtonItem(WMPopUpButton *bPtr, int index)
302 WMMenuItem *item;
304 if (index >= WMGetBagItemCount(bPtr->items) || index < 0)
305 return NULL;
307 item = WMGetFromBag(bPtr->items, index);
308 if (item == NULL)
309 return NULL;
311 return WMGetMenuItemTitle(item);
315 WMMenuItem*
316 WMGetPopUpButtonMenuItem(WMPopUpButton *bPtr, int index)
318 WMMenuItem *item;
320 item = WMGetFromBag(bPtr->items, index);
322 return item;
327 static void
328 paintPopUpButton(PopUpButton *bPtr)
330 W_Screen *scr = bPtr->view->screen;
331 char *caption;
332 Pixmap pixmap;
335 if (bPtr->flags.pullsDown) {
336 caption = bPtr->caption;
337 } else {
338 if (bPtr->selectedItemIndex < 0) {
339 /* if no item selected, show the caption */
340 caption = bPtr->caption;
341 } else {
342 caption = WMGetPopUpButtonItem(bPtr, bPtr->selectedItemIndex);
346 pixmap = XCreatePixmap(scr->display, bPtr->view->window,
347 bPtr->view->size.width, bPtr->view->size.height,
348 scr->depth);
349 XFillRectangle(scr->display, pixmap, WMColorGC(scr->gray), 0, 0,
350 bPtr->view->size.width, bPtr->view->size.height);
352 W_DrawRelief(scr, pixmap, 0, 0, bPtr->view->size.width,
353 bPtr->view->size.height, WRRaised);
355 if (caption) {
356 W_PaintText(bPtr->view, pixmap, scr->normalFont, 6,
357 (bPtr->view->size.height-WMFontHeight(scr->normalFont))/2,
358 bPtr->view->size.width, WALeft,
359 bPtr->flags.enabled ? WMColorGC(scr->black) : WMColorGC(scr->darkGray),
360 False, caption, strlen(caption));
363 if (bPtr->flags.pullsDown) {
364 XCopyArea(scr->display, scr->pullDownIndicator->pixmap,
365 pixmap, scr->copyGC, 0, 0, scr->pullDownIndicator->width,
366 scr->pullDownIndicator->height,
367 bPtr->view->size.width-scr->pullDownIndicator->width-4,
368 (bPtr->view->size.height-scr->pullDownIndicator->height)/2);
369 } else {
370 int x, y;
372 x = bPtr->view->size.width - scr->popUpIndicator->width - 4;
373 y = (bPtr->view->size.height-scr->popUpIndicator->height)/2;
375 XSetClipOrigin(scr->display, scr->clipGC, x, y);
376 XSetClipMask(scr->display, scr->clipGC, scr->popUpIndicator->mask);
377 XCopyArea(scr->display, scr->popUpIndicator->pixmap, pixmap,
378 scr->clipGC, 0, 0, scr->popUpIndicator->width,
379 scr->popUpIndicator->height, x, y);
382 XCopyArea(scr->display, pixmap, bPtr->view->window, scr->copyGC, 0, 0,
383 bPtr->view->size.width, bPtr->view->size.height, 0, 0);
385 XFreePixmap(scr->display, pixmap);
390 static void
391 handleEvents(XEvent *event, void *data)
393 PopUpButton *bPtr = (PopUpButton*)data;
395 CHECK_CLASS(data, WC_PopUpButton);
398 switch (event->type) {
399 case Expose:
400 if (event->xexpose.count!=0)
401 break;
402 paintPopUpButton(bPtr);
403 break;
405 case DestroyNotify:
406 destroyPopUpButton(bPtr);
407 break;
413 static void
414 paintMenuEntry(PopUpButton *bPtr, int index, int highlight)
416 W_Screen *scr = bPtr->view->screen;
417 int yo;
418 int width, height, itemHeight, itemCount;
419 char *title;
421 itemCount = WMGetBagItemCount(bPtr->items);
422 if (index < 0 || index >= itemCount)
423 return;
425 itemHeight = bPtr->view->size.height;
426 width = bPtr->view->size.width;
427 height = itemHeight * itemCount;
428 yo = (itemHeight - WMFontHeight(scr->normalFont))/2;
430 if (!highlight) {
431 XClearArea(scr->display, bPtr->menuView->window, 0, index*itemHeight,
432 width, itemHeight, False);
433 return;
434 } else if (index < 0 && bPtr->flags.pullsDown) {
435 return;
438 XFillRectangle(scr->display, bPtr->menuView->window, WMColorGC(scr->white),
439 1, index*itemHeight+1, width-3, itemHeight-3);
441 title = WMGetPopUpButtonItem(bPtr, index);
443 W_DrawRelief(scr, bPtr->menuView->window, 0, index*itemHeight,
444 width, itemHeight, WRRaised);
446 W_PaintText(bPtr->menuView, bPtr->menuView->window, scr->normalFont, 6,
447 index*itemHeight + yo, width, WALeft, WMColorGC(scr->black),
448 False, title, strlen(title));
450 if (!bPtr->flags.pullsDown && index == bPtr->selectedItemIndex) {
451 XCopyArea(scr->display, scr->popUpIndicator->pixmap,
452 bPtr->menuView->window, scr->copyGC, 0, 0,
453 scr->popUpIndicator->width, scr->popUpIndicator->height,
454 width-scr->popUpIndicator->width-4,
455 index*itemHeight+(itemHeight-scr->popUpIndicator->height)/2);
460 Pixmap
461 makeMenuPixmap(PopUpButton *bPtr)
463 Pixmap pixmap;
464 W_Screen *scr = bPtr->view->screen;
465 WMMenuItem *item;
466 WMBagIterator iter;
467 int yo, i;
468 int width, height, itemHeight;
470 itemHeight = bPtr->view->size.height;
471 width = bPtr->view->size.width;
472 height = itemHeight * WMGetBagItemCount(bPtr->items);
473 yo = (itemHeight - WMFontHeight(scr->normalFont))/2;
475 pixmap = XCreatePixmap(scr->display, bPtr->view->window, width, height,
476 scr->depth);
478 XFillRectangle(scr->display, pixmap, WMColorGC(scr->gray), 0, 0,
479 width, height);
481 i = 0;
482 WM_ITERATE_BAG(bPtr->items, item, iter) {
483 GC gc;
484 char *text;
486 text = WMGetMenuItemTitle(item);
488 W_DrawRelief(scr, pixmap, 0, i*itemHeight, width, itemHeight,
489 WRRaised);
491 if (!WMGetMenuItemEnabled(item))
492 gc = WMColorGC(scr->darkGray);
493 else
494 gc = WMColorGC(scr->black);
496 W_PaintText(bPtr->menuView, pixmap, scr->normalFont, 6,
497 i*itemHeight + yo, width, WALeft, gc, False,
498 text, strlen(text));
500 if (!bPtr->flags.pullsDown && i == bPtr->selectedItemIndex) {
501 XCopyArea(scr->display, scr->popUpIndicator->pixmap, pixmap,
502 scr->copyGC, 0, 0, scr->popUpIndicator->width,
503 scr->popUpIndicator->height,
504 width-scr->popUpIndicator->width-4,
505 i*itemHeight+(itemHeight-scr->popUpIndicator->height)/2);
508 i++;
511 return pixmap;
515 static void
516 resizeMenu(PopUpButton *bPtr)
518 int height;
520 height = WMGetBagItemCount(bPtr->items) * bPtr->view->size.height;
521 if (height > 0)
522 W_ResizeView(bPtr->menuView, bPtr->view->size.width, height);
526 static void
527 popUpMenu(PopUpButton *bPtr)
529 W_Screen *scr = bPtr->view->screen;
530 Window dummyW;
531 int x, y;
533 if (!bPtr->menuView->flags.realized) {
534 W_RealizeView(bPtr->menuView);
535 resizeMenu(bPtr);
538 if (WMGetBagItemCount(bPtr->items) < 1)
539 return;
541 XTranslateCoordinates(scr->display, bPtr->view->window, scr->rootWin,
542 0, 0, &x, &y, &dummyW);
544 if (bPtr->flags.pullsDown) {
545 y += bPtr->view->size.height;
546 } else {
547 y -= bPtr->view->size.height*bPtr->selectedItemIndex;
549 W_MoveView(bPtr->menuView, x, y);
551 XSetWindowBackgroundPixmap(scr->display, bPtr->menuView->window,
552 makeMenuPixmap(bPtr));
553 XClearWindow(scr->display, bPtr->menuView->window);
555 W_MapView(bPtr->menuView);
557 bPtr->highlightedItem = 0;
558 if (!bPtr->flags.pullsDown && bPtr->selectedItemIndex < 0)
559 paintMenuEntry(bPtr, bPtr->selectedItemIndex, True);
563 static void
564 popDownMenu(PopUpButton *bPtr)
566 W_UnmapView(bPtr->menuView);
568 /* free the background pixmap used to draw the menu contents */
569 XSetWindowBackgroundPixmap(bPtr->view->screen->display,
570 bPtr->menuView->window, None);
574 static void
575 autoScroll(void *data)
577 PopUpButton *bPtr = (PopUpButton*)data;
578 int scrHeight = WMWidgetScreen(bPtr)->rootView->size.height;
579 int repeat = 0;
580 int dy = 0;
583 if (bPtr->scrollStartY >= scrHeight-1
584 && bPtr->menuView->pos.y+bPtr->menuView->size.height >= scrHeight-1) {
585 repeat = 1;
587 if (bPtr->menuView->pos.y+bPtr->menuView->size.height-5
588 <= scrHeight - 1) {
589 dy = scrHeight - 1
590 - (bPtr->menuView->pos.y+bPtr->menuView->size.height);
591 } else
592 dy = -5;
594 } else if (bPtr->scrollStartY <= 1 && bPtr->menuView->pos.y < 1) {
595 repeat = 1;
597 if (bPtr->menuView->pos.y+5 > 1)
598 dy = 1 - bPtr->menuView->pos.y;
599 else
600 dy = 5;
603 if (repeat) {
604 int oldItem;
606 W_MoveView(bPtr->menuView, bPtr->menuView->pos.x,
607 bPtr->menuView->pos.y + dy);
609 oldItem = bPtr->highlightedItem;
610 bPtr->highlightedItem = (bPtr->scrollStartY - bPtr->menuView->pos.y)
611 / bPtr->view->size.height;
613 if (oldItem!=bPtr->highlightedItem) {
614 WMMenuItem *item;
616 paintMenuEntry(bPtr, oldItem, False);
618 if (bPtr->highlightedItem >= 0 &&
619 bPtr->highlightedItem < WMGetBagItemCount(bPtr->items)) {
620 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
621 paintMenuEntry(bPtr, bPtr->highlightedItem,
622 WMGetMenuItemEnabled(item));
623 } else {
624 bPtr->highlightedItem = -1;
628 bPtr->timer = WMAddTimerHandler(SCROLL_DELAY, autoScroll, bPtr);
629 } else {
630 bPtr->timer = NULL;
635 static void
636 wheelScrollUp(PopUpButton *bPtr)
638 int testIndex = bPtr->selectedItemIndex - 1;
640 while (testIndex>=0 && !WMGetPopUpButtonItemEnabled(bPtr, testIndex))
641 testIndex--;
642 if (testIndex != -1) {
643 WMSetPopUpButtonSelectedItem(bPtr, testIndex);
644 if (bPtr->action)
645 (*bPtr->action)(bPtr, bPtr->clientData);
650 static void
651 wheelScrollDown(PopUpButton *bPtr)
653 int itemCount = WMGetBagItemCount(bPtr->items);
654 int testIndex = bPtr->selectedItemIndex + 1;
656 while (testIndex<itemCount && !WMGetPopUpButtonItemEnabled(bPtr, testIndex))
657 testIndex++;
658 if (testIndex != itemCount) {
659 WMSetPopUpButtonSelectedItem(bPtr, testIndex);
660 if (bPtr->action)
661 (*bPtr->action)(bPtr, bPtr->clientData);
666 static void
667 handleActionEvents(XEvent *event, void *data)
669 PopUpButton *bPtr = (PopUpButton*)data;
670 int oldItem;
671 int scrHeight = WMWidgetScreen(bPtr)->rootView->size.height;
673 CHECK_CLASS(data, WC_PopUpButton);
675 if (WMGetBagItemCount(bPtr->items) < 1)
676 return;
678 switch (event->type) {
679 /* called for menuView */
680 case Expose:
681 paintMenuEntry(bPtr, bPtr->highlightedItem, True);
682 break;
684 case LeaveNotify:
685 bPtr->flags.insideMenu = 0;
686 if (bPtr->menuView->flags.mapped)
687 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
688 bPtr->highlightedItem = -1;
689 break;
691 case EnterNotify:
692 bPtr->flags.insideMenu = 1;
693 break;
695 case MotionNotify:
696 if (bPtr->flags.insideMenu) {
697 oldItem = bPtr->highlightedItem;
698 bPtr->highlightedItem = event->xmotion.y / bPtr->view->size.height;
699 if (oldItem!=bPtr->highlightedItem) {
700 WMMenuItem *item;
702 paintMenuEntry(bPtr, oldItem, False);
703 if (bPtr->highlightedItem >= 0 &&
704 bPtr->highlightedItem < WMGetBagItemCount(bPtr->items)) {
705 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
706 paintMenuEntry(bPtr, bPtr->highlightedItem,
707 WMGetMenuItemEnabled(item));
708 } else {
709 bPtr->highlightedItem = -1;
714 if (event->xmotion.y_root >= scrHeight-1
715 || event->xmotion.y_root <= 1) {
716 bPtr->scrollStartY = event->xmotion.y_root;
717 if (!bPtr->timer)
718 autoScroll(bPtr);
719 } else if (bPtr->timer) {
720 WMDeleteTimerHandler(bPtr->timer);
721 bPtr->timer = NULL;
724 break;
726 /* called for bPtr->view */
727 case ButtonPress:
728 if (!bPtr->flags.enabled)
729 break;
731 if (event->xbutton.button==WINGsConfiguration.mouseWheelUp) {
732 if (!bPtr->menuView->flags.mapped && !bPtr->flags.pullsDown) {
733 wheelScrollUp(bPtr);
735 break;
736 } else if (event->xbutton.button==WINGsConfiguration.mouseWheelDown) {
737 if (!bPtr->menuView->flags.mapped && !bPtr->flags.pullsDown) {
738 wheelScrollDown(bPtr);
740 break;
742 popUpMenu(bPtr);
743 if (!bPtr->flags.pullsDown) {
744 bPtr->highlightedItem = bPtr->selectedItemIndex;
745 bPtr->flags.insideMenu = 1;
746 } else {
747 bPtr->highlightedItem = -1;
748 bPtr->flags.insideMenu = 0;
750 XGrabPointer(bPtr->view->screen->display, bPtr->menuView->window,
751 False, ButtonReleaseMask|ButtonMotionMask|EnterWindowMask
752 |LeaveWindowMask, GrabModeAsync, GrabModeAsync,
753 None, None, CurrentTime);
754 break;
756 case ButtonRelease:
757 if (event->xbutton.button==WINGsConfiguration.mouseWheelUp ||
758 event->xbutton.button==WINGsConfiguration.mouseWheelDown) {
759 break;
761 XUngrabPointer(bPtr->view->screen->display, event->xbutton.time);
762 if (!bPtr->flags.pullsDown)
763 popDownMenu(bPtr);
765 if (bPtr->timer) {
766 WMDeleteTimerHandler(bPtr->timer);
767 bPtr->timer = NULL;
770 if (bPtr->flags.insideMenu && bPtr->highlightedItem>=0) {
771 WMMenuItem *item;
773 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
775 if (WMGetMenuItemEnabled(item)) {
776 int i;
777 WMSetPopUpButtonSelectedItem(bPtr, bPtr->highlightedItem);
779 if (bPtr->flags.pullsDown) {
780 for (i=0; i<MENU_BLINK_COUNT; i++) {
781 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
782 XSync(bPtr->view->screen->display, 0);
783 wusleep(MENU_BLINK_DELAY);
784 paintMenuEntry(bPtr, bPtr->highlightedItem, True);
785 XSync(bPtr->view->screen->display, 0);
786 wusleep(MENU_BLINK_DELAY);
789 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
790 popDownMenu(bPtr);
791 if (bPtr->action)
792 (*bPtr->action)(bPtr, bPtr->clientData);
795 if (bPtr->menuView->flags.mapped)
796 popDownMenu(bPtr);
797 break;
803 static void
804 destroyPopUpButton(PopUpButton *bPtr)
806 WMMenuItem *item;
807 WMBagIterator i;
809 if (bPtr->timer) {
810 WMDeleteTimerHandler(bPtr->timer);
813 WM_ITERATE_BAG(bPtr->items, item, i) {
814 WMDestroyMenuItem(item);
816 WMFreeBag(bPtr->items);
818 if (bPtr->caption)
819 wfree(bPtr->caption);
821 /* have to destroy explicitly because the popup is a toplevel */
822 W_DestroyView(bPtr->menuView);
824 wfree(bPtr);