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 }