Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wpopupbutton.c
1
2 #include "WINGsP.h"
3
4 typedef struct W_PopUpButton {
5         W_Class widgetClass;
6         WMView *view;
7
8         void *clientData;
9         WMAction *action;
10
11         char *caption;
12
13         WMArray *items;
14
15         short selectedItemIndex;
16
17         short highlightedItem;
18
19         WMView *menuView;       /* override redirect popup menu */
20
21         WMHandlerID timer;      /* for autoscroll */
22
23          /**/ int scrollStartY; /* for autoscroll */
24
25         struct {
26                 unsigned int pullsDown:1;
27
28                 unsigned int configured:1;
29
30                 unsigned int insideMenu:1;
31
32                 unsigned int enabled:1;
33
34         } flags;
35 } PopUpButton;
36
37 #define MENU_BLINK_DELAY        60000
38 #define MENU_BLINK_COUNT        2
39
40 #define SCROLL_DELAY            10
41
42 #define DEFAULT_WIDTH   60
43 #define DEFAULT_HEIGHT  20
44 #define DEFAULT_CAPTION ""
45
46 static void destroyPopUpButton(PopUpButton * bPtr);
47 static void paintPopUpButton(PopUpButton * bPtr);
48
49 static void handleEvents(XEvent * event, void *data);
50 static void handleActionEvents(XEvent * event, void *data);
51
52 static void resizeMenu(PopUpButton * bPtr);
53
54 WMPopUpButton *WMCreatePopUpButton(WMWidget * parent)
55 {
56         PopUpButton *bPtr;
57         W_Screen *scr = W_VIEW(parent)->screen;
58
59         bPtr = wmalloc(sizeof(PopUpButton));
60         memset(bPtr, 0, sizeof(PopUpButton));
61
62         bPtr->widgetClass = WC_PopUpButton;
63
64         bPtr->view = W_CreateView(W_VIEW(parent));
65         if (!bPtr->view) {
66                 wfree(bPtr);
67                 return NULL;
68         }
69         bPtr->view->self = bPtr;
70
71         WMCreateEventHandler(bPtr->view, ExposureMask | StructureNotifyMask
72                              | ClientMessageMask, handleEvents, bPtr);
73
74         W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
75         bPtr->caption = wstrdup(DEFAULT_CAPTION);
76
77         WMCreateEventHandler(bPtr->view, ButtonPressMask | ButtonReleaseMask, handleActionEvents, bPtr);
78
79         bPtr->flags.enabled = 1;
80
81         bPtr->items = WMCreateArrayWithDestructor(4, (WMFreeDataProc *) WMDestroyMenuItem);
82
83         bPtr->selectedItemIndex = -1;
84
85         bPtr->menuView = W_CreateUnmanagedTopView(scr);
86
87         W_ResizeView(bPtr->menuView, bPtr->view->size.width, 1);
88
89         WMCreateEventHandler(bPtr->menuView, ButtonPressMask | ButtonReleaseMask
90                              | EnterWindowMask | LeaveWindowMask | ButtonMotionMask
91                              | ExposureMask, handleActionEvents, bPtr);
92
93         return bPtr;
94 }
95
96 void WMSetPopUpButtonAction(WMPopUpButton * bPtr, WMAction * action, void *clientData)
97 {
98         CHECK_CLASS(bPtr, WC_PopUpButton);
99
100         bPtr->action = action;
101
102         bPtr->clientData = clientData;
103 }
104
105 WMMenuItem *WMAddPopUpButtonItem(WMPopUpButton * bPtr, char *title)
106 {
107         WMMenuItem *item;
108
109         CHECK_CLASS(bPtr, WC_PopUpButton);
110
111         item = WMCreateMenuItem();
112         WMSetMenuItemTitle(item, title);
113
114         WMAddToArray(bPtr->items, item);
115
116         if (bPtr->menuView && bPtr->menuView->flags.realized)
117                 resizeMenu(bPtr);
118
119         return item;
120 }
121
122 WMMenuItem *WMInsertPopUpButtonItem(WMPopUpButton * bPtr, int index, char *title)
123 {
124         WMMenuItem *item;
125
126         CHECK_CLASS(bPtr, WC_PopUpButton);
127
128         item = WMCreateMenuItem();
129         WMSetMenuItemTitle(item, title);
130
131         WMInsertInArray(bPtr->items, index, item);
132
133         /* if there is an selected item, update it's index to match the new
134          * position */
135         if (index < bPtr->selectedItemIndex)
136                 bPtr->selectedItemIndex++;
137
138         if (bPtr->menuView && bPtr->menuView->flags.realized)
139                 resizeMenu(bPtr);
140
141         return item;
142 }
143
144 void WMRemovePopUpButtonItem(WMPopUpButton * bPtr, int index)
145 {
146         CHECK_CLASS(bPtr, WC_PopUpButton);
147
148         wassertr(index >= 0 && index < WMGetArrayItemCount(bPtr->items));
149
150         WMDeleteFromArray(bPtr->items, index);
151
152         if (bPtr->selectedItemIndex >= 0 && !bPtr->flags.pullsDown) {
153                 if (index < bPtr->selectedItemIndex)
154                         bPtr->selectedItemIndex--;
155                 else if (index == bPtr->selectedItemIndex) {
156                         /* reselect first item if the removed item is the
157                          * selected one */
158                         bPtr->selectedItemIndex = 0;
159                         if (bPtr->view->flags.mapped)
160                                 paintPopUpButton(bPtr);
161                 }
162         }
163
164         if (bPtr->menuView && bPtr->menuView->flags.realized)
165                 resizeMenu(bPtr);
166 }
167
168 void WMSetPopUpButtonEnabled(WMPopUpButton * bPtr, Bool flag)
169 {
170         bPtr->flags.enabled = ((flag == 0) ? 0 : 1);
171         if (bPtr->view->flags.mapped)
172                 paintPopUpButton(bPtr);
173 }
174
175 Bool WMGetPopUpButtonEnabled(WMPopUpButton * bPtr)
176 {
177         return bPtr->flags.enabled;
178 }
179
180 void WMSetPopUpButtonSelectedItem(WMPopUpButton * bPtr, int index)
181 {
182
183         wassertr(index < WMGetArrayItemCount(bPtr->items));
184
185         /* if (index >= WMGetArrayCount(bPtr->items))
186            index = -1; */
187
188         bPtr->selectedItemIndex = index;
189
190         if (bPtr->view->flags.mapped)
191                 paintPopUpButton(bPtr);
192 }
193
194 int WMGetPopUpButtonSelectedItem(WMPopUpButton * bPtr)
195 {
196         if (!bPtr->flags.pullsDown && bPtr->selectedItemIndex < 0)
197                 return -1;
198         else
199                 return bPtr->selectedItemIndex;
200 }
201
202 void WMSetPopUpButtonText(WMPopUpButton * bPtr, char *text)
203 {
204         if (bPtr->caption)
205                 wfree(bPtr->caption);
206         if (text)
207                 bPtr->caption = wstrdup(text);
208         else
209                 bPtr->caption = NULL;
210         if (bPtr->view->flags.realized) {
211                 if (bPtr->flags.pullsDown || bPtr->selectedItemIndex < 0) {
212                         paintPopUpButton(bPtr);
213                 }
214         }
215 }
216
217 void WMSetPopUpButtonItemEnabled(WMPopUpButton * bPtr, int index, Bool flag)
218 {
219         WMSetMenuItemEnabled(WMGetFromArray(bPtr->items, index), (flag ? 1 : 0));
220 }
221
222 Bool WMGetPopUpButtonItemEnabled(WMPopUpButton * bPtr, int index)
223 {
224         return WMGetMenuItemEnabled(WMGetFromArray(bPtr->items, index));
225 }
226
227 void WMSetPopUpButtonPullsDown(WMPopUpButton * bPtr, Bool flag)
228 {
229         bPtr->flags.pullsDown = ((flag == 0) ? 0 : 1);
230         if (flag) {
231                 bPtr->selectedItemIndex = -1;
232         }
233
234         if (bPtr->view->flags.mapped)
235                 paintPopUpButton(bPtr);
236 }
237
238 int WMGetPopUpButtonNumberOfItems(WMPopUpButton * bPtr)
239 {
240         return WMGetArrayItemCount(bPtr->items);
241 }
242
243 char *WMGetPopUpButtonItem(WMPopUpButton * bPtr, int index)
244 {
245         if (index >= WMGetArrayItemCount(bPtr->items) || index < 0)
246                 return NULL;
247
248         return WMGetMenuItemTitle(WMGetFromArray(bPtr->items, index));
249 }
250
251 WMMenuItem *WMGetPopUpButtonMenuItem(WMPopUpButton * bPtr, int index)
252 {
253         return WMGetFromArray(bPtr->items, index);
254 }
255
256 static void paintPopUpButton(PopUpButton * bPtr)
257 {
258         W_Screen *scr = bPtr->view->screen;
259         char *caption;
260         Pixmap pixmap;
261
262         if (bPtr->flags.pullsDown) {
263                 caption = bPtr->caption;
264         } else {
265                 if (bPtr->selectedItemIndex < 0) {
266                         /* if no item selected, show the caption */
267                         caption = bPtr->caption;
268                 } else {
269                         caption = WMGetPopUpButtonItem(bPtr, bPtr->selectedItemIndex);
270                 }
271         }
272
273         pixmap = XCreatePixmap(scr->display, bPtr->view->window,
274                                bPtr->view->size.width, bPtr->view->size.height, scr->depth);
275         XFillRectangle(scr->display, pixmap, WMColorGC(scr->gray), 0, 0,
276                        bPtr->view->size.width, bPtr->view->size.height);
277
278         W_DrawRelief(scr, pixmap, 0, 0, bPtr->view->size.width, bPtr->view->size.height, WRRaised);
279
280         if (caption) {
281                 W_PaintText(bPtr->view, pixmap, scr->normalFont, 6,
282                             (bPtr->view->size.height - WMFontHeight(scr->normalFont)) / 2,
283                             bPtr->view->size.width, WALeft,
284                             bPtr->flags.enabled ? scr->black : scr->darkGray, False, caption, strlen(caption));
285         }
286
287         if (bPtr->flags.pullsDown) {
288                 XCopyArea(scr->display, scr->pullDownIndicator->pixmap,
289                           pixmap, scr->copyGC, 0, 0, scr->pullDownIndicator->width,
290                           scr->pullDownIndicator->height,
291                           bPtr->view->size.width - scr->pullDownIndicator->width - 4,
292                           (bPtr->view->size.height - scr->pullDownIndicator->height) / 2);
293         } else {
294                 int x, y;
295
296                 x = bPtr->view->size.width - scr->popUpIndicator->width - 4;
297                 y = (bPtr->view->size.height - scr->popUpIndicator->height) / 2;
298
299                 XSetClipOrigin(scr->display, scr->clipGC, x, y);
300                 XSetClipMask(scr->display, scr->clipGC, scr->popUpIndicator->mask);
301                 XCopyArea(scr->display, scr->popUpIndicator->pixmap, pixmap,
302                           scr->clipGC, 0, 0, scr->popUpIndicator->width, scr->popUpIndicator->height, x, y);
303         }
304
305         XCopyArea(scr->display, pixmap, bPtr->view->window, scr->copyGC, 0, 0,
306                   bPtr->view->size.width, bPtr->view->size.height, 0, 0);
307
308         XFreePixmap(scr->display, pixmap);
309 }
310
311 static void handleEvents(XEvent * event, void *data)
312 {
313         PopUpButton *bPtr = (PopUpButton *) data;
314
315         CHECK_CLASS(data, WC_PopUpButton);
316
317         switch (event->type) {
318         case Expose:
319                 if (event->xexpose.count != 0)
320                         break;
321                 paintPopUpButton(bPtr);
322                 break;
323
324         case DestroyNotify:
325                 destroyPopUpButton(bPtr);
326                 break;
327         }
328 }
329
330 static void paintMenuEntry(PopUpButton * bPtr, int index, int highlight)
331 {
332         W_Screen *scr = bPtr->view->screen;
333         int yo;
334         int width, height, itemHeight, itemCount;
335         char *title;
336
337         itemCount = WMGetArrayItemCount(bPtr->items);
338         if (index < 0 || index >= itemCount)
339                 return;
340
341         itemHeight = bPtr->view->size.height;
342         width = bPtr->view->size.width;
343         height = itemHeight * itemCount;
344         yo = (itemHeight - WMFontHeight(scr->normalFont)) / 2;
345
346         if (!highlight) {
347                 XClearArea(scr->display, bPtr->menuView->window, 0, index * itemHeight, width, itemHeight, False);
348                 return;
349         } else if (index < 0 && bPtr->flags.pullsDown) {
350                 return;
351         }
352
353         XFillRectangle(scr->display, bPtr->menuView->window, WMColorGC(scr->white),
354                        1, index * itemHeight + 1, width - 3, itemHeight - 3);
355
356         title = WMGetPopUpButtonItem(bPtr, index);
357
358         W_DrawRelief(scr, bPtr->menuView->window, 0, index * itemHeight, width, itemHeight, WRRaised);
359
360         W_PaintText(bPtr->menuView, bPtr->menuView->window, scr->normalFont, 6,
361                     index * itemHeight + yo, width, WALeft, scr->black, False, title, strlen(title));
362
363         if (!bPtr->flags.pullsDown && index == bPtr->selectedItemIndex) {
364                 XCopyArea(scr->display, scr->popUpIndicator->pixmap,
365                           bPtr->menuView->window, scr->copyGC, 0, 0,
366                           scr->popUpIndicator->width, scr->popUpIndicator->height,
367                           width - scr->popUpIndicator->width - 4,
368                           index * itemHeight + (itemHeight - scr->popUpIndicator->height) / 2);
369         }
370 }
371
372 Pixmap makeMenuPixmap(PopUpButton * bPtr)
373 {
374         Pixmap pixmap;
375         W_Screen *scr = bPtr->view->screen;
376         WMMenuItem *item;
377         WMArrayIterator iter;
378         int yo, i;
379         int width, height, itemHeight;
380
381         itemHeight = bPtr->view->size.height;
382         width = bPtr->view->size.width;
383         height = itemHeight * WMGetArrayItemCount(bPtr->items);
384         yo = (itemHeight - WMFontHeight(scr->normalFont)) / 2;
385
386         pixmap = XCreatePixmap(scr->display, bPtr->view->window, width, height, scr->depth);
387
388         XFillRectangle(scr->display, pixmap, WMColorGC(scr->gray), 0, 0, width, height);
389
390         i = 0;
391         WM_ITERATE_ARRAY(bPtr->items, item, iter) {
392                 WMColor *color;
393                 char *text;
394
395                 text = WMGetMenuItemTitle(item);
396
397                 W_DrawRelief(scr, pixmap, 0, i * itemHeight, width, itemHeight, WRRaised);
398
399                 if (!WMGetMenuItemEnabled(item))
400                         color = scr->darkGray;
401                 else
402                         color = scr->black;
403
404                 W_PaintText(bPtr->menuView, pixmap, scr->normalFont, 6,
405                             i * itemHeight + yo, width, WALeft, color, False, text, strlen(text));
406
407                 if (!bPtr->flags.pullsDown && i == bPtr->selectedItemIndex) {
408                         XCopyArea(scr->display, scr->popUpIndicator->pixmap, pixmap,
409                                   scr->copyGC, 0, 0, scr->popUpIndicator->width,
410                                   scr->popUpIndicator->height,
411                                   width - scr->popUpIndicator->width - 4,
412                                   i * itemHeight + (itemHeight - scr->popUpIndicator->height) / 2);
413                 }
414
415                 i++;
416         }
417
418         return pixmap;
419 }
420
421 static void resizeMenu(PopUpButton * bPtr)
422 {
423         int height;
424
425         height = WMGetArrayItemCount(bPtr->items) * bPtr->view->size.height;
426         if (height > 0)
427                 W_ResizeView(bPtr->menuView, bPtr->view->size.width, height);
428 }
429
430 static void popUpMenu(PopUpButton * bPtr)
431 {
432         W_Screen *scr = bPtr->view->screen;
433         Window dummyW;
434         int x, y;
435
436         if (!bPtr->flags.enabled)
437                 return;
438
439         if (!bPtr->menuView->flags.realized) {
440                 W_RealizeView(bPtr->menuView);
441                 resizeMenu(bPtr);
442         }
443
444         if (WMGetArrayItemCount(bPtr->items) < 1)
445                 return;
446
447         XTranslateCoordinates(scr->display, bPtr->view->window, scr->rootWin, 0, 0, &x, &y, &dummyW);
448
449         if (bPtr->flags.pullsDown) {
450                 y += bPtr->view->size.height;
451         } else {
452                 y -= bPtr->view->size.height * bPtr->selectedItemIndex;
453         }
454         W_MoveView(bPtr->menuView, x, y);
455
456         XSetWindowBackgroundPixmap(scr->display, bPtr->menuView->window, makeMenuPixmap(bPtr));
457         XClearWindow(scr->display, bPtr->menuView->window);
458
459         if (W_VIEW_WIDTH(bPtr->menuView) != W_VIEW_WIDTH(bPtr->view))
460                 resizeMenu(bPtr);
461
462         W_MapView(bPtr->menuView);
463
464         bPtr->highlightedItem = 0;
465         if (!bPtr->flags.pullsDown && bPtr->selectedItemIndex < 0)
466                 paintMenuEntry(bPtr, bPtr->selectedItemIndex, True);
467 }
468
469 static void popDownMenu(PopUpButton * bPtr)
470 {
471         W_UnmapView(bPtr->menuView);
472 }
473
474 static void autoScroll(void *data)
475 {
476         PopUpButton *bPtr = (PopUpButton *) data;
477         int scrHeight = WMWidgetScreen(bPtr)->rootView->size.height;
478         int repeat = 0;
479         int dy = 0;
480
481         if (bPtr->scrollStartY >= scrHeight - 1
482             && bPtr->menuView->pos.y + bPtr->menuView->size.height >= scrHeight - 1) {
483                 repeat = 1;
484
485                 if (bPtr->menuView->pos.y + bPtr->menuView->size.height - 5 <= scrHeight - 1) {
486                         dy = scrHeight - 1 - (bPtr->menuView->pos.y + bPtr->menuView->size.height);
487                 } else
488                         dy = -5;
489
490         } else if (bPtr->scrollStartY <= 1 && bPtr->menuView->pos.y < 1) {
491                 repeat = 1;
492
493                 if (bPtr->menuView->pos.y + 5 > 1)
494                         dy = 1 - bPtr->menuView->pos.y;
495                 else
496                         dy = 5;
497         }
498
499         if (repeat) {
500                 int oldItem;
501
502                 W_MoveView(bPtr->menuView, bPtr->menuView->pos.x, bPtr->menuView->pos.y + dy);
503
504                 oldItem = bPtr->highlightedItem;
505                 bPtr->highlightedItem = (bPtr->scrollStartY - bPtr->menuView->pos.y)
506                     / bPtr->view->size.height;
507
508                 if (oldItem != bPtr->highlightedItem) {
509                         WMMenuItem *item;
510
511                         paintMenuEntry(bPtr, oldItem, False);
512
513                         if (bPtr->highlightedItem >= 0 && bPtr->highlightedItem < WMGetArrayItemCount(bPtr->items)) {
514                                 item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
515                                 paintMenuEntry(bPtr, bPtr->highlightedItem, WMGetMenuItemEnabled(item));
516                         } else {
517                                 bPtr->highlightedItem = -1;
518                         }
519                 }
520
521                 bPtr->timer = WMAddTimerHandler(SCROLL_DELAY, autoScroll, bPtr);
522         } else {
523                 bPtr->timer = NULL;
524         }
525 }
526
527 static void wheelScrollUp(PopUpButton * bPtr)
528 {
529         int testIndex = bPtr->selectedItemIndex - 1;
530
531         while (testIndex >= 0 && !WMGetPopUpButtonItemEnabled(bPtr, testIndex))
532                 testIndex--;
533         if (testIndex != -1) {
534                 WMSetPopUpButtonSelectedItem(bPtr, testIndex);
535                 if (bPtr->action)
536                         (*bPtr->action) (bPtr, bPtr->clientData);
537         }
538 }
539
540 static void wheelScrollDown(PopUpButton * bPtr)
541 {
542         int itemCount = WMGetArrayItemCount(bPtr->items);
543         int testIndex = bPtr->selectedItemIndex + 1;
544
545         while (testIndex < itemCount && !WMGetPopUpButtonItemEnabled(bPtr, testIndex))
546                 testIndex++;
547         if (testIndex != itemCount) {
548                 WMSetPopUpButtonSelectedItem(bPtr, testIndex);
549                 if (bPtr->action)
550                         (*bPtr->action) (bPtr, bPtr->clientData);
551         }
552 }
553
554 static void handleActionEvents(XEvent * event, void *data)
555 {
556         PopUpButton *bPtr = (PopUpButton *) data;
557         int oldItem;
558         int scrHeight = WMWidgetScreen(bPtr)->rootView->size.height;
559
560         CHECK_CLASS(data, WC_PopUpButton);
561
562         if (WMGetArrayItemCount(bPtr->items) < 1)
563                 return;
564
565         switch (event->type) {
566                 /* called for menuView */
567         case Expose:
568                 paintMenuEntry(bPtr, bPtr->highlightedItem, True);
569                 break;
570
571         case LeaveNotify:
572                 bPtr->flags.insideMenu = 0;
573                 if (bPtr->menuView->flags.mapped)
574                         paintMenuEntry(bPtr, bPtr->highlightedItem, False);
575                 bPtr->highlightedItem = -1;
576                 break;
577
578         case EnterNotify:
579                 bPtr->flags.insideMenu = 1;
580                 break;
581
582         case MotionNotify:
583                 if (bPtr->flags.insideMenu) {
584                         oldItem = bPtr->highlightedItem;
585                         bPtr->highlightedItem = event->xmotion.y / bPtr->view->size.height;
586                         if (oldItem != bPtr->highlightedItem) {
587                                 WMMenuItem *item;
588
589                                 paintMenuEntry(bPtr, oldItem, False);
590                                 if (bPtr->highlightedItem >= 0 &&
591                                     bPtr->highlightedItem < WMGetArrayItemCount(bPtr->items)) {
592                                         item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
593                                         paintMenuEntry(bPtr, bPtr->highlightedItem, WMGetMenuItemEnabled(item));
594                                 } else {
595                                         bPtr->highlightedItem = -1;
596                                 }
597
598                         }
599
600                         if (event->xmotion.y_root >= scrHeight - 1 || event->xmotion.y_root <= 1) {
601                                 bPtr->scrollStartY = event->xmotion.y_root;
602                                 if (!bPtr->timer)
603                                         autoScroll(bPtr);
604                         } else if (bPtr->timer) {
605                                 WMDeleteTimerHandler(bPtr->timer);
606                                 bPtr->timer = NULL;
607                         }
608                 }
609                 break;
610
611                 /* called for bPtr->view */
612         case ButtonPress:
613                 if (!bPtr->flags.enabled)
614                         break;
615
616                 if (event->xbutton.button == WINGsConfiguration.mouseWheelUp) {
617                         if (!bPtr->menuView->flags.mapped && !bPtr->flags.pullsDown) {
618                                 wheelScrollUp(bPtr);
619                         }
620                         break;
621                 } else if (event->xbutton.button == WINGsConfiguration.mouseWheelDown) {
622                         if (!bPtr->menuView->flags.mapped && !bPtr->flags.pullsDown) {
623                                 wheelScrollDown(bPtr);
624                         }
625                         break;
626                 }
627                 popUpMenu(bPtr);
628                 if (!bPtr->flags.pullsDown) {
629                         bPtr->highlightedItem = bPtr->selectedItemIndex;
630                         bPtr->flags.insideMenu = 1;
631                 } else {
632                         bPtr->highlightedItem = -1;
633                         bPtr->flags.insideMenu = 0;
634                 }
635                 XGrabPointer(bPtr->view->screen->display, bPtr->menuView->window,
636                              False, ButtonReleaseMask | ButtonMotionMask | EnterWindowMask
637                              | LeaveWindowMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
638                 break;
639
640         case ButtonRelease:
641                 if (event->xbutton.button == WINGsConfiguration.mouseWheelUp ||
642                     event->xbutton.button == WINGsConfiguration.mouseWheelDown) {
643                         break;
644                 }
645                 XUngrabPointer(bPtr->view->screen->display, event->xbutton.time);
646                 if (!bPtr->flags.pullsDown)
647                         popDownMenu(bPtr);
648
649                 if (bPtr->timer) {
650                         WMDeleteTimerHandler(bPtr->timer);
651                         bPtr->timer = NULL;
652                 }
653
654                 if (bPtr->flags.insideMenu && bPtr->highlightedItem >= 0) {
655                         WMMenuItem *item;
656
657                         item = WMGetPopUpButtonMenuItem(bPtr, bPtr->highlightedItem);
658
659                         if (WMGetMenuItemEnabled(item)) {
660                                 int i;
661                                 WMSetPopUpButtonSelectedItem(bPtr, bPtr->highlightedItem);
662
663                                 if (bPtr->flags.pullsDown) {
664                                         for (i = 0; i < MENU_BLINK_COUNT; i++) {
665                                                 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
666                                                 XSync(bPtr->view->screen->display, 0);
667                                                 wusleep(MENU_BLINK_DELAY);
668                                                 paintMenuEntry(bPtr, bPtr->highlightedItem, True);
669                                                 XSync(bPtr->view->screen->display, 0);
670                                                 wusleep(MENU_BLINK_DELAY);
671                                         }
672                                 }
673                                 paintMenuEntry(bPtr, bPtr->highlightedItem, False);
674                                 popDownMenu(bPtr);
675                                 if (bPtr->action)
676                                         (*bPtr->action) (bPtr, bPtr->clientData);
677                         }
678                 }
679                 if (bPtr->menuView->flags.mapped)
680                         popDownMenu(bPtr);
681                 break;
682         }
683 }
684
685 static void destroyPopUpButton(PopUpButton * bPtr)
686 {
687         if (bPtr->timer) {
688                 WMDeleteTimerHandler(bPtr->timer);
689         }
690
691         WMFreeArray(bPtr->items);
692
693         if (bPtr->caption)
694                 wfree(bPtr->caption);
695
696         /* have to destroy explicitly because the popup is a toplevel */
697         W_DestroyView(bPtr->menuView);
698
699         wfree(bPtr);
700 }