diff options
Diffstat (limited to 'src/desktop.c')
-rw-r--r-- | src/desktop.c | 137 |
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); |