diff options
| author | Vito Caputo <vcaputo@gnugeneration.com> | 2016-08-28 00:36:53 -0700 | 
|---|---|---|
| committer | Vito Caputo <vcaputo@gnugeneration.com> | 2016-09-09 14:14:31 -0700 | 
| commit | 4642216f70dd98134a79f9299b7ca4bc876649c7 (patch) | |
| tree | bdf9fd892bc54a2f2a678a9828c6af9d9fc8bed2 /src/desktop.c | |
| parent | e99f5ac1293a0ae1f498bc4c73c4c04e4edb8665 (diff) | |
*: refactor all the things
Long overdue house cleaning.
The addition of compositing/monitoring overlays in vwm3 pushed vwm well past
what is a reasonable size for a simple thousand line file.  This is a first
step towards restoring sanity in the code, but no behavioral differences are
intended, this is mostly just shuffling around and organizing code.
I expect some performance regressions initially, follow-on commits will make
more improvements to that end as the dust settles.
Diffstat (limited to 'src/desktop.c')
| -rw-r--r-- | src/desktop.c | 158 | 
1 files changed, 158 insertions, 0 deletions
diff --git a/src/desktop.c b/src/desktop.c new file mode 100644 index 0000000..d3fdd13 --- /dev/null +++ b/src/desktop.c @@ -0,0 +1,158 @@ +/* + *                                  \/\/\ + * + *  Copyright (C) 2012-2016  Vito Caputo - <vcaputo@gnugeneration.com> + * + *  This program is free software: you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 3 as published + *  by the Free Software Foundation. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +	/* virtual desktops */ + +#include <X11/Xlib.h> +#include <stdlib.h> + +#include "list.h" +#include "context.h" +#include "desktop.h" +#include "vwm.h" +#include "xwindow.h" + +/* make the specified desktop the most recently used one */ +void vwm_desktop_mru(vwm_t *vwm, vwm_desktop_t *desktop) +{ +	VWM_TRACE("MRU desktop: %p", desktop); +	list_move(&desktop->desktops_mru, &vwm->desktops_mru); +} + + +/* focus a virtual desktop */ +/* this switches to the desktop context if necessary, maps and unmaps windows accordingly if necessary */ +int vwm_desktop_focus(vwm_t *vwm, vwm_desktop_t *desktop) +{ +	XGrabServer(vwm->display); +	XSync(vwm->display, False); + +	/* if the context switched and the focused desktop is the desired desktop there's nothing else to do */ +	if ((vwm_context_focus(vwm, VWM_CONTEXT_DESKTOP) && vwm->focused_desktop != desktop) || vwm->focused_desktop != desktop) { +		vwm_xwindow_t	*xwin; +		vwm_window_t	*vwin; + +		/* unmap the windows on the currently focused desktop, map those on the newly focused one */ +		list_for_each_entry(xwin, &vwm->xwindows, xwindows) { +			if (!(vwin = xwin->managed) || vwin->shelved) continue; +			if (vwin->desktop == vwm->focused_desktop) vwm_win_unmap(vwm, vwin); +		} + +		XFlush(vwm->display); + +		list_for_each_entry_prev(xwin, &vwm->xwindows, xwindows) { +			if (!(vwin = xwin->managed) || vwin->shelved) continue; +			if (vwin->desktop == desktop) vwm_win_map(vwm, vwin); +		} + +		vwm->focused_desktop = desktop; +	} + +	/* directly focus the desktop's focused window if there is one, we don't use vwm_win_focus() intentionally XXX */ +	if (vwm->focused_desktop->focused_window) { +		VWM_TRACE("Focusing \"%s\"", vwm->focused_desktop->focused_window->xwindow->name); +		XSetInputFocus(vwm->display, vwm->focused_desktop->focused_window->xwindow->id, RevertToPointerRoot, CurrentTime); +	} + +	XUngrabServer(vwm->display); + +	return 1; +} + +/* return next MRU desktop relative to the supplied desktop */ +vwm_desktop_t * vwm_desktop_next_mru(vwm_t *vwm, vwm_desktop_t *desktop) { +	list_head_t	*next; + +	/* this dance is necessary because the list head @ vwm->desktops_mru has no vwm_desktop_t container, +	 * and we're exploiting the circular nature of the doubly linked lists, so we need to take care to skip +	 * past the container-less head. +	 */ +	if (desktop->desktops_mru.next == &vwm->desktops_mru) { +		next = desktop->desktops_mru.next->next; +	} else { +		next = desktop->desktops_mru.next; +	} + +	return list_entry(next, vwm_desktop_t, desktops_mru); +} + +/* return next desktop spatially relative to the supplied desktop, no wrap-around */ +vwm_desktop_t * vwm_desktop_next(vwm_t *vwm, vwm_desktop_t *desktop) { +	if (desktop->desktops.next != &vwm->desktops) { +		desktop = list_entry(desktop->desktops.next, vwm_desktop_t, desktops); +	} + +	return desktop; +} + + +/* return previous desktop spatially relative to the supplied desktop, no wrap-around */ +vwm_desktop_t * vwm_desktop_prev(vwm_t *vwm, vwm_desktop_t *desktop) { +	if (desktop->desktops.prev != &vwm->desktops) { +		desktop = list_entry(desktop->desktops.prev, vwm_desktop_t, desktops); +	} + +	return desktop; +} + +/* create a virtual desktop */ +vwm_desktop_t * vwm_desktop_create(vwm_t *vwm, char *name) +{ +	vwm_desktop_t	*desktop; + +	desktop = malloc(sizeof(vwm_desktop_t)); +	if (desktop == NULL) { +		VWM_PERROR("Failed to allocate desktop"); +		goto _fail; +	} + +	desktop->name = name == NULL ? name : strdup(name); +	desktop->focused_window = NULL; + +	list_add_tail(&desktop->desktops, &vwm->desktops); +	list_add_tail(&desktop->desktops_mru, &vwm->desktops_mru); + +	return desktop; + +_fail: +	return NULL; +} + + +/* destroy a virtual desktop */ +void vwm_desktop_destroy(vwm_t *vwm, vwm_desktop_t *desktop) +{ +	/* silently refuse to destroy a desktop having windows (for now) */ +	/* there's _always_ a focused window on a desktop having mapped windows */ +	/* also silently refuse to destroy the last desktop (for now) */ +	if (desktop->focused_window || (desktop->desktops.next == desktop->desktops.prev)) return; + +	/* focus the MRU desktop that isn't this one if we're the focused desktop */ +	if (desktop == vwm->focused_desktop) { +		vwm_desktop_t	*next_desktop; + +		list_for_each_entry(next_desktop, &vwm->desktops_mru, desktops_mru) { +			if (next_desktop != desktop) { +				vwm_desktop_focus(vwm, next_desktop); +				break; +			} +		} +	} + +	list_del(&desktop->desktops); +	list_del(&desktop->desktops_mru); +}  | 
