CTWM
Loading...
Searching...
No Matches
/usr/src/RPM/BUILD/ctwm-4.1.0/menus.c
Go to the documentation of this file.
1/*
2 * Copyright 1988 by Evans & Sutherland Computer Corporation,
3 * Salt Lake City, Utah
4 * Portions Copyright 1989 by the Massachusetts Institute of Technology
5 * Cambridge, Massachusetts
6 *
7 * Copyright 1992 Claude Lecommandeur.
8 */
9
10/***********************************************************************
11 *
12 * $XConsortium: menus.c,v 1.186 91/07/17 13:58:00 dave Exp $
13 *
14 * twm menu code
15 *
16 * 17-Nov-87 Thomas E. LaStrange File created
17 *
18 * Do the necessary modification to be integrated in ctwm.
19 * Can no longer be used for the standard twm.
20 *
21 * 22-April-92 Claude Lecommandeur.
22 *
23 *
24 ***********************************************************************/
25
26#include "ctwm.h"
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <strings.h>
32
33#include "add_window.h"
34#include "colormaps.h"
35#include "drawing.h"
36#include "events.h"
37#include "functions.h"
38#include "functions_defs.h"
39#include "gram.tab.h"
40#include "iconmgr.h"
41#include "icons_builtin.h"
42#include "icons.h"
43#include "image.h"
44#include "list.h"
45#include "occupation.h"
46#include "otp.h"
47#include "screen.h"
48#ifdef SOUNDS
49# include "sound.h"
50#endif
51#include "util.h"
52#include "vscreen.h"
53#include "win_iconify.h"
54#include "win_resize.h"
55#include "win_utils.h"
56#include "workspace_manager.h"
57
58MenuRoot *ActiveMenu = NULL; /* the active menu */
59MenuItem *ActiveItem = NULL; /* the active menu item */
62
63/* Should probably move, since nothing in this file uses anymore */
66
67int MenuDepth = 0; /* number of menus up */
68static struct {
69 int x;
70 int y;
72static bool addingdefaults = false;
73
74
75
76static void Paint3DEntry(MenuRoot *mr, MenuItem *mi, bool exposure);
77static void PaintNormalEntry(MenuRoot *mr, MenuItem *mi, bool exposure);
78static void DestroyMenu(MenuRoot *menu);
79
80
81#define SHADOWWIDTH 5 /* in pixels */
82#define ENTRY_SPACING 4
83
84
85/***********************************************************************
86 *
87 * Procedure:
88 * AddFuncKey - add a function key to the list
89 *
90 * Inputs:
91 * name - the name of the key
92 * cont - the context to look for the key press in
93 * nmods - modifier keys that need to be pressed
94 * func - the function to perform
95 * win_name- the window name (if any)
96 * action - the action string associated with the function (if any)
97 *
98 ***********************************************************************
99 */
100
101bool
102AddFuncKey(char *name, int cont, int nmods, int func,
103 MenuRoot *menu, char *win_name, char *action)
104{
105 FuncKey *tmp;
106 KeySym keysym = NoSymbol;
107 KeyCode keycode = 0;
108
109 /*
110 * Don't let a 0 keycode go through, since that means AnyKey to the
111 * XGrabKey call in GrabKeys(). Conditionalize on dpy to handle
112 * special cases where we don't have a server to talk to.
113 */
114 keysym = XStringToKeysym(name);
115 if(dpy) {
116 keycode = XKeysymToKeycode(dpy, keysym);
117 }
118 if(keysym == NoSymbol || (dpy && keycode == 0)) {
119 fprintf(stderr, "ignore %s key binding (%s)\n", name,
120 keysym == NoSymbol
121 ? "key symbol not found"
122 : "key code not found");
123 return false;
124 }
125
126 /* see if there already is a key defined for this context */
127 for(tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) {
128 if(tmp->keysym == keysym &&
129 tmp->cont == cont &&
130 tmp->mods == nmods) {
131 break;
132 }
133 }
134
135 if(tmp == NULL) {
136 tmp = malloc(sizeof(FuncKey));
137 tmp->next = Scr->FuncKeyRoot.next;
138 Scr->FuncKeyRoot.next = tmp;
139 }
140
141 tmp->name = name;
142 tmp->keysym = keysym;
143 tmp->keycode = keycode;
144 tmp->cont = cont;
145 tmp->mods = nmods;
146 tmp->func = func;
147 tmp->menu = menu;
148 tmp->win_name = win_name;
149 tmp->action = action;
150
151 return true;
152}
153
154/***********************************************************************
155 *
156 * Procedure:
157 * AddFuncButton - add a function button to the list
158 *
159 * Inputs:
160 * num - the num of the button
161 * cont - the context to look for the key press in
162 * nmods - modifier keys that need to be pressed
163 * func - the function to perform
164 * menu - the menu (if any)
165 * item - the menu item (if any)
166 *
167 ***********************************************************************
168 */
169
170void
171AddFuncButton(int num, int cont, int nmods, int func,
172 MenuRoot *menu, MenuItem *item)
173{
175
176 /* Find existing def for this button/context/modifier if any */
177 for(tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) {
178 if((tmp->num == num) && (tmp->cont == cont) && (tmp->mods == nmods)) {
179 break;
180 }
181 }
182
183 /*
184 * If it's already set, and we're addingdefault (i.e., called from
185 * AddDefaultFuncButtons()), just return. This lets us cram on
186 * fallback mappings, without worrying about overriding user choices.
187 */
188 if(tmp && addingdefaults) {
189 return;
190 }
191
192 /* No mapping yet; create a shell */
193 if(tmp == NULL) {
194 tmp = malloc(sizeof(FuncButton));
195 tmp->next = Scr->FuncButtonRoot.next;
196 Scr->FuncButtonRoot.next = tmp;
197 }
198
199 /* Set the new details */
200 tmp->num = num;
201 tmp->cont = cont;
202 tmp->mods = nmods;
203 tmp->func = func;
204 tmp->menu = menu;
205 tmp->item = item;
206
207 return;
208}
209
210
211/*
212 * AddDefaultFuncButtons - attach default bindings so that naive users
213 * don't get messed up if they provide a minimal twmrc.
214 *
215 * This used to be in add_window.c, and maybe fits better in
216 * decorations_init.c (only place it's called) now, but is currently here
217 * so addingdefaults is in scope.
218 *
219 * XXX Probably better to adjust things so we can do that job _without_
220 * the magic global var...
221 */
222void
224{
225 addingdefaults = true;
226
227#define SETDEF(btn, ctx, func) AddFuncButton(btn, ctx, 0, func, NULL, NULL)
231
235#undef SETDEF
236
237 addingdefaults = false;
238}
239
240
241void
243{
244 if(Scr->use3Dmenus) {
246 }
247 else {
249 }
250 if(mi->state) {
251 mr->lastactive = mi;
252 }
253}
254
255static void
257{
258 int y_offset;
259 int text_y;
260 GC gc;
262 XmbTextExtents(Scr->MenuFont.font_set, mi->item, mi->strlen,
264
265 y_offset = mi->item_num * Scr->EntryHeight + Scr->MenuShadowDepth;
266 text_y = y_offset + (Scr->EntryHeight - logical_rect.height) / 2
267 - logical_rect.y;
268
269 if(mi->func != F_TITLE) {
270 int x, y;
271
272 gc = Scr->NormalGC;
273 if(mi->state) {
274 Draw3DBorder(mr->w, Scr->MenuShadowDepth, y_offset,
275 mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight, 1,
276 mi->highlight, off, true, false);
277 FB(mi->highlight.fore, mi->highlight.back);
278 XmbDrawImageString(dpy, mr->w, Scr->MenuFont.font_set, gc,
279 mi->x + Scr->MenuShadowDepth, text_y, mi->item, mi->strlen);
280 }
281 else {
282 if(mi->user_colors || !exposure) {
283 XSetForeground(dpy, gc, mi->normal.back);
284 XFillRectangle(dpy, mr->w, gc,
285 Scr->MenuShadowDepth, y_offset,
286 mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight);
287 FB(mi->normal.fore, mi->normal.back);
288 }
289 else {
290 gc = Scr->MenuGC;
291 }
292 XmbDrawImageString(dpy, mr->w, Scr->MenuFont.font_set, gc,
293 mi->x + Scr->MenuShadowDepth, text_y,
294 mi->item, mi->strlen);
295 if(mi->separated) {
296 FB(Scr->MenuC.shadd, Scr->MenuC.shadc);
297 XDrawLine(dpy, mr->w, Scr->NormalGC,
298 Scr->MenuShadowDepth,
299 y_offset + Scr->EntryHeight - 2,
300 mr->width - Scr->MenuShadowDepth,
301 y_offset + Scr->EntryHeight - 2);
302 FB(Scr->MenuC.shadc, Scr->MenuC.shadd);
303 XDrawLine(dpy, mr->w, Scr->NormalGC,
304 Scr->MenuShadowDepth,
305 y_offset + Scr->EntryHeight - 1,
306 mr->width - Scr->MenuShadowDepth,
307 y_offset + Scr->EntryHeight - 1);
308 }
309 }
310
311 if(mi->func == F_MENU) {
312 /* create the pull right pixmap if needed */
313 if(Scr->pullPm == None) {
314 Scr->pullPm = Create3DMenuIcon(Scr->EntryHeight - ENTRY_SPACING, &Scr->pullW,
315 &Scr->pullH, Scr->MenuC);
316 }
317 x = mr->width - Scr->pullW - Scr->MenuShadowDepth - 2;
318 y = y_offset + ((Scr->EntryHeight - ENTRY_SPACING - Scr->pullH) / 2) + 2;
319 XCopyArea(dpy, Scr->pullPm, mr->w, gc, 0, 0, Scr->pullW, Scr->pullH, x, y);
320 }
321 }
322 else {
323 Draw3DBorder(mr->w, Scr->MenuShadowDepth, y_offset,
324 mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight, 1,
325 mi->normal, off, true, false);
326 FB(mi->normal.fore, mi->normal.back);
327 XmbDrawImageString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC,
328 mi->x + 2, text_y, mi->item, mi->strlen);
329 }
330}
331
332
333static void
335{
336 int y_offset;
337 int text_y;
338 GC gc;
340 XmbTextExtents(Scr->MenuFont.font_set, mi->item, mi->strlen,
342
343 y_offset = mi->item_num * Scr->EntryHeight;
344 text_y = y_offset + (Scr->EntryHeight - logical_rect.height) / 2
345 - logical_rect.y;
346
347 if(mi->func != F_TITLE) {
348 int x, y;
349
350 if(mi->state) {
351 XSetForeground(dpy, Scr->NormalGC, mi->highlight.back);
352
353 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
354 mr->width, Scr->EntryHeight);
355 FB(mi->highlight.fore, mi->highlight.back);
356 XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC,
357 mi->x, text_y, mi->item, mi->strlen);
358
359 gc = Scr->NormalGC;
360 }
361 else {
362 if(mi->user_colors || !exposure) {
363 XSetForeground(dpy, Scr->NormalGC, mi->normal.back);
364
365 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
366 mr->width, Scr->EntryHeight);
367
368 FB(mi->normal.fore, mi->normal.back);
369 gc = Scr->NormalGC;
370 }
371 else {
372 gc = Scr->MenuGC;
373 }
374 XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, gc, mi->x,
375 text_y, mi->item, mi->strlen);
376 if(mi->separated)
377 XDrawLine(dpy, mr->w, gc, 0, y_offset + Scr->EntryHeight - 1,
378 mr->width, y_offset + Scr->EntryHeight - 1);
379 }
380
381 if(mi->func == F_MENU) {
382 /* create the pull right pixmap if needed */
383 if(Scr->pullPm == None) {
384 Scr->pullPm = CreateMenuIcon(Scr->MenuFont.height,
385 &Scr->pullW, &Scr->pullH);
386 }
387 x = mr->width - Scr->pullW - 5;
388 y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2);
389 XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0,
390 Scr->pullW, Scr->pullH, x, y, 1);
391 }
392 }
393 else {
394 int y;
395
396 XSetForeground(dpy, Scr->NormalGC, mi->normal.back);
397
398 /* fill the rectangle with the title background color */
399 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
400 mr->width, Scr->EntryHeight);
401
402 {
403 XSetForeground(dpy, Scr->NormalGC, mi->normal.fore);
404 /* now draw the dividing lines */
405 if(y_offset)
406 XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y_offset,
407 mr->width, y_offset);
408 y = ((mi->item_num + 1) * Scr->EntryHeight) - 1;
409 XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y);
410 }
411
412 FB(mi->normal.fore, mi->normal.back);
413 /* finally render the title */
414 XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC, mi->x,
415 text_y, mi->item, mi->strlen);
416 }
417}
418
420{
421 MenuItem *mi;
422
423 if(Scr->use3Dmenus) {
424 Draw3DBorder(mr->w, 0, 0, mr->width, mr->height,
425 Scr->MenuShadowDepth, Scr->MenuC, off, false, false);
426 }
427 for(mi = mr->first; mi != NULL; mi = mi->next) {
428 int y_offset = mi->item_num * Scr->EntryHeight;
429
430 /* be smart about handling the expose, redraw only the entries
431 * that we need to
432 */
433 if(e->xexpose.y <= (y_offset + Scr->EntryHeight) &&
434 (e->xexpose.y + e->xexpose.height) >= y_offset) {
435 PaintEntry(mr, mi, true);
436 }
437 }
438 XSync(dpy, 0);
439}
440
441
443{
444 static char **actions = NULL;
445 WorkSpace *wlist;
446 char **act;
447
448 if(! Scr->Workspaces) {
449 return;
450 }
451 AddToMenu(Scr->Workspaces, "TWM Workspaces", NULL, NULL, F_TITLE, NULL,
452 NULL);
453 if(! actions) {
454 int count = 0;
455
456 for(wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL;
457 wlist = wlist->next) {
458 count++;
459 }
460 count++;
461 actions = calloc(count, sizeof(char *));
462 act = actions;
463 for(wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL;
464 wlist = wlist->next) {
465 asprintf(act, "WGOTO : %s", wlist->name);
466 act++;
467 }
468 *act = NULL;
469 }
470 act = actions;
471 for(wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL;
472 wlist = wlist->next) {
473 AddToMenu(Scr->Workspaces, wlist->name, *act, Scr->Windows, F_MENU, NULL, NULL);
474 act++;
475 }
476 Scr->Workspaces->pinned = false;
477 MakeMenu(Scr->Workspaces);
478}
479
480static bool fromMenu;
481bool
483{
484 return fromMenu;
485}
486
487void UpdateMenu(void)
488{
489 MenuItem *mi;
490 int i, x, y, x_root, y_root, entry;
491 bool done;
493
494 fromMenu = true;
495
496 while(1) {
497 /* block until there is an event */
505 }
506 if(Event.type == MotionNotify) {
507 /* discard any extra motion events before a release */
508 while(XCheckMaskEvent(dpy,
510 if(Event.type == ButtonRelease) {
511 break;
512 }
513 }
514
515 if(!DispatchEvent()) {
516 continue;
517 }
518
519 if((! ActiveMenu) || Cancel) {
521 fromMenu = false;
522 return;
523 }
524
525 if(Event.type != MotionNotify) {
526 continue;
527 }
528
529 done = false;
531 &x_root, &y_root, &x, &y, &JunkMask);
532
533 /* if we haven't received the enter notify yet, wait */
534 if(!ActiveMenu->entered) {
535 continue;
536 }
537
539
540 if(x < 0 || y < 0 ||
541 x >= ActiveMenu->width || y >= ActiveMenu->height) {
542 if(ActiveItem && ActiveItem->func != F_TITLE) {
543 ActiveItem->state = false;
545 }
547 continue;
548 }
549
550 /* look for the entry that the mouse is in */
551 entry = y / Scr->EntryHeight;
552 for(i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi = mi->next) {
553 if(i == entry) {
554 break;
555 }
556 }
557
558 /* if there is an active item, we might have to turn it off */
559 if(ActiveItem) {
560 /* is the active item the one we are on ? */
562 done = true;
563 }
564
565 /* if we weren't on the active entry, let's turn the old
566 * active one off
567 */
568 if(!done && ActiveItem->func != F_TITLE) {
569 ActiveItem->state = false;
571 }
572 }
573
574 /* if we weren't on the active item, change the active item and turn
575 * it on
576 */
577 if(!done) {
578 ActiveItem = mi;
580 ActiveItem->state = true;
582 }
583 }
584
585 /* now check to see if we were over the arrow of a pull right entry */
586 if(ActiveItem && ActiveItem->func == F_MENU &&
587 ((ActiveMenu->width - x) < (ActiveMenu->width / 3))) {
589 int savex = MenuOrigins[MenuDepth - 1].x;
590 int savey = MenuOrigins[MenuDepth - 1].y;
591
592 if(MenuDepth < MAXMENUDEPTH) {
593 if(ActiveMenu == Scr->Workspaces) {
595 }
597 (savex + (((2 * ActiveMenu->width) / 3) - 1)),
598 (savey + ActiveItem->item_num * Scr->EntryHeight)
599 /*(savey + ActiveItem->item_num * Scr->EntryHeight +
600 (Scr->EntryHeight >> 1))*/, False);
602 }
603 else if(!badItem) {
604 XBell(dpy, 0);
606 }
607
608 /* if the menu did get popped up, unhighlight the active item */
609 if(save != ActiveMenu && ActiveItem->state) {
610 ActiveItem->state = false;
611 PaintEntry(save, ActiveItem, false);
613 }
614 }
615 if(badItem != ActiveItem) {
616 badItem = NULL;
617 }
618 XFlush(dpy);
619 }
620}
621
622
623/***********************************************************************
624 *
625 * Procedure:
626 * NewMenuRoot - create a new menu root
627 *
628 * Returned Value:
629 * (MenuRoot *)
630 *
631 * Inputs:
632 * name - the name of the menu root
633 *
634 ***********************************************************************
635 */
636
638{
639 MenuRoot *tmp;
640
641#define UNUSED_PIXEL ((unsigned long) (~0)) /* more than 24 bits */
642
643 tmp = malloc(sizeof(MenuRoot));
644 tmp->highlight.fore = UNUSED_PIXEL;
645 tmp->highlight.back = UNUSED_PIXEL;
646 tmp->name = name;
647 tmp->prev = NULL;
648 tmp->first = NULL;
649 tmp->last = NULL;
650 tmp->defaultitem = NULL;
651 tmp->items = 0;
652 tmp->width = 0;
653 tmp->mapped = MRM_NEVER;
654 tmp->pull = false;
655 tmp->w = None;
656 tmp->shadow = None;
657 tmp->real_menu = false;
658
659 if(Scr->MenuList == NULL) {
660 Scr->MenuList = tmp;
661 Scr->MenuList->next = NULL;
662 }
663
664 if(Scr->LastMenu == NULL) {
665 Scr->LastMenu = tmp;
666 Scr->LastMenu->next = NULL;
667 }
668 else {
669 Scr->LastMenu->next = tmp;
670 Scr->LastMenu = tmp;
671 Scr->LastMenu->next = NULL;
672 }
673
674 if(strcmp(name, TWM_WINDOWS) == 0) {
675 Scr->Windows = tmp;
676 }
677
678 if(strcmp(name, TWM_ICONS) == 0) {
679 Scr->Icons = tmp;
680 }
681
682 if(strcmp(name, TWM_WORKSPACES) == 0) {
683 Scr->Workspaces = tmp;
684 if(!Scr->Windows) {
686 }
687 }
688 if(strcmp(name, TWM_ALLWINDOWS) == 0) {
689 Scr->AllWindows = tmp;
690 }
691
692 /* Added by dl 2004 */
693 if(strcmp(name, TWM_ALLICONS) == 0) {
694 Scr->AllIcons = tmp;
695 }
696
697 /* Added by Dan Lilliehorn (dl@dl.nu) 2000-02-29 */
698 if(strcmp(name, TWM_KEYS) == 0) {
699 Scr->Keys = tmp;
700 }
701
702 if(strcmp(name, TWM_VISIBLE) == 0) {
703 Scr->Visible = tmp;
704 }
705
706 /* End addition */
707
708 return (tmp);
709}
710
711
712/***********************************************************************
713 *
714 * Procedure:
715 * AddToMenu - add an item to a root menu
716 *
717 * Returned Value:
718 * (MenuItem *)
719 *
720 * Inputs:
721 * menu - pointer to the root menu to add the item
722 * item - the text to appear in the menu
723 * action - the string to possibly execute
724 * sub - the menu root if it is a pull-right entry
725 * func - the numeric function
726 * fore - foreground color string
727 * back - background color string
728 *
729 ***********************************************************************
730 */
731
732MenuItem *AddToMenu(MenuRoot *menu, char *item, char *action,
733 MenuRoot *sub, int func, char *fore, char *back)
734{
735 MenuItem *tmp;
736 int width;
737 char *itemname;
740
741#ifdef DEBUG_MENUS
742 fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
743 item, action, sub, func);
744#endif
745
746 tmp = malloc(sizeof(MenuItem));
747 tmp->root = menu;
748
749 if(menu->first == NULL) {
750 menu->first = tmp;
751 tmp->prev = NULL;
752 }
753 else {
754 menu->last->next = tmp;
755 tmp->prev = menu->last;
756 }
757 menu->last = tmp;
758
759 if((menu == Scr->Workspaces) ||
760 (menu == Scr->Windows) ||
761 (menu == Scr->Icons) ||
762 (menu == Scr->AllWindows) ||
763
764 /* Added by dl 2004 */
765 (menu == Scr->AllIcons) ||
766
767 /* Added by Dan Lillehorn (dl@dl.nu) 2000-02-29 */
768 (menu == Scr->Keys) ||
769 (menu == Scr->Visible)) {
770
771 itemname = item;
772 }
773 else if(*item == '*') {
774 itemname = item + 1;
775 menu->defaultitem = tmp;
776 }
777 else {
778 itemname = item;
779 }
780
781 tmp->item = itemname;
782 tmp->strlen = strlen(itemname);
783 tmp->action = action;
784 tmp->next = NULL;
785 tmp->sub = NULL;
786 tmp->state = false;
787 tmp->func = func;
788 tmp->separated = false;
789
790 if(!Scr->HaveFonts) {
792 }
793
794 if(dpy) {
795 XmbTextExtents(Scr->MenuFont.font_set,
796 itemname, tmp->strlen,
798 width = logical_rect.width;
799 }
800 else {
801 // Fake for non-dpy cases
802 width = 25;
803 }
804
805 if(width <= 0) {
806 width = 1;
807 }
808 if(width > menu->width) {
809 menu->width = width;
810 }
811
812 tmp->user_colors = false;
813 if(Scr->Monochrome == COLOR && fore != NULL) {
814 bool save;
815
816 save = Scr->FirstTime;
817 Scr->FirstTime = true;
818 GetColor(COLOR, &tmp->normal.fore, fore);
819 GetColor(COLOR, &tmp->normal.back, back);
820 if(Scr->use3Dmenus && !Scr->BeNiceToColormap) {
821 GetShadeColors(&tmp->normal);
822 }
823 Scr->FirstTime = save;
824 tmp->user_colors = true;
825 }
826 if(sub != NULL) {
827 tmp->sub = sub;
828 menu->pull = true;
829 }
830 tmp->item_num = menu->items++;
831
832 return (tmp);
833}
834
835
836void MakeMenus(void)
837{
838 MenuRoot *mr;
839
840 for(mr = Scr->MenuList; mr != NULL; mr = mr->next) {
841 if(mr->real_menu == false) {
842 continue;
843 }
844
845 mr->pinned = false;
846 MakeMenu(mr);
847 }
848}
849
850
852{
853 MenuItem *start, *tmp;
854 XColor f1, f2, f3;
855 XColor b1, b2, b3;
857 int fred, fgreen, fblue;
858 int bred, bgreen, bblue;
859 int width, borderwidth;
860 unsigned long valuemask;
862 Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c;
865
866 Scr->EntryHeight = Scr->MenuFont.height + 4;
867
868 /* lets first size the window accordingly */
869 if(mr->mapped == MRM_NEVER) {
870 int max_entry_height = 0;
871
872 if(mr->pull == true) {
873 mr->width += 16 + 10;
874 }
875 width = mr->width + 10;
876 for(MenuItem *cur = mr->first; cur != NULL; cur = cur->next) {
877 XmbTextExtents(Scr->MenuFont.font_set, cur->item, cur->strlen,
880
881 if(cur->func != F_TITLE) {
882 cur->x = 5;
883 }
884 else {
885 cur->x = width - logical_rect.width;
886 cur->x /= 2;
887 }
888 }
889 Scr->EntryHeight = max_entry_height + ENTRY_SPACING;
890 mr->height = mr->items * Scr->EntryHeight;
891 mr->width += 10;
892 if(Scr->use3Dmenus) {
893 mr->width += 2 * Scr->MenuShadowDepth;
894 mr->height += 2 * Scr->MenuShadowDepth;
895 }
896 if(Scr->Shadow && ! mr->pinned) {
897 /*
898 * Make sure that you don't draw into the shadow window or else
899 * the background bits there will get saved
900 */
902 attributes.background_pixel = Scr->MenuShadowColor;
903 attributes.border_pixel = Scr->MenuShadowColor;
904 if(Scr->SaveUnder) {
906 attributes.save_under = True;
907 }
908 mr->shadow = XCreateWindow(dpy, Scr->Root, 0, 0,
909 mr->width,
910 mr->height,
911 0,
916 }
917
919 attributes.background_pixel = Scr->MenuC.back;
920 attributes.border_pixel = Scr->MenuC.fore;
921 if(mr->pinned) {
926 );
927 attributes.cursor = Scr->MenuCursor;
929 }
930 else {
931 attributes.event_mask = (ExposureMask | EnterWindowMask);
932 }
933
934 if(Scr->SaveUnder && ! mr->pinned) {
936 attributes.save_under = True;
937 }
938 if(Scr->BackingStore) {
940 attributes.backing_store = Always;
941 }
942 borderwidth = Scr->use3Dmenus ? 0 : 1;
943 mr->w = XCreateWindow(dpy, Scr->Root, 0, 0, mr->width,
944 mr->height, borderwidth,
948
949
952
953 mr->mapped = MRM_UNMAPPED;
954 }
955
956 if(Scr->use3Dmenus && (Scr->Monochrome == COLOR)
957 && (mr->highlight.back == UNUSED_PIXEL)) {
958 XColor xcol;
959 char colname [32];
960 bool save;
961
962 xcol.pixel = Scr->MenuC.back;
964 sprintf(colname, "#%04x%04x%04x",
965 5 * ((int)xcol.red / 6),
966 5 * ((int)xcol.green / 6),
967 5 * ((int)xcol.blue / 6));
968 save = Scr->FirstTime;
969 Scr->FirstTime = true;
970 GetColor(Scr->Monochrome, &mr->highlight.back, colname);
971 Scr->FirstTime = save;
972 }
973
974 if(Scr->use3Dmenus && (Scr->Monochrome == COLOR)
975 && (mr->highlight.fore == UNUSED_PIXEL)) {
976 XColor xcol;
977 char colname [32];
978 bool save;
979
980 xcol.pixel = Scr->MenuC.fore;
982 sprintf(colname, "#%04x%04x%04x",
983 5 * ((int)xcol.red / 6),
984 5 * ((int)xcol.green / 6),
985 5 * ((int)xcol.blue / 6));
986 save = Scr->FirstTime;
987 Scr->FirstTime = true;
988 GetColor(Scr->Monochrome, &mr->highlight.fore, colname);
989 Scr->FirstTime = save;
990 }
991 if(Scr->use3Dmenus && !Scr->BeNiceToColormap) {
992 GetShadeColors(&mr->highlight);
993 }
994
995 /* get the default colors into the menus */
996 for(tmp = mr->first; tmp != NULL; tmp = tmp->next) {
997 if(!tmp->user_colors) {
998 if(tmp->func != F_TITLE) {
999 tmp->normal.fore = Scr->MenuC.fore;
1000 tmp->normal.back = Scr->MenuC.back;
1001 }
1002 else {
1003 tmp->normal.fore = Scr->MenuTitleC.fore;
1004 tmp->normal.back = Scr->MenuTitleC.back;
1005 }
1006 }
1007
1008 if(mr->highlight.fore != UNUSED_PIXEL) {
1009 tmp->highlight.fore = mr->highlight.fore;
1010 tmp->highlight.back = mr->highlight.back;
1011 }
1012 else {
1013 tmp->highlight.fore = tmp->normal.back;
1014 tmp->highlight.back = tmp->normal.fore;
1015 }
1016 if(Scr->use3Dmenus && !Scr->BeNiceToColormap) {
1017 if(tmp->func != F_TITLE) {
1018 GetShadeColors(&tmp->highlight);
1019 }
1020 else {
1021 GetShadeColors(&tmp->normal);
1022 }
1023 }
1024 }
1025 mr->pmenu = NULL;
1026
1027 if(Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors) {
1028 return;
1029 }
1030
1031 // Do InterpolateMenuColors magic
1032 start = mr->first;
1033 while(1) {
1034 for(; start != NULL; start = start->next) {
1035 if(start->user_colors) {
1036 break;
1037 }
1038 }
1039 if(start == NULL) {
1040 break;
1041 }
1042
1043 MenuItem *end;
1044 for(end = start->next; end != NULL; end = end->next) {
1045 if(end->user_colors) {
1046 break;
1047 }
1048 }
1049 if(end == NULL) {
1050 break;
1051 }
1052
1053 /* we have a start and end to interpolate between */
1054 int num = end->item_num - start->item_num;
1055
1056 f1.pixel = start->normal.fore;
1057 XQueryColor(dpy, cmap, &f1);
1058 f2.pixel = end->normal.fore;
1059 XQueryColor(dpy, cmap, &f2);
1060
1061 b1.pixel = start->normal.back;
1062 XQueryColor(dpy, cmap, &b1);
1063 b2.pixel = end->normal.back;
1064 XQueryColor(dpy, cmap, &b2);
1065
1066 fred = ((int)f2.red - (int)f1.red) / num;
1067 fgreen = ((int)f2.green - (int)f1.green) / num;
1068 fblue = ((int)f2.blue - (int)f1.blue) / num;
1069
1070 bred = ((int)b2.red - (int)b1.red) / num;
1071 bgreen = ((int)b2.green - (int)b1.green) / num;
1072 bblue = ((int)b2.blue - (int)b1.blue) / num;
1073
1074 f3 = f1;
1075 f3.flags = DoRed | DoGreen | DoBlue;
1076
1077 b3 = b1;
1078 b3.flags = DoRed | DoGreen | DoBlue;
1079
1080 start->highlight.back = start->normal.fore;
1081 start->highlight.fore = start->normal.back;
1082 num -= 1;
1083 int i = 0;
1084 MenuItem *cur = start->next;
1085 // XXX Should be impossible to run out of cur's before num's,
1086 // unless the item_num's are wrong (which would break other
1087 // stuff), but add condition to quiet static analysis.
1088 for(; cur != NULL && i < num ; i++, cur = cur->next) {
1089 f3.red += fred;
1090 f3.green += fgreen;
1091 f3.blue += fblue;
1092 save_fore = f3;
1093
1094 b3.red += bred;
1095 b3.green += bgreen;
1096 b3.blue += bblue;
1097 save_back = b3;
1098
1099 XAllocColor(dpy, cmap, &f3);
1100 XAllocColor(dpy, cmap, &b3);
1101 cur->highlight.back = cur->normal.fore = f3.pixel;
1102 cur->highlight.fore = cur->normal.back = b3.pixel;
1103 cur->user_colors = true;
1104
1105 f3 = save_fore;
1106 b3 = save_back;
1107 }
1108 start = end;
1109 start->highlight.back = start->normal.fore;
1110 start->highlight.fore = start->normal.back;
1111 }
1112 return;
1113}
1114
1115
1116/***********************************************************************
1117 *
1118 * Procedure:
1119 * PopUpMenu - pop up a pull down menu
1120 *
1121 * Inputs:
1122 * menu - the root pointer of the menu to pop up
1123 * x, y - location of upper left of menu
1124 * center - whether or not to center horizontally over position
1125 *
1126 ***********************************************************************
1127 */
1128
1129bool
1130PopUpMenu(MenuRoot *menu, int x, int y, bool center)
1131{
1132 int WindowNameCount;
1135 int i;
1136 bool clipped;
1137 if(!menu) {
1138 return false;
1139 }
1140
1142
1143 if((menu == Scr->Windows) ||
1144 (menu == Scr->Icons) ||
1145 (menu == Scr->AllWindows) ||
1146 /* Added by Dan 'dl' Lilliehorn 040607 */
1147 (menu == Scr->AllIcons) ||
1148 /* Added by Dan Lilliehorn (dl@dl.nu) 2000-02-29 */
1149 (menu == Scr->Visible)) {
1151 WorkSpace *ws;
1152 bool all, icons, visible_, allicons; /* visible, allicons:
1153 Added by dl */
1154 int func;
1155
1156 /* this is the twm windows menu, let's go ahead and build it */
1157
1158 all = (menu == Scr->AllWindows);
1159 icons = (menu == Scr->Icons);
1160 visible_ = (menu == Scr->Visible); /* Added by dl */
1161 allicons = (menu == Scr->AllIcons);
1162 DestroyMenu(menu);
1163
1164 menu->first = NULL;
1165 menu->last = NULL;
1166 menu->items = 0;
1167 menu->width = 0;
1168 menu->mapped = MRM_NEVER;
1169 menu->highlight.fore = UNUSED_PIXEL;
1170 menu->highlight.back = UNUSED_PIXEL;
1171 if(menu == Scr->Windows) {
1172 AddToMenu(menu, "TWM Windows", NULL, NULL, F_TITLE, NULL, NULL);
1173 }
1174 else if(menu == Scr->Icons) {
1175 AddToMenu(menu, "TWM Icons", NULL, NULL, F_TITLE, NULL, NULL);
1176 }
1177 else if(menu == Scr->Visible) { /* Added by dl 2000 */
1178 AddToMenu(menu, "TWM Visible", NULL, NULL, F_TITLE, NULL, NULL);
1179 }
1180 else if(menu == Scr->AllIcons) { /* Added by dl 2004 */
1181 AddToMenu(menu, "TWM All Icons", NULL, NULL, F_TITLE, NULL, NULL);
1182 }
1183 else {
1184 AddToMenu(menu, "TWM All Windows", NULL, NULL, F_TITLE, NULL, NULL);
1185 }
1186
1187 ws = NULL;
1188
1189 if(!(all || allicons)
1190 && CurrentSelectedWorkspace && Scr->workSpaceManagerActive) {
1191 for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
1192 if(strcmp(ws->name, CurrentSelectedWorkspace) == 0) {
1193 break;
1194 }
1195 }
1196 }
1197 if(!Scr->currentvs) {
1198 return false;
1199 }
1200 if(!ws) {
1201 ws = Scr->currentvs->wsw->currentwspc;
1202 }
1203
1204 for(tmp_win = Scr->FirstWindow, WindowNameCount = 0;
1205 tmp_win != NULL;
1206 tmp_win = tmp_win->next) {
1207 if(tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) {
1208 continue;
1209 }
1210 if(Scr->ShortAllWindowsMenus && (tmp_win->iswspmgr || tmp_win->isiconmgr)) {
1211 continue;
1212 }
1213
1214 if(!(all || allicons) && !OCCUPY(tmp_win, ws)) {
1215 continue;
1216 }
1217 if(allicons && !tmp_win->isicon) {
1218 continue;
1219 }
1220 if(icons && !tmp_win->isicon) {
1221 continue;
1222 }
1223 if(visible_ && tmp_win->isicon) {
1224 continue; /* added by dl */
1225 }
1227 }
1228
1229 // Hack: always pretend there's at least one window, even if
1230 // there are none; that lets us skip special cases for empty
1231 // lists...
1232 if(WindowNameCount == 0) {
1233 WindowNameCount = 1;
1234 }
1236
1237 WindowNameCount = 0;
1238 for(tmp_win = Scr->FirstWindow;
1239 tmp_win != NULL;
1240 tmp_win = tmp_win->next) {
1241 if(LookInList(Scr->IconMenuDontShow, tmp_win->name, &tmp_win->class)) {
1242 continue;
1243 }
1244
1245 if(tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) {
1246 continue;
1247 }
1248 if(Scr->ShortAllWindowsMenus &&
1249 tmp_win == Scr->currentvs->wsw->twm_win) {
1250 continue;
1251 }
1252 if(Scr->ShortAllWindowsMenus && tmp_win->isiconmgr) {
1253 continue;
1254 }
1255
1256 if(!(all || allicons) && ! OCCUPY(tmp_win, ws)) {
1257 continue;
1258 }
1259 if(allicons && !tmp_win->isicon) {
1260 continue;
1261 }
1262 if(icons && !tmp_win->isicon) {
1263 continue;
1264 }
1265 if(visible_ && tmp_win->isicon) {
1266 continue; /* added by dl */
1267 }
1268 tmp_win2 = tmp_win;
1269
1270 for(i = 0; i < WindowNameCount; i++) {
1271 int compresult;
1272 char *tmpname1, *tmpname2;
1273 tmpname1 = tmp_win2->name;
1274 tmpname2 = WindowNames[i]->name;
1275 if(Scr->CaseSensitive) {
1277 }
1278 else {
1280 }
1281 if(compresult < 0) {
1283 tmp_win2 = WindowNames[i];
1284 WindowNames[i] = tmp_win3;
1285 }
1286 }
1289 }
1291 F_POPUP;
1292 for(i = 0; i < WindowNameCount; i++) {
1293 char *tmpname;
1294 tmpname = WindowNames[i]->name;
1295 AddToMenu(menu, tmpname, (char *)WindowNames[i],
1296 NULL, func, NULL, NULL);
1297 }
1299
1300 menu->pinned = false;
1301 MakeMenu(menu);
1302 }
1303
1304 /* Keys added by dl */
1305
1306 if(menu == Scr->Keys) {
1307 char *oldact = 0;
1308 int oldmod = 0;
1309
1310 DestroyMenu(menu);
1311
1312 menu->first = NULL;
1313 menu->last = NULL;
1314 menu->items = 0;
1315 menu->width = 0;
1316 menu->mapped = MRM_NEVER;
1317 menu->highlight.fore = UNUSED_PIXEL;
1318 menu->highlight.back = UNUSED_PIXEL;
1319
1320 AddToMenu(menu, "Twm Keys", NULL, NULL, F_TITLE, NULL, NULL);
1321
1322 for(const FuncKey *tmpKey = Scr->FuncKeyRoot.next; tmpKey != NULL;
1323 tmpKey = tmpKey->next) {
1324 char *tmpStr;
1325
1326 if(tmpKey->func != F_EXEC) {
1327 continue;
1328 }
1329 if((tmpKey->action == oldact) && (tmpKey->mods == oldmod)) {
1330 continue;
1331 }
1332
1334 if(tmpStr == NULL) {
1335 tmpStr = strdup("(error)");
1336 }
1337
1338 AddToMenu(menu, tmpStr, tmpKey->action, NULL, tmpKey->func, NULL, NULL);
1339 oldact = tmpKey->action;
1340 oldmod = tmpKey->mods;
1341 }
1342 menu->pinned = false;
1343 MakeMenu(menu);
1344 }
1345 if(menu->w == None || menu->items == 0) {
1346 return false;
1347 }
1348
1349 /* Prevent recursively bringing up menus. */
1350 if((!menu->pinned) && (menu->mapped == MRM_MAPPED)) {
1351 return false;
1352 }
1353
1354 /*
1355 * Dynamically set the parent; this allows pull-ups to also be main
1356 * menus, or to be brought up from more than one place.
1357 */
1358 menu->prev = ActiveMenu;
1359
1360 if(menu->pinned) {
1361 ActiveMenu = menu;
1362 menu->mapped = MRM_MAPPED;
1363 menu->entered = true;
1364 MenuOrigins [MenuDepth].x = menu->x;
1365 MenuOrigins [MenuDepth].y = menu->y;
1366 MenuDepth++;
1367
1368 XRaiseWindow(dpy, menu->w);
1369 return true;
1370 }
1371
1372 XGrabPointer(dpy, Scr->Root, True,
1376 Scr->Root,
1377 Scr->MenuCursor, CurrentTime);
1378
1380
1381 ActiveMenu = menu;
1382 menu->mapped = MRM_MAPPED;
1383 menu->entered = false;
1384
1385 if(center) {
1386 x -= (menu->width / 2);
1387 y -= (Scr->EntryHeight / 2); /* sticky menus would be nice here */
1388 }
1389
1390 /*
1391 * clip to screen
1392 */
1393 clipped = ConstrainByLayout(Scr->Layout, -1, &x, menu->width, &y, menu->height);
1394 MenuOrigins[MenuDepth].x = x;
1395 MenuOrigins[MenuDepth].y = y;
1396 MenuDepth++;
1397
1398
1399 /*
1400 * Position and display the menu, and its shadow if it has one. We
1401 * start by positioning and raising (above everything else on screen)
1402 * the shadow. Then position the menu itself, raise it up above
1403 * that, and map it. Then map the shadow; doing that after raising
1404 * and mapping the menu avoids spending time drawing the bulk of the
1405 * window which the menu covers up anyway.
1406 */
1407 if(Scr->Shadow) {
1409 XRaiseWindow(dpy, menu->shadow);
1410 }
1411
1412 XMoveWindow(dpy, menu->w, x, y);
1413 XMapRaised(dpy, menu->w);
1414
1415 if(Scr->Shadow) {
1416 XMapWindow(dpy, menu->shadow);
1417 }
1418
1419 /* Move mouse pointer if we're supposed to */
1420 if(!Scr->NoWarpToMenuTitle && clipped && center) {
1421 const int xl = x + (menu->width / 2);
1422 const int yt = y + (Scr->EntryHeight / 2);
1423 XWarpPointer(dpy, Scr->Root, Scr->Root, x, y,
1424 menu->width, menu->height, xl, yt);
1425 }
1426
1427
1428 XSync(dpy, 0);
1429 return true;
1430}
1431
1432
1433/***********************************************************************
1434 *
1435 * Procedure:
1436 * PopDownMenu - unhighlight the current menu selection and
1437 * take down the menus
1438 *
1439 ***********************************************************************
1440 */
1441
1442void PopDownMenu(void)
1443{
1444 MenuRoot *tmp;
1445
1446 if(ActiveMenu == NULL) {
1447 return;
1448 }
1449
1450 if(ActiveItem) {
1451 ActiveItem->state = false;
1453 }
1454
1455 for(tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev) {
1456 if(! tmp->pinned) {
1457 HideMenu(tmp);
1458 }
1460 }
1461
1462 XFlush(dpy);
1463 ActiveMenu = NULL;
1464 ActiveItem = NULL;
1465 MenuDepth = 0;
1467 if(Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE
1468 || Context == C_ICON) {
1470 }
1471
1472 return;
1473}
1474
1475
1477{
1478 if(!menu) {
1479 return;
1480 }
1481
1482 if(Scr->Shadow) {
1483 XUnmapWindow(dpy, menu->shadow);
1484 }
1485 XUnmapWindow(dpy, menu->w);
1486 menu->mapped = MRM_UNMAPPED;
1487}
1488
1489/***********************************************************************
1490 *
1491 * Procedure:
1492 * FindMenuRoot - look for a menu root
1493 *
1494 * Returned Value:
1495 * (MenuRoot *) - a pointer to the menu root structure
1496 *
1497 * Inputs:
1498 * name - the name of the menu root
1499 *
1500 ***********************************************************************
1501 */
1502
1504{
1505 MenuRoot *tmp;
1506
1507 for(tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next) {
1508 if(strcmp(name, tmp->name) == 0) {
1509 return (tmp);
1510 }
1511 }
1512 return NULL;
1513}
1514
1515
1516
1517static void DestroyMenu(MenuRoot *menu)
1518{
1519 MenuItem *item;
1520
1521 if(menu->w) {
1524 if(Scr->Shadow) {
1525 XDestroyWindow(dpy, menu->shadow);
1526 }
1527 XDestroyWindow(dpy, menu->w);
1528 }
1529
1530 for(item = menu->first; item;) {
1531 MenuItem *tmp = item;
1532 item = item->next;
1533 free(tmp);
1534 }
1535}
1536
1537
1539{
1540 int XW, YW, newX, newY;
1541 bool cont;
1542 bool newev;
1543 unsigned long event_mask;
1544 XEvent ev;
1545
1546 if(! ActiveMenu) {
1547 return;
1548 }
1549 if(! ActiveMenu->pinned) {
1550 return;
1551 }
1552
1553 XW = eventp->xbutton.x_root - ActiveMenu->x;
1554 YW = eventp->xbutton.y_root - ActiveMenu->y;
1558 None, Scr->MoveCursor, CurrentTime);
1559
1560 newX = ActiveMenu->x;
1561 newY = ActiveMenu->y;
1562 cont = true;
1566 while(cont) {
1567 ev.xbutton.x_root -= Scr->rootx;
1568 ev.xbutton.y_root -= Scr->rooty;
1569 switch(ev.xany.type) {
1570 case ButtonRelease :
1571 cont = false;
1572 case MotionNotify :
1573 if(!cont) {
1574 newev = false;
1576 newev = true;
1577 if(ev.type == ButtonRelease) {
1578 break;
1579 }
1580 }
1581 if(ev.type == ButtonRelease) {
1582 continue;
1583 }
1584 if(newev) {
1585 ev.xbutton.x_root -= Scr->rootx;
1586 ev.xbutton.y_root -= Scr->rooty;
1587 }
1588 }
1589 newX = ev.xbutton.x_root - XW;
1590 newY = ev.xbutton.y_root - YW;
1591 if(Scr->DontMoveOff) {
1594 }
1597 break;
1598 case ButtonPress :
1599 cont = false;
1600 newX = ActiveMenu->x;
1601 newY = ActiveMenu->y;
1602 break;
1603 case Expose:
1604 case NoExpose:
1605 Event = ev;
1606 DispatchEvent();
1608 break;
1609 }
1610 }
1612 if(ev.xany.type == ButtonRelease) {
1613 ButtonPressed = -1;
1614 }
1615 /*XPutBackEvent (dpy, &ev);*/
1617 ActiveMenu->x = newX;
1618 ActiveMenu->y = newY;
1619 MenuOrigins [MenuDepth - 1].x = newX;
1620 MenuOrigins [MenuDepth - 1].y = newY;
1621
1622 return;
1623}
1624
1625
1627{
1628 MenuItem *item;
1629 Window root;
1630 int i, x, y, xl, yt;
1631 unsigned int w, h, bw, d;
1632
1633 for(i = 0, item = menu->first; item != menu->last; item = item->next) {
1634 if(item == menu->defaultitem) {
1635 break;
1636 }
1637 i++;
1638 }
1639 if(!XGetGeometry(dpy, menu->w, &root, &x, &y, &w, &h, &bw, &d)) {
1640 return;
1641 }
1642 xl = x + (menu->width / 2);
1643 yt = y + (i + 0.5) * Scr->EntryHeight;
1644
1645 XWarpPointer(dpy, Scr->Root, Scr->Root,
1646 Event.xbutton.x_root, Event.xbutton.y_root,
1647 menu->width, menu->height, xl, yt);
1648}
1649
1650
1651
1652/**
1653 * Generate up a string representation of a keybinding->action.
1654 * Internally used in generating TwmKeys menu.
1655 */
1656char *
1658{
1659 char *ret;
1660 // S+ C+ 5(Mx+) 5(Ax+)
1661#define MSLEN (2 + 2 + 5 * 3 + 5 * 3)
1662 char modStr[MSLEN + 1];
1663 char *modStrCur = modStr;
1664
1665 // Init
1666 *modStrCur = '\0';
1667
1668 // Check and add prefixes for each modifier
1669#define DO(mask, str) do { \
1670 if(key->mods & mask##Mask) { \
1671 const int tslen = sizeof(str) - 1; \
1672 if((modStrCur - modStr + tslen) >= MSLEN) { \
1673 fprintf(stderr, "BUG: No space to add '%s' " \
1674 "in %s()\n", str, __func__); \
1675 return NULL; \
1676 } \
1677 strcpy(modStrCur, str); \
1678 modStrCur += tslen; \
1679 } \
1680 } while(0)
1681
1682 // Mod1 is Meta (== Alt), so is special and comes first, apart and
1683 // differing from the other more generic ModX's.
1684 DO(Mod1, "M+");
1685
1686 // Shift/Ctrl are normal common bits.
1687 DO(Shift, "S+");
1688 DO(Control, "C+");
1689
1690 // Other Mod's and Alt's are weirder, but possible.
1691 DO(Mod2, "M2+");
1692 DO(Mod3, "M3+");
1693 DO(Mod4, "M4+");
1694 DO(Mod5, "M5+");
1695
1696 DO(Alt1, "A1+");
1697 DO(Alt2, "A2+");
1698 DO(Alt3, "A3+");
1699 DO(Alt4, "A4+");
1700 DO(Alt5, "A5+");
1701
1702 // Overflows for test. Watch out for colliding with X or our *Mask
1703 // defs.
1704 // +1 when combined with above, should be enough
1705#define Over1Mask (1<<30)
1706 DO(Over1, "a");
1707 // Way too big no matter what
1708#define OverAllMask (1<<31)
1709 DO(OverAll, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
1710
1711#undef OverAllMask
1712#undef Over1Mask
1713
1714#undef DO
1715
1716 asprintf(&ret, "[%s%s] %s", modStr, key->name, key->action);
1717 return ret;
1718}
static int PlaceX
Definition add_window.c:82
void UninstallRootColormap(void)
Definition colormaps.c:213
void InstallRootColormap(void)
Definition colormaps.c:173
XContext MenuContext
Definition ctwm_main.c:120
#define OCCUPY(w, b)
Definition ctwm.h:369
Window JunkRoot
Definition ctwm_main.c:142
XContext ScreenContext
Definition ctwm_main.c:121
Display * dpy
Definition ctwm_main.c:84
unsigned int JunkMask
Definition ctwm.h:359
#define C_TITLE
Definition ctwm.h:76
#define C_WINDOW
Definition ctwm.h:75
#define FB(fix_fore, fix_back)
Definition ctwm.h:119
#define C_FRAME
Definition ctwm.h:79
#define C_ICONMGR
Definition ctwm.h:80
Window JunkChild
Definition ctwm.h:357
#define C_ICON
Definition ctwm.h:77
#define Scr
void Draw3DBorder(Window w, int x, int y, int width, int height, int bw, ColorPair cp, ButtonState state, bool fill, bool forcebw)
Definition drawing.c:34
@ off
Definition drawing.h:8
bool Cancel
Definition event_core.c:94
bool DispatchEvent(void)
Definition event_core.c:305
XEvent Event
Definition event_core.c:66
int ButtonPressed
Definition event_core.c:93
int Context
Definition event_core.c:65
Pixmap Create3DMenuIcon(unsigned int height, unsigned int *widthp, unsigned int *heightp, ColorPair cp)
Pixmap CreateMenuIcon(int height, unsigned int *widthp, unsigned int *heightp)
void * LookInList(name_list *list_head, const char *name, XClassHint *class)
Definition list.c:101
void MakeWorkspacesMenu(void)
Definition menus.c:442
static bool addingdefaults
Definition menus.c:72
#define ENTRY_SPACING
Definition menus.c:82
int y
Definition menus.c:70
MenuItem * AddToMenu(MenuRoot *menu, char *item, char *action, MenuRoot *sub, int func, char *fore, char *back)
Definition menus.c:732
void HideMenu(MenuRoot *menu)
Definition menus.c:1476
static bool fromMenu
Definition menus.c:480
#define MSLEN
bool menuFromFrameOrWindowOrTitlebar
Definition menus.c:60
char * mk_twmkeys_entry(const FuncKey *key)
Generate up a string representation of a keybinding->action.
Definition menus.c:1657
#define SHADOWWIDTH
Definition menus.c:81
#define DO(mask, str)
#define SETDEF(btn, ctx, func)
static void DestroyMenu(MenuRoot *menu)
Definition menus.c:1517
bool AddFuncKey(char *name, int cont, int nmods, int func, MenuRoot *menu, char *win_name, char *action)
Definition menus.c:102
void PaintMenu(MenuRoot *mr, XEvent *e)
Definition menus.c:419
MenuRoot * FindMenuRoot(char *name)
Definition menus.c:1503
#define UNUSED_PIXEL
void MakeMenus(void)
Definition menus.c:836
int x
Definition menus.c:69
static void PaintNormalEntry(MenuRoot *mr, MenuItem *mi, bool exposure)
Definition menus.c:334
void AddDefaultFuncButtons(void)
Definition menus.c:223
void MoveMenu(XEvent *eventp)
Definition menus.c:1538
MenuItem * ActiveItem
Definition menus.c:59
char * CurrentSelectedWorkspace
Definition menus.c:61
static void Paint3DEntry(MenuRoot *mr, MenuItem *mi, bool exposure)
Definition menus.c:256
MenuRoot * ActiveMenu
Definition menus.c:58
MenuRoot * NewMenuRoot(char *name)
Definition menus.c:637
void WarpCursorToDefaultEntry(MenuRoot *menu)
Definition menus.c:1626
bool PopUpMenu(MenuRoot *menu, int x, int y, bool center)
Definition menus.c:1130
void PaintEntry(MenuRoot *mr, MenuItem *mi, bool exposure)
Definition menus.c:242
void MakeMenu(MenuRoot *mr)
Definition menus.c:851
static struct @0 MenuOrigins[10/*max number of nested menus */]
void PopDownMenu(void)
Definition menus.c:1442
bool AlternateContext
Definition menus.c:65
int MenuDepth
Definition menus.c:67
int AlternateKeymap
Definition menus.c:64
void AddFuncButton(int num, int cont, int nmods, int func, MenuRoot *menu, MenuItem *item)
Definition menus.c:171
bool cur_fromMenu(void)
Definition menus.c:482
void UpdateMenu(void)
Definition menus.c:487
#define MAXMENUDEPTH
Definition menus.h:128
#define TWM_WORKSPACES
Definition menus.h:23
#define TWM_ALLICONS
Definition menus.h:27
#define TWM_KEYS
Definition menus.h:31
#define TWM_ICONS
Definition menus.h:22
#define TWM_VISIBLE
Definition menus.h:32
#define TWM_ALLWINDOWS
Definition menus.h:24
@ MRM_NEVER
Definition menus.h:42
@ MRM_UNMAPPED
Definition menus.h:43
@ MRM_MAPPED
Definition menus.h:44
#define TWM_WINDOWS
Definition menus.h:21
MenuRoot * root
Definition parse_yacc.c:26
int cont
Definition parse_yacc.c:28
Pixel back
Definition ctwm.h:141
Pixel fore
Definition ctwm.h:141
struct FuncKey * next
Definition menus.h:108
bool state
Definition menus.h:60
struct MenuItem * next
Definition menus.h:49
short func
Definition menus.h:59
short item_num
Definition menus.h:57
struct MenuItem * prev
Definition menus.h:50
char * item
Definition menus.h:53
struct MenuRoot * sub
Definition menus.h:51
short x
Definition menus.h:84
short height
Definition menus.h:78
struct MenuItem * last
Definition menus.h:68
Window shadow
Definition menus.h:75
short width
Definition menus.h:79
struct MenuItem * defaultitem
Definition menus.h:70
struct MenuRoot * prev
Definition menus.h:71
bool entered
Definition menus.h:82
struct MenuItem * first
Definition menus.h:67
short items
Definition menus.h:80
short y
Definition menus.h:84
MRMapState mapped
Definition menus.h:77
Window w
Definition menus.h:74
ColorPair highlight
Definition menus.h:76
bool pull
Definition menus.h:81
bool pinned
Definition menus.h:85
Info and control for every X Window we take over.
struct WorkSpace * next
void GetColor(int kind, Pixel *what, const char *name)
Get info from the server about a given color.
Definition util.c:154
void GetShadeColors(ColorPair *cp)
Try and create a 'shaded' version of a color for prettier UI.
Definition util.c:245
void CreateFonts(ScreenInfo *scr)
Load up our various defined fonts.
Definition util.c:383
#define MAX(x, y)
Definition util.h:36
bool ConstrainByLayout(RLayout *layout, int move_off_res, int *left, int width, int *top, int height)
Definition win_utils.c:760
void ConstrainByBorders1(int *left, int width, int *top, int height)
Definition win_utils.c:818