summaryrefslogtreecommitdiff
path: root/src/desktop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/desktop.c')
-rw-r--r--src/desktop.c137
1 files changed, 92 insertions, 45 deletions
diff --git a/src/desktop.c b/src/desktop.c
index 8abc4d6..d88fa93 100644
--- a/src/desktop.c
+++ b/src/desktop.c
@@ -33,26 +33,27 @@ vwm_desktop_t * vwm_desktop_mru(vwm_t *vwm, vwm_desktop_t *desktop)
{
VWM_TRACE("MRU desktop: %p", desktop);
list_move(&desktop->desktops_mru, &vwm->desktops_mru);
+ vwm_context_mru(vwm, desktop->context);
return desktop;
}
/* focus a virtual desktop */
-/* this switches to the desktop context if necessary, maps and unmaps windows accordingly if necessary */
+/* this updates the focused context if necessary, maps and unmaps windows accordingly if necessary */
int vwm_desktop_focus(vwm_t *vwm, vwm_desktop_t *desktop)
{
XGrabServer(VWM_XDISPLAY(vwm));
XSync(VWM_XDISPLAY(vwm), 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) {
+ if (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)
+ vwin = xwin->managed;
+ if (!vwin)
continue;
if (vwin->desktop == vwm->focused_desktop)
@@ -62,7 +63,8 @@ int vwm_desktop_focus(vwm_t *vwm, vwm_desktop_t *desktop)
XFlush(VWM_XDISPLAY(vwm));
list_for_each_entry_prev(xwin, &vwm->xwindows, xwindows) {
- if (!(vwin = xwin->managed) || vwin->shelved)
+ vwin = xwin->managed;
+ if (!vwin)
continue;
if (vwin->desktop == desktop)
@@ -70,6 +72,7 @@ int vwm_desktop_focus(vwm_t *vwm, vwm_desktop_t *desktop)
}
vwm->focused_desktop = desktop;
+ desktop->context->focused_desktop = desktop;
}
/* directly focus the desktop's focused window if there is one, we don't use vwm_win_focus() intentionally XXX */
@@ -84,53 +87,67 @@ int vwm_desktop_focus(vwm_t *vwm, vwm_desktop_t *desktop)
}
-/* return next MRU desktop relative to the supplied desktop, wraps-around */
+/* return next MRU desktop within the same context relative to the supplied desktop, wraps-around */
vwm_desktop_t * vwm_desktop_next_mru(vwm_t *vwm, vwm_desktop_t *desktop, vwm_direction_t direction)
{
vwm_desktop_t *next = desktop;
- /* 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.
- */
- switch (direction) {
- case VWM_DIRECTION_FORWARD:
- if (next->desktops_mru.next == &vwm->desktops_mru) {
- next = list_entry(next->desktops_mru.next->next, vwm_desktop_t, desktops_mru);
- } else {
- next = list_entry(next->desktops_mru.next, vwm_desktop_t, desktops_mru);
- }
- break;
+ do {
+ /* 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.
+ */
+ switch (direction) {
+ case VWM_DIRECTION_FORWARD:
+ if (next->desktops_mru.next == &vwm->desktops_mru) {
+ next = list_entry(next->desktops_mru.next->next, vwm_desktop_t, desktops_mru);
+ } else {
+ next = list_entry(next->desktops_mru.next, vwm_desktop_t, desktops_mru);
+ }
+ break;
- case VWM_DIRECTION_REVERSE:
- if (next->desktops_mru.prev == &vwm->desktops_mru) {
- next = list_entry(next->desktops_mru.prev->prev, vwm_desktop_t, desktops_mru);
- } else {
- next = list_entry(next->desktops_mru.prev, vwm_desktop_t, desktops_mru);
- }
- break;
+ case VWM_DIRECTION_REVERSE:
+ if (next->desktops_mru.prev == &vwm->desktops_mru) {
+ next = list_entry(next->desktops_mru.prev->prev, vwm_desktop_t, desktops_mru);
+ } else {
+ next = list_entry(next->desktops_mru.prev, vwm_desktop_t, desktops_mru);
+ }
+ break;
- default:
- assert(0);
- }
+ default:
+ assert(0);
+ }
+ } while (next->context != desktop->context);
return next;
}
-/* return next desktop spatially relative to the supplied desktop, no wrap-around */
+/* return next in-context desktop spatially relative to the supplied desktop, no wrap-around */
vwm_desktop_t * vwm_desktop_next(vwm_t *vwm, vwm_desktop_t *desktop, vwm_direction_t direction)
{
switch (direction) {
- case VWM_DIRECTION_FORWARD:
- if (desktop->desktops.next != &vwm->desktops)
- return list_entry(desktop->desktops.next, vwm_desktop_t, desktops);
+ case VWM_DIRECTION_FORWARD: {
+ vwm_desktop_t *next = desktop;
+
+ while (next->desktops.next != &vwm->desktops) {
+ next = list_entry(next->desktops.next, vwm_desktop_t, desktops);
+ if (next->context == desktop->context)
+ return next;
+ }
break;
+ }
- case VWM_DIRECTION_REVERSE:
- if (desktop->desktops.prev != &vwm->desktops)
- return list_entry(desktop->desktops.prev, vwm_desktop_t, desktops);
+ case VWM_DIRECTION_REVERSE: {
+ vwm_desktop_t *next = desktop;
+
+ while (next->desktops.prev != &vwm->desktops) {
+ next = list_entry(next->desktops.prev, vwm_desktop_t, desktops);
+ if (next->context == desktop->context)
+ return next;
+ }
break;
+ }
default:
assert(0);
@@ -139,24 +156,39 @@ vwm_desktop_t * vwm_desktop_next(vwm_t *vwm, vwm_desktop_t *desktop, vwm_directi
return desktop;
}
-/* create a virtual desktop */
-vwm_desktop_t * vwm_desktop_create(vwm_t *vwm)
+
+/* TODO: when "sending" windows to contexts, I currently always create a
+ * new desktop with this function. There should really be a "create if needed"
+ * variant which just returns an empty desktop in the target context, creating
+ * only if no empty one already exists, for "sending" purposes. The current
+ * approach tends to litter empty desktops unnecessarily.
+ */
+/* create a virtual desktop on the supplied context,
+ * if context is NULL a new one is created
+ * the desktop becomes the context's focused desktop if there isn't already one
+ */
+vwm_desktop_t * vwm_desktop_create(vwm_t *vwm, vwm_context_t *context)
{
vwm_desktop_t *desktop;
desktop = calloc(1, sizeof(vwm_desktop_t));
if (desktop == NULL) {
VWM_PERROR("Failed to allocate desktop");
- goto _fail;
+ return NULL;
}
+ if (!context)
+ context = vwm_context_create(vwm, -1, desktop);
+
+ if (!context->focused_desktop)
+ context->focused_desktop = desktop;
+
+ desktop->context = context;
+
list_add_tail(&desktop->desktops, &vwm->desktops);
list_add_tail(&desktop->desktops_mru, &vwm->desktops_mru);
return desktop;
-
-_fail:
- return NULL;
}
@@ -169,16 +201,31 @@ void vwm_desktop_destroy(vwm_t *vwm, vwm_desktop_t *desktop)
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) {
+ /* focus the desktop context's MRU desktop that isn't this one,
+ * if desktop is the context's focused desktop */
+ if (desktop == desktop->context->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);
+ if (next_desktop != desktop && next_desktop->context == desktop->context) {
+ desktop->context->focused_desktop = next_desktop;
break;
}
}
+
+ /* if *still* the context's focused desktop, the context is finished.
+ * find a desktop from the next MRU context to focus if this desktop
+ * was the vwm focused one before destroying the context
+ */
+ if (desktop == desktop->context->focused_desktop) {
+ if (desktop == vwm->focused_desktop)
+ next_desktop = vwm_context_next_mru(vwm, desktop->context, VWM_DIRECTION_FORWARD)->focused_desktop;
+
+ vwm_context_destroy(vwm, desktop->context);
+ }
+
+ if (desktop == vwm->focused_desktop)
+ vwm_desktop_focus(vwm, next_desktop);
}
list_del(&desktop->desktops);
© All Rights Reserved