1 #include "rxvtlib.h"
2
3 /*--------------------------------*-C-*---------------------------------*
4 * File: menubar.c
5 *----------------------------------------------------------------------*
6 * $Id: menubar.c,v 1.27 1999/01/23 14:26:36 mason Exp $
7 *
8 * Copyright (C) 1997,1998 mj olesen <olesen@me.QueensU.CA>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *----------------------------------------------------------------------*
24 * refer.html (or refer.txt) contains up-to-date documentation. The
25 * summary that appears at the end of this file was taken from there.
26 *----------------------------------------------------------------------*/
27
28 #ifdef MENUBAR
29
30 /* okay to alter menu? */
31
32 /* (l)eft, (u)p, (d)own, (r)ight *//* str[0] = strlen (str+1) */
33
34 /* currently active menu */
35 #endif
36
37 /*}}} */
38
39 #ifdef MENUBAR
40 /*
41 * find an item called NAME in MENU
42 */
43 /* INTPROTO */
menuitem_find(const menu_t * menu,const char * name)44 menuitem_t *menuitem_find (const menu_t * menu, const char *name)
45 {
46 menuitem_t *item;
47
48 assert (name != NULL);
49 assert (menu != NULL);
50
51 /* find the last item in the menu, this is good for separators */
52 for (item = menu->tail; item != NULL; item = item->prev) {
53 if (item->entry.type == MenuSubMenu) {
54 if (!strcmp (name, (item->entry.submenu.menu)->name))
55 break;
56 } else if ((isSeparator (name) && isSeparator (item->name))
57 || !strcmp (name, item->name))
58 break;
59 }
60 return item;
61 }
62 #endif
63
64 #ifdef MENUBAR
65 /*
66 * unlink ITEM from its MENU and free its memory
67 */
68 /* INTPROTO */
rxvtlib_menuitem_free(rxvtlib * o,menu_t * menu,menuitem_t * item)69 void rxvtlib_menuitem_free (rxvtlib *o, menu_t * menu, menuitem_t * item)
70 {
71 /* disconnect */
72 menuitem_t *prev, *next;
73
74 assert (menu != NULL);
75
76 prev = item->prev;
77 next = item->next;
78 if (prev != NULL)
79 prev->next = next;
80 if (next != NULL)
81 next->prev = prev;
82
83 /* new head, tail */
84 if (menu->tail == item)
85 menu->tail = prev;
86 if (menu->head == item)
87 menu->head = next;
88
89 switch (item->entry.type) {
90 case MenuAction:
91 case MenuTerminalAction:
92 FREE (item->entry.action.str);
93 break;
94 case MenuSubMenu:
95 (void)rxvtlib_menu_delete (o, item->entry.submenu.menu);
96 break;
97 }
98 if (item->name != NULL)
99 FREE (item->name);
100 if (item->name2 != NULL)
101 FREE (item->name2);
102 FREE (item);
103 }
104 #endif
105
106 #ifdef MENUBAR
107 /*
108 * sort command vs. terminal actions and
109 * remove the first character of STR if it's '\0'
110 */
111 /* INTPROTO */
action_type(action_t * action,unsigned char * str)112 int action_type (action_t * action, unsigned char *str)
113 {
114 unsigned int len;
115
116 #if defined (DEBUG_MENU) || defined (DEBUG_MENUARROWS)
117 len = strlen (str);
118 fprintf (stderr, "(len %d) = %s\n", len, str);
119 #else
120 len = Str_escaped ((char *)str);
121 #endif
122
123 if (!len)
124 return -1;
125
126 /* sort command vs. terminal actions */
127 action->type = MenuAction;
128 if (str[0] == '\0') {
129 /* the functional equivalent: memmove (str, str+1, len); */
130 unsigned char *dst = (str);
131 unsigned char *src = (str + 1);
132 unsigned char *end = (str + len);
133
134 while (src <= end)
135 *dst++ = *src++;
136
137 len--; /* decrement length */
138 if (str[0] != '\0')
139 action->type = MenuTerminalAction;
140 }
141 action->str = str;
142 action->len = len;
143
144 return 0;
145 }
146 #endif
147
148 #ifdef MENUBAR
149 /* INTPROTO */
rxvtlib_action_dispatch(rxvtlib * o,action_t * action)150 int rxvtlib_action_dispatch (rxvtlib *o, action_t * action)
151 {
152 switch (action->type) {
153 case MenuTerminalAction:
154 rxvtlib_cmd_write (o, action->str, action->len);
155 break;
156
157 case MenuAction:
158 rxvtlib_tt_write (o, action->str, action->len);
159 break;
160
161 default:
162 return -1;
163 break;
164 }
165 return 0;
166 }
167 #endif
168
169 #ifdef MENUBAR
170 /* return the arrow index corresponding to NAME */
171 /* INTPROTO */
rxvtlib_menuarrow_find(rxvtlib * o,char name)172 int rxvtlib_menuarrow_find (rxvtlib *o, char name)
173 {
174 int i;
175
176 for (i = 0; i < NARROWS; i++)
177 if (name == o->Arrows[i].name)
178 return i;
179 return -1;
180 }
181 #endif
182
183 #ifdef MENUBAR
184 /* free the memory associated with arrow NAME of the current menubar */
185 /* INTPROTO */
rxvtlib_menuarrow_free(rxvtlib * o,char name)186 void rxvtlib_menuarrow_free (rxvtlib *o, char name)
187 {
188 int i;
189
190 if (name) {
191 i = rxvtlib_menuarrow_find (o, name);
192 if (i >= 0) {
193 action_t *act = &(o->CurrentBar->arrows[i]);
194
195 switch (act->type) {
196 case MenuAction:
197 case MenuTerminalAction:
198 FREE (act->str);
199 act->str = NULL;
200 act->len = 0;
201 break;
202 }
203 act->type = MenuLabel;
204 }
205 } else {
206 for (i = 0; i < NARROWS; i++)
207 rxvtlib_menuarrow_free (o, o->Arrows[i].name);
208 }
209 }
210 #endif
211
212 #ifdef MENUBAR
213 /* INTPROTO */
rxvtlib_menuarrow_add(rxvtlib * o,char * string)214 void rxvtlib_menuarrow_add (rxvtlib *o, char *string)
215 {
216 int i;
217 unsigned xtra_len;
218 char *p;
219
220 struct {
221 char *str;
222 int len;
223 } beg = {
224 NULL, 0}
225 , end = {
226 NULL, 0}
227 , *cur, parse[NARROWS];
228
229 MEMSET (parse, 0, sizeof (parse));
230
231 /* fprintf(stderr, "add arrows = `%s'\n", string); */
232 for (p = string; p != NULL && *p; string = p) {
233 p = (string + 3);
234 /* fprintf(stderr, "parsing at %s\n", string); */
235 switch (string[1]) {
236 case 'b':
237 cur = &beg;
238 break;
239 case 'e':
240 cur = &end;
241 break;
242
243 default:
244 i = rxvtlib_menuarrow_find (o, string[1]);
245 if (i >= 0)
246 cur = &(parse[i]);
247 else
248 continue; /* not found */
249 break;
250 }
251
252 string = p;
253 cur->str = string;
254 cur->len = 0;
255
256 if (cur == &end) {
257 p = strchr (string, '\0');
258 } else {
259 char *next = string;
260
261 while (1) {
262 p = strchr (next, '<');
263 if (p != NULL) {
264 if (p[1] && p[2] == '>')
265 break;
266 /* parsed */
267 } else {
268 if (beg.str == NULL) /* no end needed */
269 p = strchr (next, '\0');
270 break;
271 }
272 next = (p + 1);
273 }
274 }
275
276 if (p == NULL)
277 return;
278 cur->len = (p - string);
279 }
280
281 #ifdef DEBUG_MENUARROWS
282 cur = &beg;
283 fprintf (stderr, "<b>(len %d) = %.*s\n",
284 cur->len, cur->len, (cur->str ? cur->str : ""));
285 for (i = 0; i < NARROWS; i++) {
286 cur = &(parse[i]);
287 fprintf (stderr, "<%c>(len %d) = %.*s\n",
288 o->Arrows[i].name,
289 cur->len, cur->len, (cur->str ? cur->str : ""));
290 }
291 cur = &end;
292 fprintf (stderr, "<e>(len %d) = %.*s\n",
293 cur->len, cur->len, (cur->str ? cur->str : ""));
294 #endif
295
296 xtra_len = (beg.len + end.len);
297 for (i = 0; i < NARROWS; i++) {
298 if (xtra_len || parse[i].len)
299 rxvtlib_menuarrow_free (o, o->Arrows[i].name);
300 }
301
302 for (i = 0; i < NARROWS; i++) {
303 unsigned char *str;
304 unsigned int len;
305
306 if (!parse[i].len)
307 continue;
308
309 str = MALLOC (parse[i].len + xtra_len + 1);
310 if (str == NULL)
311 continue;
312
313 len = 0;
314 if (beg.len) {
315 STRNCPY (str + len, beg.str, beg.len);
316 len += beg.len;
317 }
318 STRNCPY (str + len, parse[i].str, parse[i].len);
319 len += parse[i].len;
320
321 if (end.len) {
322 STRNCPY (str + len, end.str, end.len);
323 len += end.len;
324 }
325 str[len] = '\0';
326
327 #ifdef DEBUG_MENUARROWS
328 fprintf (stderr, "<%c>(len %d) = %s\n", o->Arrows[i].name, len, str);
329 #endif
330 if (action_type (&(o->CurrentBar->arrows[i]), str) < 0)
331 FREE (str);
332 }
333 }
334 #endif
335
336 #ifdef MENUBAR
337 /* INTPROTO */
rxvtlib_menuitem_add(rxvtlib * o,menu_t * menu,const char * name,const char * name2,const char * action)338 menuitem_t *rxvtlib_menuitem_add (rxvtlib *o, menu_t * menu, const char *name,
339 const char *name2, const char *action)
340 {
341 menuitem_t *item;
342 unsigned int len;
343
344 assert (name != NULL);
345 assert (action != NULL);
346
347 if (menu == NULL)
348 return NULL;
349
350 if (isSeparator (name)) {
351 /* add separator, no action */
352 name = "";
353 action = "";
354 } else {
355 /*
356 * add/replace existing menu item
357 */
358 item = menuitem_find (menu, name);
359 if (item != NULL) {
360 if (item->name2 != NULL && name2 != NULL) {
361 FREE (item->name2);
362 item->len2 = 0;
363 item->name2 = NULL;
364 }
365 switch (item->entry.type) {
366 case MenuAction:
367 case MenuTerminalAction:
368 FREE (item->entry.action.str);
369 item->entry.action.str = NULL;
370 break;
371 }
372 goto Item_Found;
373 }
374 }
375 /* allocate a new itemect */
376 if ((item = (menuitem_t *) MALLOC (sizeof (menuitem_t))) == NULL)
377 return NULL;
378
379 item->len2 = 0;
380 item->name2 = NULL;
381
382 len = strlen (name);
383 item->name = MALLOC (len + 1);
384 if (item->name != NULL) {
385 STRCPY (item->name, name);
386 if (name[0] == '.' && name[1] != '.')
387 len = 0; /* hidden menu name */
388 } else {
389 FREE (item);
390 return NULL;
391 }
392 item->len = len;
393
394 /* add to tail of list */
395 item->prev = menu->tail;
396 item->next = NULL;
397
398 if (menu->tail != NULL)
399 (menu->tail)->next = item;
400 menu->tail = item;
401 /* fix head */
402 if (menu->head == NULL)
403 menu->head = item;
404
405 /*
406 * add action
407 */
408 Item_Found:
409 if (name2 != NULL && item->name2 == NULL) {
410 len = strlen (name2);
411 if (len == 0 || (item->name2 = MALLOC (len + 1)) == NULL) {
412 len = 0;
413 item->name2 = NULL;
414 } else {
415 STRCPY (item->name2, name2);
416 }
417 item->len2 = len;
418 }
419 item->entry.type = MenuLabel;
420 len = strlen (action);
421
422 if (len == 0 && item->name2 != NULL) {
423 action = item->name2;
424 len = item->len2;
425 }
426 if (len) {
427 unsigned char *str = MALLOC (len + 1);
428
429 if (str == NULL) {
430 rxvtlib_menuitem_free (o, menu, item);
431 return NULL;
432 }
433 STRCPY (str, action);
434
435 if (action_type (&(item->entry.action), str) < 0)
436 FREE (str);
437 }
438 /* new item and a possible increase in width */
439 if (menu->width < (item->len + item->len2))
440 menu->width = (item->len + item->len2);
441
442 return item;
443 }
444 #endif
445
446 #ifdef MENUBAR
447 /*
448 * search for the base starting menu for NAME.
449 * return a pointer to the portion of NAME that remains
450 */
451 /* INTPROTO */
rxvtlib_menu_find_base(rxvtlib * o,menu_t ** menu,char * path)452 char *rxvtlib_menu_find_base (rxvtlib *o, menu_t ** menu, char *path)
453 {
454 menu_t *m = NULL;
455 menuitem_t *item;
456
457 assert (menu != NULL);
458 assert (o->CurrentBar != NULL);
459
460 if (path[0] == '\0')
461 return path;
462
463 if (strchr (path, '/') != NULL) {
464 register char *p = path;
465
466 while ((p = strchr (p, '/')) != NULL) {
467 p++;
468 if (*p == '/')
469 path = p;
470 }
471 if (path[0] == '/') {
472 path++;
473 *menu = NULL;
474 }
475 while ((p = strchr (path, '/')) != NULL) {
476 p[0] = '\0';
477 if (path[0] == '\0')
478 return NULL;
479 if (!strcmp (path, DOT)) {
480 /* nothing to do */
481 } else if (!strcmp (path, DOTS)) {
482 if (*menu != NULL)
483 *menu = (*menu)->parent;
484 } else {
485 path = rxvtlib_menu_find_base (o, menu, path);
486 if (path[0] != '\0') { /* not found */
487 p[0] = '/'; /* fix-up name again */
488 return path;
489 }
490 }
491
492 path = (p + 1);
493 }
494 }
495 if (!strcmp (path, DOTS)) {
496 path += strlen (DOTS);
497 if (*menu != NULL)
498 *menu = (*menu)->parent;
499 return path;
500 }
501 /* find this menu */
502 if (*menu == NULL) {
503 for (m = o->CurrentBar->tail; m != NULL; m = m->prev) {
504 if (!strcmp (path, m->name))
505 break;
506 }
507 } else {
508 /* find this menu */
509 for (item = (*menu)->tail; item != NULL; item = item->prev) {
510 if (item->entry.type == MenuSubMenu
511 && !strcmp (path, (item->entry.submenu.menu)->name)) {
512 m = (item->entry.submenu.menu);
513 break;
514 }
515 }
516 }
517 if (m != NULL) {
518 *menu = m;
519 path += strlen (path);
520 }
521 return path;
522 }
523 #endif
524
525 #ifdef MENUBAR
526 /*
527 * delete this entire menu
528 */
529 /* INTPROTO */
rxvtlib_menu_delete(rxvtlib * o,menu_t * menu)530 menu_t *rxvtlib_menu_delete (rxvtlib *o, menu_t * menu)
531 {
532 menu_t *parent = NULL, *prev, *next;
533 menuitem_t *item;
534
535 assert (o->CurrentBar != NULL);
536
537 /* delete the entire menu */
538 if (menu == NULL)
539 return NULL;
540
541 parent = menu->parent;
542
543 /* unlink MENU */
544 prev = menu->prev;
545 next = menu->next;
546 if (prev != NULL)
547 prev->next = next;
548 if (next != NULL)
549 next->prev = prev;
550
551 /* fix the index */
552 if (parent == NULL) {
553 const int len = (menu->len + HSPACE);
554
555 if (o->CurrentBar->tail == menu)
556 o->CurrentBar->tail = prev;
557 if (o->CurrentBar->head == menu)
558 o->CurrentBar->head = next;
559
560 for (next = menu->next; next != NULL; next = next->next)
561 next->x -= len;
562 } else {
563 for (item = parent->tail; item != NULL; item = item->prev) {
564 if (item->entry.type == MenuSubMenu
565 && item->entry.submenu.menu == menu) {
566 item->entry.submenu.menu = NULL;
567 rxvtlib_menuitem_free (o, menu->parent, item);
568 break;
569 }
570 }
571 }
572
573 item = menu->tail;
574 while (item != NULL) {
575 menuitem_t *p = item->prev;
576
577 rxvtlib_menuitem_free (o, menu, item);
578 item = p;
579 }
580
581 if (menu->name != NULL)
582 FREE (menu->name);
583 FREE (menu);
584
585 return parent;
586 }
587 #endif
588
589 #ifdef MENUBAR
590 /* INTPROTO */
rxvtlib_menu_add(rxvtlib * o,menu_t * parent,char * path)591 menu_t *rxvtlib_menu_add (rxvtlib *o, menu_t * parent, char *path)
592 {
593 menu_t *menu;
594
595 assert (o->CurrentBar != NULL);
596
597 if (strchr (path, '/') != NULL) {
598 register char *p;
599
600 if (path[0] == '/') {
601 /* shouldn't happen */
602 path++;
603 parent = NULL;
604 }
605 while ((p = strchr (path, '/')) != NULL) {
606 p[0] = '\0';
607 if (path[0] == '\0')
608 return NULL;
609
610 parent = rxvtlib_menu_add (o, parent, path);
611 path = (p + 1);
612 }
613 }
614 if (!strcmp (path, DOTS))
615 return (parent != NULL ? parent->parent : parent);
616
617 if (!strcmp (path, DOT) || path[0] == '\0')
618 return parent;
619
620 /* allocate a new menu */
621 if ((menu = (menu_t *) MALLOC (sizeof (menu_t))) == NULL)
622 return parent;
623
624 menu->width = 0;
625 menu->parent = parent;
626 menu->len = strlen (path);
627 menu->name = MALLOC ((menu->len + 1));
628 if (menu->name == NULL) {
629 FREE (menu);
630 return parent;
631 }
632 STRCPY (menu->name, path);
633
634 /* initialize head/tail */
635 menu->head = menu->tail = NULL;
636 menu->prev = menu->next = NULL;
637
638 menu->win = None;
639 menu->x = menu->y = menu->w = menu->h = 0;
640 menu->item = NULL;
641
642 /* add to tail of list */
643 if (parent == NULL) {
644 menu->prev = o->CurrentBar->tail;
645 if (o->CurrentBar->tail != NULL)
646 o->CurrentBar->tail->next = menu;
647 o->CurrentBar->tail = menu;
648 if (o->CurrentBar->head == NULL)
649 o->CurrentBar->head = menu; /* fix head */
650 if (menu->prev)
651 menu->x = (menu->prev->x + menu->prev->len + HSPACE);
652 } else {
653 menuitem_t *item;
654
655 item = rxvtlib_menuitem_add (o, parent, path, "", "");
656 if (item == NULL) {
657 FREE (menu);
658 return parent;
659 }
660 assert (item->entry.type == MenuLabel);
661 item->entry.type = MenuSubMenu;
662 item->entry.submenu.menu = menu;
663 }
664
665 return menu;
666 }
667 #endif
668
669 #ifdef MENUBAR
670 /* INTPROTO */
rxvtlib_drawbox_menubar(rxvtlib * o,int x,int len,int state)671 void rxvtlib_drawbox_menubar (rxvtlib *o, int x, int len, int state)
672 {
673 GC top, bot;
674
675 x = Width2Pixel (x);
676 len = Width2Pixel (len + HSPACE);
677 if (x >= o->TermWin.width)
678 return;
679 else if (x + len >= o->TermWin.width)
680 len = (TermWin_TotalWidth () - x);
681
682 #ifdef MENUBAR_SHADOW_IN
683 state = -state;
684 #endif
685 switch (state) {
686 case +1:
687 top = o->topShadowGC;
688 bot = o->botShadowGC;
689 break; /* SHADOW_OUT */
690 case -1:
691 top = o->botShadowGC;
692 bot = o->topShadowGC;
693 break; /* SHADOW_IN */
694 default:
695 top = bot = o->neutralGC;
696 break; /* neutral */
697 }
698
699 rxvtlib_Draw_Shadow (o, o->menuBar.win, top, bot, x, 0, len, menuBar_TotalHeight ());
700 }
701 #endif
702
703 #ifdef MENUBAR
704 /* INTPROTO */
rxvtlib_drawtriangle(rxvtlib * o,int x,int y,int state)705 void rxvtlib_drawtriangle (rxvtlib *o, int x, int y, int state)
706 {
707 GC top, bot;
708 int w;
709
710 #ifdef MENU_SHADOW_IN
711 state = -state;
712 #endif
713 switch (state) {
714 case +1:
715 top = o->topShadowGC;
716 bot = o->botShadowGC;
717 break; /* SHADOW_OUT */
718 case -1:
719 top = o->botShadowGC;
720 bot = o->topShadowGC;
721 break; /* SHADOW_IN */
722 default:
723 top = bot = o->neutralGC;
724 break; /* neutral */
725 }
726
727 w = Height2Pixel (1) - 2 * SHADOW;
728
729 x -= SHADOW + (3 * w / 2);
730 y += SHADOW * 3;
731
732 rxvtlib_Draw_Triangle (o, o->ActiveMenu->win, top, bot, x, y, w, 'r');
733 }
734 #endif
735
736 #ifdef MENUBAR
737 /* INTPROTO */
rxvtlib_drawbox_menuitem(rxvtlib * o,int y,int state)738 void rxvtlib_drawbox_menuitem (rxvtlib *o, int y, int state)
739 {
740 GC top, bot;
741
742 #ifdef MENU_SHADOW_IN
743 state = -state;
744 #endif
745 switch (state) {
746 case +1:
747 top = o->topShadowGC;
748 bot = o->botShadowGC;
749 break; /* SHADOW_OUT */
750 case -1:
751 top = o->botShadowGC;
752 bot = o->topShadowGC;
753 break; /* SHADOW_IN */
754 default:
755 top = bot = o->neutralGC;
756 break; /* neutral */
757 }
758
759 rxvtlib_Draw_Shadow (o, o->ActiveMenu->win, top, bot,
760 SHADOW + 0,
761 SHADOW + y,
762 o->ActiveMenu->w - 2 * (SHADOW), HEIGHT_TEXT + 2 * SHADOW);
763 XFlush (o->Xdisplay);
764 }
765 #endif
766
767 #ifdef DEBUG_MENU_LAYOUT
768 #ifdef MENUBAR
769 /* INTPROTO */
rxvtlib_print_menu_ancestors(rxvtlib * o,menu_t * menu)770 void rxvtlib_print_menu_ancestors (rxvtlib *o, menu_t * menu)
771 {
772 if (menu == NULL) {
773 fprintf (stderr, "Top Level menu\n");
774 return;
775 }
776 fprintf (stderr, "menu %s ", menu->name);
777 if (menu->parent != NULL) {
778 menuitem_t *item;
779
780 for (item = menu->parent->head; item != NULL; item = item->next) {
781 if (item->entry.type == MenuSubMenu
782 && item->entry.submenu.menu == menu) {
783 break;
784 }
785 }
786 if (item == NULL) {
787 fprintf (stderr, "is an orphan!\n");
788 return;
789 }
790 }
791 fprintf (stderr, "\n");
792 rxvtlib_print_menu_ancestors (o, menu->parent);
793 }
794 #endif
795
796 #ifdef MENUBAR
797 /* INTPROTO */
rxvtlib_print_menu_descendants(rxvtlib * o,menu_t * menu)798 void rxvtlib_print_menu_descendants (rxvtlib *o, menu_t * menu)
799 {
800 menuitem_t *item;
801 menu_t *parent;
802 int i, level = 0;
803
804 parent = menu;
805 do {
806 level++;
807 parent = parent->parent;
808 }
809 while (parent != NULL);
810
811 for (i = 0; i < level; i++)
812 fprintf (stderr, ">");
813 fprintf (stderr, "%s\n", menu->name);
814
815 for (item = menu->head; item != NULL; item = item->next) {
816 if (item->entry.type == MenuSubMenu) {
817 if (item->entry.submenu.menu == NULL)
818 fprintf (stderr, "> %s == NULL\n", item->name);
819 else
820 rxvtlib_print_menu_descendants (o, item->entry.submenu.menu);
821 } else {
822 for (i = 0; i < level; i++)
823 fprintf (stderr, "+");
824 if (item->entry.type == MenuLabel)
825 fprintf (stderr, "label: ");
826 fprintf (stderr, "%s\n", item->name);
827 }
828 }
829
830 for (i = 0; i < level; i++)
831 fprintf (stderr, "<");
832 fprintf (stderr, "\n");
833 }
834 #endif
835 #endif
836
837 #ifdef MENUBAR
838 /* pop up/down the current menu and redraw the menuBar button */
839 /* INTPROTO */
rxvtlib_menu_show(rxvtlib * o)840 void rxvtlib_menu_show (rxvtlib *o)
841 {
842 int x, y, xright;
843 menuitem_t *item;
844
845 if (o->ActiveMenu == NULL)
846 return;
847
848 x = o->ActiveMenu->x;
849 if (o->ActiveMenu->parent == NULL) {
850 register int h;
851
852 rxvtlib_drawbox_menubar (o, x, o->ActiveMenu->len, -1);
853 x = Width2Pixel (x);
854
855 o->ActiveMenu->y = 1;
856 o->ActiveMenu->w = Menu_PixelWidth (o->ActiveMenu);
857
858 if ((x + o->ActiveMenu->w) >= o->TermWin.width)
859 x = (TermWin_TotalWidth () - o->ActiveMenu->w);
860
861 /* find the height */
862 for (h = 0, item = o->ActiveMenu->head; item != NULL; item = item->next)
863 h += isSeparator (item->name) ? HEIGHT_SEPARATOR
864 : HEIGHT_TEXT + 2 * SHADOW;
865 o->ActiveMenu->h = h + 2 * SHADOW;
866 }
867 if (o->ActiveMenu->win == None) {
868 o->ActiveMenu->win = XCreateSimpleWindow (o->Xdisplay, o->TermWin.vt,
869 x,
870 o->ActiveMenu->y,
871 o->ActiveMenu->w,
872 o->ActiveMenu->h,
873 0,
874 o->PixColors[Color_fg],
875 o->PixColors[Color_scroll]);
876 XMapWindow (o->Xdisplay, o->ActiveMenu->win);
877 }
878 rxvtlib_Draw_Shadow (o, o->ActiveMenu->win,
879 o->topShadowGC, o->botShadowGC, 0, 0, o->ActiveMenu->w, o->ActiveMenu->h);
880
881 /* determine the correct right-alignment */
882 for (xright = 0, item = o->ActiveMenu->head; item != NULL; item = item->next)
883 if (item->len2 > xright)
884 xright = item->len2;
885
886 for (y = 0, item = o->ActiveMenu->head; item != NULL; item = item->next) {
887 const int xoff = (SHADOW + Width2Pixel (HSPACE) / 2);
888 register int h;
889 GC gc = o->menubarGC;
890
891 if (isSeparator (item->name)) {
892 rxvtlib_Draw_Shadow (o, o->ActiveMenu->win,
893 o->topShadowGC, o->botShadowGC,
894 SHADOW, y + SHADOW + 1, o->ActiveMenu->w - 2 * SHADOW,
895 0);
896 h = HEIGHT_SEPARATOR;
897 } else {
898 char *name = item->name;
899 int len = item->len;
900
901 if (item->entry.type == MenuLabel) {
902 gc = o->botShadowGC;
903 } else if (item->entry.type == MenuSubMenu) {
904 int x1, y1;
905 menuitem_t *it;
906 menu_t *menu = item->entry.submenu.menu;
907
908 rxvtlib_drawtriangle (o, o->ActiveMenu->w, y, +1);
909
910 name = menu->name;
911 len = menu->len;
912
913 y1 = o->ActiveMenu->y + y;
914
915 menu->w = Menu_PixelWidth (menu);
916
917 /* place sub-menu at midpoint of parent menu */
918 x1 = o->ActiveMenu->w / 2;
919 if (x1 > menu->w) /* right-flush menu if too small */
920 x1 += (x1 - menu->w);
921 x1 += x;
922
923 /* find the height of this submenu */
924 for (h = 0, it = menu->head; it != NULL; it = it->next)
925 h += isSeparator (it->name) ? HEIGHT_SEPARATOR
926 : HEIGHT_TEXT + 2 * SHADOW;
927 menu->h = h + 2 * SHADOW;
928
929 /* ensure menu is in window limits */
930 if ((x1 + menu->w) >= o->TermWin.width)
931 x1 = (TermWin_TotalWidth () - menu->w);
932
933 if ((y1 + menu->h) >= o->TermWin.height)
934 y1 = (TermWin_TotalHeight () - menu->h);
935
936 menu->x = (x1 < 0 ? 0 : x1);
937 menu->y = (y1 < 0 ? 0 : y1);
938 } else if (item->name2 && !strcmp (name, item->name2))
939 name = NULL;
940
941 if (len && name)
942 XDrawString (o->Xdisplay,
943 o->ActiveMenu->win, gc,
944 xoff,
945 2 * SHADOW + y + o->TermWin.font->ascent + 1,
946 name, len);
947
948 len = item->len2;
949 name = item->name2;
950 if (len && name)
951 XDrawString (o->Xdisplay,
952 o->ActiveMenu->win, gc,
953 o->ActiveMenu->w - (xoff + Width2Pixel (xright)),
954 2 * SHADOW + y + o->TermWin.font->ascent + 1,
955 name, len);
956
957 h = HEIGHT_TEXT + 2 * SHADOW;
958 }
959 y += h;
960 }
961 }
962 #endif
963
964 #ifdef MENUBAR
965 /* INTPROTO */
rxvtlib_menu_display(rxvtlib * o,void (* update)(rxvtlib *))966 void rxvtlib_menu_display (rxvtlib *o, void (*update) (rxvtlib *))
967 {
968 if (o->ActiveMenu == NULL)
969 return;
970 if (o->ActiveMenu->win != None)
971 XDestroyWindow (o->Xdisplay, o->ActiveMenu->win);
972 o->ActiveMenu->win = None;
973 o->ActiveMenu->item = NULL;
974
975 if (o->ActiveMenu->parent == NULL)
976 rxvtlib_drawbox_menubar (o, o->ActiveMenu->x, o->ActiveMenu->len, +1);
977 o->ActiveMenu = o->ActiveMenu->parent;
978 update (o);
979 }
980 #endif
981
982 #ifdef MENUBAR
983 /* INTPROTO */
rxvtlib_menu_hide_all(rxvtlib * o)984 void rxvtlib_menu_hide_all (rxvtlib *o)
985 {
986 rxvtlib_menu_display (o, rxvtlib_menu_hide_all);
987 }
988
989 #endif
990
991 #ifdef MENUBAR
992 /* INTPROTO */
rxvtlib_menu_hide(rxvtlib * o)993 void rxvtlib_menu_hide (rxvtlib *o)
994 {
995 rxvtlib_menu_display (o, rxvtlib_menu_show);
996 }
997
998 #endif
999
1000 #ifdef MENUBAR
1001 /* INTPROTO */
rxvtlib_menu_clear(rxvtlib * o,menu_t * menu)1002 void rxvtlib_menu_clear (rxvtlib *o, menu_t * menu)
1003 {
1004 if (menu != NULL) {
1005 menuitem_t *item = menu->tail;
1006
1007 while (item != NULL) {
1008 rxvtlib_menuitem_free (o, menu, item);
1009 /* it didn't get freed ... why? */
1010 if (item == menu->tail)
1011 return;
1012 item = menu->tail;
1013 }
1014 menu->width = 0;
1015 }
1016 }
1017 #endif
1018
1019 #ifdef MENUBAR
1020 /* INTPROTO */
rxvtlib_menubar_clear(rxvtlib * o)1021 void rxvtlib_menubar_clear (rxvtlib *o)
1022 {
1023 if (o->CurrentBar != NULL) {
1024 menu_t *menu = o->CurrentBar->tail;
1025
1026 while (menu != NULL) {
1027 menu_t *prev = menu->prev;
1028
1029 rxvtlib_menu_delete (o, menu);
1030 menu = prev;
1031 }
1032 o->CurrentBar->head = o->CurrentBar->tail = o->ActiveMenu = NULL;
1033
1034 if (o->CurrentBar->title) {
1035 FREE (o->CurrentBar->title);
1036 o->CurrentBar->title = NULL;
1037 }
1038 rxvtlib_menuarrow_free (o, 0); /* remove all arrow functions */
1039 }
1040 o->ActiveMenu = NULL;
1041 }
1042 #endif
1043
1044 #if (MENUBAR_MAX > 1)
1045 #ifdef MENUBAR
1046 /* find if menu already exists */
1047 /* INTPROTO */
rxvtlib_menubar_find(rxvtlib * o,const char * name)1048 bar_t *rxvtlib_menubar_find (rxvtlib *o, const char *name)
1049 {
1050 bar_t *bar = o->CurrentBar;
1051
1052 #ifdef DEBUG_MENUBAR_STACKING
1053 fprintf (stderr, "looking for [menu:%s] ...", name ? name : "(nil)");
1054 #endif
1055 if (bar == NULL || name == NULL)
1056 return NULL;
1057
1058 if (strlen (name) && strcmp (name, "*")) {
1059 do {
1060 if (!strcmp (bar->name, name)) {
1061 #ifdef DEBUG_MENUBAR_STACKING
1062 fprintf (stderr, " found!\n");
1063 #endif
1064 return bar;
1065 }
1066 bar = bar->next;
1067 }
1068 while (bar != o->CurrentBar);
1069 bar = NULL;
1070 }
1071 #ifdef DEBUG_MENUBAR_STACKING
1072 fprintf (stderr, "%s found!\n", (bar ? "" : " NOT"));
1073 #endif
1074
1075 return bar;
1076 }
1077 #endif
1078
1079 #ifdef MENUBAR
1080 /* INTPROTO */
rxvtlib_menubar_push(rxvtlib * o,const char * name)1081 int rxvtlib_menubar_push (rxvtlib *o, const char *name)
1082 {
1083 int ret = 1;
1084 bar_t *bar;
1085
1086 if (o->CurrentBar == NULL) {
1087 /* allocate first one */
1088 bar = (bar_t *) MALLOC (sizeof (bar_t));
1089
1090 if (bar == NULL)
1091 return 0;
1092
1093 MEMSET (bar, 0, sizeof (bar_t));
1094 /* circular linked-list */
1095 bar->next = bar->prev = bar;
1096 bar->head = bar->tail = NULL;
1097 bar->title = NULL;
1098 o->CurrentBar = bar;
1099 o->Nbars++;
1100
1101 rxvtlib_menubar_clear (o);
1102 } else {
1103 /* find if menu already exists */
1104 bar = rxvtlib_menubar_find (o, name);
1105 if (bar != NULL) {
1106 /* found it, use it */
1107 o->CurrentBar = bar;
1108 } else {
1109 /* create if needed, or reuse the existing empty menubar */
1110 if (o->CurrentBar->head != NULL) {
1111 /* need to malloc another one */
1112 if (o->Nbars < MENUBAR_MAX)
1113 bar = (bar_t *) MALLOC (sizeof (bar_t));
1114 else
1115 bar = NULL;
1116
1117 /* malloc failed or too many menubars, reuse another */
1118 if (bar == NULL) {
1119 bar = o->CurrentBar->next;
1120 ret = -1;
1121 } else {
1122 bar->head = bar->tail = NULL;
1123 bar->title = NULL;
1124
1125 bar->next = o->CurrentBar->next;
1126 o->CurrentBar->next = bar;
1127 bar->prev = o->CurrentBar;
1128 bar->next->prev = bar;
1129
1130 o->Nbars++;
1131 }
1132 o->CurrentBar = bar;
1133
1134 }
1135 rxvtlib_menubar_clear (o);
1136 }
1137 }
1138
1139 /* give menubar this name */
1140 STRNCPY (o->CurrentBar->name, name, MAXNAME);
1141 o->CurrentBar->name[MAXNAME - 1] = '\0';
1142
1143 return ret;
1144 }
1145 #endif
1146
1147 #ifdef MENUBAR
1148 /* switch to a menu called NAME and remove it */
1149 /* INTPROTO */
rxvtlib_menubar_remove(rxvtlib * o,const char * name)1150 void rxvtlib_menubar_remove (rxvtlib *o, const char *name)
1151 {
1152 bar_t *bar;
1153
1154 if ((bar = rxvtlib_menubar_find (o, name)) == NULL)
1155 return;
1156 o->CurrentBar = bar;
1157
1158 do {
1159 rxvtlib_menubar_clear (o);
1160 /*
1161 * pop a menubar, clean it up first
1162 */
1163 if (o->CurrentBar != NULL) {
1164 bar_t *prev = o->CurrentBar->prev;
1165 bar_t *next = o->CurrentBar->next;
1166
1167 if (prev == next && prev == o->CurrentBar) { /* only 1 left */
1168 prev = NULL;
1169 o->Nbars = 0; /* safety */
1170 } else {
1171 next->prev = prev;
1172 prev->next = next;
1173 o->Nbars--;
1174 }
1175
1176 FREE (o->CurrentBar);
1177 o->CurrentBar = prev;
1178 }
1179 }
1180 while (o->CurrentBar && !strcmp (name, "*"));
1181 }
1182 #endif
1183
1184 #ifdef MENUBAR
1185 /* INTPROTO */
action_decode(FILE * fp,action_t * act)1186 void action_decode (FILE * fp, action_t * act)
1187 {
1188 unsigned char *str;
1189 short len;
1190
1191 if (act == NULL || (len = act->len) == 0 || (str = act->str) == NULL)
1192 return;
1193
1194 if (act->type == MenuTerminalAction) {
1195 fprintf (fp, "^@");
1196 /* can strip trailing ^G from XTerm sequence */
1197 if (str[0] == 033 && str[1] == ']' && str[len - 1] == 007)
1198 len--;
1199 } else if (str[0] == 033) {
1200 switch (str[1]) {
1201 case '[':
1202 case ']':
1203 break;
1204
1205 case 'x':
1206 /* can strip trailing '\r' from M-x sequence */
1207 if (str[len - 1] == '\r')
1208 len--;
1209 /* FALLTHROUGH */
1210
1211 default:
1212 fprintf (fp, "M-"); /* meta prefix */
1213 str++;
1214 len--;
1215 break;
1216 }
1217 }
1218 /*
1219 * control character form is preferred, since backslash-escaping
1220 * can be really ugly looking when the backslashes themselves also
1221 * have to be escaped to avoid Shell (or whatever scripting
1222 * language) interpretation
1223 */
1224 while (len > 0) {
1225 unsigned char ch = *str++;
1226
1227 switch (ch) {
1228 case 033:
1229 fprintf (fp, "\\E");
1230 break; /* escape */
1231 case '\r':
1232 fprintf (fp, "\\r");
1233 break; /* carriage-return */
1234 case '\\':
1235 fprintf (fp, "\\\\");
1236 break; /* backslash */
1237 case '^':
1238 fprintf (fp, "\\^");
1239 break; /* caret */
1240 case 127:
1241 fprintf (fp, "^?");
1242 default:
1243 if (ch <= 31)
1244 fprintf (fp, "^%c", ('@' + ch));
1245 else if (ch > 127)
1246 fprintf (fp, "\\%o", ch);
1247 else
1248 fprintf (fp, "%c", ch);
1249 break;
1250 }
1251 len--;
1252 }
1253 fprintf (fp, "\n");
1254 }
1255 #endif
1256
1257 #ifdef MENUBAR
1258 /* INTPROTO */
rxvtlib_menu_dump(rxvtlib * o,FILE * fp,menu_t * menu)1259 void rxvtlib_menu_dump (rxvtlib *o, FILE * fp, menu_t * menu)
1260 {
1261 menuitem_t *item;
1262
1263 /* create a new menu and clear it */
1264 fprintf (fp, (menu->parent ? "./%s/*\n" : "/%s/*\n"), menu->name);
1265
1266 for (item = menu->head; item != NULL; item = item->next) {
1267 switch (item->entry.type) {
1268 case MenuSubMenu:
1269 if (item->entry.submenu.menu == NULL)
1270 fprintf (fp, "> %s == NULL\n", item->name);
1271 else
1272 rxvtlib_menu_dump (o, fp, item->entry.submenu.menu);
1273 break;
1274
1275 case MenuLabel:
1276 fprintf (fp, "{%s}\n", (strlen (item->name) ? item->name : "-"));
1277 break;
1278
1279 case MenuTerminalAction:
1280 case MenuAction:
1281 fprintf (fp, "{%s}", item->name);
1282 if (item->name2 != NULL && strlen (item->name2))
1283 fprintf (fp, "{%s}", item->name2);
1284 fprintf (fp, "\t");
1285 action_decode (fp, &(item->entry.action));
1286 break;
1287 }
1288 }
1289
1290 fprintf (fp, (menu->parent ? "../\n" : "/\n\n"));
1291 }
1292 #endif
1293
1294 #ifdef MENUBAR
1295 /* INTPROTO */
rxvtlib_menubar_dump(rxvtlib * o,FILE * fp)1296 void rxvtlib_menubar_dump (rxvtlib *o, FILE * fp)
1297 {
1298 bar_t *bar = o->CurrentBar;
1299 time_t t;
1300
1301 if (bar == NULL || fp == NULL)
1302 return;
1303 time (&t);
1304
1305 fprintf (fp,
1306 "# " APL_SUBCLASS " (%s) Pid: %u\n# Date: %s\n\n",
1307 o->rs[Rs_name], (unsigned int)getpid (), ctime (&t));
1308
1309 /* dump in reverse order */
1310 bar = o->CurrentBar->prev;
1311 do {
1312 menu_t *menu;
1313 int i;
1314
1315 fprintf (fp, "[menu:%s]\n", bar->name);
1316
1317 if (bar->title != NULL)
1318 fprintf (fp, "[title:%s]\n", bar->title);
1319
1320 for (i = 0; i < NARROWS; i++) {
1321 switch (bar->arrows[i].type) {
1322 case MenuTerminalAction:
1323 case MenuAction:
1324 fprintf (fp, "<%c>", o->Arrows[i].name);
1325 action_decode (fp, &(bar->arrows[i]));
1326 break;
1327 }
1328 }
1329 fprintf (fp, "\n");
1330
1331 for (menu = bar->head; menu != NULL; menu = menu->next)
1332 rxvtlib_menu_dump (o, fp, menu);
1333
1334 fprintf (fp, "\n[done:%s]\n\n", bar->name);
1335 bar = bar->prev;
1336 }
1337 while (bar != o->CurrentBar->prev);
1338 }
1339 #endif
1340 #endif /* (MENUBAR_MAX > 1) */
1341
1342 /*
1343 * read in menubar commands from FILENAME
1344 * ignore all input before the tag line [menu] or [menu:???]
1345 *
1346 * Note that since File_find () is used, FILENAME can be semi-colon
1347 * delimited such that the second part can refer to a tag
1348 * so that a large `database' of menus can be collected together
1349 *
1350 * FILENAME = "file"
1351 * FILENAME = "file;"
1352 * read `file' starting with first [menu] or [menu:???] line
1353 *
1354 * FILENAME = "file;tag"
1355 * read `file' starting with [menu:tag]
1356 */
1357 /* EXTPROTO */
rxvtlib_menubar_read(rxvtlib * o,const char * filename)1358 void rxvtlib_menubar_read (rxvtlib *o, const char *filename)
1359 {
1360 #ifdef MENUBAR
1361 /* read in a menu from a file */
1362 FILE *fp;
1363 char buffer[256];
1364 char *p, *file, *tag = NULL;
1365
1366 file = (char *)rxvtlib_File_find (o, filename, ".menu");
1367 if (file == NULL)
1368 return;
1369 fp = fopen (file, "rb");
1370 FREE (file);
1371 if (fp == NULL)
1372 return;
1373
1374 #if (MENUBAR_MAX > 1)
1375 /* semi-colon delimited */
1376 if ((tag = strchr (filename, ';')) != NULL) {
1377 tag++;
1378 if (*tag == '\0')
1379 tag = NULL;
1380 }
1381 #endif /* (MENUBAR_MAX > 1) */
1382 #ifdef DEBUG_MENU
1383 fprintf (stderr, "[read:%s]\n", p);
1384 if (tag)
1385 fprintf (stderr, "looking for [menu:%s]\n", tag);
1386 #endif
1387
1388 while ((p = fgets (buffer, sizeof (buffer), fp)) != NULL) {
1389 int n;
1390
1391 if ((n = Str_match (p, "[menu")) != 0) {
1392 if (tag) {
1393 /* looking for [menu:tag] */
1394 if (p[n] == ':' && p[n + 1] != ']') {
1395 n++;
1396 n += Str_match (p + n, tag);
1397 if (p[n] == ']') {
1398 #ifdef DEBUG_MENU
1399 fprintf (stderr, "[menu:%s]\n", tag);
1400 #endif
1401 break;
1402 }
1403 }
1404 } else if (p[n] == ':' || p[n] == ']')
1405 break;
1406 }
1407 }
1408
1409 /* found [menu], [menu:???] tag */
1410 while (p != NULL) {
1411 int n;
1412
1413 #ifdef DEBUG_MENU
1414 fprintf (stderr, "read line = %s\n", p);
1415 #endif
1416
1417 /* looking for [done:tag] or [done:] */
1418 if ((n = Str_match (p, "[done")) != 0) {
1419 if (p[n] == ']') {
1420 o->menu_readonly = 1;
1421 break;
1422 } else if (p[n] == ':') {
1423 n++;
1424 if (p[n] == ']') {
1425 o->menu_readonly = 1;
1426 break;
1427 } else if (tag) {
1428 n += Str_match (p + n, tag);
1429 if (p[n] == ']') {
1430 #ifdef DEBUG_MENU
1431 fprintf (stderr, "[done:%s]\n", tag);
1432 #endif
1433 o->menu_readonly = 1;
1434 break;
1435 }
1436 } else {
1437 /* what? ... skip this line */
1438 p[0] = COMMENT_CHAR;
1439 }
1440 }
1441 }
1442 /*
1443 * remove leading/trailing space
1444 * and strip-off leading/trailing quotes
1445 * skip blank or comment lines
1446 */
1447 (void)Str_trim (p);
1448 if (*p && *p != '#') {
1449 o->menu_readonly = 0; /* if case we read another file */
1450 rxvtlib_menubar_dispatch (o, p);
1451 }
1452 /* get another line */
1453 p = fgets (buffer, sizeof (buffer), fp);
1454 }
1455
1456 fclose (fp);
1457 #endif
1458 }
1459
1460 /*
1461 * user interface for building/deleting and otherwise managing menus
1462 */
1463 /* EXTPROTO */
rxvtlib_menubar_dispatch(rxvtlib * o,char * str)1464 void rxvtlib_menubar_dispatch (rxvtlib *o, char *str)
1465 {
1466 #ifdef MENUBAR
1467 int n, cmd;
1468 char *path, *name, *name2;
1469
1470 if (menubar_visible () && o->ActiveMenu != NULL)
1471 rxvtlib_menubar_expose (o);
1472 else
1473 o->ActiveMenu = NULL;
1474
1475 cmd = *str;
1476 switch (cmd) {
1477 case '.':
1478 case '/': /* absolute & relative path */
1479 case MENUITEM_BEG: /* menuitem */
1480 /* add `+' prefix for these cases */
1481 cmd = '+';
1482 break;
1483
1484 case '+':
1485 case '-':
1486 str++; /* skip cmd character */
1487 break;
1488
1489 case '<':
1490 #if (MENUBAR_MAX > 1)
1491 if (o->CurrentBar == NULL)
1492 break;
1493 #endif /* (MENUBAR_MAX > 1) */
1494 if (str[1] && str[2] == '>') /* arrow commands */
1495 rxvtlib_menuarrow_add (o, str);
1496 break;
1497
1498 case '[': /* extended command */
1499 while (str[0] == '[') {
1500 char *next = (++str); /* skip leading '[' */
1501
1502 if (str[0] == ':') { /* [:command:] */
1503 do {
1504 next++;
1505 if ((next = strchr (next, ':')) == NULL)
1506 return; /* parse error */
1507 }
1508 while (next[1] != ']');
1509 /* remove and skip ':]' */
1510 *next = '\0';
1511 next += 2;
1512 } else {
1513 if ((next = strchr (next, ']')) == NULL)
1514 return; /* parse error */
1515 /* remove and skip ']' */
1516 *next = '\0';
1517 next++;
1518 }
1519
1520 if (str[0] == ':') {
1521 int saved;
1522
1523 /* try and dispatch it, regardless of read/write status */
1524 saved = o->menu_readonly;
1525 o->menu_readonly = 0;
1526 rxvtlib_menubar_dispatch (o, str + 1);
1527 o->menu_readonly = saved;
1528 }
1529 /* these ones don't require menu stacking */
1530 else if (!strcmp (str, "clear")) {
1531 rxvtlib_menubar_clear (o);
1532 } else if (!strcmp (str, "done") || Str_match (str, "done:")) {
1533 o->menu_readonly = 1;
1534 } else if (!strcmp (str, "show")) {
1535 rxvtlib_map_menuBar (o, 1);
1536 o->menu_readonly = 1;
1537 } else if (!strcmp (str, "hide")) {
1538 rxvtlib_map_menuBar (o, 0);
1539 o->menu_readonly = 1;
1540 } else if ((n = Str_match (str, "read:")) != 0) {
1541 /* read in a menu from a file */
1542 str += n;
1543 rxvtlib_menubar_read (o, str);
1544 } else if ((n = Str_match (str, "title:")) != 0) {
1545 str += n;
1546 if (o->CurrentBar != NULL && !o->menu_readonly) {
1547 if (*str) {
1548 name = REALLOC (o->CurrentBar->title, strlen (str) + 1);
1549 if (name != NULL) {
1550 STRCPY (name, str);
1551 o->CurrentBar->title = name;
1552 }
1553 rxvtlib_menubar_expose (o);
1554 } else {
1555 FREE (o->CurrentBar->title);
1556 o->CurrentBar->title = NULL;
1557 }
1558 }
1559 } else if ((n = Str_match (str, "pixmap:")) != 0) {
1560 str += n;
1561 rxvtlib_xterm_seq (o, XTerm_Pixmap, str);
1562 }
1563 #if (MENUBAR_MAX > 1)
1564 else if ((n = Str_match (str, "rm")) != 0) {
1565 str += n;
1566 switch (str[0]) {
1567 case ':':
1568 str++;
1569 rxvtlib_menubar_remove (o, str);
1570 break;
1571
1572 case '\0':
1573 rxvtlib_menubar_remove (o, str);
1574 break;
1575
1576 case '*':
1577 rxvtlib_menubar_remove (o, str);
1578 break;
1579 }
1580 o->menu_readonly = 1;
1581 } else if ((n = Str_match (str, "menu")) != 0) {
1582 str += n;
1583 switch (str[0]) {
1584 case ':':
1585 str++;
1586 /* add/access menuBar */
1587 if (*str != '\0' && *str != '*')
1588 rxvtlib_menubar_push (o, str);
1589 break;
1590 default:
1591 if (o->CurrentBar == NULL) {
1592 rxvtlib_menubar_push (o, "default");
1593 }
1594 }
1595
1596 if (o->CurrentBar != NULL)
1597 o->menu_readonly = 0; /* allow menu build commands */
1598 } else if (!strcmp (str, "dump")) {
1599 /* dump current menubars to a file */
1600 FILE *fp;
1601
1602 /* enough space to hold the results */
1603 char buffer[32];
1604
1605 sprintf (buffer, "/tmp/" APL_SUBCLASS "-%u",
1606 (unsigned int)getpid ());
1607
1608 if ((fp = fopen (buffer, "wb")) != NULL) {
1609 rxvtlib_xterm_seq (o, XTerm_title, buffer);
1610 rxvtlib_menubar_dump (o, fp);
1611 fclose (fp);
1612 }
1613 } else if (!strcmp (str, "next")) {
1614 if (o->CurrentBar) {
1615 o->CurrentBar = o->CurrentBar->next;
1616 o->menu_readonly = 1;
1617 }
1618 } else if (!strcmp (str, "prev")) {
1619 if (o->CurrentBar) {
1620 o->CurrentBar = o->CurrentBar->prev;
1621 o->menu_readonly = 1;
1622 }
1623 } else if (!strcmp (str, "swap")) {
1624 /* swap the top 2 menus */
1625 if (o->CurrentBar) {
1626 bar_t *prev = o->CurrentBar->prev;
1627 bar_t *next = o->CurrentBar->next;
1628
1629 prev->next = next;
1630 next->prev = prev;
1631
1632 o->CurrentBar->next = prev;
1633 o->CurrentBar->prev = prev->prev;
1634
1635 prev->prev->next = o->CurrentBar;
1636 prev->prev = o->CurrentBar;
1637
1638 o->CurrentBar = prev;
1639 o->menu_readonly = 1;
1640 }
1641 }
1642 #endif /* (MENUBAR_MAX > 1) */
1643 str = next;
1644
1645 o->BuildMenu = o->ActiveMenu = NULL;
1646 rxvtlib_menubar_expose (o);
1647 #ifdef DEBUG_MENUBAR_STACKING
1648 fprintf (stderr, "menus are read%s\n",
1649 o->menu_readonly ? "only" : "/write");
1650 #endif
1651 }
1652 return;
1653 break;
1654 }
1655
1656 #if (MENUBAR_MAX > 1)
1657 if (o->CurrentBar == NULL)
1658 return;
1659 if (o->menu_readonly) {
1660 #ifdef DEBUG_MENUBAR_STACKING
1661 fprintf (stderr, "menus are read%s\n",
1662 o->menu_readonly ? "only" : "/write");
1663 #endif
1664 return;
1665 }
1666 #endif /* (MENUBAR_MAX > 1) */
1667
1668 switch (cmd) {
1669 case '+':
1670 case '-':
1671 path = name = str;
1672
1673 name2 = NULL;
1674 /* parse STR, allow spaces inside (name) */
1675 if (path[0] != '\0') {
1676 name = strchr (path, MENUITEM_BEG);
1677 str = strchr (path, MENUITEM_END);
1678 if (name != NULL || str != NULL) {
1679 if (name == NULL || str == NULL || str <= (name + 1)
1680 || (name > path && name[-1] != '/')) {
1681 print_error ("menu error <%s>\n", path);
1682 break;
1683 }
1684 if (str[1] == MENUITEM_BEG) {
1685 name2 = (str + 2);
1686 str = strchr (name2, MENUITEM_END);
1687
1688 if (str == NULL) {
1689 print_error ("menu error <%s>\n", path);
1690 break;
1691 }
1692 name2[-2] = '\0'; /* remove prev MENUITEM_END */
1693 }
1694 if (name > path && name[-1] == '/')
1695 name[-1] = '\0';
1696
1697 *name++ = '\0'; /* delimit */
1698 *str++ = '\0'; /* delimit */
1699
1700 while (isspace (*str))
1701 str++; /* skip space */
1702 }
1703 #ifdef DEBUG_MENU
1704 fprintf (stderr,
1705 "`%c' path = <%s>, name = <%s>, name2 = <%s>, action = <%s>\n",
1706 cmd, (path ? path : "(nil)"), (name ? name : "(nil)"),
1707 (name2 ? name2 : "(nil)"), (str ? str : "(nil)")
1708 );
1709 #endif
1710 }
1711 /* process the different commands */
1712 switch (cmd) {
1713 case '+': /* add/replace existing menu or menuitem */
1714 if (path[0] != '\0') {
1715 int len;
1716
1717 path = rxvtlib_menu_find_base (o, &o->BuildMenu, path);
1718 len = strlen (path);
1719
1720 /* don't allow menus called `*' */
1721 if (path[0] == '*') {
1722 rxvtlib_menu_clear (o, o->BuildMenu);
1723 break;
1724 } else if (len >= 2 && !strcmp ((path + len - 2), "/*")) {
1725 path[len - 2] = '\0';
1726 }
1727 if (path[0] != '\0')
1728 o->BuildMenu = rxvtlib_menu_add (o, o->BuildMenu, path);
1729 }
1730 if (name != NULL && name[0] != '\0')
1731 rxvtlib_menuitem_add (o, o->BuildMenu,
1732 (strcmp (name, SEPARATOR_NAME) ? name : ""),
1733 name2, str);
1734 break;
1735
1736 case '-': /* delete menu entry */
1737 if (!strcmp (path, "/*") && (name == NULL || name[0] == '\0')) {
1738 rxvtlib_menubar_clear (o);
1739 o->BuildMenu = NULL;
1740 rxvtlib_menubar_expose (o);
1741 break;
1742 } else if (path[0] != '\0') {
1743 int len;
1744 menu_t *menu = o->BuildMenu;
1745
1746 path = rxvtlib_menu_find_base (o, &menu, path);
1747 len = strlen (path);
1748
1749 /* submenu called `*' clears all menu items */
1750 if (path[0] == '*') {
1751 rxvtlib_menu_clear (o, menu);
1752 break; /* done */
1753 } else if (len >= 2 && !strcmp (&path[len - 2], "/*")) {
1754 /* done */
1755 break;
1756 } else if (path[0] != '\0') {
1757 o->BuildMenu = NULL;
1758 break;
1759 } else {
1760 o->BuildMenu = menu;
1761 }
1762 }
1763 if (o->BuildMenu != NULL) {
1764 if (name == NULL || name[0] == '\0') {
1765 o->BuildMenu = rxvtlib_menu_delete (o, o->BuildMenu);
1766 } else {
1767 menuitem_t *item;
1768
1769 item = menuitem_find (o->BuildMenu,
1770 strcmp (name, SEPARATOR_NAME) ? name
1771 : "");
1772
1773 if (item != NULL && item->entry.type != MenuSubMenu) {
1774 rxvtlib_menuitem_free (o, o->BuildMenu, item);
1775
1776 /* fix up the width */
1777 o->BuildMenu->width = 0;
1778 for (item = o->BuildMenu->head;
1779 item != NULL; item = item->next) {
1780 if (o->BuildMenu->width < (item->len + item->len2))
1781 o->BuildMenu->width = (item->len + item->len2);
1782 }
1783 }
1784 }
1785 rxvtlib_menubar_expose (o);
1786 }
1787 break;
1788 }
1789 break;
1790 }
1791 #endif
1792 }
1793
1794 #ifdef MENUBAR
1795 /* INTPROTO */
rxvtlib_draw_Arrows(rxvtlib * o,int name,int state)1796 void rxvtlib_draw_Arrows (rxvtlib *o, int name, int state)
1797 {
1798 GC top, bot;
1799
1800 int i;
1801
1802 #ifdef MENU_SHADOW_IN
1803 state = -state;
1804 #endif
1805 switch (state) {
1806 case +1:
1807 top = o->topShadowGC;
1808 bot = o->botShadowGC;
1809 break; /* SHADOW_OUT */
1810 case -1:
1811 top = o->botShadowGC;
1812 bot = o->topShadowGC;
1813 break; /* SHADOW_IN */
1814 default:
1815 top = bot = o->neutralGC;
1816 break; /* neutral */
1817 }
1818
1819 if (!o->Arrows_x)
1820 return;
1821
1822 for (i = 0; i < NARROWS; i++) {
1823 const int w = Width2Pixel (1);
1824 const int y = (menuBar_TotalHeight () - w) / 2;
1825 int x = o->Arrows_x + (5 * Width2Pixel (i)) / 4;
1826
1827 if (!name || name == o->Arrows[i].name)
1828 rxvtlib_Draw_Triangle (o, o->menuBar.win, top, bot, x, y, w, o->Arrows[i].name);
1829 }
1830 XFlush (o->Xdisplay);
1831 }
1832 #endif
1833
1834 /* EXTPROTO */
rxvtlib_menubar_expose(rxvtlib * o)1835 void rxvtlib_menubar_expose (rxvtlib *o)
1836 {
1837 #ifdef MENUBAR
1838 menu_t *menu;
1839 int x;
1840
1841 if (!menubar_visible () || o->menuBar.win == 0)
1842 return;
1843
1844 if (o->menubarGC == None) {
1845 /* Create the graphics context */
1846 XGCValues gcvalue;
1847
1848 gcvalue.font = o->TermWin.font->fid;
1849
1850 gcvalue.foreground = (o->Xdepth <= 2 ?
1851 o->PixColors[Color_fg] : o->PixColors[Color_Black]);
1852 o->menubarGC = XCreateGC (o->Xdisplay, o->menuBar.win,
1853 GCForeground | GCFont, &gcvalue);
1854
1855 gcvalue.foreground = o->PixColors[Color_scroll];
1856 o->neutralGC = XCreateGC (o->Xdisplay, o->menuBar.win, GCForeground, &gcvalue);
1857
1858 gcvalue.foreground = o->PixColors[Color_bottomShadow];
1859 o->botShadowGC = XCreateGC (o->Xdisplay, o->menuBar.win,
1860 GCForeground | GCFont, &gcvalue);
1861
1862 gcvalue.foreground = o->PixColors[Color_topShadow];
1863 o->topShadowGC =
1864 XCreateGC (o->Xdisplay, o->menuBar.win, GCForeground, &gcvalue);
1865 }
1866 /* make sure the font is correct */
1867 XSetFont (o->Xdisplay, o->menubarGC, o->TermWin.font->fid);
1868 XSetFont (o->Xdisplay, o->botShadowGC, o->TermWin.font->fid);
1869 XClearWindow (o->Xdisplay, o->menuBar.win);
1870
1871 rxvtlib_menu_hide_all (o);
1872
1873 x = 0;
1874 if (o->CurrentBar != NULL) {
1875 for (menu = o->CurrentBar->head; menu != NULL; menu = menu->next) {
1876 int len = menu->len;
1877
1878 x = (menu->x + menu->len + HSPACE);
1879
1880 #ifdef DEBUG_MENU_LAYOUT
1881 rxvtlib_print_menu_descendants (o, menu);
1882 #endif
1883
1884 if (x >= o->TermWin.ncol)
1885 len = (o->TermWin.ncol - (menu->x + HSPACE));
1886
1887 rxvtlib_drawbox_menubar (o, menu->x, len, +1);
1888
1889 XDrawString (o->Xdisplay,
1890 o->menuBar.win, o->menubarGC,
1891 (Width2Pixel (menu->x) + Width2Pixel (HSPACE) / 2),
1892 menuBar_height () - SHADOW, menu->name, len);
1893
1894 if (x >= o->TermWin.ncol)
1895 break;
1896 }
1897 }
1898 rxvtlib_drawbox_menubar (o, x, o->TermWin.ncol, (o->CurrentBar ? +1 : -1));
1899
1900 /* add the menuBar title, if it exists and there's plenty of room */
1901 o->Arrows_x = 0;
1902 if (x < o->TermWin.ncol) {
1903 const char *str;
1904 int len, ncol = o->TermWin.ncol;
1905 char title[256];
1906
1907 if (x < (ncol - (NARROWS + 1))) {
1908 ncol -= (NARROWS + 1);
1909 o->Arrows_x = Width2Pixel (ncol);
1910 }
1911 rxvtlib_draw_Arrows (o, 0, +1);
1912
1913 str = (o->CurrentBar && o->CurrentBar->title) ? o->CurrentBar->title : "%n-%v";
1914 for (len = 0; str[0] && len < sizeof (title) - 1; str++) {
1915 const char *s = NULL;
1916
1917 switch (str[0]) {
1918 case '%':
1919 str++;
1920 switch (str[0]) {
1921 case 'n':
1922 s = o->rs[Rs_name];
1923 break; /* resource name */
1924 case 'v':
1925 s = VERSION;
1926 break; /* version number */
1927 case '%':
1928 s = "%";
1929 break; /* literal '%' */
1930 }
1931 if (s != NULL)
1932 while (*s && len < sizeof (title) - 1)
1933 title[len++] = *s++;
1934 break;
1935
1936 default:
1937 title[len++] = str[0];
1938 break;
1939 }
1940 }
1941 title[len] = '\0';
1942
1943 ncol -= (x + len + HSPACE);
1944 if (len > 0 && ncol >= 0)
1945 XDrawString (o->Xdisplay,
1946 o->menuBar.win, o->menubarGC,
1947 Width2Pixel (x) + Width2Pixel (ncol + HSPACE) / 2,
1948 menuBar_height () - SHADOW, title, len);
1949 }
1950 #endif
1951 }
1952
1953 /* EXTPROTO */
rxvtlib_menubar_mapping(rxvtlib * o,int map)1954 int rxvtlib_menubar_mapping (rxvtlib *o, int map)
1955 {
1956 #ifdef MENUBAR
1957 int change = 0;
1958
1959 if (map && !menubar_visible ()) {
1960 o->menuBar.state = 1;
1961 if (o->menuBar.win == 0)
1962 return 0;
1963 XMapWindow (o->Xdisplay, o->menuBar.win);
1964 change = 1;
1965 } else if (!map && menubar_visible ()) {
1966 rxvtlib_menubar_expose (o);
1967 o->menuBar.state = 0;
1968 XUnmapWindow (o->Xdisplay, o->menuBar.win);
1969 change = 1;
1970 } else
1971 rxvtlib_menubar_expose (o);
1972
1973 return change;
1974 #else
1975 return 0;
1976 #endif
1977 }
1978
1979 #ifdef MENUBAR
1980 /* INTPROTO */
rxvtlib_menu_select(rxvtlib * o,XButtonEvent * ev)1981 int rxvtlib_menu_select (rxvtlib *o, XButtonEvent * ev)
1982 {
1983 menuitem_t *thisitem, *item = NULL;
1984 int this_y, y;
1985
1986 Window unused_root, unused_child;
1987 int unused_root_x, unused_root_y;
1988 unsigned int unused_mask;
1989
1990 if (o->ActiveMenu == NULL)
1991 return 0;
1992
1993 XQueryPointer (o->Xdisplay, o->ActiveMenu->win,
1994 &unused_root, &unused_child,
1995 &unused_root_x, &unused_root_y,
1996 &(ev->x), &(ev->y), &unused_mask);
1997
1998 if (o->ActiveMenu->parent != NULL && (ev->x < 0 || ev->y < 0)) {
1999 rxvtlib_menu_hide (o);
2000 return 1;
2001 }
2002 /* determine the menu item corresponding to the Y index */
2003 y = SHADOW;
2004 if (ev->x >= 0 && ev->x <= (o->ActiveMenu->w - SHADOW)) {
2005 for (item = o->ActiveMenu->head; item != NULL; item = item->next) {
2006 int h = HEIGHT_TEXT + 2 * SHADOW;
2007
2008 if (isSeparator (item->name))
2009 h = HEIGHT_SEPARATOR;
2010 else if (ev->y >= y && ev->y < (y + h))
2011 break;
2012 y += h;
2013 }
2014 }
2015 if (item == NULL && ev->type == ButtonRelease) {
2016 rxvtlib_menu_hide_all (o);
2017 return 0;
2018 }
2019 thisitem = item;
2020 this_y = y - SHADOW;
2021
2022 /* erase the last item */
2023 if (o->ActiveMenu->item != NULL) {
2024 if (o->ActiveMenu->item != thisitem) {
2025 for (y = 0, item = o->ActiveMenu->head;
2026 item != NULL; item = item->next) {
2027 int h;
2028
2029 if (isSeparator (item->name))
2030 h = HEIGHT_SEPARATOR;
2031 else if (item == o->ActiveMenu->item) {
2032 /* erase old menuitem */
2033 rxvtlib_drawbox_menuitem (o, y, 0); /* No Shadow */
2034 if (item->entry.type == MenuSubMenu)
2035 rxvtlib_drawtriangle (o, o->ActiveMenu->w, y, +1);
2036 break;
2037 } else
2038 h = HEIGHT_TEXT + 2 * SHADOW;
2039 y += h;
2040 }
2041 } else {
2042 switch (ev->type) {
2043 case ButtonRelease:
2044 switch (item->entry.type) {
2045 case MenuLabel:
2046 case MenuSubMenu:
2047 rxvtlib_menu_hide_all (o);
2048 break;
2049
2050 case MenuAction:
2051 case MenuTerminalAction:
2052 rxvtlib_drawbox_menuitem (o, this_y, -1);
2053 /*
2054 * use select for timing
2055 * remove menu before sending keys to the application
2056 */
2057 {
2058 struct timeval tv;
2059
2060 tv.tv_sec = 0;
2061 tv.tv_usec = MENU_DELAY_USEC;
2062 select (0, NULL, NULL, NULL, &tv);
2063 }
2064 rxvtlib_menu_hide_all (o);
2065 #ifndef DEBUG_MENU
2066 rxvtlib_action_dispatch (o, &(item->entry.action));
2067 #else /* DEBUG_MENU */
2068 fprintf (stderr, "%s: %s\n", item->name,
2069 item->entry.action.str);
2070 #endif /* DEBUG_MENU */
2071 break;
2072 }
2073 break;
2074
2075 default:
2076 if (item->entry.type == MenuSubMenu)
2077 goto DoMenu;
2078 break;
2079 }
2080 return 0;
2081 }
2082 }
2083 DoMenu:
2084 o->ActiveMenu->item = thisitem;
2085 y = this_y;
2086 if (thisitem != NULL) {
2087 item = o->ActiveMenu->item;
2088 if (item->entry.type != MenuLabel)
2089 rxvtlib_drawbox_menuitem (o, y, +1);
2090 if (item->entry.type == MenuSubMenu) {
2091 int x;
2092
2093 rxvtlib_drawtriangle (o, o->ActiveMenu->w, y, -1);
2094
2095 x = ev->x + (o->ActiveMenu->parent ?
2096 o->ActiveMenu->x : Width2Pixel (o->ActiveMenu->x));
2097
2098 if (x >= item->entry.submenu.menu->x) {
2099 o->ActiveMenu = item->entry.submenu.menu;
2100 rxvtlib_menu_show (o);
2101 return 1;
2102 }
2103 }
2104 }
2105 return 0;
2106 }
2107 #endif
2108
2109 #ifdef MENUBAR
2110 /* INTPROTO */
rxvtlib_menubar_select(rxvtlib * o,XButtonEvent * ev)2111 void rxvtlib_menubar_select (rxvtlib *o, XButtonEvent * ev)
2112 {
2113 menu_t *menu = NULL;
2114
2115 /* determine the pulldown menu corresponding to the X index */
2116 if (ev->y >= 0 && ev->y <= menuBar_height () && o->CurrentBar != NULL) {
2117 for (menu = o->CurrentBar->head; menu != NULL; menu = menu->next) {
2118 int x = Width2Pixel (menu->x);
2119 int w = Width2Pixel (menu->len + HSPACE);
2120
2121 if ((ev->x >= x && ev->x < x + w))
2122 break;
2123 }
2124 }
2125 switch (ev->type) {
2126 case ButtonRelease:
2127 rxvtlib_menu_hide_all (o);
2128 break;
2129
2130 case ButtonPress:
2131 if (menu == NULL && o->Arrows_x && ev->x >= o->Arrows_x) {
2132 int i;
2133
2134 for (i = 0; i < NARROWS; i++) {
2135 if (ev->x >= (o->Arrows_x + (Width2Pixel (4 * i + i)) / 4)
2136 && ev->x < (o->Arrows_x + (Width2Pixel (4 * i + i + 4)) / 4)) {
2137 rxvtlib_draw_Arrows (o, o->Arrows[i].name, -1);
2138 /*
2139 * use select for timing
2140 */
2141 {
2142 struct timeval tv;
2143
2144 tv.tv_sec = 0;
2145 tv.tv_usec = MENU_DELAY_USEC;
2146 select (0, NULL, NULL, NULL, &tv);
2147 }
2148 rxvtlib_draw_Arrows (o, o->Arrows[i].name, +1);
2149 #ifdef DEBUG_MENUARROWS
2150 fprintf (stderr, "'%c': ", o->Arrows[i].name);
2151
2152 if (o->CurrentBar == NULL
2153 || (o->CurrentBar->arrows[i].type != MenuAction
2154 && o->CurrentBar->arrows[i].type !=
2155 MenuTerminalAction)) {
2156 if (o->Arrows[i].str != NULL && o->Arrows[i].str[0])
2157 fprintf (stderr, "(default) \\033%s\n",
2158 &(o->Arrows[i].str[2]));
2159 } else {
2160 fprintf (stderr, "%s\n", o->CurrentBar->arrows[i].str);
2161 }
2162 #else /* DEBUG_MENUARROWS */
2163 if (o->CurrentBar == NULL
2164 || rxvtlib_action_dispatch (o, &(o->CurrentBar->arrows[i]))) {
2165 if (o->Arrows[i].str != NULL && o->Arrows[i].str[0] != 0)
2166 rxvtlib_tt_write (o, o->Arrows[i].str + 1, o->Arrows[i].str[0]);
2167 }
2168 #endif /* DEBUG_MENUARROWS */
2169 return;
2170 }
2171 }
2172 }
2173 /* FALLTHROUGH */
2174
2175 default:
2176 /*
2177 * press menubar or move to a new entry
2178 */
2179 if (menu != NULL && menu != o->ActiveMenu) {
2180 rxvtlib_menu_hide_all (o); /* pop down old menu */
2181 o->ActiveMenu = menu;
2182 rxvtlib_menu_show (o); /* pop up new menu */
2183 }
2184 break;
2185 }
2186 }
2187 #endif
2188
2189 /*
2190 * general dispatch routine,
2191 * it would be nice to have `sticky' menus
2192 */
2193 /* EXTPROTO */
rxvtlib_menubar_control(rxvtlib * o,XButtonEvent * ev)2194 void rxvtlib_menubar_control (rxvtlib *o, XButtonEvent * ev)
2195 {
2196 #ifdef MENUBAR
2197 switch (ev->type) {
2198 case ButtonPress:
2199 if (ev->button == Button1)
2200 rxvtlib_menubar_select (o, ev);
2201 break;
2202
2203 case ButtonRelease:
2204 if (ev->button == Button1)
2205 rxvtlib_menu_select (o, ev);
2206 break;
2207
2208 case MotionNotify:
2209 while (XCheckTypedWindowEvent (o->Xdisplay, o->TermWin.parent[0],
2210 MotionNotify, (XEvent *) ev)) ;
2211
2212 if (o->ActiveMenu)
2213 while (rxvtlib_menu_select (o, ev)) ;
2214 else
2215 ev->y = -1;
2216 if (ev->y < 0) {
2217 Window unused_root, unused_child;
2218 int unused_root_x, unused_root_y;
2219 unsigned int unused_mask;
2220
2221 XQueryPointer (o->Xdisplay, o->menuBar.win,
2222 &unused_root, &unused_child,
2223 &unused_root_x, &unused_root_y,
2224 &(ev->x), &(ev->y), &unused_mask);
2225 rxvtlib_menubar_select (o, ev);
2226 }
2227 break;
2228 }
2229 #endif
2230 }
2231
2232 /* EXTPROTO */
rxvtlib_map_menuBar(rxvtlib * o,int map)2233 void rxvtlib_map_menuBar (rxvtlib *o, int map)
2234 {
2235 #ifdef MENUBAR
2236 if (rxvtlib_menubar_mapping (o, map))
2237 rxvtlib_resize_all_windows (o);
2238 #endif
2239 }
2240
2241 /* EXTPROTO */
rxvtlib_create_menuBar(rxvtlib * o,Cursor cursor)2242 void rxvtlib_create_menuBar (rxvtlib *o, Cursor cursor)
2243 {
2244 #ifdef MENUBAR
2245 /* menuBar: size doesn't matter */
2246 o->menuBar.win = XCreateSimpleWindow (o->Xdisplay, o->TermWin.parent[0],
2247 0, 0,
2248 1, 1,
2249 0,
2250 o->PixColors[Color_fg],
2251 o->PixColors[Color_scroll]);
2252 XDefineCursor (o->Xdisplay, o->menuBar.win, cursor);
2253 XSelectInput (o->Xdisplay, o->menuBar.win,
2254 (ExposureMask | ButtonPressMask | ButtonReleaseMask |
2255 Button1MotionMask));
2256
2257 #endif
2258 }
2259
2260 /* EXTPROTO */
rxvtlib_Resize_menuBar(rxvtlib * o,int x,int y,unsigned int width,unsigned int height)2261 void rxvtlib_Resize_menuBar (rxvtlib *o, int x, int y, unsigned int width,
2262 unsigned int height)
2263 {
2264 #ifdef MENUBAR
2265 XMoveResizeWindow (o->Xdisplay, o->menuBar.win, x, y, width, height);
2266 #endif
2267 }
2268
2269 /*----------------------- end-of-file (C source) -----------------------*/
2270