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