ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/menubar.C
(Generate patch)

Comparing rxvt-unicode/src/menubar.C (file contents):
Revision 1.4 by pcg, Sat Jan 31 00:20:21 2004 UTC vs.
Revision 1.6 by pcg, Sun Feb 1 01:34:41 2004 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines