various table widget updates
[wmaker-crm.git] / WINGs / wpopupbutton.c
blobbafbb1102941176974ea1377b17a23c65a63df5b
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);
229 WMGetPopUpButtonSelectedItem(WMPopUpButton *bPtr)
231 if (!bPtr->flags.pullsDown && bPtr->selectedItemIndex < 0)
232 return -1;
233 else
234 return bPtr->selectedItemIndex;
238 void
239 WMSetPopUpButtonText(WMPopUpButton *bPtr, char *text)
241 if (bPtr->caption)
242 wfree(bPtr->caption);
243 if (text)
244 bPtr->caption = wstrdup(text);
245 else
246 bPtr->caption = NULL;
247 if (bPtr->view->flags.realized) {
248 if (bPtr->flags.pullsDown || bPtr->selectedItemIndex < 0) {
249 paintPopUpButton(bPtr);
256 void
257 WMSetPopUpButtonItemEnabled(WMPopUpButton *bPtr, int index, Bool flag)
259 WMMenuItem *item;
261 item = WMGetFromBag(bPtr->items, index);
262 wassertr(item != NULL);
264 WMSetMenuItemEnabled(item, flag);
268 Bool
269 WMGetPopUpButtonItemEnabled(WMPopUpButton *bPtr, int index)
271 WMMenuItem *item;
273 item = WMGetFromBag(bPtr->items, index);
274 wassertrv(item != NULL, False);
276 return WMGetMenuItemEnabled(item);
280 void
281 WMSetPopUpButtonPullsDown(WMPopUpButton *bPtr, Bool flag)
283 bPtr->flags.pullsDown = flag;
284 if (flag) {
285 bPtr->selectedItemIndex = -1;
288 if (bPtr->view->flags.mapped)
289 paintPopUpButton(bPtr);
294 WMGetPopUpButtonNumberOfItems(WMPopUpButton *bPtr)
296 return WMGetBagItemCount(bPtr->items);
300 char*
301 WMGetPopUpButtonItem(WMPopUpButton *bPtr, int index)
303 WMMenuItem *item;
305 if (index >= WMGetBagItemCount(bPtr->items) || index < 0)
306 return NULL;
308 item = WMGetFromBag(bPtr->items, index);
309 if (item == NULL)
310 return NULL;
312 return WMGetMenuItemTitle(item);
316 WMMenuItem*
317 WMGetPopUpButtonMenuItem(WMPopUpButton *bPtr, int index)
319 WMMenuItem *item;
321 item = WMGetFromBag(bPtr->items, index);
323 return item;
328 static void
329 paintPopUpButton(PopUpButton *bPtr)
331 W_Screen *scr = bPtr->view->screen;
332 char *caption;
333 Pixmap pixmap;
336 if (bPtr->flags.pullsDown) {
337 caption = bPtr->caption;
338 } else {
339 if (bPtr->selectedItemIndex < 0) {
340 /* if no item selected, show the caption */
341 caption = bPtr->caption;
342 } else {
343 caption = WMGetPopUpButtonItem(bPtr, bPtr->selectedItemIndex);
347 pixmap = XCreatePixmap(scr->display, bPtr->view->window,
348 bPtr->view->size.width, bPtr->view->size.height,
349 scr->depth);
350 XFillRectangle(scr->display, pixmap, WMColorGC(scr->gray), 0, 0,
351 bPtr->view->size.width, bPtr->view->size.height);
353 W_DrawRelief(scr, pixmap, 0, 0, bPtr->view->size.width,
354 bPtr->view->size.height, WRRaised);
356 if (caption) {
357 W_PaintText(bPtr->view, pixmap, scr->normalFont, 6,
358 (bPtr->view->size.height-WMFontHeight(scr->normalFont))/2,
359 bPtr->view->size.width, WALeft,
360 bPtr->flags.enabled ? WMColorGC(scr->black) : WMColorGC(scr->darkGray),
361 False, caption, strlen(caption));
364 if (bPtr->flags.pullsDown) {
365 XCopyArea(scr->display, scr->pullDownIndicator->pixmap,
366 pixmap, scr->copyGC, 0, 0, scr->pullDownIndicator->width,
367 scr->pullDownIndicator->height,
368 bPtr->view->size.width-scr->pullDownIndicator->width-4,
369 (bPtr->view->size.height-scr->pullDownIndicator->height)/2);
370 } else {
371 int x, y;
373 x = bPtr->view->size.width - scr->popUpIndicator->width - 4;
374 y = (bPtr->view->size.height-scr->popUpIndicator->height)/2;
376 XSetClipOrigin(scr->display, scr->clipGC, x, y);
377 XSetClipMask(scr->display, scr->clipGC, scr->popUpIndicator->mask);
378 XCopyArea(scr->display, scr->popUpIndicator->pixmap, pixmap,
379 scr->clipGC, 0, 0, scr->popUpIndicator->width,
380 scr->popUpIndicator->height, x, y);
383 XCopyArea(scr->display, pixmap, bPtr->view->window, scr->copyGC, 0, 0,
384 bPtr->view->size.width, bPtr->view->size.height, 0, 0);
386 XFreePixmap(scr->display, pixmap);
391 static void
392 handleEvents(XEvent *event, void *data)
394 PopUpButton *bPtr = (PopUpButton*)data;
396 CHECK_CLASS(data, WC_PopUpButton);
399 switch (event->type) {
400 case Expose:
401 if (event->xexpose.count!=0)
402 break;
403 paintPopUpButton(bPtr);
404 break;
406 case DestroyNotify:
407 destroyPopUpButton(bPtr);
408 break;
414 static void
415 paintMenuEntry(PopUpButton *bPtr, int index, int highlight)
417 W_Screen *scr = bPtr->view->screen;
418 int yo;
419 int width, height, itemHeight, itemCount;
420 char *title;
422 itemCount = WMGetBagItemCount(bPtr->items);
423 if (index < 0 || index >= itemCount)
424 return;
426 itemHeight = bPtr->view->size.height;
427 width = bPtr->view->size.width;
428 height = itemHeight * itemCount;
429 yo = (itemHeight - WMFontHeight(scr->normalFont))/2;
431 if (!highlight) {
432 XClearArea(scr->display, bPtr->menuView->window, 0, index*itemHeight,
433 width, itemHeight, False);
434 return;
435 } else if (index < 0 && bPtr->flags.pullsDown) {
436 return;
439 XFillRectangle(scr->display, bPtr->menuView->window, WMColorGC(scr->white),
440 1, index*itemHeight+1, width-3, itemHeight-3);
442 title = WMGetPopUpButtonItem(bPtr, index);
444 W_DrawRelief(scr, bPtr->menuView->window, 0, index*itemHeight,
445 width, itemHeight, WRRaised);
447 W_PaintText(bPtr->menuView, bPtr->menuView->window, scr->normalFont, 6,
448 index*itemHeight + yo, width, WALeft, WMColorGC(scr->black),
449 False, title, strlen(title));
451 if (!bPtr->flags.pullsDown && index == bPtr->selectedItemIndex) {
452 XCopyArea(scr->display, scr->popUpIndicator->pixmap,
453 bPtr->menuView->window, scr->copyGC, 0, 0,
454 scr->popUpIndicator->width, scr->popUpIndicator->height,
455 width-scr->popUpIndicator->width-4,
456 index*itemHeight+(itemHeight-scr->popUpIndicator->height)/2);
461 Pixmap
462 makeMenuPixmap(PopUpButton *bPtr)
464 Pixmap pixmap;
465 W_Screen *scr = bPtr->view->screen;
466 WMMenuItem *item;
467 WMBagIterator iter;
468 int yo, i;
469 int width, height, itemHeight;
471 itemHeight = bPtr->view->size.height;
472 width = bPtr->view->size.width;
473 height = itemHeight * WMGetBagItemCount(bPtr->items);
474 yo = (itemHeight - WMFontHeight(scr->normalFont))/2;
476 pixmap = XCreatePixmap(scr->display, bPtr->view->window, width, height,
477 scr->depth);
479 XFillRectangle(scr->display, pixmap, WMColorGC(scr->gray), 0, 0,
480 width, height);
482 i = 0;
483 WM_ITERATE_BAG(bPtr->items, item, iter) {
484 GC gc;
485 char *text;
487 text = WMGetMenuItemTitle(item);
489 W_DrawRelief(scr, pixmap, 0, i*itemHeight, width, itemHeight,
490 WRRaised);
492 if (!WMGetMenuItemEnabled(item))
493 gc = WMColorGC(scr->darkGray);
494 else
495 gc = WMColorGC(scr->black);
497 W_PaintText(bPtr->menuView, pixmap, scr->normalFont, 6,
498 i*itemHeight + yo, width, WALeft, gc, False,
499 text, strlen(text));
501 if (!bPtr->flags.pullsDown && i == bPtr->selectedItemIndex) {
502 XCopyArea(scr->display, scr->popUpIndicator->pixmap, pixmap,
503 scr->copyGC, 0, 0, scr->popUpIndicator->width,
504 scr->popUpIndicator->height,
505 width-scr->popUpIndicator->width-4,
506 i*itemHeight+(itemHeight-scr->popUpIndicator->height)/2);
509 i++;
512 return pixmap;
516 static void
517 resizeMenu(PopUpButton *bPtr)
519 int height;
521 height = WMGetBagItemCount(bPtr->items) * bPtr->view->size.height;
522 if (height > 0)
523 W_ResizeView(bPtr->menuView, bPtr->view->size.width, height);
527 static void
528 popUpMenu(PopUpButton *bPtr)
530 W_Screen *scr = bPtr->view->screen;
531 Window dummyW;
532 int x, y;
534 if (!bPtr->flags.enabled)
535 return;
537 if (!bPtr->menuView->flags.realized) {
538 W_RealizeView(bPtr->menuView);
539 resizeMenu(bPtr);
542 if (WMGetBagItemCount(bPtr->items) < 1)
543 return;
545 XTranslateCoordinates(scr->display, bPtr->view->window, scr->rootWin,
546 0, 0, &x, &y, &dummyW);
548 if (bPtr->flags.pullsDown) {
549 y += bPtr->view->size.height;
550 } else {
551 y -= bPtr->view->size.height*bPtr->selectedItemIndex;
553 W_MoveView(bPtr->menuView, x, y);
555 XSetWindowBackgroundPixmap(scr->display, bPtr->menuView->window,
556 makeMenuPixmap(bPtr));
557 XClearWindow(scr->display, bPtr->menuView->window);
559 if (W_VIEW_WIDTH(bPtr->menuView) != W_VIEW_WIDTH(bPtr->view))
560 resizeMenu(bPtr);
562 W_MapView(bPtr->menuView);
564 bPtr->highlightedItem = 0;
565 if (!bPtr->flags.pullsDown && bPtr->selectedItemIndex < 0)
566 paintMenuEntry(bPtr, bPtr->selectedItemIndex, True);
570 static void
571 popDownMenu(PopUpButton *bPtr)
573 W_UnmapView(bPtr->menuView);
575 /* free the background pixmap used to draw the menu contents */
576 XSetWindowBackgroundPixmap(bPtr->view->screen->display,
577 bPtr->menuView->window, None);
581 static void
582 autoScroll(void *data)
584 PopUpButton *bPtr = (PopUpButton*)data;
585 int scrHeight = WMWidgetScreen(bPtr)->rootView->size.height;
586 int repeat = 0;
587 int dy = 0;
590 if (bPtr->scrollStartY >= scrHeight-1
591 && bPtr->menuView->pos.y+bPtr->menuView->size.height >= scrHeight-1) {
592 repeat = 1;
594 if (bPtr->menuView->pos.y+bPtr->menuView->size.height-5
595 <= scrHeight - 1) {
596 dy = scrHeight - 1
597 - (bPtr->menuView->pos.y+bPtr->menuView->size.height);
598 } else
599 dy = -5;
601 } else if (bPtr->scrollStartY <= 1 && bPtr->menuView->pos.y < 1) {
602 repeat = 1;
604 if (bPtr->menuView->pos.y+5 > 1)
605 dy = 1 - bPtr->menuView->pos.y;
606 else
607 dy = 5;
610 if (repeat) {
611 int oldItem;
613 W_MoveView(bPtr->menuView, bPtr->menuView->pos.x,
614 bPtr->menuView->pos.y + dy);
616 oldItem = bPtr->highlightedItem;
617 bPtr->highlightedItem = (bPtr->scrollStartY - bPtr->menuView->pos.y)
618 / bPtr->view->size.height;
620 if (oldItem!=bPtr->highlightedItem) {
621 WMMenuItem *item;
623 paintMenuEntry(bPtr, oldItem, False);
625 if (bPtr->highlightedItem >= 0 &&
626 bPtr->highlightedItem < WMGetBagItemCount(bPtr->items)) {
627 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
628 paintMenuEntry(bPtr, bPtr->highlightedItem,
629 WMGetMenuItemEnabled(item));
630 } else {
631 bPtr->highlightedItem = -1;
635 bPtr->timer = WMAddTimerHandler(SCROLL_DELAY, autoScroll, bPtr);
636 } else {
637 bPtr->timer = NULL;
642 static void
643 wheelScrollUp(PopUpButton *bPtr)
645 int testIndex = bPtr->selectedItemIndex - 1;
647 while (testIndex>=0 && !WMGetPopUpButtonItemEnabled(bPtr, testIndex))
648 testIndex--;
649 if (testIndex != -1) {
650 WMSetPopUpButtonSelectedItem(bPtr, testIndex);
651 if (bPtr->action)
652 (*bPtr->action)(bPtr, bPtr->clientData);
657 static void
658 wheelScrollDown(PopUpButton *bPtr)
660 int itemCount = WMGetBagItemCount(bPtr->items);
661 int testIndex = bPtr->selectedItemIndex + 1;
663 while (testIndex<itemCount && !WMGetPopUpButtonItemEnabled(bPtr, testIndex))
664 testIndex++;
665 if (testIndex != itemCount) {
666 WMSetPopUpButtonSelectedItem(bPtr, testIndex);
667 if (bPtr->action)
668 (*bPtr->action)(bPtr, bPtr->clientData);
673 static void
674 handleActionEvents(XEvent *event, void *data)
676 PopUpButton *bPtr = (PopUpButton*)data;
677 int oldItem;
678 int scrHeight = WMWidgetScreen(bPtr)->rootView->size.height;
680 CHECK_CLASS(data, WC_PopUpButton);
682 if (WMGetBagItemCount(bPtr->items) < 1)
683 return;
685 switch (event->type) {
686 /* called for menuView */
687 case Expose:
688 paintMenuEntry(bPtr, bPtr->highlightedItem, True);
689 break;
691 case LeaveNotify:
692 bPtr->flags.insideMenu = 0;
693 if (bPtr->menuView->flags.mapped)
694 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
695 bPtr->highlightedItem = -1;
696 break;
698 case EnterNotify:
699 bPtr->flags.insideMenu = 1;
700 break;
702 case MotionNotify:
703 if (bPtr->flags.insideMenu) {
704 oldItem = bPtr->highlightedItem;
705 bPtr->highlightedItem = event->xmotion.y / bPtr->view->size.height;
706 if (oldItem!=bPtr->highlightedItem) {
707 WMMenuItem *item;
709 paintMenuEntry(bPtr, oldItem, False);
710 if (bPtr->highlightedItem >= 0 &&
711 bPtr->highlightedItem < WMGetBagItemCount(bPtr->items)) {
712 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
713 paintMenuEntry(bPtr, bPtr->highlightedItem,
714 WMGetMenuItemEnabled(item));
715 } else {
716 bPtr->highlightedItem = -1;
721 if (event->xmotion.y_root >= scrHeight-1
722 || event->xmotion.y_root <= 1) {
723 bPtr->scrollStartY = event->xmotion.y_root;
724 if (!bPtr->timer)
725 autoScroll(bPtr);
726 } else if (bPtr->timer) {
727 WMDeleteTimerHandler(bPtr->timer);
728 bPtr->timer = NULL;
731 break;
733 /* called for bPtr->view */
734 case ButtonPress:
735 if (!bPtr->flags.enabled)
736 break;
738 if (event->xbutton.button==WINGsConfiguration.mouseWheelUp) {
739 if (!bPtr->menuView->flags.mapped && !bPtr->flags.pullsDown) {
740 wheelScrollUp(bPtr);
742 break;
743 } else if (event->xbutton.button==WINGsConfiguration.mouseWheelDown) {
744 if (!bPtr->menuView->flags.mapped && !bPtr->flags.pullsDown) {
745 wheelScrollDown(bPtr);
747 break;
749 popUpMenu(bPtr);
750 if (!bPtr->flags.pullsDown) {
751 bPtr->highlightedItem = bPtr->selectedItemIndex;
752 bPtr->flags.insideMenu = 1;
753 } else {
754 bPtr->highlightedItem = -1;
755 bPtr->flags.insideMenu = 0;
757 XGrabPointer(bPtr->view->screen->display, bPtr->menuView->window,
758 False, ButtonReleaseMask|ButtonMotionMask|EnterWindowMask
759 |LeaveWindowMask, GrabModeAsync, GrabModeAsync,
760 None, None, CurrentTime);
761 break;
763 case ButtonRelease:
764 if (event->xbutton.button==WINGsConfiguration.mouseWheelUp ||
765 event->xbutton.button==WINGsConfiguration.mouseWheelDown) {
766 break;
768 XUngrabPointer(bPtr->view->screen->display, event->xbutton.time);
769 if (!bPtr->flags.pullsDown)
770 popDownMenu(bPtr);
772 if (bPtr->timer) {
773 WMDeleteTimerHandler(bPtr->timer);
774 bPtr->timer = NULL;
777 if (bPtr->flags.insideMenu && bPtr->highlightedItem>=0) {
778 WMMenuItem *item;
780 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
782 if (WMGetMenuItemEnabled(item)) {
783 int i;
784 WMSetPopUpButtonSelectedItem(bPtr, bPtr->highlightedItem);
786 if (bPtr->flags.pullsDown) {
787 for (i=0; i<MENU_BLINK_COUNT; i++) {
788 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
789 XSync(bPtr->view->screen->display, 0);
790 wusleep(MENU_BLINK_DELAY);
791 paintMenuEntry(bPtr, bPtr->highlightedItem, True);
792 XSync(bPtr->view->screen->display, 0);
793 wusleep(MENU_BLINK_DELAY);
796 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
797 popDownMenu(bPtr);
798 if (bPtr->action)
799 (*bPtr->action)(bPtr, bPtr->clientData);
802 if (bPtr->menuView->flags.mapped)
803 popDownMenu(bPtr);
804 break;
810 static void
811 destroyPopUpButton(PopUpButton *bPtr)
813 WMMenuItem *item;
814 WMBagIterator i;
816 if (bPtr->timer) {
817 WMDeleteTimerHandler(bPtr->timer);
820 WM_ITERATE_BAG(bPtr->items, item, i) {
821 WMDestroyMenuItem(item);
823 WMFreeBag(bPtr->items);
825 if (bPtr->caption)
826 wfree(bPtr->caption);
828 /* have to destroy explicitly because the popup is a toplevel */
829 W_DestroyView(bPtr->menuView);
831 wfree(bPtr);