workspace_utils.c revision 0bbfda8a
10bbfda8aSnia/*
20bbfda8aSnia * Various workspace handling and utilities.
30bbfda8aSnia */
40bbfda8aSnia
50bbfda8aSnia#include "ctwm.h"
60bbfda8aSnia
70bbfda8aSnia#include <stdio.h>
80bbfda8aSnia#include <string.h>
90bbfda8aSnia#include <stdlib.h>
100bbfda8aSnia
110bbfda8aSnia#include <X11/Xatom.h>
120bbfda8aSnia
130bbfda8aSnia#include "animate.h"
140bbfda8aSnia#include "clicktofocus.h"
150bbfda8aSnia#include "ctwm_atoms.h"
160bbfda8aSnia#include "drawing.h"
170bbfda8aSnia#include "functions.h"
180bbfda8aSnia#include "iconmgr.h"
190bbfda8aSnia#include "image.h"
200bbfda8aSnia#include "otp.h"
210bbfda8aSnia#include "screen.h"
220bbfda8aSnia#include "vscreen.h"
230bbfda8aSnia#include "win_ops.h"
240bbfda8aSnia#include "win_utils.h"
250bbfda8aSnia#include "workspace_manager.h"
260bbfda8aSnia#include "workspace_utils.h"
270bbfda8aSnia
280bbfda8aSnia#ifdef EWMH
290bbfda8aSnia#  include "ewmh_atoms.h"
300bbfda8aSnia#endif
310bbfda8aSnia
320bbfda8aSnia
330bbfda8aSnia/*
340bbfda8aSnia * XXX I'm not sure this should be here; maybe it's more of a per-screen
350bbfda8aSnia * thing, and so should be in the Screen struct?
360bbfda8aSnia */
370bbfda8aSniabool useBackgroundInfo = false;
380bbfda8aSnia
390bbfda8aSnia
400bbfda8aSnia/*
410bbfda8aSnia * Move the display (of a given vs) over to a new workspace.
420bbfda8aSnia */
430bbfda8aSniavoid
440bbfda8aSniaGotoWorkSpace(VirtualScreen *vs, WorkSpace *ws)
450bbfda8aSnia{
460bbfda8aSnia	TwmWindow            *twmWin;
470bbfda8aSnia	WorkSpace            *oldws, *newws;
480bbfda8aSnia	WList                *wl, *wl1;
490bbfda8aSnia	WinList              *winl;
500bbfda8aSnia	XSetWindowAttributes attr;
510bbfda8aSnia	long                 eventMask;
520bbfda8aSnia	IconMgr              *iconmgr;
530bbfda8aSnia	Window               oldw;
540bbfda8aSnia	Window               neww;
550bbfda8aSnia	TwmWindow            *focuswindow;
560bbfda8aSnia	VirtualScreen        *tmpvs;
570bbfda8aSnia
580bbfda8aSnia	if(! Scr->workSpaceManagerActive) {
590bbfda8aSnia		return;
600bbfda8aSnia	}
610bbfda8aSnia	for(tmpvs = Scr->vScreenList; tmpvs != NULL; tmpvs = tmpvs->next) {
620bbfda8aSnia		if(ws == tmpvs->wsw->currentwspc) {
630bbfda8aSnia			XBell(dpy, 0);
640bbfda8aSnia			return;
650bbfda8aSnia		}
660bbfda8aSnia	}
670bbfda8aSnia	oldws = vs->wsw->currentwspc;
680bbfda8aSnia	newws = ws;
690bbfda8aSnia	if(oldws == newws) {
700bbfda8aSnia		return;
710bbfda8aSnia	}
720bbfda8aSnia
730bbfda8aSnia	/* XXX X-ref CTAG_BGDRAW in CreateWorkSpaceManager() and below */
740bbfda8aSnia	if(useBackgroundInfo && ! Scr->DontPaintRootWindow) {
750bbfda8aSnia		if(newws->image == NULL) {
760bbfda8aSnia			XSetWindowBackground(dpy, vs->window, newws->backcp.back);
770bbfda8aSnia		}
780bbfda8aSnia		else {
790bbfda8aSnia			XSetWindowBackgroundPixmap(dpy, vs->window, newws->image->pixmap);
800bbfda8aSnia		}
810bbfda8aSnia		XClearWindow(dpy, vs->window);
820bbfda8aSnia	}
830bbfda8aSnia
840bbfda8aSnia	/* If SaveWorkspaceFocus is on, save the focus of the last window. */
850bbfda8aSnia	if(Scr->SaveWorkspaceFocus) {
860bbfda8aSnia		oldws->save_focus = Scr->Focus;
870bbfda8aSnia	}
880bbfda8aSnia
890bbfda8aSnia	focuswindow = NULL;
900bbfda8aSnia	/* For better visual effect, the order or map/unmap is important:
910bbfda8aSnia	   - map from top to bottom.
920bbfda8aSnia	   - unmap from bottom to top.
930bbfda8aSnia	   - unmap after mapping.
940bbfda8aSnia	   The guiding factor: at any point during the transition, something
950bbfda8aSnia	   should be visible only if it was visible before the transition or if
960bbfda8aSnia	   it will be visible at the end.  */
970bbfda8aSnia	OtpCheckConsistency();
980bbfda8aSnia
990bbfda8aSnia	for(twmWin = OtpTopWin(); twmWin != NULL;
1000bbfda8aSnia	                twmWin = OtpNextWinDown(twmWin)) {
1010bbfda8aSnia
1020bbfda8aSnia		if(OCCUPY(twmWin, newws)) {
1030bbfda8aSnia			if(!twmWin->vs) {
1040bbfda8aSnia				DisplayWin(vs, twmWin);
1050bbfda8aSnia			}
1060bbfda8aSnia#ifdef EWMH
1070bbfda8aSnia			if(OCCUPY(twmWin, oldws)) {
1080bbfda8aSnia				/*
1090bbfda8aSnia				 * If the window remains visible, re-order the workspace
1100bbfda8aSnia				 * numbers in NET_WM_DESKTOP.
1110bbfda8aSnia				 */
1120bbfda8aSnia				EwmhSet_NET_WM_DESKTOP_ws(twmWin, newws);
1130bbfda8aSnia			}
1140bbfda8aSnia#endif
1150bbfda8aSnia		}
1160bbfda8aSnia	}
1170bbfda8aSnia
1180bbfda8aSnia	for(twmWin = OtpBottomWin(); twmWin != NULL;
1190bbfda8aSnia	                twmWin = OtpNextWinUp(twmWin)) {
1200bbfda8aSnia		if(twmWin->vs == vs) {
1210bbfda8aSnia			if(!OCCUPY(twmWin, newws)) {
1220bbfda8aSnia				VirtualScreen *tvs;
1230bbfda8aSnia
1240bbfda8aSnia				Vanish(vs, twmWin);
1250bbfda8aSnia				/*
1260bbfda8aSnia				 * Now that the window has Vanished from one virtual screen,
1270bbfda8aSnia				 * check to see if it is wanted on another one.
1280bbfda8aSnia				 * This is relatively rare, so don't bother with the
1290bbfda8aSnia				 * top-to-bottom order here.
1300bbfda8aSnia				 */
1310bbfda8aSnia				if(Scr->numVscreens > 1) {
1320bbfda8aSnia					for(tvs = Scr->vScreenList; tvs != NULL; tvs = tvs->next) {
1330bbfda8aSnia						if(tvs == vs) { /* no, not back on the old one */
1340bbfda8aSnia							continue;
1350bbfda8aSnia						}
1360bbfda8aSnia						if(OCCUPY(twmWin, tvs->wsw->currentwspc)) {
1370bbfda8aSnia							DisplayWin(tvs, twmWin);
1380bbfda8aSnia							break;
1390bbfda8aSnia						}
1400bbfda8aSnia					}
1410bbfda8aSnia				}
1420bbfda8aSnia			}
1430bbfda8aSnia			else if(twmWin->hasfocusvisible) {
1440bbfda8aSnia				focuswindow = twmWin;
1450bbfda8aSnia				SetFocusVisualAttributes(focuswindow, false);
1460bbfda8aSnia			}
1470bbfda8aSnia		}
1480bbfda8aSnia	}
1490bbfda8aSnia	OtpCheckConsistency();
1500bbfda8aSnia
1510bbfda8aSnia	/*
1520bbfda8aSnia	   Reorganize icon manager window lists
1530bbfda8aSnia	*/
1540bbfda8aSnia	for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
1550bbfda8aSnia		wl = twmWin->iconmanagerlist;
1560bbfda8aSnia		if(wl == NULL) {
1570bbfda8aSnia			continue;
1580bbfda8aSnia		}
1590bbfda8aSnia		if(OCCUPY(wl->iconmgr->twm_win, newws)) {
1600bbfda8aSnia			continue;
1610bbfda8aSnia		}
1620bbfda8aSnia		wl1 = wl;
1630bbfda8aSnia		wl  = wl->nextv;
1640bbfda8aSnia		while(wl != NULL) {
1650bbfda8aSnia			if(OCCUPY(wl->iconmgr->twm_win, newws)) {
1660bbfda8aSnia				break;
1670bbfda8aSnia			}
1680bbfda8aSnia			wl1 = wl;
1690bbfda8aSnia			wl  = wl->nextv;
1700bbfda8aSnia		}
1710bbfda8aSnia		if(wl != NULL) {
1720bbfda8aSnia			wl1->nextv = wl->nextv;
1730bbfda8aSnia			wl->nextv  = twmWin->iconmanagerlist;
1740bbfda8aSnia			twmWin->iconmanagerlist = wl;
1750bbfda8aSnia		}
1760bbfda8aSnia	}
1770bbfda8aSnia	wl = NULL;
1780bbfda8aSnia	for(iconmgr = newws->iconmgr; iconmgr; iconmgr = iconmgr->next) {
1790bbfda8aSnia		if(iconmgr->first) {
1800bbfda8aSnia			wl = iconmgr->first;
1810bbfda8aSnia			break;
1820bbfda8aSnia		}
1830bbfda8aSnia	}
1840bbfda8aSnia	CurrentIconManagerEntry(wl);
1850bbfda8aSnia	if(focuswindow) {
1860bbfda8aSnia		SetFocusVisualAttributes(focuswindow, true);
1870bbfda8aSnia	}
1880bbfda8aSnia	vs->wsw->currentwspc = newws;
1890bbfda8aSnia	if(Scr->ReverseCurrentWorkspace && vs->wsw->state == WMS_map) {
1900bbfda8aSnia		MapSubwindow *msw = vs->wsw->mswl [oldws->number];
1910bbfda8aSnia		for(winl = msw->wl; winl != NULL; winl = winl->next) {
1920bbfda8aSnia			WMapRedrawName(vs, winl);
1930bbfda8aSnia		}
1940bbfda8aSnia		msw = vs->wsw->mswl [newws->number];
1950bbfda8aSnia		for(winl = msw->wl; winl != NULL; winl = winl->next) {
1960bbfda8aSnia			WMapRedrawName(vs, winl);
1970bbfda8aSnia		}
1980bbfda8aSnia	}
1990bbfda8aSnia	else if(vs->wsw->state == WMS_buttons) {
2000bbfda8aSnia		ButtonSubwindow *bsw = vs->wsw->bswl [oldws->number];
2010bbfda8aSnia		PaintWsButton(WSPCWINDOW, vs, bsw->w, oldws->label, oldws->cp, off);
2020bbfda8aSnia		bsw = vs->wsw->bswl [newws->number];
2030bbfda8aSnia		PaintWsButton(WSPCWINDOW, vs, bsw->w, newws->label, newws->cp,  on);
2040bbfda8aSnia	}
2050bbfda8aSnia	oldws->iconmgr = Scr->iconmgr;
2060bbfda8aSnia	Scr->iconmgr = newws->iconmgr;
2070bbfda8aSnia
2080bbfda8aSnia	/* XXX X-ref CTAG_BGDRAW in CreateWorkSpaceManager() and above */
2090bbfda8aSnia	oldw = vs->wsw->mswl [oldws->number]->w;
2100bbfda8aSnia	neww = vs->wsw->mswl [newws->number]->w;
2110bbfda8aSnia	if(useBackgroundInfo) {
2120bbfda8aSnia		if(oldws->image == NULL || Scr->NoImagesInWorkSpaceManager) {
2130bbfda8aSnia			XSetWindowBackground(dpy, oldw, oldws->backcp.back);
2140bbfda8aSnia		}
2150bbfda8aSnia		else {
2160bbfda8aSnia			XSetWindowBackgroundPixmap(dpy, oldw, oldws->image->pixmap);
2170bbfda8aSnia		}
2180bbfda8aSnia	}
2190bbfda8aSnia	else {
2200bbfda8aSnia		if(Scr->workSpaceMgr.defImage == NULL || Scr->NoImagesInWorkSpaceManager) {
2210bbfda8aSnia			XSetWindowBackground(dpy, oldw, Scr->workSpaceMgr.defColors.back);
2220bbfda8aSnia		}
2230bbfda8aSnia		else {
2240bbfda8aSnia			XSetWindowBackgroundPixmap(dpy, oldw, Scr->workSpaceMgr.defImage->pixmap);
2250bbfda8aSnia		}
2260bbfda8aSnia	}
2270bbfda8aSnia	attr.border_pixel = Scr->workSpaceMgr.defBorderColor;
2280bbfda8aSnia	XChangeWindowAttributes(dpy, oldw, CWBorderPixel, &attr);
2290bbfda8aSnia
2300bbfda8aSnia	if(Scr->workSpaceMgr.curImage == NULL) {
2310bbfda8aSnia		if(Scr->workSpaceMgr.curPaint) {
2320bbfda8aSnia			XSetWindowBackground(dpy, neww, Scr->workSpaceMgr.curColors.back);
2330bbfda8aSnia		}
2340bbfda8aSnia	}
2350bbfda8aSnia	else {
2360bbfda8aSnia		XSetWindowBackgroundPixmap(dpy, neww, Scr->workSpaceMgr.curImage->pixmap);
2370bbfda8aSnia	}
2380bbfda8aSnia	attr.border_pixel =  Scr->workSpaceMgr.curBorderColor;
2390bbfda8aSnia	XChangeWindowAttributes(dpy, neww, CWBorderPixel, &attr);
2400bbfda8aSnia
2410bbfda8aSnia	XClearWindow(dpy, oldw);
2420bbfda8aSnia	XClearWindow(dpy, neww);
2430bbfda8aSnia
2440bbfda8aSnia	eventMask = mask_out_event(Scr->Root, PropertyChangeMask);
2450bbfda8aSnia
2460bbfda8aSnia	XChangeProperty(dpy, Scr->Root, XA_WM_CURRENTWORKSPACE, XA_STRING, 8,
2470bbfda8aSnia	                PropModeReplace, (unsigned char *) newws->name, strlen(newws->name));
2480bbfda8aSnia#ifdef EWMH
2490bbfda8aSnia	{
2500bbfda8aSnia		long number = newws->number;
2510bbfda8aSnia		/*
2520bbfda8aSnia		 * TODO: this should probably not use Scr->Root but ->XineramaRoot.
2530bbfda8aSnia		 * That is the real root window if we're using virtual screens.
2540bbfda8aSnia		 * Also, on the real root it would need values for each of the
2550bbfda8aSnia		 * virtual roots, but that doesn't fit in the EWMH ideas.
2560bbfda8aSnia		 */
2570bbfda8aSnia		XChangeProperty(dpy, Scr->Root, XA__NET_CURRENT_DESKTOP,
2580bbfda8aSnia		                XA_CARDINAL, 32,
2590bbfda8aSnia		                PropModeReplace, (unsigned char *) &number, 1);
2600bbfda8aSnia	}
2610bbfda8aSnia#endif /* EWMH */
2620bbfda8aSnia
2630bbfda8aSnia	restore_mask(Scr->Root, eventMask);
2640bbfda8aSnia
2650bbfda8aSnia	/*    XDestroyWindow (dpy, cachew);*/
2660bbfda8aSnia	if(Scr->ChangeWorkspaceFunction.func != 0) {
2670bbfda8aSnia		char *action;
2680bbfda8aSnia		XEvent event;
2690bbfda8aSnia
2700bbfda8aSnia		action = Scr->ChangeWorkspaceFunction.item ?
2710bbfda8aSnia		         Scr->ChangeWorkspaceFunction.item->action : NULL;
2720bbfda8aSnia		ExecuteFunction(Scr->ChangeWorkspaceFunction.func, action,
2730bbfda8aSnia		                (Window) 0, NULL, &event, C_ROOT, false);
2740bbfda8aSnia	}
2750bbfda8aSnia
2760bbfda8aSnia	/* If SaveWorkspaceFocus is on, try to restore the focus to the last
2770bbfda8aSnia	   window which was focused when we left this workspace. */
2780bbfda8aSnia	if(Scr->SaveWorkspaceFocus && newws->save_focus) {
2790bbfda8aSnia		twmWin = newws->save_focus;
2800bbfda8aSnia		if(OCCUPY(twmWin, newws)) {     /* check should not even be needed anymore */
2810bbfda8aSnia			WarpToWindow(twmWin, false);
2820bbfda8aSnia		}
2830bbfda8aSnia		else {
2840bbfda8aSnia			newws->save_focus = NULL;
2850bbfda8aSnia		}
2860bbfda8aSnia	}
2870bbfda8aSnia
2880bbfda8aSnia	/* keep track of the order of the workspaces across restarts */
2890bbfda8aSnia	CtwmSetVScreenMap(dpy, Scr->Root, Scr->vScreenList);
2900bbfda8aSnia
2910bbfda8aSnia	XSync(dpy, 0);
2920bbfda8aSnia	if(Scr->ClickToFocus || Scr->SloppyFocus) {
2930bbfda8aSnia		set_last_window(newws);
2940bbfda8aSnia	}
2950bbfda8aSnia	MaybeAnimate = true;
2960bbfda8aSnia}
2970bbfda8aSnia
2980bbfda8aSnia
2990bbfda8aSnia
3000bbfda8aSnia/*
3010bbfda8aSnia * Various frontends to GotoWorkSpace()
3020bbfda8aSnia */
3030bbfda8aSnia
3040bbfda8aSnia/*
3050bbfda8aSnia * Simplify redundant checks.  If no multiple workspaces, or no vs given
3060bbfda8aSnia * to the func, there's nothing to do.
3070bbfda8aSnia */
3080bbfda8aSnia#define GWS_CHECK do { \
3090bbfda8aSnia                if(! Scr->workSpaceManagerActive) {   \
3100bbfda8aSnia                        return;                       \
3110bbfda8aSnia                }                                     \
3120bbfda8aSnia                if(!vs) {                             \
3130bbfda8aSnia                        return;                       \
3140bbfda8aSnia                }                                     \
3150bbfda8aSnia        } while(0)
3160bbfda8aSnia
3170bbfda8aSniavoid
3180bbfda8aSniaGotoWorkSpaceByName(VirtualScreen *vs, const char *wname)
3190bbfda8aSnia{
3200bbfda8aSnia	WorkSpace *ws;
3210bbfda8aSnia
3220bbfda8aSnia	GWS_CHECK;
3230bbfda8aSnia
3240bbfda8aSnia	ws = GetWorkspace(wname);
3250bbfda8aSnia	if(ws == NULL) {
3260bbfda8aSnia		return;
3270bbfda8aSnia	}
3280bbfda8aSnia	GotoWorkSpace(vs, ws);
3290bbfda8aSnia}
3300bbfda8aSnia
3310bbfda8aSnia
3320bbfda8aSniavoid
3330bbfda8aSniaGotoWorkSpaceByNumber(VirtualScreen *vs, int workspacenum)
3340bbfda8aSnia{
3350bbfda8aSnia	WorkSpace *ws;
3360bbfda8aSnia
3370bbfda8aSnia	GWS_CHECK;
3380bbfda8aSnia
3390bbfda8aSnia	for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
3400bbfda8aSnia		if(ws->number == workspacenum) {
3410bbfda8aSnia			break;
3420bbfda8aSnia		}
3430bbfda8aSnia	}
3440bbfda8aSnia	if(ws == NULL) {
3450bbfda8aSnia		return;
3460bbfda8aSnia	}
3470bbfda8aSnia	GotoWorkSpace(vs, ws);
3480bbfda8aSnia}
3490bbfda8aSnia
3500bbfda8aSnia
3510bbfda8aSniavoid
3520bbfda8aSniaGotoPrevWorkSpace(VirtualScreen *vs)
3530bbfda8aSnia{
3540bbfda8aSnia	WorkSpace *ws1, *ws2;
3550bbfda8aSnia
3560bbfda8aSnia	GWS_CHECK;
3570bbfda8aSnia
3580bbfda8aSnia	ws1 = Scr->workSpaceMgr.workSpaceList;
3590bbfda8aSnia	if(ws1 == NULL) {
3600bbfda8aSnia		return;
3610bbfda8aSnia	}
3620bbfda8aSnia	ws2 = ws1->next;
3630bbfda8aSnia
3640bbfda8aSnia	while((ws2 != vs->wsw->currentwspc) && (ws2 != NULL)) {
3650bbfda8aSnia		ws1 = ws2;
3660bbfda8aSnia		ws2 = ws2->next;
3670bbfda8aSnia	}
3680bbfda8aSnia	GotoWorkSpace(vs, ws1);
3690bbfda8aSnia}
3700bbfda8aSnia
3710bbfda8aSnia
3720bbfda8aSniavoid
3730bbfda8aSniaGotoNextWorkSpace(VirtualScreen *vs)
3740bbfda8aSnia{
3750bbfda8aSnia	WorkSpace *ws;
3760bbfda8aSnia
3770bbfda8aSnia	GWS_CHECK;
3780bbfda8aSnia
3790bbfda8aSnia	ws = vs->wsw->currentwspc;
3800bbfda8aSnia	ws = (ws->next != NULL) ? ws->next : Scr->workSpaceMgr.workSpaceList;
3810bbfda8aSnia	GotoWorkSpace(vs, ws);
3820bbfda8aSnia}
3830bbfda8aSnia
3840bbfda8aSnia
3850bbfda8aSniavoid
3860bbfda8aSniaGotoRightWorkSpace(VirtualScreen *vs)
3870bbfda8aSnia{
3880bbfda8aSnia	WorkSpace *ws;
3890bbfda8aSnia	int number, columns, count;
3900bbfda8aSnia
3910bbfda8aSnia	GWS_CHECK;
3920bbfda8aSnia
3930bbfda8aSnia	ws      = vs->wsw->currentwspc;
3940bbfda8aSnia	number  = ws->number;
3950bbfda8aSnia	columns = Scr->workSpaceMgr.columns;
3960bbfda8aSnia	count   = Scr->workSpaceMgr.count;
3970bbfda8aSnia	number++;
3980bbfda8aSnia	if((number % columns) == 0) {
3990bbfda8aSnia		number -= columns;
4000bbfda8aSnia	}
4010bbfda8aSnia	else if(number >= count) {
4020bbfda8aSnia		number = (number / columns) * columns;
4030bbfda8aSnia	}
4040bbfda8aSnia
4050bbfda8aSnia	GotoWorkSpaceByNumber(vs, number);
4060bbfda8aSnia}
4070bbfda8aSnia
4080bbfda8aSnia
4090bbfda8aSniavoid
4100bbfda8aSniaGotoLeftWorkSpace(VirtualScreen *vs)
4110bbfda8aSnia{
4120bbfda8aSnia	WorkSpace *ws;
4130bbfda8aSnia	int number, columns, count;
4140bbfda8aSnia
4150bbfda8aSnia	GWS_CHECK;
4160bbfda8aSnia
4170bbfda8aSnia	ws      = vs->wsw->currentwspc;
4180bbfda8aSnia	number  = ws->number;
4190bbfda8aSnia	columns = Scr->workSpaceMgr.columns;
4200bbfda8aSnia	count   = Scr->workSpaceMgr.count;
4210bbfda8aSnia	number += (number % columns) ? -1 : (columns - 1);
4220bbfda8aSnia	if(number >= count) {
4230bbfda8aSnia		number = count - 1;
4240bbfda8aSnia	}
4250bbfda8aSnia	GotoWorkSpaceByNumber(vs, number);
4260bbfda8aSnia}
4270bbfda8aSnia
4280bbfda8aSnia
4290bbfda8aSniavoid
4300bbfda8aSniaGotoUpWorkSpace(VirtualScreen *vs)
4310bbfda8aSnia{
4320bbfda8aSnia	WorkSpace *ws;
4330bbfda8aSnia	int number, lines, columns, count;
4340bbfda8aSnia
4350bbfda8aSnia	GWS_CHECK;
4360bbfda8aSnia
4370bbfda8aSnia	ws      = vs->wsw->currentwspc;
4380bbfda8aSnia	number  = ws->number;
4390bbfda8aSnia	lines   = Scr->workSpaceMgr.lines;
4400bbfda8aSnia	columns = Scr->workSpaceMgr.columns;
4410bbfda8aSnia	count   = Scr->workSpaceMgr.count;
4420bbfda8aSnia	number -=  columns;
4430bbfda8aSnia	if(number < 0) {
4440bbfda8aSnia		number += lines * columns;
4450bbfda8aSnia		/* If the number of workspaces is not a multiple of nr of columns */
4460bbfda8aSnia		if(number >= count) {
4470bbfda8aSnia			number -= columns;
4480bbfda8aSnia		}
4490bbfda8aSnia	}
4500bbfda8aSnia	GotoWorkSpaceByNumber(vs, number);
4510bbfda8aSnia}
4520bbfda8aSnia
4530bbfda8aSnia
4540bbfda8aSniavoid
4550bbfda8aSniaGotoDownWorkSpace(VirtualScreen *vs)
4560bbfda8aSnia{
4570bbfda8aSnia	WorkSpace *ws;
4580bbfda8aSnia	int number, columns, count;
4590bbfda8aSnia
4600bbfda8aSnia	GWS_CHECK;
4610bbfda8aSnia
4620bbfda8aSnia	ws      = vs->wsw->currentwspc;
4630bbfda8aSnia	number  = ws->number;
4640bbfda8aSnia	columns = Scr->workSpaceMgr.columns;
4650bbfda8aSnia	count   = Scr->workSpaceMgr.count;
4660bbfda8aSnia	number +=  columns;
4670bbfda8aSnia	if(number >= count) {
4680bbfda8aSnia		number %= columns;
4690bbfda8aSnia	}
4700bbfda8aSnia	GotoWorkSpaceByNumber(vs, number);
4710bbfda8aSnia}
4720bbfda8aSnia
4730bbfda8aSnia#undef GWS_CHECK
4740bbfda8aSnia
4750bbfda8aSnia
4760bbfda8aSnia
4770bbfda8aSnia/*
4780bbfda8aSnia * Show the background (by hiding all windows) or undo it.
4790bbfda8aSnia * f.showbackground, also can be called via EWMH bits.
4800bbfda8aSnia *
4810bbfda8aSnia * newstate is the desired showing state.
4820bbfda8aSnia * Pass -1 to toggle, 1 to show the background,
4830bbfda8aSnia * or 0 to re-show the windows.
4840bbfda8aSnia *
4850bbfda8aSnia * XXX Doesn't really belong here; more of a functions.c-ish thing
4860bbfda8aSnia * probably.  But left here for the moment.
4870bbfda8aSnia */
4880bbfda8aSniavoid
4890bbfda8aSniaShowBackground(VirtualScreen *vs, int newstate)
4900bbfda8aSnia{
4910bbfda8aSnia	static int state = 0;
4920bbfda8aSnia	TwmWindow *twmWin;
4930bbfda8aSnia
4940bbfda8aSnia	if(newstate == state) {
4950bbfda8aSnia		return;
4960bbfda8aSnia	}
4970bbfda8aSnia
4980bbfda8aSnia	if(state) {
4990bbfda8aSnia		for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
5000bbfda8aSnia			if(twmWin->savevs == vs) {
5010bbfda8aSnia				DisplayWin(vs, twmWin);
5020bbfda8aSnia			}
5030bbfda8aSnia			twmWin->savevs = NULL;
5040bbfda8aSnia		}
5050bbfda8aSnia		state = 0;
5060bbfda8aSnia	}
5070bbfda8aSnia	else {
5080bbfda8aSnia		for(twmWin = Scr->FirstWindow; twmWin != NULL; twmWin = twmWin->next) {
5090bbfda8aSnia			if(twmWin->vs == vs
5100bbfda8aSnia#ifdef EWMH
5110bbfda8aSnia			                /* leave wt_Desktop and wt_Dock visible */
5120bbfda8aSnia			                && twmWin->ewmhWindowType == wt_Normal
5130bbfda8aSnia#endif /* EWMH */
5140bbfda8aSnia			  ) {
5150bbfda8aSnia				twmWin->savevs = twmWin->vs;
5160bbfda8aSnia				Vanish(vs, twmWin);
5170bbfda8aSnia			}
5180bbfda8aSnia		}
5190bbfda8aSnia		state = 1;
5200bbfda8aSnia	}
5210bbfda8aSnia#ifdef EWMH
5220bbfda8aSnia	EwmhSet_NET_SHOWING_DESKTOP(state);
5230bbfda8aSnia#endif /* EWMH */
5240bbfda8aSnia}
5250bbfda8aSnia
5260bbfda8aSnia
5270bbfda8aSnia/*
5280bbfda8aSnia * Get the name of the currently active WS.  Used in Execute() for
5290bbfda8aSnia * sub'ing in $currentworkspace in executing commands.
5300bbfda8aSnia */
5310bbfda8aSniachar *
5320bbfda8aSniaGetCurrentWorkSpaceName(VirtualScreen *vs)
5330bbfda8aSnia{
5340bbfda8aSnia	if(! Scr->workSpaceManagerActive) {
5350bbfda8aSnia		return (NULL);
5360bbfda8aSnia	}
5370bbfda8aSnia	if(!vs) {
5380bbfda8aSnia		vs = Scr->vScreenList;
5390bbfda8aSnia	}
5400bbfda8aSnia	return vs->wsw->currentwspc->name;
5410bbfda8aSnia}
5420bbfda8aSnia
5430bbfda8aSnia
5440bbfda8aSnia/*
5450bbfda8aSnia * Find workspace by name
5460bbfda8aSnia */
5470bbfda8aSniaWorkSpace *
5480bbfda8aSniaGetWorkspace(const char *wname)
5490bbfda8aSnia{
5500bbfda8aSnia	WorkSpace *ws;
5510bbfda8aSnia
5520bbfda8aSnia	/* Guard */
5530bbfda8aSnia	if(!wname) {
5540bbfda8aSnia		return (NULL);
5550bbfda8aSnia	}
5560bbfda8aSnia
5570bbfda8aSnia	/* Check by label */
5580bbfda8aSnia	for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
5590bbfda8aSnia		if(strcmp(ws->label, wname) == 0) {
5600bbfda8aSnia			return ws;
5610bbfda8aSnia		}
5620bbfda8aSnia	}
5630bbfda8aSnia
5640bbfda8aSnia	/* Check by name */
5650bbfda8aSnia	for(ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) {
5660bbfda8aSnia		if(strcmp(ws->name, wname) == 0) {
5670bbfda8aSnia			return ws;
5680bbfda8aSnia		}
5690bbfda8aSnia	}
5700bbfda8aSnia
5710bbfda8aSnia	/* Nope */
5720bbfda8aSnia	return NULL;
5730bbfda8aSnia}
574