~ctwm/ctwm/trunk

535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
1
/*
2
 * Misc function implementation
3
 *
4
 * These are things that either don't fit neatly into another category,
5
 * or fit into a category too small to be worth making individual files
6
 * for.
7
 */
8
9
#include "ctwm.h"
10
11
#include <stdlib.h>
12
13
#include "animate.h"
648.1.1 by Matthew Fuller
Extract the funcs relating to shutting down ctwm ('restart' is a kind
14
#include "ctwm_shutdown.h"
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
15
#include "functions.h"
16
#include "functions_defs.h"
17
#include "functions_internal.h"
18
#include "icons.h"
19
#include "otp.h"
20
#include "screen.h"
535.1.65 by Matthew Fuller
These sound handling funcs are real, so move them into functions_misc.
21
#ifdef SOUNDS
22
#include "sound.h"
23
#endif
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
24
#include "util.h"
25
#include "win_iconify.h"
700.1.6 by Matthew Fuller
ifdef away the include too.
26
#ifdef WINBOX
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
27
#include "windowbox.h"
700.1.6 by Matthew Fuller
ifdef away the include too.
28
#endif
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
29
#include "workspace_utils.h"
30
31
#include "ext/repl_str.h"
32
33
34
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
35
/*
36
 * Animation-related
37
 */
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
38
DFHANDLER(startanimation)
39
{
40
	StartAnimation();
41
}
42
43
DFHANDLER(stopanimation)
44
{
45
	StopAnimation();
46
}
47
48
DFHANDLER(speedupanimation)
49
{
50
	ModifyAnimationSpeed(1);
51
}
52
53
DFHANDLER(slowdownanimation)
54
{
55
	ModifyAnimationSpeed(-1);
56
}
57
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
58
59
60
/*
61
 * Menu-related
62
 */
63
DFHANDLER(menu)
64
{
598.1.14 by Matthew Fuller
Add a big comment to the f.menu handler, describing how it's actually
65
	/*
66
	 * n.b.: The f.menu handler is all kinds of magic; it's actually
67
	 * completely unrelated to pulling up the menu.
68
	 *
69
	 * When a button/key binding invokes f.menu to open up a menu, that's
70
	 * actually handled in the KeyPress or ButtonPress handlers by
71
	 * calling do{_key,}_menu().  When we descend into a submenu, that's
72
	 * handled in KeyPress handler for keyboard navigation when we hit
73
	 * the Right arrow, or inside the
74
	 * event loop recapture in UpdateMenu() for mouse navigation when we
75
	 * move it to the right side of the menu entry.
76
	 *
77
	 * This handler is only used by "invoking" a menu item; releasing the
78
	 * mouse button on the left side without moving right to open out the
79
	 * submenu, or hitting the Enter key.  All it does is immediately
80
	 * invoke the default entry, if there is one.
81
	 */
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
82
	if(action && ! strncmp(action, "WGOTO : ", 8)) {
83
		GotoWorkSpaceByName(/* XXXXX */ Scr->currentvs,
84
		                                ((char *)action) + 8);
85
	}
86
	else {
87
		MenuItem *item;
88
89
		item = ActiveItem;
90
		while(item && item->sub) {
91
			if(!item->sub->defaultitem) {
92
				break;
93
			}
94
			if(item->sub->defaultitem->func != F_MENU) {
95
				break;
96
			}
97
			item = item->sub->defaultitem;
98
		}
99
		if(item && item->sub && item->sub->defaultitem) {
100
			ExecuteFunction(item->sub->defaultitem->func,
101
			                item->sub->defaultitem->action,
102
			                w, tmp_win, eventp, context, pulldown);
103
		}
104
	}
105
}
106
107
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
108
DFHANDLER(pin)
109
{
110
	if(! ActiveMenu) {
111
		return;
112
	}
113
	if(ActiveMenu->pinned) {
114
		XUnmapWindow(dpy, ActiveMenu->w);
115
		ActiveMenu->mapped = MRM_UNMAPPED;
116
	}
117
	else {
118
		XWindowAttributes attr;
119
		MenuRoot *menu;
120
121
		if(ActiveMenu->pmenu == NULL) {
122
			menu  = malloc(sizeof(MenuRoot));
123
			*menu = *ActiveMenu;
124
			menu->pinned = true;
125
			menu->mapped = MRM_NEVER;
126
			menu->width -= 10;
127
			if(menu->pull) {
128
				menu->width -= 16 + 10;
129
			}
130
			MakeMenu(menu);
131
			ActiveMenu->pmenu = menu;
132
		}
133
		else {
134
			menu = ActiveMenu->pmenu;
135
		}
136
		if(menu->mapped == MRM_MAPPED) {
137
			return;
138
		}
139
		XGetWindowAttributes(dpy, ActiveMenu->w, &attr);
140
		menu->x = attr.x;
141
		menu->y = attr.y;
142
		XMoveWindow(dpy, menu->w, menu->x, menu->y);
143
		XMapRaised(dpy, menu->w);
144
		menu->mapped = MRM_MAPPED;
145
	}
146
	PopDownMenu();
147
}
148
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
149
150
151
/*
152
 * Alternate keymaps/contexts
153
 */
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
154
DFHANDLER(altkeymap)
155
{
156
	int alt, stat_;
157
158
	if(! action) {
159
		return;
160
	}
161
	stat_ = sscanf(action, "%d", &alt);
162
	if(stat_ != 1) {
163
		return;
164
	}
165
	if((alt < 1) || (alt > 5)) {
166
		return;
167
	}
168
	AlternateKeymap = Alt1Mask << (alt - 1);
169
	XGrabPointer(dpy, Scr->Root, True, ButtonPressMask | ButtonReleaseMask,
170
	             GrabModeAsync, GrabModeAsync,
171
	             Scr->Root, Scr->AlterCursor, CurrentTime);
172
	func_reset_cursor = false;  // Leave special cursor alone
173
	XGrabKeyboard(dpy, Scr->Root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
174
	return;
175
}
176
177
DFHANDLER(altcontext)
178
{
179
	AlternateContext = true;
180
	XGrabPointer(dpy, Scr->Root, False, ButtonPressMask | ButtonReleaseMask,
181
	             GrabModeAsync, GrabModeAsync,
182
	             Scr->Root, Scr->AlterCursor, CurrentTime);
183
	func_reset_cursor = false;  // Leave special cursor alone
184
	XGrabKeyboard(dpy, Scr->Root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
185
	return;
186
}
187
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
188
189
190
/*
191
 * A few trivial ctwm-control-ish meta-functions
192
 */
193
DFHANDLER(quit)
194
{
648.1.19 by Matthew Fuller
Done() -> DoShutdown(). Imperative form is more descriptive, and it's
195
	DoShutdown();
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
196
}
197
198
DFHANDLER(restart)
199
{
200
	DoRestart(eventp->xbutton.time);
201
}
202
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
203
DFHANDLER(beep)
204
{
205
	XBell(dpy, 0);
206
}
207
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
208
DFHANDLER(trace)
209
{
210
	DebugTrace(action);
211
}
212
213
214
700.1.5 by Matthew Fuller
Hide f.fittocontent implementation behind ifdefs.
215
#ifdef WINBOX
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
216
/*
217
 * Special windowbox-related
218
 */
219
DFHANDLER(fittocontent)
220
{
221
	if(!tmp_win->iswinbox) {
222
		XBell(dpy, 0);
223
		return;
224
	}
225
	fittocontent(tmp_win);
226
}
700.1.5 by Matthew Fuller
Hide f.fittocontent implementation behind ifdefs.
227
#endif
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
228
229
230
231
/*
232
 * A few things that are sorta windows/icons related, but don't really
233
 * fit with the window-targetted things in functions_win.
234
 */
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
235
DFHANDLER(showbackground)
236
{
237
	ShowBackground(Scr->currentvs, -1);
238
}
239
240
DFHANDLER(raiseicons)
241
{
242
	for(TwmWindow *t = Scr->FirstWindow; t != NULL; t = t->next) {
243
		if(t->icon && t->icon->w) {
244
			OtpRaise(t, IconWin);
245
		}
246
	}
247
}
248
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
249
DFHANDLER(rescuewindows)
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
250
{
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
251
	RescueWindows();
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
252
}
253
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
254
255
256
/*
257
 * Despite the name, this is more like 'gotoworkspace' than the other
258
 * 'warpto*' funcs, as it's just about switching your view, not anything
259
 * going to a window.
260
 */
539.1.16 by Matthew Fuller
None of these return values are used, so just void-ify the func.
261
static void
539.1.15 by Matthew Fuller
WarpToScreen() isn't menu related, and is only used as a backend for
262
WarpToScreen(int n, int inc)
263
{
264
	Window dumwin;
265
	int x, y, dumint;
266
	unsigned int dummask;
267
	ScreenInfo *newscr = NULL;
268
269
	while(!newscr) {
270
		/* wrap around */
271
		if(n < 0) {
272
			n = NumScreens - 1;
273
		}
274
		else if(n >= NumScreens) {
275
			n = 0;
276
		}
277
278
		newscr = ScreenList[n];
279
		if(!newscr) {                   /* make sure screen is managed */
280
			if(inc) {                   /* walk around the list */
281
				n += inc;
282
				continue;
283
			}
284
			fprintf(stderr, "%s:  unable to warp to unmanaged screen %d\n",
285
			        ProgramName, n);
286
			XBell(dpy, 0);
539.1.16 by Matthew Fuller
None of these return values are used, so just void-ify the func.
287
			return;
539.1.15 by Matthew Fuller
WarpToScreen() isn't menu related, and is only used as a backend for
288
		}
289
	}
290
291
	if(Scr->screen == n) {
539.1.16 by Matthew Fuller
None of these return values are used, so just void-ify the func.
292
		return;        /* already on that screen */
539.1.15 by Matthew Fuller
WarpToScreen() isn't menu related, and is only used as a backend for
293
	}
294
295
	PreviousScreen = Scr->screen;
296
	XQueryPointer(dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
297
	              &dumint, &dumint, &dummask);
298
299
	XWarpPointer(dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
300
	Scr = newscr;
539.1.16 by Matthew Fuller
None of these return values are used, so just void-ify the func.
301
	return;
539.1.15 by Matthew Fuller
WarpToScreen() isn't menu related, and is only used as a backend for
302
}
303
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
304
DFHANDLER(warptoscreen)
305
{
306
	if(strcmp(action, WARPSCREEN_NEXT) == 0) {
307
		WarpToScreen(Scr->screen + 1, 1);
308
	}
309
	else if(strcmp(action, WARPSCREEN_PREV) == 0) {
310
		WarpToScreen(Scr->screen - 1, -1);
311
	}
312
	else if(strcmp(action, WARPSCREEN_BACK) == 0) {
313
		WarpToScreen(PreviousScreen, 0);
314
	}
315
	else {
316
		WarpToScreen(atoi(action), 0);
317
	}
318
}
319
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
320
321
322
/*
535.1.65 by Matthew Fuller
These sound handling funcs are real, so move them into functions_misc.
323
 * Sound-related
324
 */
325
#ifdef SOUNDS
326
DFHANDLER(togglesound)
327
{
328
	toggle_sound();
329
}
535.1.67 by Matthew Fuller
De-staticize.
330
535.1.65 by Matthew Fuller
These sound handling funcs are real, so move them into functions_misc.
331
DFHANDLER(rereadsounds)
332
{
333
	reread_sounds();
334
}
335
#endif
336
337
338
339
/*
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
340
 * And executing an external program
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
341
 */
535.1.60 by Matthew Fuller
Rearrange/sectionalize functions_misc.
342
static void Execute(const char *_s);
343
344
DFHANDLER(exec)
345
{
346
	PopDownMenu();
347
	if(!Scr->NoGrabServer) {
348
		XUngrabServer(dpy);
349
		XSync(dpy, 0);
350
	}
351
	XUngrabPointer(dpy, CurrentTime);
352
	XSync(dpy, 0);
353
	Execute(action);
354
}
355
356
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
357
static void
358
Execute(const char *_s)
359
{
360
	char *s;
361
	char *_ds;
362
	char *orig_display;
363
	int restorevar = 0;
364
	char *subs;
365
366
	/* Seatbelt */
367
	if(!_s) {
368
		return;
369
	}
370
371
	/* Work on a local copy since we're mutating it */
372
	s = strdup(_s);
373
	if(!s) {
374
		return;
375
	}
376
377
	/* Stash up current $DISPLAY value for resetting */
378
	orig_display = getenv("DISPLAY");
379
380
381
	/*
382
	 * Build a display string using the current screen number, so that
383
	 * X programs which get fired up from a menu come up on the screen
384
	 * that they were invoked from, unless specifically overridden on
385
	 * their command line.
386
	 *
387
	 * Which is to say, given that we're on display "foo.bar:1.2", we
388
	 * want to translate that into "foo.bar:1.{Scr->screen}".
389
	 *
390
	 * We strdup() because DisplayString() is a macro returning into the
391
	 * dpy structure, and we're going to mutate the value we get from it.
392
	 */
393
	_ds = DisplayString(dpy);
394
	if(_ds) {
395
		char *ds;
396
		char *colon;
397
398
		ds = strdup(_ds);
399
		if(!ds) {
400
			goto end_execute;
401
		}
402
403
		/* If it's not host:dpy, we don't have anything to do here */
404
		colon = strrchr(ds, ':');
405
		if(colon) {
406
			char *dot, *new_display;
407
408
			/* Find the . in display.screen and chop it off */
409
			dot = strchr(colon, '.');
410
			if(dot) {
411
				*dot = '\0';
412
			}
413
414
			/* Build a new string with our correct screen info */
415
			asprintf(&new_display, "%s.%d", ds, Scr->screen);
416
			if(!new_display) {
417
				free(ds);
418
				goto end_execute;
419
			}
420
421
			/* And set */
422
			setenv("DISPLAY", new_display, 1);
423
			free(new_display);
424
			restorevar = 1;
425
		}
426
		free(ds);
427
	}
428
429
430
	/*
431
	 * We replace a couple placeholders in the string.  $currentworkspace
432
	 * is documented in the manual; $redirect is not.
433
	 */
434
	subs = strstr(s, "$currentworkspace");
435
	if(subs) {
436
		char *tmp;
437
		char *wsname;
438
439
		wsname = GetCurrentWorkSpaceName(Scr->currentvs);
440
		if(!wsname) {
441
			wsname = "";
442
		}
443
444
		tmp = replace_substr(s, "$currentworkspace", wsname);
445
		if(!tmp) {
446
			goto end_execute;
447
		}
448
		free(s);
449
		s = tmp;
450
	}
451
692.1.5 by Matthew Fuller
Add ifdef's around references to Screen and CLargs members that are
452
#ifdef CAPTIVE
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
453
	subs = strstr(s, "$redirect");
454
	if(subs) {
455
		char *tmp;
456
		char *redir;
457
458
		if(CLarg.is_captive) {
459
			asprintf(&redir, "-xrm 'ctwm.redirect:%s'", Scr->captivename);
460
			if(!redir) {
461
				goto end_execute;
462
			}
463
		}
464
		else {
465
			redir = malloc(1);
466
			*redir = '\0';
467
		}
468
469
		tmp = replace_substr(s, "$redirect", redir);
470
		free(s);
471
		s = tmp;
472
473
		free(redir);
474
	}
692.1.5 by Matthew Fuller
Add ifdef's around references to Screen and CLargs members that are
475
#endif
535.1.57 by Matthew Fuller
Pull remaining funcs out of the switch and into dispatched functions
476
477
478
	/*
479
	 * Call it.  Return value doesn't really matter, since whatever
480
	 * happened we're done.  Maybe someday if we develop a "show user
481
	 * message" generalized func, we can tell the user if executing
482
	 * failed somehow.
483
	 */
484
	system(s);
485
486
487
	/*
488
	 * Restore $DISPLAY if we changed it.  It's probably only necessary
489
	 * in edge cases (it might be used by ctwm restarting itself, for
490
	 * instance) and it's not quite clear whether the DisplayString()
491
	 * result would even be wrong for that, but what the heck, setenv()
492
	 * is cheap.
493
	 */
494
	if(restorevar) {
495
		if(orig_display) {
496
			setenv("DISPLAY", orig_display, 1);
497
		}
498
		else {
499
			unsetenv("DISPLAY");
500
		}
501
	}
502
503
504
	/* Clean up */
505
end_execute:
506
	free(s);
507
	return;
508
}