~ctwm/ctwm/trunk

304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1
/*
554.1.10 by Matthew Fuller
Pull out the simple cases of long-form twm+Claude copyright/license
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.
11 by Claude Lecommandeur
CTWM version 3.2p1
8
 */
1 by Claude Lecommandeur
CTWM version 1.1
9
10
/***********************************************************************
11
 *
12
 * $XConsortium: menus.c,v 1.186 91/07/17 13:58:00 dave Exp $
13
 *
14
 * twm menu code
15
 *
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
16
 * 17-Nov-87 Thomas E. LaStrange                File created
1 by Claude Lecommandeur
CTWM version 1.1
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
395.1.1 by Matthew Fuller
Move ctwm.h to always be included first.
26
#include "ctwm.h"
27
1 by Claude Lecommandeur
CTWM version 1.1
28
#include <stdio.h>
491.1.14 by Matthew Fuller
Remove incorrect pre-ANSI potential override prototypes for malloc()
29
#include <stdlib.h>
324.1.5 by Matthew Fuller
Another place to use strcasecmp() instead of Xmu stuff.
30
#include <string.h>
31
#include <strings.h>
13 by Claude Lecommandeur
CTWM version 3.3.1
32
539.1.8 by Matthew Fuller
Sort includes.
33
#include "add_window.h"
34
#include "colormaps.h"
35
#include "drawing.h"
1 by Claude Lecommandeur
CTWM version 1.1
36
#include "events.h"
539.1.8 by Matthew Fuller
Sort includes.
37
#include "functions.h"
528.1.63 by Matthew Fuller
#if 0 out the old function #define's in parse.h, and add
38
#include "functions_defs.h"
539.1.8 by Matthew Fuller
Sort includes.
39
#include "gram.tab.h"
518.1.24 by Matthew Fuller
iconmgr.h isn't needed for add_window.h. Pull it out and add it to
40
#include "iconmgr.h"
503.1.54 by Matthew Fuller
Split funcs building some of our UI icons into their own file out of
41
#include "icons_builtin.h"
14 by Claude Lecommandeur
CTWM version 3.4
42
#include "icons.h"
479.1.27 by Matthew Fuller
Move the remaining image bits out of util.h and into image.h, and add
43
#include "image.h"
524.1.5 by Matthew Fuller
Pull list.h out of screen.h and #include it in the places that need
44
#include "list.h"
539.1.8 by Matthew Fuller
Sort includes.
45
#include "occupation.h"
46
#include "otp.h"
492.2.120 by Matthew Fuller
Do another round of #include cleanups.
47
#include "screen.h"
539.1.8 by Matthew Fuller
Sort includes.
48
#ifdef SOUNDS
49
#  include "sound.h"
50
#endif
51
#include "util.h"
524.1.3 by Matthew Fuller
Pull vscreen.h out of screen.h and #include it directly in the files
52
#include "vscreen.h"
520.1.2 by Matthew Fuller
Bust functions related to iconifying/deiconifying windows out of
53
#include "win_iconify.h"
538.1.5 by Matthew Fuller
And rename over resize.h.
54
#include "win_resize.h"
523.1.5 by Matthew Fuller
GetTwmWindow() is pretty obvious _utils fodder.
55
#include "win_utils.h"
510.1.9 by Matthew Fuller
Only stuff left in workmgr is the actual workspace manager stuff.
56
#include "workspace_manager.h"
492.2.33 by Matthew Fuller
Do some more cleanup of headers including headers.
57
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
58
MenuRoot *ActiveMenu = NULL;            /* the active menu */
59
MenuItem *ActiveItem = NULL;            /* the active menu item */
492.2.31 by Matthew Fuller
This var is and is only used as a boolean, so make it a bool holding
60
bool menuFromFrameOrWindowOrTitlebar = false;
11 by Claude Lecommandeur
CTWM version 3.2p1
61
char *CurrentSelectedWorkspace;
482.1.4 by Matthew Fuller
Move some vars around between menus.c and execute_function.c to match
62
63
/* Should probably move, since nothing in this file uses anymore */
12 by Claude Lecommandeur
CTWM version 3.3
64
int AlternateKeymap;
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
65
bool AlternateContext;
1 by Claude Lecommandeur
CTWM version 1.1
66
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
67
int MenuDepth = 0;              /* number of menus up */
1 by Claude Lecommandeur
CTWM version 1.1
68
static struct {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
69
	int x;
70
	int y;
1 by Claude Lecommandeur
CTWM version 1.1
71
} MenuOrigins[MAXMENUDEPTH];
488.1.20 by Matthew Fuller
This isn't something passed into X, so use C99 bool.
72
static bool addingdefaults = false;
1 by Claude Lecommandeur
CTWM version 1.1
73
496.1.11 by Matthew Fuller
Create a local enum for TryToPush_be's directional arg, to stop
74
75
492.2.114 by Matthew Fuller
bool-ify more function args/return values.
76
static void Paint3DEntry(MenuRoot *mr, MenuItem *mi, bool exposure);
77
static void PaintNormalEntry(MenuRoot *mr, MenuItem *mi, bool exposure);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
78
static void DestroyMenu(MenuRoot *menu);
79
80
81
#define SHADOWWIDTH 5                   /* in pixels */
240.1.2 by Rhialto
3 - Selected a number of cleanups from Stefan Monnier
82
#define ENTRY_SPACING 4
21 by Richard Levitte
This constitutes all the changes Claude had done since version 3.6.
83
1 by Claude Lecommandeur
CTWM version 1.1
84
85
/***********************************************************************
86
 *
87
 *  Procedure:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
88
 *      AddFuncKey - add a function key to the list
1 by Claude Lecommandeur
CTWM version 1.1
89
 *
90
 *  Inputs:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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)
1 by Claude Lecommandeur
CTWM version 1.1
97
 *
98
 ***********************************************************************
99
 */
100
492.2.124 by Matthew Fuller
Go ahead and break some function definitions that I've changed anyway.
101
bool
102
AddFuncKey(char *name, int cont, int nmods, int func,
103
           MenuRoot *menu, char *win_name, char *action)
1 by Claude Lecommandeur
CTWM version 1.1
104
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
105
	FuncKey *tmp;
644.2.21 by Matthew Fuller
Adjust this logic to handle lacking dpy for our special cases.
106
	KeySym keysym = NoSymbol;
107
	KeyCode keycode = 0;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
108
109
	/*
110
	 * Don't let a 0 keycode go through, since that means AnyKey to the
644.2.21 by Matthew Fuller
Adjust this logic to handle lacking dpy for our special cases.
111
	 * XGrabKey call in GrabKeys().  Conditionalize on dpy to handle
112
	 * special cases where we don't have a server to talk to.
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
113
	 */
644.2.20 by Matthew Fuller
Extract this logic out of the conditional so it's easier to make some
114
	keysym = XStringToKeysym(name);
644.2.21 by Matthew Fuller
Adjust this logic to handle lacking dpy for our special cases.
115
	if(dpy) {
116
		keycode = XKeysymToKeycode(dpy, keysym);
117
	}
118
	if(keysym == NoSymbol || (dpy && keycode == 0)) {
614.1.29 by Maxime Soulé
Prints a warning if a configuration key binding is not recognized
119
		fprintf(stderr, "ignore %s key binding (%s)\n", name,
120
		        keysym == NoSymbol
121
		        ? "key symbol not found"
122
		        : "key code not found");
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
123
		return false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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) {
491.1.8 by Matthew Fuller
Stop casting return values of [mc]alloc(). void * has existed for 27
136
		tmp = malloc(sizeof(FuncKey));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
151
	return true;
1 by Claude Lecommandeur
CTWM version 1.1
152
}
153
9 by Claude Lecommandeur
CTWM version 3.1
154
/***********************************************************************
155
 *
156
 *  Procedure:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
157
 *      AddFuncButton - add a function button to the list
9 by Claude Lecommandeur
CTWM version 3.1
158
 *
159
 *  Inputs:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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)
9 by Claude Lecommandeur
CTWM version 3.1
166
 *
167
 ***********************************************************************
168
 */
169
488.1.97 by Matthew Fuller
AddFuncButton() only ever returns true, and its return value is never
170
void
171
AddFuncButton(int num, int cont, int nmods, int func,
172
              MenuRoot *menu, MenuItem *item)
9 by Claude Lecommandeur
CTWM version 3.1
173
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
174
	FuncButton *tmp;
175
488.1.95 by Matthew Fuller
Add a little commenting through AddFuncButton, and update comment on
176
	/* Find existing def for this button/context/modifier if any */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
	}
488.1.95 by Matthew Fuller
Add a little commenting through AddFuncButton, and update comment on
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
	 */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
188
	if(tmp && addingdefaults) {
488.1.97 by Matthew Fuller
AddFuncButton() only ever returns true, and its return value is never
189
		return;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
190
	}
191
488.1.95 by Matthew Fuller
Add a little commenting through AddFuncButton, and update comment on
192
	/* No mapping yet; create a shell */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
193
	if(tmp == NULL) {
488.1.96 by Matthew Fuller
As long as I'm in here, don't cast malloc() return.
194
		tmp = malloc(sizeof(FuncButton));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
195
		tmp->next = Scr->FuncButtonRoot.next;
196
		Scr->FuncButtonRoot.next = tmp;
197
	}
198
488.1.95 by Matthew Fuller
Add a little commenting through AddFuncButton, and update comment on
199
	/* Set the new details */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
488.1.97 by Matthew Fuller
AddFuncButton() only ever returns true, and its return value is never
207
	return;
9 by Claude Lecommandeur
CTWM version 3.1
208
}
209
488.1.12 by Matthew Fuller
Move AddDefaultBindings over into menus.c verbatim in preparation.
210
488.1.16 by Matthew Fuller
Improve comment a little and describe why it's here.
211
/*
212
 * AddDefaultFuncButtons - attach default bindings so that naive users
213
 * don't get messed up if they provide a minimal twmrc.
488.1.12 by Matthew Fuller
Move AddDefaultBindings over into menus.c verbatim in preparation.
214
 *
488.1.98 by Matthew Fuller
Tweak comment and split def.
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.
488.1.95 by Matthew Fuller
Add a little commenting through AddFuncButton, and update comment on
218
 *
219
 * XXX Probably better to adjust things so we can do that job _without_
220
 * the magic global var...
488.1.12 by Matthew Fuller
Move AddDefaultBindings over into menus.c verbatim in preparation.
221
 */
488.1.98 by Matthew Fuller
Tweak comment and split def.
222
void
223
AddDefaultFuncButtons(void)
488.1.12 by Matthew Fuller
Move AddDefaultBindings over into menus.c verbatim in preparation.
224
{
488.1.20 by Matthew Fuller
This isn't something passed into X, so use C99 bool.
225
	addingdefaults = true;
488.1.13 by Matthew Fuller
Move setting the addingdefaults flag inside the AddDefault function.
226
488.1.15 by Matthew Fuller
Skip static helper func and just use helper macro. Tweak desc with
227
#define SETDEF(btn, ctx, func) AddFuncButton(btn, ctx, 0, func, NULL, NULL)
228
	SETDEF(Button1, C_TITLE,    F_MOVE);
229
	SETDEF(Button1, C_ICON,     F_ICONIFY);
230
	SETDEF(Button1, C_ICONMGR,  F_ICONIFY);
231
232
	SETDEF(Button2, C_TITLE,    F_RAISELOWER);
233
	SETDEF(Button2, C_ICON,     F_ICONIFY);
234
	SETDEF(Button2, C_ICONMGR,  F_ICONIFY);
235
#undef SETDEF
488.1.13 by Matthew Fuller
Move setting the addingdefaults flag inside the AddDefault function.
236
488.1.20 by Matthew Fuller
This isn't something passed into X, so use C99 bool.
237
	addingdefaults = false;
488.1.12 by Matthew Fuller
Move AddDefaultBindings over into menus.c verbatim in preparation.
238
}
239
240
492.2.114 by Matthew Fuller
bool-ify more function args/return values.
241
void
242
PaintEntry(MenuRoot *mr, MenuItem *mi, bool exposure)
1 by Claude Lecommandeur
CTWM version 1.1
243
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
244
	if(Scr->use3Dmenus) {
245
		Paint3DEntry(mr, mi, exposure);
246
	}
247
	else {
248
		PaintNormalEntry(mr, mi, exposure);
249
	}
250
	if(mi->state) {
251
		mr->lastactive = mi;
252
	}
8 by Claude Lecommandeur
CTWM version 3.0
253
}
254
492.2.114 by Matthew Fuller
bool-ify more function args/return values.
255
static void
256
Paint3DEntry(MenuRoot *mr, MenuItem *mi, bool exposure)
8 by Claude Lecommandeur
CTWM version 3.0
257
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
258
	int y_offset;
259
	int text_y;
260
	GC gc;
261
	XRectangle ink_rect, logical_rect;
262
	XmbTextExtents(Scr->MenuFont.font_set, mi->item, mi->strlen,
263
	               &ink_rect, &logical_rect);
264
265
	y_offset = mi->item_num * Scr->EntryHeight + Scr->MenuShadowDepth;
627 by Matthew Fuller
Make Paint3DEntry() use the results of font-size calculation for the y
266
	text_y = y_offset + (Scr->EntryHeight - logical_rect.height) / 2
267
	         - logical_rect.y;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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,
492.2.113 by Matthew Fuller
boolify Draw3DBorder args.
276
			             mi->highlight, off, true, false);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
		}
8 by Claude Lecommandeur
CTWM version 3.0
321
	}
322
	else {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
323
		Draw3DBorder(mr->w, Scr->MenuShadowDepth, y_offset,
324
		             mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight, 1,
492.2.113 by Matthew Fuller
boolify Draw3DBorder args.
325
		             mi->normal, off, true, false);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
	}
8 by Claude Lecommandeur
CTWM version 3.0
330
}
93 by Richard Levitte
- Convert all functions to use proper prototypes.
331
8 by Claude Lecommandeur
CTWM version 3.0
332
492.2.114 by Matthew Fuller
bool-ify more function args/return values.
333
static void
334
PaintNormalEntry(MenuRoot *mr, MenuItem *mi, bool exposure)
8 by Claude Lecommandeur
CTWM version 3.0
335
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
336
	int y_offset;
337
	int text_y;
338
	GC gc;
339
	XRectangle ink_rect, logical_rect;
340
	XmbTextExtents(Scr->MenuFont.font_set, mi->item, mi->strlen,
341
	               &ink_rect, &logical_rect);
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
		}
1 by Claude Lecommandeur
CTWM version 1.1
392
	}
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
393
	else {
394
		int y;
395
8 by Claude Lecommandeur
CTWM version 3.0
396
		XSetForeground(dpy, Scr->NormalGC, mi->normal.back);
1 by Claude Lecommandeur
CTWM version 1.1
397
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
398
		/* fill the rectangle with the title background color */
1 by Claude Lecommandeur
CTWM version 1.1
399
		XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset,
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
		}
1 by Claude Lecommandeur
CTWM version 1.1
411
17 by Claude Lecommandeur
CTWM version 3.5
412
		FB(mi->normal.fore, mi->normal.back);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
	}
1 by Claude Lecommandeur
CTWM version 1.1
417
}
93 by Richard Levitte
- Convert all functions to use proper prototypes.
418
419
void PaintMenu(MenuRoot *mr, XEvent *e)
1 by Claude Lecommandeur
CTWM version 1.1
420
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
421
	MenuItem *mi;
422
423
	if(Scr->use3Dmenus) {
424
		Draw3DBorder(mr->w, 0, 0, mr->width, mr->height,
492.2.113 by Matthew Fuller
boolify Draw3DBorder args.
425
		             Scr->MenuShadowDepth, Scr->MenuC, off, false, false);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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) {
492.2.114 by Matthew Fuller
bool-ify more function args/return values.
435
			PaintEntry(mr, mi, true);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
436
		}
437
	}
438
	XSync(dpy, 0);
1 by Claude Lecommandeur
CTWM version 1.1
439
}
440
441
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
442
void MakeWorkspacesMenu(void)
93 by Richard Levitte
- Convert all functions to use proper prototypes.
443
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
444
	static char **actions = NULL;
445
	WorkSpace *wlist;
446
	char **act;
447
448
	if(! Scr->Workspaces) {
449
		return;
450
	}
437 by Matthew Fuller
Anyplace looking for a char * will find NULL as acceptable as (char
451
	AddToMenu(Scr->Workspaces, "TWM Workspaces", NULL, NULL, F_TITLE, NULL,
452
	          NULL);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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++;
485 by Matthew Fuller
Minor cleanup in TwmWorkspaces menu building. Use calloc() for
461
		actions = calloc(count, sizeof(char *));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
462
		act = actions;
463
		for(wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL;
464
		                wlist = wlist->next) {
485 by Matthew Fuller
Minor cleanup in TwmWorkspaces menu building. Use calloc() for
465
			asprintf(act, "WGOTO : %s", wlist->name);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
466
			act++;
467
		}
468
		*act = NULL;
469
	}
11 by Claude Lecommandeur
CTWM version 3.2p1
470
	act = actions;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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++;
11 by Claude Lecommandeur
CTWM version 3.2p1
475
	}
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
476
	Scr->Workspaces->pinned = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
477
	MakeMenu(Scr->Workspaces);
11 by Claude Lecommandeur
CTWM version 3.2p1
478
}
479
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
480
static bool fromMenu;
481
bool
691.1.1 by Matthew Fuller
Be explicit about void arguments; current compilers are starting to
482
cur_fromMenu(void)
482.1.1 by Matthew Fuller
Minimal functional break out of ExecuteFunction() and its subsidiary
483
{
484
	return fromMenu;
485
}
1 by Claude Lecommandeur
CTWM version 1.1
486
240.1.2 by Rhialto
3 - Selected a number of cleanups from Stefan Monnier
487
void UpdateMenu(void)
1 by Claude Lecommandeur
CTWM version 1.1
488
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
489
	MenuItem *mi;
490
	int i, x, y, x_root, y_root, entry;
492.2.91 by Matthew Fuller
Track down a bunch more boolean vars, and make them bool.
491
	bool done;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
492
	MenuItem *badItem = NULL;
493
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
494
	fromMenu = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
495
492.2.92 by Matthew Fuller
Convert while(TRUE) into while(1). No semantic change, but it makes
496
	while(1) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
497
		/* block until there is an event */
498
		if(!menuFromFrameOrWindowOrTitlebar) {
499
			XMaskEvent(dpy,
500
			           ButtonPressMask | ButtonReleaseMask |
501
			           KeyPressMask | KeyReleaseMask |
502
			           EnterWindowMask | ExposureMask |
503
			           VisibilityChangeMask | LeaveWindowMask |
504
			           ButtonMotionMask, &Event);
505
		}
506
		if(Event.type == MotionNotify) {
507
			/* discard any extra motion events before a release */
508
			while(XCheckMaskEvent(dpy,
509
			                      ButtonMotionMask | ButtonReleaseMask, &Event))
510
				if(Event.type == ButtonRelease) {
511
					break;
512
				}
513
		}
514
515
		if(!DispatchEvent()) {
516
			continue;
517
		}
518
519
		if((! ActiveMenu) || Cancel) {
492.2.31 by Matthew Fuller
This var is and is only used as a boolean, so make it a bool holding
520
			menuFromFrameOrWindowOrTitlebar = false;
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
521
			fromMenu = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
522
			return;
523
		}
524
525
		if(Event.type != MotionNotify) {
526
			continue;
527
		}
528
492.2.91 by Matthew Fuller
Track down a bunch more boolean vars, and make them bool.
529
		done = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
530
		XQueryPointer(dpy, ActiveMenu->w, &JunkRoot, &JunkChild,
531
		              &x_root, &y_root, &x, &y, &JunkMask);
532
311.1.3 by Matthew Fuller
Eye before ee except after cee.
533
		/* if we haven't received the enter notify yet, wait */
614.1.16 by Maxime Soulé
Useless test
534
		if(!ActiveMenu->entered) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
535
			continue;
536
		}
537
538
		XFindContext(dpy, ActiveMenu->w, ScreenContext, (XPointer *)&Scr);
539
540
		if(x < 0 || y < 0 ||
541
		                x >= ActiveMenu->width || y >= ActiveMenu->height) {
542
			if(ActiveItem && ActiveItem->func != F_TITLE) {
492.2.119 by Matthew Fuller
This 'state' is in practice boolean, so might as well give in and
543
				ActiveItem->state = false;
492.2.114 by Matthew Fuller
bool-ify more function args/return values.
544
				PaintEntry(ActiveMenu, ActiveItem, false);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
545
			}
546
			ActiveItem = NULL;
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 ? */
561
			if(ActiveItem->item_num == entry && ActiveItem->state) {
492.2.91 by Matthew Fuller
Track down a bunch more boolean vars, and make them bool.
562
				done = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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) {
492.2.119 by Matthew Fuller
This 'state' is in practice boolean, so might as well give in and
569
				ActiveItem->state = false;
492.2.114 by Matthew Fuller
bool-ify more function args/return values.
570
				PaintEntry(ActiveMenu, ActiveItem, false);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
579
			if(ActiveItem && ActiveItem->func != F_TITLE && !ActiveItem->state) {
492.2.119 by Matthew Fuller
This 'state' is in practice boolean, so might as well give in and
580
				ActiveItem->state = true;
492.2.114 by Matthew Fuller
bool-ify more function args/return values.
581
				PaintEntry(ActiveMenu, ActiveItem, false);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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))) {
588
			MenuRoot *save = ActiveMenu;
589
			int savex = MenuOrigins[MenuDepth - 1].x;
590
			int savey = MenuOrigins[MenuDepth - 1].y;
591
592
			if(MenuDepth < MAXMENUDEPTH) {
593
				if(ActiveMenu == Scr->Workspaces) {
594
					CurrentSelectedWorkspace = ActiveItem->item;
595
				}
596
				PopUpMenu(ActiveItem->sub,
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);
601
				CurrentSelectedWorkspace = NULL;
602
			}
603
			else if(!badItem) {
604
				XBell(dpy, 0);
605
				badItem = ActiveItem;
606
			}
607
608
			/* if the menu did get popped up, unhighlight the active item */
609
			if(save != ActiveMenu && ActiveItem->state) {
492.2.119 by Matthew Fuller
This 'state' is in practice boolean, so might as well give in and
610
				ActiveItem->state = false;
492.2.114 by Matthew Fuller
bool-ify more function args/return values.
611
				PaintEntry(save, ActiveItem, false);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
612
				ActiveItem = NULL;
613
			}
614
		}
615
		if(badItem != ActiveItem) {
616
			badItem = NULL;
617
		}
618
		XFlush(dpy);
619
	}
1 by Claude Lecommandeur
CTWM version 1.1
620
}
621
622
623
/***********************************************************************
624
 *
625
 *  Procedure:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
626
 *      NewMenuRoot - create a new menu root
1 by Claude Lecommandeur
CTWM version 1.1
627
 *
628
 *  Returned Value:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
629
 *      (MenuRoot *)
1 by Claude Lecommandeur
CTWM version 1.1
630
 *
631
 *  Inputs:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
632
 *      name    - the name of the menu root
1 by Claude Lecommandeur
CTWM version 1.1
633
 *
634
 ***********************************************************************
635
 */
636
93 by Richard Levitte
- Convert all functions to use proper prototypes.
637
MenuRoot *NewMenuRoot(char *name)
1 by Claude Lecommandeur
CTWM version 1.1
638
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
639
	MenuRoot *tmp;
640
641
#define UNUSED_PIXEL ((unsigned long) (~0))     /* more than 24 bits */
642
491.1.8 by Matthew Fuller
Stop casting return values of [mc]alloc(). void * has existed for 27
643
	tmp = malloc(sizeof(MenuRoot));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
497.1.10 by Matthew Fuller
enum-ify MenuRoot.mapped, and leave a comment for future work. This
653
	tmp->mapped = MRM_NEVER;
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
654
	tmp->pull = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
655
	tmp->w = None;
656
	tmp->shadow = None;
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
657
	tmp->real_menu = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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) {
685
			NewMenuRoot(TWM_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);
1 by Claude Lecommandeur
CTWM version 1.1
709
}
710
711
712
/***********************************************************************
713
 *
714
 *  Procedure:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
715
 *      AddToMenu - add an item to a root menu
1 by Claude Lecommandeur
CTWM version 1.1
716
 *
717
 *  Returned Value:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
718
 *      (MenuItem *)
1 by Claude Lecommandeur
CTWM version 1.1
719
 *
720
 *  Inputs:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
1 by Claude Lecommandeur
CTWM version 1.1
728
 *
729
 ***********************************************************************
730
 */
731
93 by Richard Levitte
- Convert all functions to use proper prototypes.
732
MenuItem *AddToMenu(MenuRoot *menu, char *item, char *action,
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
733
                    MenuRoot *sub, int func, char *fore, char *back)
1 by Claude Lecommandeur
CTWM version 1.1
734
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
735
	MenuItem *tmp;
736
	int width;
737
	char *itemname;
738
	XRectangle ink_rect;
739
	XRectangle logical_rect;
1 by Claude Lecommandeur
CTWM version 1.1
740
741
#ifdef DEBUG_MENUS
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
742
	fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n",
743
	        item, action, sub, func);
1 by Claude Lecommandeur
CTWM version 1.1
744
#endif
745
491.1.8 by Matthew Fuller
Stop casting return values of [mc]alloc(). void * has existed for 27
746
	tmp = malloc(sizeof(MenuItem));
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
492.2.119 by Matthew Fuller
This 'state' is in practice boolean, so might as well give in and
786
	tmp->state = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
787
	tmp->func = func;
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
788
	tmp->separated = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
789
790
	if(!Scr->HaveFonts) {
641.1.33 by Matthew Fuller
Pass Scr into CreateFonts() rather than it just going straight to the
791
		CreateFonts(Scr);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
792
	}
793
644.2.45 by Matthew Fuller
One more codepath config loading hits that interacts poorly with
794
	if(dpy) {
795
		XmbTextExtents(Scr->MenuFont.font_set,
796
		               itemname, tmp->strlen,
797
		               &ink_rect, &logical_rect);
798
		width = logical_rect.width;
799
	}
800
	else {
801
		// Fake for non-dpy cases
802
		width = 25;
803
	}
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
804
805
	if(width <= 0) {
806
		width = 1;
807
	}
808
	if(width > menu->width) {
809
		menu->width = width;
810
	}
811
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
812
	tmp->user_colors = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
813
	if(Scr->Monochrome == COLOR && fore != NULL) {
492.2.105 by Matthew Fuller
Switch some temp vars holding Scr->FirstTime over to bool.
814
		bool save;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
815
816
		save = Scr->FirstTime;
492.2.104 by Matthew Fuller
Massive rewrite of various struct Screen config params that are
817
		Scr->FirstTime = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
824
		tmp->user_colors = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
825
	}
826
	if(sub != NULL) {
827
		tmp->sub = sub;
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
828
		menu->pull = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
829
	}
830
	tmp->item_num = menu->items++;
831
832
	return (tmp);
1 by Claude Lecommandeur
CTWM version 1.1
833
}
834
835
93 by Richard Levitte
- Convert all functions to use proper prototypes.
836
void MakeMenus(void)
1 by Claude Lecommandeur
CTWM version 1.1
837
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
838
	MenuRoot *mr;
839
840
	for(mr = Scr->MenuList; mr != NULL; mr = mr->next) {
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
841
		if(mr->real_menu == false) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
842
			continue;
843
		}
844
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
845
		mr->pinned = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
846
		MakeMenu(mr);
847
	}
1 by Claude Lecommandeur
CTWM version 1.1
848
}
849
850
482.1.1 by Matthew Fuller
Minimal functional break out of ExecuteFunction() and its subsidiary
851
void MakeMenu(MenuRoot *mr)
1 by Claude Lecommandeur
CTWM version 1.1
852
{
685.1.23 by Matthew Fuller
Narrow var scope.
853
	MenuItem *start, *tmp;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
854
	XColor f1, f2, f3;
855
	XColor b1, b2, b3;
856
	XColor save_fore, save_back;
857
	int fred, fgreen, fblue;
858
	int bred, bgreen, bblue;
859
	int width, borderwidth;
860
	unsigned long valuemask;
861
	XSetWindowAttributes attributes;
862
	Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c;
863
	XRectangle ink_rect;
864
	XRectangle logical_rect;
865
866
	Scr->EntryHeight = Scr->MenuFont.height + 4;
867
868
	/* lets first size the window accordingly */
497.1.10 by Matthew Fuller
enum-ify MenuRoot.mapped, and leave a comment for future work. This
869
	if(mr->mapped == MRM_NEVER) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
870
		int max_entry_height = 0;
871
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
872
		if(mr->pull == true) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
873
			mr->width += 16 + 10;
874
		}
875
		width = mr->width + 10;
685.1.21 by Matthew Fuller
Narrow the scope of some vars, to make it a little easier to reason
876
		for(MenuItem *cur = mr->first; cur != NULL; cur = cur->next) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
877
			XmbTextExtents(Scr->MenuFont.font_set, cur->item, cur->strlen,
878
			               &ink_rect, &logical_rect);
879
			max_entry_height = MAX(max_entry_height, logical_rect.height);
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
			 */
901
			valuemask = (CWBackPixel | CWBorderPixel);
902
			attributes.background_pixel = Scr->MenuShadowColor;
903
			attributes.border_pixel = Scr->MenuShadowColor;
904
			if(Scr->SaveUnder) {
905
				valuemask |= CWSaveUnder;
906
				attributes.save_under = True;
907
			}
908
			mr->shadow = XCreateWindow(dpy, Scr->Root, 0, 0,
505.1.19 by Matthew Fuller
Remove casts from XCreateWindow() calls. Some of these were probably
909
			                           mr->width,
910
			                           mr->height,
911
			                           0,
912
			                           CopyFromParent,
913
			                           CopyFromParent,
914
			                           CopyFromParent,
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
915
			                           valuemask, &attributes);
916
		}
917
918
		valuemask = (CWBackPixel | CWBorderPixel | CWEventMask);
919
		attributes.background_pixel = Scr->MenuC.back;
920
		attributes.border_pixel = Scr->MenuC.fore;
921
		if(mr->pinned) {
922
			attributes.event_mask = (ExposureMask | EnterWindowMask
923
			                         | LeaveWindowMask | ButtonPressMask
924
			                         | ButtonReleaseMask | PointerMotionMask
925
			                         | ButtonMotionMask
926
			                        );
927
			attributes.cursor = Scr->MenuCursor;
928
			valuemask |= CWCursor;
929
		}
930
		else {
931
			attributes.event_mask = (ExposureMask | EnterWindowMask);
932
		}
933
934
		if(Scr->SaveUnder && ! mr->pinned) {
935
			valuemask |= CWSaveUnder;
936
			attributes.save_under = True;
937
		}
938
		if(Scr->BackingStore) {
939
			valuemask |= CWBackingStore;
940
			attributes.backing_store = Always;
941
		}
942
		borderwidth = Scr->use3Dmenus ? 0 : 1;
505.1.19 by Matthew Fuller
Remove casts from XCreateWindow() calls. Some of these were probably
943
		mr->w = XCreateWindow(dpy, Scr->Root, 0, 0, mr->width,
944
		                      mr->height, borderwidth,
945
		                      CopyFromParent, CopyFromParent,
946
		                      CopyFromParent,
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
947
		                      valuemask, &attributes);
948
949
950
		XSaveContext(dpy, mr->w, MenuContext, (XPointer)mr);
951
		XSaveContext(dpy, mr->w, ScreenContext, (XPointer)Scr);
952
497.1.10 by Matthew Fuller
enum-ify MenuRoot.mapped, and leave a comment for future work. This
953
		mr->mapped = MRM_UNMAPPED;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
954
	}
955
956
	if(Scr->use3Dmenus && (Scr->Monochrome == COLOR)
957
	                && (mr->highlight.back == UNUSED_PIXEL)) {
958
		XColor xcol;
959
		char colname [32];
492.2.105 by Matthew Fuller
Switch some temp vars holding Scr->FirstTime over to bool.
960
		bool save;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
961
962
		xcol.pixel = Scr->MenuC.back;
963
		XQueryColor(dpy, cmap, &xcol);
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;
492.2.104 by Matthew Fuller
Massive rewrite of various struct Screen config params that are
969
		Scr->FirstTime = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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];
492.2.105 by Matthew Fuller
Switch some temp vars holding Scr->FirstTime over to bool.
978
		bool save;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
979
980
		xcol.pixel = Scr->MenuC.fore;
981
		XQueryColor(dpy, cmap, &xcol);
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;
492.2.104 by Matthew Fuller
Massive rewrite of various struct Screen config params that are
987
		Scr->FirstTime = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
685.1.22 by Matthew Fuller
Comment what this whole block is for.
1031
	// Do InterpolateMenuColors magic
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1032
	start = mr->first;
492.2.92 by Matthew Fuller
Convert while(TRUE) into while(1). No semantic change, but it makes
1033
	while(1) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1034
		for(; start != NULL; start = start->next) {
1035
			if(start->user_colors) {
1036
				break;
1037
			}
1038
		}
1039
		if(start == NULL) {
1040
			break;
1041
		}
1042
685.1.23 by Matthew Fuller
Narrow var scope.
1043
		MenuItem *end;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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 */
685.1.21 by Matthew Fuller
Narrow the scope of some vars, to make it a little easier to reason
1054
		int num = end->item_num - start->item_num;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
685.1.24 by Matthew Fuller
Add guard condition that should be impossible to trip in practice, but
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.
685.1.37 by Matthew Fuller
make indent
1088
		for(; cur != NULL && i < num ; i++, cur = cur->next) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
492.2.112 by Matthew Fuller
Missed True->true conversion.
1103
			cur->user_colors = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
	}
240.1.2 by Rhialto
3 - Selected a number of cleanups from Stefan Monnier
1112
	return;
1 by Claude Lecommandeur
CTWM version 1.1
1113
}
1114
1115
1116
/***********************************************************************
1117
 *
1118
 *  Procedure:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1119
 *      PopUpMenu - pop up a pull down menu
1 by Claude Lecommandeur
CTWM version 1.1
1120
 *
1121
 *  Inputs:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
1 by Claude Lecommandeur
CTWM version 1.1
1125
 *
1126
 ***********************************************************************
1127
 */
1128
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
1129
bool
492.2.55 by Matthew Fuller
boolify last PopUpMenu() arg, which cascades to changing some local
1130
PopUpMenu(MenuRoot *menu, int x, int y, bool center)
1 by Claude Lecommandeur
CTWM version 1.1
1131
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1132
	int WindowNameCount;
1133
	TwmWindow **WindowNames;
1134
	TwmWindow *tmp_win2, *tmp_win3;
1135
	int i;
492.2.56 by Matthew Fuller
Convert local vars to bool.
1136
	bool clipped;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1137
	if(!menu) {
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
1138
		return false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1139
	}
1140
1141
	InstallRootColormap();
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)) {
1150
		TwmWindow *tmp_win;
1151
		WorkSpace *ws;
492.2.46 by Matthew Fuller
Convert Boolean's -> bool, plus one int treated as a Boolean.
1152
		bool all, icons, visible_, allicons; /* visible, allicons:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
497.1.10 by Matthew Fuller
enum-ify MenuRoot.mapped, and leave a comment for future work. This
1168
		menu->mapped = MRM_NEVER;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1169
		menu->highlight.fore = UNUSED_PIXEL;
1170
		menu->highlight.back = UNUSED_PIXEL;
1171
		if(menu == Scr->Windows) {
437 by Matthew Fuller
Anyplace looking for a char * will find NULL as acceptable as (char
1172
			AddToMenu(menu, "TWM Windows", NULL, NULL, F_TITLE, NULL, NULL);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1173
		}
1174
		else if(menu == Scr->Icons) {
437 by Matthew Fuller
Anyplace looking for a char * will find NULL as acceptable as (char
1175
			AddToMenu(menu, "TWM Icons", NULL, NULL, F_TITLE, NULL, NULL);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1176
		}
1177
		else if(menu == Scr->Visible) { /* Added by dl 2000 */
437 by Matthew Fuller
Anyplace looking for a char * will find NULL as acceptable as (char
1178
			AddToMenu(menu, "TWM Visible", NULL, NULL, F_TITLE, NULL, NULL);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1179
		}
1180
		else if(menu == Scr->AllIcons) { /* Added by dl 2004 */
437 by Matthew Fuller
Anyplace looking for a char * will find NULL as acceptable as (char
1181
			AddToMenu(menu, "TWM All Icons", NULL, NULL, F_TITLE, NULL, NULL);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1182
		}
1183
		else {
437 by Matthew Fuller
Anyplace looking for a char * will find NULL as acceptable as (char
1184
			AddToMenu(menu, "TWM All Windows", NULL, NULL, F_TITLE, NULL, NULL);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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) {
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
1198
			return false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
			}
492.2.75 by Matthew Fuller
Convert a bunch of boolean flags in the TwmWindow structure
1210
			if(Scr->ShortAllWindowsMenus && (tmp_win->iswspmgr || tmp_win->isiconmgr)) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
			}
1226
			WindowNameCount++;
1227
		}
685.1.20 by Matthew Fuller
Add a little hack to be sure there's always memory here, even in the
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...
685.1.37 by Matthew Fuller
make indent
1232
		if(WindowNameCount == 0) {
685.1.20 by Matthew Fuller
Add a little hack to be sure there's always memory here, even in the
1233
			WindowNameCount = 1;
685.1.37 by Matthew Fuller
make indent
1234
		}
491.1.13 by Matthew Fuller
Replace malloc(num*size) with calloc(num, size) (with order corrected
1235
		WindowNames = calloc(WindowNameCount, sizeof(TwmWindow *));
685.1.20 by Matthew Fuller
Add a little hack to be sure there's always memory here, even in the
1236
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1237
		WindowNameCount = 0;
1238
		for(tmp_win = Scr->FirstWindow;
1239
		                tmp_win != NULL;
1240
		                tmp_win = tmp_win->next) {
563.1.4 by Matthew Fuller
Mechanically translate all these full_name references to name.
1241
			if(LookInList(Scr->IconMenuDontShow, tmp_win->name, &tmp_win->class)) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
			}
492.2.75 by Matthew Fuller
Convert a bunch of boolean flags in the TwmWindow structure
1252
			if(Scr->ShortAllWindowsMenus && tmp_win->isiconmgr) {
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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) {
1276
					compresult = strcmp(tmpname1, tmpname2);
1277
				}
1278
				else {
324.1.5 by Matthew Fuller
Another place to use strcasecmp() instead of Xmu stuff.
1279
					compresult = strcasecmp(tmpname1, tmpname2);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1280
				}
1281
				if(compresult < 0) {
1282
					tmp_win3 = tmp_win2;
1283
					tmp_win2 = WindowNames[i];
1284
					WindowNames[i] = tmp_win3;
1285
				}
1286
			}
1287
			WindowNames[WindowNameCount] = tmp_win2;
1288
			WindowNameCount++;
1289
		}
1290
		func = (all || allicons || CurrentSelectedWorkspace) ? F_WINWARP :
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
		}
1298
		free(WindowNames);
1299
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
1300
		menu->pinned = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
497.1.10 by Matthew Fuller
enum-ify MenuRoot.mapped, and leave a comment for future work. This
1316
		menu->mapped = MRM_NEVER;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1317
		menu->highlight.fore = UNUSED_PIXEL;
1318
		menu->highlight.back = UNUSED_PIXEL;
1319
437 by Matthew Fuller
Anyplace looking for a char * will find NULL as acceptable as (char
1320
		AddToMenu(menu, "Twm Keys", NULL, NULL, F_TITLE, NULL, NULL);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1321
667.1.4 by Matthew Fuller
We can const this, so why not?
1322
		for(const FuncKey *tmpKey = Scr->FuncKeyRoot.next; tmpKey != NULL;
667.1.19 by Matthew Fuller
make indent.
1323
		                tmpKey = tmpKey->next) {
667.1.3 by Matthew Fuller
Pull these vars into the inner scope, since it's the only place that
1324
			char *tmpStr;
1325
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1326
			if(tmpKey->func != F_EXEC) {
1327
				continue;
1328
			}
1329
			if((tmpKey->action == oldact) && (tmpKey->mods == oldmod)) {
1330
				continue;
1331
			}
667.1.5 by Matthew Fuller
Extract this string building into a separate func.
1332
1333
			tmpStr = mk_twmkeys_entry(tmpKey);
667.1.12 by Matthew Fuller
Be a tad more forgiving of NULL here. Nonsense in a weird menu is way
1334
			if(tmpStr == NULL) {
1335
				tmpStr = strdup("(error)");
1336
			}
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1337
491.1.4 by Matthew Fuller
Simplify building the (undocumented) TwmKeys menu by using asprintf()
1338
			AddToMenu(menu, tmpStr, tmpKey->action, NULL, tmpKey->func, NULL, NULL);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1339
			oldact = tmpKey->action;
1340
			oldmod = tmpKey->mods;
1341
		}
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
1342
		menu->pinned = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1343
		MakeMenu(menu);
1344
	}
1345
	if(menu->w == None || menu->items == 0) {
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
1346
		return false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1347
	}
1348
1349
	/* Prevent recursively bringing up menus. */
497.1.10 by Matthew Fuller
enum-ify MenuRoot.mapped, and leave a comment for future work. This
1350
	if((!menu->pinned) && (menu->mapped == MRM_MAPPED)) {
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
1351
		return false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
497.1.10 by Matthew Fuller
enum-ify MenuRoot.mapped, and leave a comment for future work. This
1362
		menu->mapped  = MRM_MAPPED;
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
1363
		menu->entered = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1364
		MenuOrigins [MenuDepth].x = menu->x;
1365
		MenuOrigins [MenuDepth].y = menu->y;
1366
		MenuDepth++;
1367
1368
		XRaiseWindow(dpy, menu->w);
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
1369
		return true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1370
	}
1371
1372
	XGrabPointer(dpy, Scr->Root, True,
1373
	             ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
1374
	             ButtonMotionMask | PointerMotionHintMask,
1375
	             GrabModeAsync, GrabModeAsync,
1376
	             Scr->Root,
1377
	             Scr->MenuCursor, CurrentTime);
1378
1379
	XGrabKeyboard(dpy, Scr->Root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
1380
1381
	ActiveMenu = menu;
497.1.10 by Matthew Fuller
enum-ify MenuRoot.mapped, and leave a comment for future work. This
1382
	menu->mapped = MRM_MAPPED;
492.2.84 by Matthew Fuller
bool-ify booleans in menus.h structs.
1383
	menu->entered = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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
	*/
614.1.2 by Maxime Soulé
Menus are now clipped using layout
1393
	clipped = ConstrainByLayout(Scr->Layout, -1, &x, menu->width, &y, menu->height);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1394
	MenuOrigins[MenuDepth].x = x;
1395
	MenuOrigins[MenuDepth].y = y;
5 by Claude Lecommandeur
CTWM version 2.1
1396
	MenuDepth++;
1397
551.1.3 by Matthew Fuller
Add comments.
1398
1399
	/*
551.1.7 by Matthew Fuller
Collapse these 3 comments on single-ish lines into a longer one on the
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.
551.1.3 by Matthew Fuller
Add comments.
1406
	 */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1407
	if(Scr->Shadow) {
1408
		XMoveWindow(dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH);
1409
		XRaiseWindow(dpy, menu->shadow);
1410
	}
551.1.3 by Matthew Fuller
Add comments.
1411
551.1.2 by Matthew Fuller
Move moving the menu to its new location down below moving the shadow.
1412
	XMoveWindow(dpy, menu->w, x, y);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1413
	XMapRaised(dpy, menu->w);
551.1.3 by Matthew Fuller
Add comments.
1414
551.1.6 by Matthew Fuller
Move mapping the shadow up before warping the pointer. Makes the code
1415
	if(Scr->Shadow) {
1416
		XMapWindow(dpy, menu->shadow);
1417
	}
1418
551.1.3 by Matthew Fuller
Add comments.
1419
	/* Move mouse pointer if we're supposed to */
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1420
	if(!Scr->NoWarpToMenuTitle && clipped && center) {
551.1.4 by Matthew Fuller
Pull these vars into their inner scope.
1421
		const int xl = x + (menu->width      / 2);
1422
		const int yt = y + (Scr->EntryHeight / 2);
551.1.5 by Matthew Fuller
Rewrap.
1423
		XWarpPointer(dpy, Scr->Root, Scr->Root, x, y,
1424
		             menu->width, menu->height, xl, yt);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1425
	}
551.1.3 by Matthew Fuller
Add comments.
1426
1427
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1428
	XSync(dpy, 0);
492.2.54 by Matthew Fuller
bool-ify most of the functions and exported vars from menus.c.
1429
	return true;
1 by Claude Lecommandeur
CTWM version 1.1
1430
}
1431
1432
1433
/***********************************************************************
1434
 *
1435
 *  Procedure:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1436
 *      PopDownMenu - unhighlight the current menu selection and
1437
 *              take down the menus
1 by Claude Lecommandeur
CTWM version 1.1
1438
 *
1439
 ***********************************************************************
1440
 */
1441
240.1.2 by Rhialto
3 - Selected a number of cleanups from Stefan Monnier
1442
void PopDownMenu(void)
1 by Claude Lecommandeur
CTWM version 1.1
1443
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1444
	MenuRoot *tmp;
1445
1446
	if(ActiveMenu == NULL) {
1447
		return;
1448
	}
1449
1450
	if(ActiveItem) {
492.2.119 by Matthew Fuller
This 'state' is in practice boolean, so might as well give in and
1451
		ActiveItem->state = false;
492.2.114 by Matthew Fuller
bool-ify more function args/return values.
1452
		PaintEntry(ActiveMenu, ActiveItem, false);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1453
	}
1454
1455
	for(tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev) {
1456
		if(! tmp->pinned) {
1457
			HideMenu(tmp);
1458
		}
1459
		UninstallRootColormap();
1460
	}
1461
1462
	XFlush(dpy);
1463
	ActiveMenu = NULL;
1464
	ActiveItem = NULL;
1465
	MenuDepth = 0;
1466
	XUngrabKeyboard(dpy, CurrentTime);
1467
	if(Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE
1468
	                || Context == C_ICON) {
492.2.31 by Matthew Fuller
This var is and is only used as a boolean, so make it a bool holding
1469
		menuFromFrameOrWindowOrTitlebar = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1470
	}
1471
240.1.2 by Rhialto
3 - Selected a number of cleanups from Stefan Monnier
1472
	return;
1 by Claude Lecommandeur
CTWM version 1.1
1473
}
1474
1475
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1476
void HideMenu(MenuRoot *menu)
8 by Claude Lecommandeur
CTWM version 3.0
1477
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1478
	if(!menu) {
1479
		return;
1480
	}
8 by Claude Lecommandeur
CTWM version 3.0
1481
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1482
	if(Scr->Shadow) {
1483
		XUnmapWindow(dpy, menu->shadow);
1484
	}
1485
	XUnmapWindow(dpy, menu->w);
497.1.10 by Matthew Fuller
enum-ify MenuRoot.mapped, and leave a comment for future work. This
1486
	menu->mapped = MRM_UNMAPPED;
8 by Claude Lecommandeur
CTWM version 3.0
1487
}
1488
1 by Claude Lecommandeur
CTWM version 1.1
1489
/***********************************************************************
1490
 *
1491
 *  Procedure:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1492
 *      FindMenuRoot - look for a menu root
1 by Claude Lecommandeur
CTWM version 1.1
1493
 *
1494
 *  Returned Value:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1495
 *      (MenuRoot *)  - a pointer to the menu root structure
1 by Claude Lecommandeur
CTWM version 1.1
1496
 *
1497
 *  Inputs:
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1498
 *      name    - the name of the menu root
1 by Claude Lecommandeur
CTWM version 1.1
1499
 *
1500
 ***********************************************************************
1501
 */
1502
93 by Richard Levitte
- Convert all functions to use proper prototypes.
1503
MenuRoot *FindMenuRoot(char *name)
1 by Claude Lecommandeur
CTWM version 1.1
1504
{
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1505
	MenuRoot *tmp;
1 by Claude Lecommandeur
CTWM version 1.1
1506
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
1 by Claude Lecommandeur
CTWM version 1.1
1513
}
1514
1515
1516
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1517
static void DestroyMenu(MenuRoot *menu)
1518
{
1519
	MenuItem *item;
1520
1521
	if(menu->w) {
1522
		XDeleteContext(dpy, menu->w, MenuContext);
1523
		XDeleteContext(dpy, menu->w, ScreenContext);
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;
491.1.11 by Matthew Fuller
Stop casting arg to free(), especially to char *.
1533
		free(tmp);
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1534
	}
1 by Claude Lecommandeur
CTWM version 1.1
1535
}
1536
1537
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1538
void MoveMenu(XEvent *eventp)
1539
{
492.2.91 by Matthew Fuller
Track down a bunch more boolean vars, and make them bool.
1540
	int    XW, YW, newX, newY;
1541
	bool   cont;
492.2.56 by Matthew Fuller
Convert local vars to bool.
1542
	bool   newev;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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;
1555
	XGrabPointer(dpy, ActiveMenu->w, True,
1556
	             ButtonPressMask  | ButtonReleaseMask | ButtonMotionMask,
1557
	             GrabModeAsync, GrabModeAsync,
1558
	             None, Scr->MoveCursor, CurrentTime);
1559
1560
	newX = ActiveMenu->x;
1561
	newY = ActiveMenu->y;
492.2.91 by Matthew Fuller
Track down a bunch more boolean vars, and make them bool.
1562
	cont = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1563
	event_mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask |
1564
	             ExposureMask;
1565
	XMaskEvent(dpy, event_mask, &ev);
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 :
492.2.91 by Matthew Fuller
Track down a bunch more boolean vars, and make them bool.
1571
				cont = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1572
			case MotionNotify :
1573
				if(!cont) {
492.2.56 by Matthew Fuller
Convert local vars to bool.
1574
					newev = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1575
					while(XCheckMaskEvent(dpy, ButtonMotionMask | ButtonReleaseMask, &ev)) {
492.2.56 by Matthew Fuller
Convert local vars to bool.
1576
						newev = true;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
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) {
1592
					ConstrainByBorders1(&newX, ActiveMenu->width,
1593
					                    &newY, ActiveMenu->height);
1594
				}
1595
				XMoveWindow(dpy, ActiveMenu->w, newX, newY);
1596
				XMaskEvent(dpy, event_mask, &ev);
1597
				break;
1598
			case ButtonPress :
492.2.91 by Matthew Fuller
Track down a bunch more boolean vars, and make them bool.
1599
				cont = false;
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1600
				newX = ActiveMenu->x;
1601
				newY = ActiveMenu->y;
1602
				break;
1603
			case Expose:
1604
			case NoExpose:
1605
				Event = ev;
1606
				DispatchEvent();
1607
				XMaskEvent(dpy, event_mask, &ev);
1608
				break;
1609
		}
1610
	}
1611
	XUngrabPointer(dpy, CurrentTime);
1612
	if(ev.xany.type == ButtonRelease) {
1613
		ButtonPressed = -1;
1614
	}
1615
	/*XPutBackEvent (dpy, &ev);*/
1616
	XMoveWindow(dpy, ActiveMenu->w, newX, newY);
1617
	ActiveMenu->x = newX;
1618
	ActiveMenu->y = newY;
1619
	MenuOrigins [MenuDepth - 1].x = newX;
1620
	MenuOrigins [MenuDepth - 1].y = newY;
1621
1622
	return;
5 by Claude Lecommandeur
CTWM version 2.1
1623
}
1624
21 by Richard Levitte
This constitutes all the changes Claude had done since version 3.6.
1625
304.1.2 by Matthew Fuller
Run 'make indent' to reindent the world.
1626
void WarpCursorToDefaultEntry(MenuRoot *menu)
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);
14 by Claude Lecommandeur
CTWM version 3.4
1648
}
21 by Richard Levitte
This constitutes all the changes Claude had done since version 3.6.
1649
667.1.5 by Matthew Fuller
Extract this string building into a separate func.
1650
1651
1652
/**
1653
 * Generate up a string representation of a keybinding->action.
1654
 * Internally used in generating TwmKeys menu.
1655
 */
1656
char *
1657
mk_twmkeys_entry(const FuncKey *key)
1658
{
667.1.18 by Matthew Fuller
Improve var name a bit.
1659
	char *ret;
667.1.9 by Matthew Fuller
Add some bounds checking to be sure we don't accidentally overflow
1660
	//         S+  C+  5(Mx+)  5(Ax+)
1661
#define MSLEN (2 + 2 + 5 * 3 + 5 * 3)
1662
	char modStr[MSLEN + 1];
667.1.7 by Matthew Fuller
Macro-ize this so the common bits don't obscure the individual cases.
1663
	char *modStrCur = modStr;
667.1.5 by Matthew Fuller
Extract this string building into a separate func.
1664
667.1.7 by Matthew Fuller
Macro-ize this so the common bits don't obscure the individual cases.
1665
	// Init
667.1.5 by Matthew Fuller
Extract this string building into a separate func.
1666
	*modStrCur = '\0';
667.1.7 by Matthew Fuller
Macro-ize this so the common bits don't obscure the individual cases.
1667
1668
	// Check and add prefixes for each modifier
1669
#define DO(mask, str) do { \
667.1.19 by Matthew Fuller
make indent.
1670
                if(key->mods & mask##Mask) { \
1671
                        const int tslen = sizeof(str) - 1; \
1672
                        if((modStrCur - modStr + tslen) >= MSLEN) { \
667.1.20 by Matthew Fuller
Rewrap now over-long lines.
1673
                                fprintf(stderr, "BUG: No space to add '%s' " \
1674
                                                "in %s()\n", str, __func__); \
667.1.19 by Matthew Fuller
make indent.
1675
                                return NULL; \
1676
                        } \
1677
                        strcpy(modStrCur, str); \
1678
                        modStrCur += tslen; \
1679
                } \
1680
        } while(0)
667.1.7 by Matthew Fuller
Macro-ize this so the common bits don't obscure the individual cases.
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
667.1.21 by Matthew Fuller
Add some x-ref comments to warn of future collisions.
1702
	// Overflows for test.  Watch out for colliding with X or our *Mask
1703
	// defs.
667.1.16 by Matthew Fuller
Test overflowing by just 1 additive on everything, as well as
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");
667.1.17 by Matthew Fuller
Correct #undef's.
1710
1711
#undef OverAllMask
1712
#undef Over1Mask
667.1.15 by Matthew Fuller
Add a magic hatch in the code to overflow all the things, and test
1713
667.1.7 by Matthew Fuller
Macro-ize this so the common bits don't obscure the individual cases.
1714
#undef DO
667.1.5 by Matthew Fuller
Extract this string building into a separate func.
1715
667.1.18 by Matthew Fuller
Improve var name a bit.
1716
	asprintf(&ret, "[%s%s] %s", modStr, key->name, key->action);
1717
	return ret;
667.1.5 by Matthew Fuller
Extract this string building into a separate func.
1718
}