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