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 |
}
|