10bbfda8aSnia/*
20bbfda8aSnia * Misc function implementation
30bbfda8aSnia *
40bbfda8aSnia * These are things that either don't fit neatly into another category,
50bbfda8aSnia * or fit into a category too small to be worth making individual files
60bbfda8aSnia * for.
70bbfda8aSnia */
80bbfda8aSnia
90bbfda8aSnia#include "ctwm.h"
100bbfda8aSnia
110bbfda8aSnia#include <stdlib.h>
120bbfda8aSnia
130bbfda8aSnia#include "animate.h"
14b18c2d1eSnia#include "ctwm_shutdown.h"
150bbfda8aSnia#include "functions.h"
160bbfda8aSnia#include "functions_defs.h"
170bbfda8aSnia#include "functions_internal.h"
180bbfda8aSnia#include "icons.h"
190bbfda8aSnia#include "otp.h"
200bbfda8aSnia#include "screen.h"
210bbfda8aSnia#ifdef SOUNDS
220bbfda8aSnia#include "sound.h"
230bbfda8aSnia#endif
240bbfda8aSnia#include "util.h"
250bbfda8aSnia#include "win_iconify.h"
26b18c2d1eSnia#ifdef WINBOX
270bbfda8aSnia#include "windowbox.h"
28b18c2d1eSnia#endif
290bbfda8aSnia#include "workspace_utils.h"
300bbfda8aSnia
310bbfda8aSnia#include "ext/repl_str.h"
320bbfda8aSnia
330bbfda8aSnia
340bbfda8aSnia
350bbfda8aSnia/*
360bbfda8aSnia * Animation-related
370bbfda8aSnia */
380bbfda8aSniaDFHANDLER(startanimation)
390bbfda8aSnia{
400bbfda8aSnia	StartAnimation();
410bbfda8aSnia}
420bbfda8aSnia
430bbfda8aSniaDFHANDLER(stopanimation)
440bbfda8aSnia{
450bbfda8aSnia	StopAnimation();
460bbfda8aSnia}
470bbfda8aSnia
480bbfda8aSniaDFHANDLER(speedupanimation)
490bbfda8aSnia{
500bbfda8aSnia	ModifyAnimationSpeed(1);
510bbfda8aSnia}
520bbfda8aSnia
530bbfda8aSniaDFHANDLER(slowdownanimation)
540bbfda8aSnia{
550bbfda8aSnia	ModifyAnimationSpeed(-1);
560bbfda8aSnia}
570bbfda8aSnia
580bbfda8aSnia
590bbfda8aSnia
600bbfda8aSnia/*
610bbfda8aSnia * Menu-related
620bbfda8aSnia */
630bbfda8aSniaDFHANDLER(menu)
640bbfda8aSnia{
650bbfda8aSnia	/*
660bbfda8aSnia	 * n.b.: The f.menu handler is all kinds of magic; it's actually
670bbfda8aSnia	 * completely unrelated to pulling up the menu.
680bbfda8aSnia	 *
690bbfda8aSnia	 * When a button/key binding invokes f.menu to open up a menu, that's
700bbfda8aSnia	 * actually handled in the KeyPress or ButtonPress handlers by
710bbfda8aSnia	 * calling do{_key,}_menu().  When we descend into a submenu, that's
720bbfda8aSnia	 * handled in KeyPress handler for keyboard navigation when we hit
730bbfda8aSnia	 * the Right arrow, or inside the
740bbfda8aSnia	 * event loop recapture in UpdateMenu() for mouse navigation when we
750bbfda8aSnia	 * move it to the right side of the menu entry.
760bbfda8aSnia	 *
770bbfda8aSnia	 * This handler is only used by "invoking" a menu item; releasing the
780bbfda8aSnia	 * mouse button on the left side without moving right to open out the
790bbfda8aSnia	 * submenu, or hitting the Enter key.  All it does is immediately
800bbfda8aSnia	 * invoke the default entry, if there is one.
810bbfda8aSnia	 */
820bbfda8aSnia	if(action && ! strncmp(action, "WGOTO : ", 8)) {
830bbfda8aSnia		GotoWorkSpaceByName(/* XXXXX */ Scr->currentvs,
840bbfda8aSnia		                                ((char *)action) + 8);
850bbfda8aSnia	}
860bbfda8aSnia	else {
870bbfda8aSnia		MenuItem *item;
880bbfda8aSnia
890bbfda8aSnia		item = ActiveItem;
900bbfda8aSnia		while(item && item->sub) {
910bbfda8aSnia			if(!item->sub->defaultitem) {
920bbfda8aSnia				break;
930bbfda8aSnia			}
940bbfda8aSnia			if(item->sub->defaultitem->func != F_MENU) {
950bbfda8aSnia				break;
960bbfda8aSnia			}
970bbfda8aSnia			item = item->sub->defaultitem;
980bbfda8aSnia		}
990bbfda8aSnia		if(item && item->sub && item->sub->defaultitem) {
1000bbfda8aSnia			ExecuteFunction(item->sub->defaultitem->func,
1010bbfda8aSnia			                item->sub->defaultitem->action,
1020bbfda8aSnia			                w, tmp_win, eventp, context, pulldown);
1030bbfda8aSnia		}
1040bbfda8aSnia	}
1050bbfda8aSnia}
1060bbfda8aSnia
1070bbfda8aSnia
1080bbfda8aSniaDFHANDLER(pin)
1090bbfda8aSnia{
1100bbfda8aSnia	if(! ActiveMenu) {
1110bbfda8aSnia		return;
1120bbfda8aSnia	}
1130bbfda8aSnia	if(ActiveMenu->pinned) {
1140bbfda8aSnia		XUnmapWindow(dpy, ActiveMenu->w);
1150bbfda8aSnia		ActiveMenu->mapped = MRM_UNMAPPED;
1160bbfda8aSnia	}
1170bbfda8aSnia	else {
1180bbfda8aSnia		XWindowAttributes attr;
1190bbfda8aSnia		MenuRoot *menu;
1200bbfda8aSnia
1210bbfda8aSnia		if(ActiveMenu->pmenu == NULL) {
1220bbfda8aSnia			menu  = malloc(sizeof(MenuRoot));
1230bbfda8aSnia			*menu = *ActiveMenu;
1240bbfda8aSnia			menu->pinned = true;
1250bbfda8aSnia			menu->mapped = MRM_NEVER;
1260bbfda8aSnia			menu->width -= 10;
1270bbfda8aSnia			if(menu->pull) {
1280bbfda8aSnia				menu->width -= 16 + 10;
1290bbfda8aSnia			}
1300bbfda8aSnia			MakeMenu(menu);
1310bbfda8aSnia			ActiveMenu->pmenu = menu;
1320bbfda8aSnia		}
1330bbfda8aSnia		else {
1340bbfda8aSnia			menu = ActiveMenu->pmenu;
1350bbfda8aSnia		}
1360bbfda8aSnia		if(menu->mapped == MRM_MAPPED) {
1370bbfda8aSnia			return;
1380bbfda8aSnia		}
1390bbfda8aSnia		XGetWindowAttributes(dpy, ActiveMenu->w, &attr);
1400bbfda8aSnia		menu->x = attr.x;
1410bbfda8aSnia		menu->y = attr.y;
1420bbfda8aSnia		XMoveWindow(dpy, menu->w, menu->x, menu->y);
1430bbfda8aSnia		XMapRaised(dpy, menu->w);
1440bbfda8aSnia		menu->mapped = MRM_MAPPED;
1450bbfda8aSnia	}
1460bbfda8aSnia	PopDownMenu();
1470bbfda8aSnia}
1480bbfda8aSnia
1490bbfda8aSnia
1500bbfda8aSnia
1510bbfda8aSnia/*
1520bbfda8aSnia * Alternate keymaps/contexts
1530bbfda8aSnia */
1540bbfda8aSniaDFHANDLER(altkeymap)
1550bbfda8aSnia{
1560bbfda8aSnia	int alt, stat_;
1570bbfda8aSnia
1580bbfda8aSnia	if(! action) {
1590bbfda8aSnia		return;
1600bbfda8aSnia	}
1610bbfda8aSnia	stat_ = sscanf(action, "%d", &alt);
1620bbfda8aSnia	if(stat_ != 1) {
1630bbfda8aSnia		return;
1640bbfda8aSnia	}
1650bbfda8aSnia	if((alt < 1) || (alt > 5)) {
1660bbfda8aSnia		return;
1670bbfda8aSnia	}
1680bbfda8aSnia	AlternateKeymap = Alt1Mask << (alt - 1);
1690bbfda8aSnia	XGrabPointer(dpy, Scr->Root, True, ButtonPressMask | ButtonReleaseMask,
1700bbfda8aSnia	             GrabModeAsync, GrabModeAsync,
1710bbfda8aSnia	             Scr->Root, Scr->AlterCursor, CurrentTime);
1720bbfda8aSnia	func_reset_cursor = false;  // Leave special cursor alone
1730bbfda8aSnia	XGrabKeyboard(dpy, Scr->Root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
1740bbfda8aSnia	return;
1750bbfda8aSnia}
1760bbfda8aSnia
1770bbfda8aSniaDFHANDLER(altcontext)
1780bbfda8aSnia{
1790bbfda8aSnia	AlternateContext = true;
1800bbfda8aSnia	XGrabPointer(dpy, Scr->Root, False, ButtonPressMask | ButtonReleaseMask,
1810bbfda8aSnia	             GrabModeAsync, GrabModeAsync,
1820bbfda8aSnia	             Scr->Root, Scr->AlterCursor, CurrentTime);
1830bbfda8aSnia	func_reset_cursor = false;  // Leave special cursor alone
1840bbfda8aSnia	XGrabKeyboard(dpy, Scr->Root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
1850bbfda8aSnia	return;
1860bbfda8aSnia}
1870bbfda8aSnia
1880bbfda8aSnia
1890bbfda8aSnia
1900bbfda8aSnia/*
1910bbfda8aSnia * A few trivial ctwm-control-ish meta-functions
1920bbfda8aSnia */
1930bbfda8aSniaDFHANDLER(quit)
1940bbfda8aSnia{
195b18c2d1eSnia	DoShutdown();
1960bbfda8aSnia}
1970bbfda8aSnia
1980bbfda8aSniaDFHANDLER(restart)
1990bbfda8aSnia{
2000bbfda8aSnia	DoRestart(eventp->xbutton.time);
2010bbfda8aSnia}
2020bbfda8aSnia
2030bbfda8aSniaDFHANDLER(beep)
2040bbfda8aSnia{
2050bbfda8aSnia	XBell(dpy, 0);
2060bbfda8aSnia}
2070bbfda8aSnia
2080bbfda8aSniaDFHANDLER(trace)
2090bbfda8aSnia{
2100bbfda8aSnia	DebugTrace(action);
2110bbfda8aSnia}
2120bbfda8aSnia
2130bbfda8aSnia
2140bbfda8aSnia
215b18c2d1eSnia#ifdef WINBOX
2160bbfda8aSnia/*
2170bbfda8aSnia * Special windowbox-related
2180bbfda8aSnia */
2190bbfda8aSniaDFHANDLER(fittocontent)
2200bbfda8aSnia{
2210bbfda8aSnia	if(!tmp_win->iswinbox) {
2220bbfda8aSnia		XBell(dpy, 0);
2230bbfda8aSnia		return;
2240bbfda8aSnia	}
2250bbfda8aSnia	fittocontent(tmp_win);
2260bbfda8aSnia}
227b18c2d1eSnia#endif
2280bbfda8aSnia
2290bbfda8aSnia
2300bbfda8aSnia
2310bbfda8aSnia/*
2320bbfda8aSnia * A few things that are sorta windows/icons related, but don't really
2330bbfda8aSnia * fit with the window-targetted things in functions_win.
2340bbfda8aSnia */
2350bbfda8aSniaDFHANDLER(showbackground)
2360bbfda8aSnia{
2370bbfda8aSnia	ShowBackground(Scr->currentvs, -1);
2380bbfda8aSnia}
2390bbfda8aSnia
2400bbfda8aSniaDFHANDLER(raiseicons)
2410bbfda8aSnia{
2420bbfda8aSnia	for(TwmWindow *t = Scr->FirstWindow; t != NULL; t = t->next) {
2430bbfda8aSnia		if(t->icon && t->icon->w) {
2440bbfda8aSnia			OtpRaise(t, IconWin);
2450bbfda8aSnia		}
2460bbfda8aSnia	}
2470bbfda8aSnia}
2480bbfda8aSnia
2490bbfda8aSniaDFHANDLER(rescuewindows)
2500bbfda8aSnia{
2510bbfda8aSnia	RescueWindows();
2520bbfda8aSnia}
2530bbfda8aSnia
2540bbfda8aSnia
2550bbfda8aSnia
2560bbfda8aSnia/*
2570bbfda8aSnia * Despite the name, this is more like 'gotoworkspace' than the other
2580bbfda8aSnia * 'warpto*' funcs, as it's just about switching your view, not anything
2590bbfda8aSnia * going to a window.
2600bbfda8aSnia */
2610bbfda8aSniastatic void
2620bbfda8aSniaWarpToScreen(int n, int inc)
2630bbfda8aSnia{
2640bbfda8aSnia	Window dumwin;
2650bbfda8aSnia	int x, y, dumint;
2660bbfda8aSnia	unsigned int dummask;
2670bbfda8aSnia	ScreenInfo *newscr = NULL;
2680bbfda8aSnia
2690bbfda8aSnia	while(!newscr) {
2700bbfda8aSnia		/* wrap around */
2710bbfda8aSnia		if(n < 0) {
2720bbfda8aSnia			n = NumScreens - 1;
2730bbfda8aSnia		}
2740bbfda8aSnia		else if(n >= NumScreens) {
2750bbfda8aSnia			n = 0;
2760bbfda8aSnia		}
2770bbfda8aSnia
2780bbfda8aSnia		newscr = ScreenList[n];
2790bbfda8aSnia		if(!newscr) {                   /* make sure screen is managed */
2800bbfda8aSnia			if(inc) {                   /* walk around the list */
2810bbfda8aSnia				n += inc;
2820bbfda8aSnia				continue;
2830bbfda8aSnia			}
2840bbfda8aSnia			fprintf(stderr, "%s:  unable to warp to unmanaged screen %d\n",
2850bbfda8aSnia			        ProgramName, n);
2860bbfda8aSnia			XBell(dpy, 0);
2870bbfda8aSnia			return;
2880bbfda8aSnia		}
2890bbfda8aSnia	}
2900bbfda8aSnia
2910bbfda8aSnia	if(Scr->screen == n) {
2920bbfda8aSnia		return;        /* already on that screen */
2930bbfda8aSnia	}
2940bbfda8aSnia
2950bbfda8aSnia	PreviousScreen = Scr->screen;
2960bbfda8aSnia	XQueryPointer(dpy, Scr->Root, &dumwin, &dumwin, &x, &y,
2970bbfda8aSnia	              &dumint, &dumint, &dummask);
2980bbfda8aSnia
2990bbfda8aSnia	XWarpPointer(dpy, None, newscr->Root, 0, 0, 0, 0, x, y);
3000bbfda8aSnia	Scr = newscr;
3010bbfda8aSnia	return;
3020bbfda8aSnia}
3030bbfda8aSnia
3040bbfda8aSniaDFHANDLER(warptoscreen)
3050bbfda8aSnia{
3060bbfda8aSnia	if(strcmp(action, WARPSCREEN_NEXT) == 0) {
3070bbfda8aSnia		WarpToScreen(Scr->screen + 1, 1);
3080bbfda8aSnia	}
3090bbfda8aSnia	else if(strcmp(action, WARPSCREEN_PREV) == 0) {
3100bbfda8aSnia		WarpToScreen(Scr->screen - 1, -1);
3110bbfda8aSnia	}
3120bbfda8aSnia	else if(strcmp(action, WARPSCREEN_BACK) == 0) {
3130bbfda8aSnia		WarpToScreen(PreviousScreen, 0);
3140bbfda8aSnia	}
3150bbfda8aSnia	else {
3160bbfda8aSnia		WarpToScreen(atoi(action), 0);
3170bbfda8aSnia	}
3180bbfda8aSnia}
3190bbfda8aSnia
3200bbfda8aSnia
3210bbfda8aSnia
3220bbfda8aSnia/*
3230bbfda8aSnia * Sound-related
3240bbfda8aSnia */
3250bbfda8aSnia#ifdef SOUNDS
3260bbfda8aSniaDFHANDLER(togglesound)
3270bbfda8aSnia{
3280bbfda8aSnia	toggle_sound();
3290bbfda8aSnia}
3300bbfda8aSnia
3310bbfda8aSniaDFHANDLER(rereadsounds)
3320bbfda8aSnia{
3330bbfda8aSnia	reread_sounds();
3340bbfda8aSnia}
3350bbfda8aSnia#endif
3360bbfda8aSnia
3370bbfda8aSnia
3380bbfda8aSnia
3390bbfda8aSnia/*
3400bbfda8aSnia * And executing an external program
3410bbfda8aSnia */
3420bbfda8aSniastatic void Execute(const char *_s);
3430bbfda8aSnia
3440bbfda8aSniaDFHANDLER(exec)
3450bbfda8aSnia{
3460bbfda8aSnia	PopDownMenu();
3470bbfda8aSnia	if(!Scr->NoGrabServer) {
3480bbfda8aSnia		XUngrabServer(dpy);
3490bbfda8aSnia		XSync(dpy, 0);
3500bbfda8aSnia	}
3510bbfda8aSnia	XUngrabPointer(dpy, CurrentTime);
3520bbfda8aSnia	XSync(dpy, 0);
3530bbfda8aSnia	Execute(action);
3540bbfda8aSnia}
3550bbfda8aSnia
3560bbfda8aSnia
3570bbfda8aSniastatic void
3580bbfda8aSniaExecute(const char *_s)
3590bbfda8aSnia{
3600bbfda8aSnia	char *s;
3610bbfda8aSnia	char *_ds;
3620bbfda8aSnia	char *orig_display;
3630bbfda8aSnia	int restorevar = 0;
3640bbfda8aSnia	char *subs;
3650bbfda8aSnia
3660bbfda8aSnia	/* Seatbelt */
3670bbfda8aSnia	if(!_s) {
3680bbfda8aSnia		return;
3690bbfda8aSnia	}
3700bbfda8aSnia
3710bbfda8aSnia	/* Work on a local copy since we're mutating it */
3720bbfda8aSnia	s = strdup(_s);
3730bbfda8aSnia	if(!s) {
3740bbfda8aSnia		return;
3750bbfda8aSnia	}
3760bbfda8aSnia
3770bbfda8aSnia	/* Stash up current $DISPLAY value for resetting */
3780bbfda8aSnia	orig_display = getenv("DISPLAY");
3790bbfda8aSnia
3800bbfda8aSnia
3810bbfda8aSnia	/*
3820bbfda8aSnia	 * Build a display string using the current screen number, so that
3830bbfda8aSnia	 * X programs which get fired up from a menu come up on the screen
3840bbfda8aSnia	 * that they were invoked from, unless specifically overridden on
3850bbfda8aSnia	 * their command line.
3860bbfda8aSnia	 *
3870bbfda8aSnia	 * Which is to say, given that we're on display "foo.bar:1.2", we
3880bbfda8aSnia	 * want to translate that into "foo.bar:1.{Scr->screen}".
3890bbfda8aSnia	 *
3900bbfda8aSnia	 * We strdup() because DisplayString() is a macro returning into the
3910bbfda8aSnia	 * dpy structure, and we're going to mutate the value we get from it.
3920bbfda8aSnia	 */
3930bbfda8aSnia	_ds = DisplayString(dpy);
3940bbfda8aSnia	if(_ds) {
3950bbfda8aSnia		char *ds;
3960bbfda8aSnia		char *colon;
3970bbfda8aSnia
3980bbfda8aSnia		ds = strdup(_ds);
3990bbfda8aSnia		if(!ds) {
4000bbfda8aSnia			goto end_execute;
4010bbfda8aSnia		}
4020bbfda8aSnia
4030bbfda8aSnia		/* If it's not host:dpy, we don't have anything to do here */
4040bbfda8aSnia		colon = strrchr(ds, ':');
4050bbfda8aSnia		if(colon) {
4060bbfda8aSnia			char *dot, *new_display;
4070bbfda8aSnia
4080bbfda8aSnia			/* Find the . in display.screen and chop it off */
4090bbfda8aSnia			dot = strchr(colon, '.');
4100bbfda8aSnia			if(dot) {
4110bbfda8aSnia				*dot = '\0';
4120bbfda8aSnia			}
4130bbfda8aSnia
4140bbfda8aSnia			/* Build a new string with our correct screen info */
4150bbfda8aSnia			asprintf(&new_display, "%s.%d", ds, Scr->screen);
4160bbfda8aSnia			if(!new_display) {
4170bbfda8aSnia				free(ds);
4180bbfda8aSnia				goto end_execute;
4190bbfda8aSnia			}
4200bbfda8aSnia
4210bbfda8aSnia			/* And set */
4220bbfda8aSnia			setenv("DISPLAY", new_display, 1);
4230bbfda8aSnia			free(new_display);
4240bbfda8aSnia			restorevar = 1;
4250bbfda8aSnia		}
4260bbfda8aSnia		free(ds);
4270bbfda8aSnia	}
4280bbfda8aSnia
4290bbfda8aSnia
4300bbfda8aSnia	/*
4310bbfda8aSnia	 * We replace a couple placeholders in the string.  $currentworkspace
4320bbfda8aSnia	 * is documented in the manual; $redirect is not.
4330bbfda8aSnia	 */
4340bbfda8aSnia	subs = strstr(s, "$currentworkspace");
4350bbfda8aSnia	if(subs) {
4360bbfda8aSnia		char *tmp;
4370bbfda8aSnia		char *wsname;
4380bbfda8aSnia
4390bbfda8aSnia		wsname = GetCurrentWorkSpaceName(Scr->currentvs);
4400bbfda8aSnia		if(!wsname) {
4410bbfda8aSnia			wsname = "";
4420bbfda8aSnia		}
4430bbfda8aSnia
4440bbfda8aSnia		tmp = replace_substr(s, "$currentworkspace", wsname);
4450bbfda8aSnia		if(!tmp) {
4460bbfda8aSnia			goto end_execute;
4470bbfda8aSnia		}
4480bbfda8aSnia		free(s);
4490bbfda8aSnia		s = tmp;
4500bbfda8aSnia	}
4510bbfda8aSnia
452b18c2d1eSnia#ifdef CAPTIVE
4530bbfda8aSnia	subs = strstr(s, "$redirect");
4540bbfda8aSnia	if(subs) {
4550bbfda8aSnia		char *tmp;
4560bbfda8aSnia		char *redir;
4570bbfda8aSnia
4580bbfda8aSnia		if(CLarg.is_captive) {
4590bbfda8aSnia			asprintf(&redir, "-xrm 'ctwm.redirect:%s'", Scr->captivename);
4600bbfda8aSnia			if(!redir) {
4610bbfda8aSnia				goto end_execute;
4620bbfda8aSnia			}
4630bbfda8aSnia		}
4640bbfda8aSnia		else {
4650bbfda8aSnia			redir = malloc(1);
4660bbfda8aSnia			*redir = '\0';
4670bbfda8aSnia		}
4680bbfda8aSnia
4690bbfda8aSnia		tmp = replace_substr(s, "$redirect", redir);
4700bbfda8aSnia		free(s);
4710bbfda8aSnia		s = tmp;
4720bbfda8aSnia
4730bbfda8aSnia		free(redir);
4740bbfda8aSnia	}
475b18c2d1eSnia#endif
4760bbfda8aSnia
4770bbfda8aSnia
4780bbfda8aSnia	/*
4790bbfda8aSnia	 * Call it.  Return value doesn't really matter, since whatever
4800bbfda8aSnia	 * happened we're done.  Maybe someday if we develop a "show user
4810bbfda8aSnia	 * message" generalized func, we can tell the user if executing
4820bbfda8aSnia	 * failed somehow.
4830bbfda8aSnia	 */
4840bbfda8aSnia	system(s);
4850bbfda8aSnia
4860bbfda8aSnia
4870bbfda8aSnia	/*
4880bbfda8aSnia	 * Restore $DISPLAY if we changed it.  It's probably only necessary
4890bbfda8aSnia	 * in edge cases (it might be used by ctwm restarting itself, for
4900bbfda8aSnia	 * instance) and it's not quite clear whether the DisplayString()
4910bbfda8aSnia	 * result would even be wrong for that, but what the heck, setenv()
4920bbfda8aSnia	 * is cheap.
4930bbfda8aSnia	 */
4940bbfda8aSnia	if(restorevar) {
4950bbfda8aSnia		if(orig_display) {
4960bbfda8aSnia			setenv("DISPLAY", orig_display, 1);
4970bbfda8aSnia		}
4980bbfda8aSnia		else {
4990bbfda8aSnia			unsetenv("DISPLAY");
5000bbfda8aSnia		}
5010bbfda8aSnia	}
5020bbfda8aSnia
5030bbfda8aSnia
5040bbfda8aSnia	/* Clean up */
5050bbfda8aSniaend_execute:
5060bbfda8aSnia	free(s);
5070bbfda8aSnia	return;
5080bbfda8aSnia}
509