From 4642216f70dd98134a79f9299b7ca4bc876649c7 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Sun, 28 Aug 2016 00:36:53 -0700 Subject: *: 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. --- src/desktop.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 src/desktop.c (limited to 'src/desktop.c') 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 - + * + * 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 . + */ + /* virtual desktops */ + +#include +#include + +#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); +} -- cgit v1.2.3