summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/colors.def3
-rw-r--r--src/context.c222
-rw-r--r--src/context.h23
-rw-r--r--src/desktop.c137
-rw-r--r--src/desktop.h4
-rw-r--r--src/key.c235
-rw-r--r--src/screen.c11
-rw-r--r--src/vwm.c12
-rw-r--r--src/vwm.h19
-rw-r--r--src/window.c185
-rw-r--r--src/window.h2
-rw-r--r--src/xwindow.c20
12 files changed, 550 insertions, 323 deletions
diff --git a/src/colors.def b/src/colors.def
index 97c0dc9..7c71da0 100644
--- a/src/colors.def
+++ b/src/colors.def
@@ -1,6 +1,3 @@
-color(focused_window_border, "Green")
-color(shelved_window_border, "purple")
color(unfocused_window_border, "DarkGray")
-color(shelved_console_border, "red")
color(rubberband, "Orange")
color(logo, "LimeGreen")
diff --git a/src/context.c b/src/context.c
index 32d7b3f..255480c 100644
--- a/src/context.c
+++ b/src/context.c
@@ -15,89 +15,163 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- /* desktop/shelf context handling */
+ /* contexts (this is derived from desktops) */
+#include <assert.h>
#include <X11/Xlib.h>
+#include <stdlib.h>
+#include <string.h>
+#include "list.h"
#include "context.h"
#include "desktop.h"
#include "vwm.h"
#include "xwindow.h"
-#include "window.h"
-/* switch to the desired context if it isn't already the focused one, inform caller if anything happened */
-int vwm_context_focus(vwm_t *vwm, vwm_context_t desired_context)
+/* make the specified context the most recently used one */
+vwm_context_t * vwm_context_mru(vwm_t *vwm, vwm_context_t *context)
{
- vwm_context_t entry_context = vwm->focused_context;
-
- switch (vwm->focused_context) {
- vwm_xwindow_t *xwin;
- vwm_window_t *vwin;
-
- case VWM_CONTEXT_SHELF:
- if (desired_context == VWM_CONTEXT_SHELF)
- break;
-
- /* desired == DESKTOP && focused == SHELF */
-
- VWM_TRACE("unmapping shelf window \"%s\"", vwm->focused_shelf->xwindow->name);
- vwm_win_unmap(vwm, vwm->focused_shelf);
- XFlush(VWM_XDISPLAY(vwm)); /* for a more responsive feel */
-
- /* map the focused desktop, from the top of the stack down */
- list_for_each_entry_prev(xwin, &vwm->xwindows, xwindows) {
- if (!(vwin = xwin->managed))
- continue;
-
- if (vwin->desktop == vwm->focused_desktop && !vwin->shelved) {
- VWM_TRACE("Mapping desktop window \"%s\"", xwin->name);
- vwm_win_map(vwm, vwin);
- }
- }
-
- if (vwm->focused_desktop->focused_window) {
- VWM_TRACE("Focusing \"%s\"", vwm->focused_desktop->focused_window->xwindow->name);
- XSetInputFocus(VWM_XDISPLAY(vwm), vwm->focused_desktop->focused_window->xwindow->id, RevertToPointerRoot, CurrentTime);
- }
-
- vwm->focused_context = VWM_CONTEXT_DESKTOP;
- break;
-
- case VWM_CONTEXT_DESKTOP:
- /* unmap everything, map the shelf */
- if (desired_context == VWM_CONTEXT_DESKTOP)
- break;
-
- /* desired == SHELF && focused == DESKTOP */
-
- /* there should be a focused shelf if the shelf contains any windows, we NOOP the switch if the shelf is empty. */
- if (vwm->focused_shelf) {
- /* unmap everything on the current desktop */
- list_for_each_entry(xwin, &vwm->xwindows, xwindows) {
- if (!(vwin = xwin->managed))
- continue;
-
- if (vwin->desktop == vwm->focused_desktop) {
- VWM_TRACE("Unmapping desktop window \"%s\"", xwin->name);
- vwm_win_unmap(vwm, vwin);
- }
- }
-
- XFlush(VWM_XDISPLAY(vwm)); /* for a more responsive feel */
-
- VWM_TRACE("Mapping shelf window \"%s\"", vwm->focused_shelf->xwindow->name);
- vwm_win_map(vwm, vwm->focused_shelf);
- vwm_win_focus(vwm, vwm->focused_shelf);
-
- vwm->focused_context = VWM_CONTEXT_SHELF;
- }
- break;
-
- default:
- VWM_BUG("unexpected focused context %x", vwm->focused_context);
- break;
+ VWM_TRACE("MRU context: %p", context);
+ list_move(&context->contexts_mru, &vwm->contexts_mru);
+
+ return context;
+}
+
+
+/* return next MRU context relative to the supplied context */
+vwm_context_t * vwm_context_next_mru(vwm_t *vwm, vwm_context_t *context, vwm_direction_t direction)
+{
+ list_head_t *next;
+
+ switch (direction) {
+ case VWM_DIRECTION_FORWARD:
+ if (context->contexts_mru.next == &vwm->contexts_mru) {
+ next = context->contexts_mru.next->next;
+ } else {
+ next = context->contexts_mru.next;
+ }
+ break;
+
+ case VWM_DIRECTION_REVERSE:
+ if (context->contexts_mru.prev == &vwm->contexts_mru) {
+ next = context->contexts_mru.prev->prev;
+ } else {
+ next = context->contexts_mru.prev;
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+
+ return list_entry(next, vwm_context_t, contexts_mru);
+}
+
+
+/* return next context spatially relative to the supplied context, no wrap-around */
+vwm_context_t * vwm_context_next(vwm_t *vwm, vwm_context_t *context, vwm_direction_t direction)
+{
+ switch (direction) {
+ case VWM_DIRECTION_FORWARD:
+ if (context->contexts.next != &vwm->contexts)
+ context = list_entry(context->contexts.next, vwm_context_t, contexts);
+ break;
+
+ case VWM_DIRECTION_REVERSE:
+ if (context->contexts.prev != &vwm->contexts)
+ context = list_entry(context->contexts.prev, vwm_context_t, contexts);
+ break;
+ }
+
+ return context;
+}
+
+
+/* helper for automatically assigning context colors */
+static int next_context_color_idx(vwm_t *vwm)
+{
+ int counts[VWM_CONTEXT_COLOR_MAX] = {};
+ vwm_context_t *context;
+ int color = 0;
+
+ /* TODO: contexts should probably keep a window count,
+ * so this could skip empty contexts, then those
+ * would be automatically recycled.
+ */
+ list_for_each_entry(context, &vwm->contexts, contexts)
+ counts[context->color]++;
+
+ for (int i = 0; i < NELEMS(counts); i++) {
+ if (counts[i] < counts[color])
+ color = i;
+ }
+
+ return color;
+}
+
+
+/* create a context */
+/* if color = -1 one is automatically assigned,
+ * otherwise the supplied color is used.
+ */
+vwm_context_t * vwm_context_create(vwm_t *vwm, int color, vwm_desktop_t *desktop)
+{
+ vwm_context_t *context;
+
+ context = calloc(1, sizeof(vwm_context_t));
+ if (context == NULL) {
+ VWM_PERROR("Failed to allocate context");
+ goto _fail;
+ }
+
+ if (color < 0)
+ color = next_context_color_idx(vwm);
+
+ assert(color < NELEMS(vwm->context_colors));
+
+ context->color = color;
+
+ list_add_tail(&context->contexts, &vwm->contexts);
+ list_add_tail(&context->contexts_mru, &vwm->contexts_mru);
+
+ if (!desktop)
+ desktop = vwm_desktop_create(vwm, context);
+
+ context->focused_desktop = desktop;
+
+ return context;
+
+_fail:
+ return NULL;
+}
+
+
+/* destroy a context */
+void vwm_context_destroy(vwm_t *vwm, vwm_context_t *context)
+{
+ /* silently refuse to destroy a context having windows (for now) */
+ /* there's _always_ a focused window on a context having mapped windows */
+ if (context->focused_desktop && context->focused_desktop->focused_window)
+ return;
+
+ /* also silently refuse to destroy the last context (for now) */
+ if (context->contexts.next == context->contexts.prev)
+ return;
+
+ list_del(&context->contexts);
+ list_del(&context->contexts_mru);
+}
+
+
+/* find a context by color, creating one if needed */
+vwm_context_t * vwm_context_by_color(vwm_t *vwm, unsigned color)
+{
+ vwm_context_t *context;
+
+ list_for_each_entry(context, &vwm->contexts, contexts) {
+ if (context->color == color)
+ return context;
}
- /* return if the context has been changed, the caller may need to branch differently if nothing happened */
- return (vwm->focused_context != entry_context);
+ return vwm_context_create(vwm, color, NULL);
}
diff --git a/src/context.h b/src/context.h
index 1604bd3..5eebc43 100644
--- a/src/context.h
+++ b/src/context.h
@@ -1,14 +1,27 @@
#ifndef _CONTEXT_H
#define _CONTEXT_H
+#include "direction.h"
+#include "list.h"
+
typedef struct _vwm_t vwm_t;
+typedef struct _vwm_desktop_t vwm_desktop_t;
-typedef enum _vwm_context_t {
- VWM_CONTEXT_DESKTOP = 0, /* focus the desktop context */
- VWM_CONTEXT_SHELF, /* focus the shelf context */
- VWM_CONTEXT_OTHER /* focus the other context relative to the current one */
+/* contexts and desktops are *very* similar, they should likely share code,
+ * simply duplicating for now.
+ */
+typedef struct _vwm_context_t {
+ list_head_t contexts; /* global list of contexts in spatial created-in order */
+ list_head_t contexts_mru; /* global list of contexts in MRU order */
+ vwm_desktop_t *focused_desktop; /* the focused desktop on this context */
+ unsigned color; /* color used for focused border on this context */
} vwm_context_t;
-int vwm_context_focus(vwm_t *vwm, vwm_context_t desired_context);
+vwm_context_t * vwm_context_mru(vwm_t *vwm, vwm_context_t *context);
+vwm_context_t * vwm_context_create(vwm_t *vwm, int color, vwm_desktop_t *desktop);
+void vwm_context_destroy(vwm_t *vwm, vwm_context_t *context);
+vwm_context_t * vwm_context_next_mru(vwm_t *vwm, vwm_context_t *context, vwm_direction_t direction);
+vwm_context_t * vwm_context_next(vwm_t *vwm, vwm_context_t *context, vwm_direction_t direction);
+vwm_context_t * vwm_context_by_color(vwm_t *vwm, unsigned color);
#endif
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);
diff --git a/src/desktop.h b/src/desktop.h
index 1503407..597adb8 100644
--- a/src/desktop.h
+++ b/src/desktop.h
@@ -7,16 +7,18 @@
typedef struct _vwm_t vwm_t;
typedef struct _vwm_window_t vwm_window_t;
+typedef struct _vwm_context_t vwm_context_t;
typedef struct _vwm_desktop_t {
list_head_t desktops; /* global list of (virtual) desktops */
list_head_t desktops_mru; /* global list of (virtual) desktops in MRU order */
+ vwm_context_t *context; /* context this desktop belongs to */
vwm_window_t *focused_window; /* the focused window on this virtual desktop */
} vwm_desktop_t;
vwm_desktop_t * vwm_desktop_mru(vwm_t *vwm, vwm_desktop_t *desktop);
int vwm_desktop_focus(vwm_t *vwm, vwm_desktop_t *desktop);
-vwm_desktop_t * vwm_desktop_create(vwm_t *vwm);
+vwm_desktop_t * vwm_desktop_create(vwm_t *vwm, vwm_context_t *context);
void vwm_desktop_destroy(vwm_t *vwm, vwm_desktop_t *desktop);
vwm_desktop_t * vwm_desktop_next_mru(vwm_t *vwm, vwm_desktop_t *desktop, vwm_direction_t direction);
vwm_desktop_t * vwm_desktop_next(vwm_t *vwm, vwm_desktop_t *desktop, vwm_direction_t direction);
diff --git a/src/key.c b/src/key.c
index e1eee5d..da1a22b 100644
--- a/src/key.c
+++ b/src/key.c
@@ -31,6 +31,7 @@
static int key_is_grabbed; /* flag for tracking keyboard grab state */
static vwm_direction_t direction = VWM_DIRECTION_FORWARD; /* flag for reversing directional actions */
+static int send_it; /* flag for "sending" a migration operation without following it */
/* Poll the keyboard state to see if _any_ keys are pressed */
static int keys_pressed(vwm_t *vwm)
@@ -75,8 +76,7 @@ void vwm_key_released(vwm_t *vwm, Window win, XKeyReleasedEvent *keyrelease)
vwm_win_mru(vwm, vwin);
/* make the focused desktop the most recently used */
- if (vwm->focused_context == VWM_CONTEXT_DESKTOP && vwm->focused_desktop)
- vwm_desktop_mru(vwm, vwm->focused_desktop);
+ vwm_desktop_mru(vwm, vwm->focused_desktop);
break;
@@ -85,6 +85,11 @@ void vwm_key_released(vwm_t *vwm, Window win, XKeyReleasedEvent *keyrelease)
direction = VWM_DIRECTION_FORWARD;
break;
+ case XK_s:
+ VWM_TRACE("XK_s released with send_it=%i", send_it);
+ send_it = 0;
+ break;
+
default:
VWM_TRACE("Unhandled keycode: %x", (unsigned int)sym);
break;
@@ -144,9 +149,32 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress)
direction = VWM_DIRECTION_REVERSE;
break;
- case XK_grave: /* toggle shelf visibility */
- vwm_context_focus(vwm, VWM_CONTEXT_OTHER);
+ case XK_s: /* "send" migrational actions */
+ VWM_TRACE("XK_s pressed with send_it=%i", send_it);
+ send_it = 1;
+ break;
+
+ case XK_grave: { /* cycle focused desktop by context */
+ vwm_context_t *next_context;
+
+ do_grab = 1; /* update MRU desktop on commit (Mod1 release) */
+ next_context = vwm_context_next_mru(vwm, vwm->focused_desktop->context, direction);
+
+ if (send_it && (keypress->state & ShiftMask)) { /* "send" the focused window to the MRU context's MRU desktop */
+ if (vwin)
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, next_context->focused_desktop));
+ } else if (send_it) { /* "send" the focused window to a new desktop created on the MRU context */
+ if (vwin)
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, vwm_desktop_create(vwm, next_context)));
+ } else if (keypress->state & ShiftMask) {
+ /* migrate the focused window with the desktop focus to the MRU context's MRU desktop */
+ if (vwin)
+ vwm_win_migrate(vwm, vwin, next_context->focused_desktop);
+ } else {
+ vwm_desktop_focus(vwm, next_context->focused_desktop);
+ }
break;
+ }
case XK_Tab: /* cycle focused window */
do_grab = 1; /* update MRU window on commit (Mod1 release) */
@@ -154,22 +182,53 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress)
/* focus the next window, note this doesn't affect MRU yet, that happens on Mod1 release */
if (vwin) {
if (keypress->state & ShiftMask) {
- vwm_win_focus_next(vwm, vwin, direction, VWM_FENCE_MASKED_VIOLATE);
+ /* TODO: in keeping with the Shift==migrate behavior, perhaps
+ * for Tab it should really do a in-desktop migration of sorts
+ * where the focused window swaps places with the next window?
+ */
+ VWM_TRACE("in-desktop migrate not implemented yet");
} else {
vwm_win_focus_next(vwm, vwin, direction, VWM_FENCE_RESPECT);
}
}
break;
+ case XK_backslash:
+ do_grab = 1;
+
+ if (vwin) {
+ if (keypress->state & ShiftMask) {
+ /* TODO: migrate window to another screen within this desktop,
+ * like VWM_FENCE_MASKED_VIOLATE would focus the next window on
+ * the next screen, but instead of focusing the next window on
+ * the next display, move the focused one to that next desktop.
+ *
+ * since screens are handled within vwm_win_focus_next() via
+ * the fence abstraction, but fences aren't exposed outside of
+ * their, it's non-trivial to implement here. I may want to
+ * break that out into a more public interface to make things
+ * more composable at the screen level.
+ */
+ VWM_TRACE("migrate window to screen not implemented yet");
+ } else {
+ vwm_win_focus_next(vwm, vwin, direction, VWM_FENCE_MASKED_VIOLATE);
+ }
+ }
+ break;
+
case XK_space: { /* cycle focused desktop utilizing MRU */
vwm_desktop_t *next_desktop;
- next_desktop = vwm_desktop_next_mru(vwm, vwm->focused_desktop, direction);
-
do_grab = 1; /* update MRU desktop on commit (Mod1 release) */
+ next_desktop = vwm_desktop_next_mru(vwm, vwm->focused_desktop, direction);
- if (keypress->state & ShiftMask) {
- /* migrate the focused window with the desktop focus to the most recently used desktop */
+ if (send_it && (keypress->state & ShiftMask)) { /* "send" the focused window to the MRU desktop */
+ if (vwin)
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, next_desktop));
+ } else if (send_it) { /* "send" the focused window to a new desktop in the current context, kind of an alias of send_it+XK_v */
+ if (vwin)
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, vwm_desktop_create(vwm, vwin->desktop->context)));
+ } else if (keypress->state & ShiftMask) { /* migrate the focused window with the desktop focus to the most recently used desktop */
if (vwin)
vwm_win_migrate(vwm, vwin, next_desktop);
} else {
@@ -185,7 +244,7 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress)
} else { /* kindly destroy the focused window */
vwm_xwin_message(vwm, vwin->xwindow, vwm->wm_protocols_atom, vwm->wm_delete_atom);
}
- } else if (vwm->focused_context == VWM_CONTEXT_DESKTOP) {
+ } else {
/* destroy the focused desktop when destroy occurs without any windows */
vwm_desktop_destroy(vwm, vwm->focused_desktop);
}
@@ -201,80 +260,111 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress)
case XK_v: /* instantiate (and focus) a new (potentially empty, unless migrating) virtual desktop */
do_grab = 1; /* update MRU desktop on commit (Mod1 release) */
- if (keypress->state & ShiftMask) {
- if (vwin) {
- /* migrate the focused window to a newly created virtual desktop, focusing the new desktop simultaneously */
- vwm_win_migrate(vwm, vwin, vwm_desktop_create(vwm));
- }
+ if (send_it) { /* "send" the focused window to a newly created virtual desktop, */
+ if (vwin)
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, vwm_desktop_create(vwm, vwin->desktop->context)));
+ } else if (keypress->state & ShiftMask) { /* migrate the focused window to a newly created virtual desktop, focusing the new desktop simultaneously */
+ if (vwin)
+ vwm_win_migrate(vwm, vwin, vwm_desktop_create(vwm, vwin->desktop->context));
} else {
- vwm_desktop_focus(vwm, vwm_desktop_create(vwm));
- vwm_desktop_mru(vwm, vwm->focused_desktop);
+ vwm_desktop_focus(vwm, vwm_desktop_create(vwm, vwm->focused_desktop->context));
}
break;
- case XK_h: /* previous virtual desktop, if we're in the shelf context this will simply switch to desktop context */
+ case XK_c: /* instantiate (and focus) a new (potentialy empty, unless migrating) virtual desktop in a new context */
do_grab = 1; /* update MRU desktop on commit (Mod1 release) */
- if (keypress->state & ShiftMask) {
- if (vwin) {
- /* migrate the focused window with the desktop focus to the previous desktop */
- vwm_win_migrate(vwm, vwin, vwm_desktop_next(vwm, vwin->desktop, VWM_DIRECTION_REVERSE));
- }
+ if (send_it) { /* "send" the focused window to a newly created virtual desktop in a new context */
+ if (vwin)
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, vwm_desktop_create(vwm, NULL)));
+ } else if (keypress->state & ShiftMask) { /* migrate the focused window to a newly created virtual desktop in a new context, focusing the new desktop simultaneously */
+
+ if (vwin)
+ vwm_win_migrate(vwm, vwin, vwm_desktop_create(vwm, NULL));
} else {
- if (vwm->focused_context == VWM_CONTEXT_SHELF) {
- /* focus the focused desktop instead of the shelf */
- vwm_context_focus(vwm, VWM_CONTEXT_DESKTOP);
- } else {
- /* focus the previous desktop */
- vwm_desktop_focus(vwm, vwm_desktop_next(vwm, vwm->focused_desktop, VWM_DIRECTION_REVERSE));
- }
+ vwm_desktop_focus(vwm, vwm_desktop_create(vwm, NULL));
}
break;
- case XK_l: /* next virtual desktop, if we're in the shelf context this will simply switch to desktop context */
+ case XK_0:
+ case XK_1:
+ case XK_2:
+ case XK_3:
+ case XK_4:
+ case XK_5:
+ case XK_6:
+ case XK_7:
+ case XK_8:
+ case XK_9:
do_grab = 1; /* update MRU desktop on commit (Mod1 release) */
- if (keypress->state & ShiftMask) {
- if (vwin) {
- /* migrate the focused window with the desktop focus to the next desktop */
- vwm_win_migrate(vwm, vwin, vwm_desktop_next(vwm, vwin->desktop, VWM_DIRECTION_FORWARD));
- }
+ if (send_it && (keypress->state & ShiftMask)) { /* "send" the focused window to the specified context */
+ if (vwin)
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, vwm_context_by_color(vwm, sym - XK_0)->focused_desktop));
+ } else if (send_it) { /* "send" the focused window to a new desktop created on the specified context */
+ if (vwin)
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, vwm_desktop_create(vwm, vwm_context_by_color(vwm, sym - XK_0))));
+ } else if (keypress->state & ShiftMask) { /* migrate the focused window to the specified context */
+ if (vwin)
+ vwm_win_migrate(vwm, vwin, vwm_context_by_color(vwm, sym - XK_0)->focused_desktop);
} else {
- if (vwm->focused_context == VWM_CONTEXT_SHELF) {
- /* focus the focused desktop instead of the shelf */
- vwm_context_focus(vwm, VWM_CONTEXT_DESKTOP);
- } else {
- /* focus the next desktop */
- vwm_desktop_focus(vwm, vwm_desktop_next(vwm, vwm->focused_desktop, VWM_DIRECTION_FORWARD));
- }
+ vwm_desktop_focus(vwm, vwm_context_by_color(vwm, sym - XK_0)->focused_desktop);
+ }
+ break;
+
+ case XK_h: /* previous virtual desktop spatially */
+ do_grab = 1; /* update MRU desktop on commit (Mod1 release) */
+
+ if (send_it) { /* "send" the focused window to the previous desktop */
+ if (vwin)
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, vwm_desktop_next(vwm, vwin->desktop, VWM_DIRECTION_REVERSE)));
+ } else if (keypress->state & ShiftMask) { /* migrate the focused window with the desktop focus to the previous desktop */
+ if (vwin)
+ vwm_win_migrate(vwm, vwin, vwm_desktop_next(vwm, vwin->desktop, VWM_DIRECTION_REVERSE));
+ } else { /* focus the previous desktop */
+ vwm_desktop_focus(vwm, vwm_desktop_next(vwm, vwm->focused_desktop, VWM_DIRECTION_REVERSE));
+ }
+ break;
+
+ case XK_l: /* next virtual desktop spatially */
+ do_grab = 1; /* update MRU desktop on commit (Mod1 release) */
+
+ if (send_it) { /* "send" the focused window to the next desktop */
+ if (vwin)
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, vwm_desktop_next(vwm, vwin->desktop, VWM_DIRECTION_FORWARD)));
+ } else if (keypress->state & ShiftMask) { /* migrate the focused window with the desktop focus to the next desktop */
+ if (vwin)
+ vwm_win_migrate(vwm, vwin, vwm_desktop_next(vwm, vwin->desktop, VWM_DIRECTION_FORWARD));
+ } else { /* focus the next desktop */
+ vwm_desktop_focus(vwm, vwm_desktop_next(vwm, vwm->focused_desktop, VWM_DIRECTION_FORWARD));
}
break;
- case XK_k: /* raise or shelve the focused window */
+ case XK_k: /* raise or context-migrate the focused window up */
if (vwin) {
- if (keypress->state & ShiftMask) { /* shelf the window and focus the shelf */
- if (vwm->focused_context != VWM_CONTEXT_SHELF) {
- /* shelve the focused window while focusing the shelf */
- vwm_win_shelve(vwm, vwin);
- vwm_context_focus(vwm, VWM_CONTEXT_SHELF);
- }
- } else {
- do_grab = 1;
+ do_grab = 1;
+
+ /* TODO: maybe bare send_it should create a new desktop in the next context,
+ * with Shift+send_it being the migrate-like send */
+ if (send_it) { /* "send" the focused window to the next context */
+ vwm_context_t *next_context = vwm_context_next(vwm, vwin->desktop->context, VWM_DIRECTION_FORWARD);
+
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, next_context->focused_desktop));
+ } else if (keypress->state & ShiftMask) { /* migrate the window and focus the new context */
+ vwm_context_t *next_context = vwm_context_next(vwm, vwin->desktop->context, VWM_DIRECTION_FORWARD);
+ vwm_win_migrate(vwm, vwin, next_context->focused_desktop);
+ } else {
XRaiseWindow(VWM_XDISPLAY(vwm), vwin->xwindow->id);
- if (repeat_cnt == 1) {
- /* double: reraise & fullscreen */
+ if (repeat_cnt == 1) { /* double: reraise & fullscreen */
vwm_win_autoconf(vwm, vwin, VWM_SCREEN_REL_XWIN, VWM_WIN_AUTOCONF_FULL);
- } else if (repeat_cnt == 2) {
- /* triple: reraise & fullscreen w/borders obscured by screen perimiter */
+ } else if (repeat_cnt == 2) { /* triple: reraise & fullscreen w/borders obscured by screen perimiter */
vwm_win_autoconf(vwm, vwin, VWM_SCREEN_REL_XWIN, VWM_WIN_AUTOCONF_ALL);
} else if (vwm->xinerama_screens_cnt > 1) {
- if (repeat_cnt == 3) {
- /* triple: reraise & fullscreen across all screens */
+ if (repeat_cnt == 3) { /* triple: reraise & fullscreen across all screens */
vwm_win_autoconf(vwm, vwin, VWM_SCREEN_REL_TOTAL, VWM_WIN_AUTOCONF_FULL);
- } else if (repeat_cnt == 4) {
- /* quadruple: reraise & fullscreen w/borders obscured by screen perimiter */
+ } else if (repeat_cnt == 4) { /* quadruple: reraise & fullscreen w/borders obscured by screen perimiter */
vwm_win_autoconf(vwm, vwin, VWM_SCREEN_REL_TOTAL, VWM_WIN_AUTOCONF_ALL);
}
}
@@ -283,13 +373,20 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress)
}
break;
- case XK_j: /* lower or unshelve the focused window */
+ case XK_j: /* lower or context-migrate the focused window down */
if (vwin) {
- if (keypress->state & ShiftMask) { /* unshelf the window to the focused desktop, and focus the desktop */
- if (vwm->focused_context == VWM_CONTEXT_SHELF) {
- /* unshelve the focused window, focus the desktop it went to */
- vwm_win_migrate(vwm, vwin, vwm->focused_desktop);
- }
+ do_grab = 1;
+
+ /* TODO: maybe bare send_it should create a new desktop in the previous context,
+ * with Shift+send_it being the migrate-like send */
+ if (send_it) { /* "send" the focused window to the previous context */
+ vwm_context_t *prev_context = vwm_context_next(vwm, vwin->desktop->context, VWM_DIRECTION_REVERSE);
+
+ vwm_win_send(vwm, vwin, vwm_desktop_mru(vwm, prev_context->focused_desktop));
+ } else if (keypress->state & ShiftMask) { /* migrate the window and focus the new context */
+ vwm_context_t *prev_context = vwm_context_next(vwm, vwin->desktop->context, VWM_DIRECTION_REVERSE);
+
+ vwm_win_migrate(vwm, vwin, prev_context->focused_desktop);
} else {
if (vwin->autoconfigured == VWM_WIN_AUTOCONF_ALL) {
vwm_win_autoconf(vwm, vwin, VWM_SCREEN_REL_XWIN, VWM_WIN_AUTOCONF_FULL);
@@ -311,12 +408,6 @@ void vwm_key_pressed(vwm_t *vwm, Window win, XKeyPressedEvent *keypress)
}
break;
- case XK_s: /* shelve focused window */
- if (vwin && !vwin->shelved)
- vwm_win_shelve(vwm, vwin);
-
- break;
-
case XK_bracketleft: /* reconfigure the focused window to occupy the left or top half of the screen or left quarters on repeat */
if (vwin) {
do_grab = 1;
diff --git a/src/screen.c b/src/screen.c
index 32a0fc7..4449fb5 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -169,23 +169,20 @@ _out:
int vwm_screen_is_empty(vwm_t *vwm, const vwm_screen_t *scr, vwm_xwindow_t *ignore_xwin)
{
vwm_xwindow_t *xwin;
- int is_empty = 1;
list_for_each_entry(xwin, &vwm->xwindows, xwindows) {
if (xwin == ignore_xwin || !xwin->client_mapped)
continue;
- if (!xwin->managed || (xwin->managed->desktop == vwm->focused_desktop && !xwin->managed->shelved)) {
+ if (!xwin->managed || xwin->managed->desktop == vwm->focused_desktop) {
/* XXX: it may make more sense to see what %age of the screen is overlapped by windows, and consider it empty if < some % */
/* This is just seeing if any window is predominantly within the specified screen, the rationale being if you had a focusable
* window on the screen you would have used the keyboard to make windows go there; this function is only used in determining
* wether a new window should go where the pointer is or not. */
- if (vwm_screen_overlaps_xwin(vwm, scr, xwin) >= 0.05) {
- is_empty = 0;
- break;
- }
+ if (vwm_screen_overlaps_xwin(vwm, scr, xwin) >= 0.05)
+ return 0;
}
}
- return is_empty;
+ return 1;
}
diff --git a/src/vwm.c b/src/vwm.c
index 0e47fb0..9bc60de 100644
--- a/src/vwm.c
+++ b/src/vwm.c
@@ -70,6 +70,8 @@ static vwm_t * vwm_startup(void)
goto _err;
}
+ INIT_LIST_HEAD(&vwm->contexts);
+ INIT_LIST_HEAD(&vwm->contexts_mru);
INIT_LIST_HEAD(&vwm->desktops);
INIT_LIST_HEAD(&vwm->desktops_mru);
INIT_LIST_HEAD(&vwm->windows_mru);
@@ -125,6 +127,11 @@ static vwm_t * vwm_startup(void)
#include "colors.def"
#undef color
+#define color(_num, _str) \
+ XAllocNamedColor(VWM_XDISPLAY(vwm), VWM_XCMAP(vwm), _str, &vwm->context_colors[_num], &vwm->context_colors[_num]);
+#include "context_colors.def"
+#undef color
+
XSelectInput(VWM_XDISPLAY(vwm), VWM_XROOT(vwm),
FocusChangeMask | PropertyChangeMask | SubstructureNotifyMask | SubstructureRedirectMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
XGrabKey(VWM_XDISPLAY(vwm), AnyKey, WM_GRAB_MODIFIER, VWM_XROOT(vwm), False, GrabModeAsync, GrabModeAsync);
@@ -133,8 +140,9 @@ static vwm_t * vwm_startup(void)
XSetInputFocus(VWM_XDISPLAY(vwm), VWM_XROOT(vwm), RevertToPointerRoot, CurrentTime);
- /* create initial virtual desktop */
- vwm_desktop_focus(vwm, vwm_desktop_create(vwm));
+ /* create initial contexts and desktop */
+ vwm_desktop_create(vwm, NULL); /* shelf */
+ vwm_desktop_focus(vwm, vwm_desktop_create(vwm, NULL)); /* general */
vwm_desktop_mru(vwm, vwm->focused_desktop);
/* manage all preexisting windows */
diff --git a/src/vwm.h b/src/vwm.h
index a25e2b6..fec6a58 100644
--- a/src/vwm.h
+++ b/src/vwm.h
@@ -32,6 +32,15 @@
typedef struct _vwm_window_t vwm_window_t;
typedef struct _vwm_desktop_t vwm_desktop_t;
+/* this contortion is currently just to get VWM_CONTEXT_COLOR_MAX defined */
+typedef enum _vwm_context_color_t {
+#define color(_num, _str) \
+ VWM_CONTEXT_COLOR_ ## _num,
+#include "context_colors.def"
+#undef color
+ VWM_CONTEXT_COLOR_MAX
+} vwm_context_color_t;
+
typedef struct _vwm_t {
vwm_xserver_t *xserver; /* global xserver instance */
vwm_charts_t *charts; /* golbal charts instance */
@@ -45,24 +54,26 @@ typedef struct _vwm_t {
int xinerama_screens_cnt;
int done; /* global flag to cause vwm to quit */
+ list_head_t contexts; /* global list of all contexts in spatial created-in order */
+ list_head_t contexts_mru; /* global list of all contexts kept in MRU order */
list_head_t desktops; /* global list of all (virtual) desktops in spatial created-in order */
list_head_t desktops_mru; /* global list of all (virtual) desktops in MRU order */
list_head_t windows_mru; /* global list of all managed windows kept in MRU order */
list_head_t xwindows; /* global list of all xwindows kept in the X server stacking order */
+
vwm_window_t *console; /* the console window */
vwm_window_t *focused_origin; /* the originating window in a grabbed operation/transaction */
- vwm_desktop_t *focused_desktop; /* currently focused (virtual) desktop */
- vwm_window_t *focused_shelf; /* currently focused shelved window */
- vwm_context_t focused_context; /* currently focused context */
+ vwm_desktop_t *focused_desktop; /* currently focused desktop */
int priority; /* scheduling priority of the vwm process, launcher nices relative to this */
unsigned long fence_mask; /* global mask state for vwm_win_focus_next(... VWM_FENCE_MASKED_VIOLATE),
- * if you use vwm on enough screens to overflow this, pics or it didn't happen. */
+ * if you use vwm on enough screens to overflow this, pics or it didn't happen. */
struct colors {
#define color(_sym, _str) \
XColor _sym ## _color;
#include "colors.def"
#undef color
} colors;
+ XColor context_colors[VWM_CONTEXT_COLOR_MAX];
} vwm_t;
#endif
diff --git a/src/window.c b/src/window.c
index d1441f3..5410ba6 100644
--- a/src/window.c
+++ b/src/window.c
@@ -80,20 +80,10 @@ vwm_window_t * vwm_win_lookup(vwm_t *vwm, Window win)
}
-/* return the currently focused window (considers current context...), may return NULL */
+/* return the currently focused window, may return NULL */
vwm_window_t * vwm_win_get_focused(vwm_t *vwm)
{
- switch (vwm->focused_context) {
- case VWM_CONTEXT_SHELF:
- return vwm->focused_shelf;
-
- case VWM_CONTEXT_DESKTOP:
- return vwm->focused_desktop->focused_window;
-
- default:
- VWM_BUG("Unsupported context");
- assert(0);
- }
+ return vwm->focused_desktop->focused_window;
}
@@ -103,22 +93,15 @@ vwm_window_t * vwm_win_get_focused(vwm_t *vwm)
void vwm_win_set_focused(vwm_t *vwm, vwm_window_t *vwin)
{
/* update the border color accordingly */
- if (vwin->shelved) {
- /* set the border of the newly focused window to the shelved color */
- XSetWindowBorder(VWM_XDISPLAY(vwm), vwin->xwindow->id, vwin == vwm->console ? vwm->colors.shelved_console_border_color.pixel : vwm->colors.shelved_window_border_color.pixel);
- /* fullscreen windows in the shelf when focused, since we don't intend to overlap there */
- vwm_win_autoconf(vwm, vwin, VWM_SCREEN_REL_POINTER, VWM_WIN_AUTOCONF_FULL); /* XXX TODO: for now the shelf follows the pointer, it's simple. */
- } else {
- if (vwin->desktop->focused_window)
- /* set the border of the previously focused window on the same desktop to the unfocused color */
- XSetWindowBorder(VWM_XDISPLAY(vwm), vwin->desktop->focused_window->xwindow->id, vwm->colors.unfocused_window_border_color.pixel);
+ if (vwin->desktop->focused_window)
+ /* set the border of the previously focused window on the same desktop to the unfocused color */
+ XSetWindowBorder(VWM_XDISPLAY(vwm), vwin->desktop->focused_window->xwindow->id, vwm->colors.unfocused_window_border_color.pixel);
- /* set the border of the newly focused window to the focused color */
- XSetWindowBorder(VWM_XDISPLAY(vwm), vwin->xwindow->id, vwm->colors.focused_window_border_color.pixel);
+ /* set the border of the newly focused window to the focused color */
+ XSetWindowBorder(VWM_XDISPLAY(vwm), vwin->xwindow->id, vwm->context_colors[vwin->desktop->context->color].pixel);
- /* persist this on a per-desktop basis so it can be restored on desktop switches */
- vwin->desktop->focused_window = vwin;
- }
+ /* persist this on a per-desktop basis so it can be restored on desktop switches */
+ vwin->desktop->focused_window = vwin;
}
@@ -131,7 +114,7 @@ void vwm_win_autoconf_magic(vwm_t *vwm, vwm_window_t *vwin, const vwm_screen_t *
if (!scr)
scr = vwm_screen_find(vwm, VWM_SCREEN_REL_RECT, x, y, width, height);
- if (!vwin->shelved && scr &&
+ if (scr &&
width == scr->width &&
height == scr->height) {
VWM_TRACE_WIN(vwin->xwindow->id, "auto-allscreened window");
@@ -329,21 +312,9 @@ _retry:
VWM_TRACE("VWM_FENCE_MASKED_VIOLATE fence_mask now: 0x%lx\n", vwm->fence_mask);
}
- if (vwin->shelved) {
- if (next != vwm->focused_shelf) {
- if (vwm->focused_context == VWM_CONTEXT_SHELF) {
- vwm_win_unmap(vwm, vwm->focused_shelf);
- XFlush(VWM_XDISPLAY(vwm));
- vwm_win_map(vwm, next);
- }
- vwm->focused_shelf = next;
- vwm_win_focus(vwm, next);
- }
- } else {
- if (next != next->desktop->focused_window) {
- vwm_win_focus(vwm, next);
- XRaiseWindow(VWM_XDISPLAY(vwm), next->xwindow->id);
- }
+ if (next != next->desktop->focused_window) {
+ vwm_win_focus(vwm, next);
+ XRaiseWindow(VWM_XDISPLAY(vwm), next->xwindow->id);
}
VWM_TRACE("vwin=%p xwin=%p name=\"%s\"", next, next->xwindow, next->xwindow->name);
@@ -352,48 +323,62 @@ _retry:
}
-/* shelves a window, if the window is focused we focus the next one (if possible) */
+/* "shelves" a window, if the window is focused we focus the next one (if exists) */
+/* originally there was a special shelf context having different semantics of a fullscreen
+ * window at a time, this evolved into generic contexts containing virtual
+ * desktops, and now shelving is just the process of sending a window to the bottom/first
+ * context into a newly created desktop there, in an unattended fashion (like an unattended migrate,
+ * to an assumed bottom destination context created for this purpose at startup, and into its own
+ * desktop there).
+ */
void vwm_win_shelve(vwm_t *vwm, vwm_window_t *vwin)
{
- /* already shelved, NOOP */
- if (vwin->shelved)
+ vwm_context_t *shelf = list_entry(vwm->contexts.next, vwm_context_t, contexts);
+ vwm_desktop_t *desktop;
+
+ /* already in the first, AKA "shelf" context, NOOP */
+ if (&vwin->desktop->context->contexts == vwm->contexts.next)
return;
/* shelving focused window, focus the next window */
if (vwin == vwin->desktop->focused_window)
vwm_win_mru(vwm, vwm_win_focus_next(vwm, vwin, VWM_DIRECTION_FORWARD, VWM_FENCE_RESPECT));
+ /* vwin appears to be alone */
if (vwin == vwin->desktop->focused_window)
- /* TODO: we can probably put this into vwm_win_focus_next() and have it always handled there... */
vwin->desktop->focused_window = NULL;
- vwin->shelved = 1;
- vwm_win_mru(vwm, vwin);
+ /* TODO: ^^^ there should probably be a helper for withdrawing a window
+ * from a desktop which handles the above focus next -> lone window
+ * nonsense, and hands back an orphan window to do whatever with.
+ */
+
+ /* shelved windows always get an empty desktop in the shelf context,
+ * look for an empty one and only create a new one if there is none
+ * to use.
+ */
+ vwin->desktop = NULL;
+ list_for_each_entry(desktop, &vwm->desktops_mru, desktops_mru) {
+ if (desktop->context == shelf && !desktop->focused_window) {
+ vwin->desktop = desktop;
+ break;
+ }
+ }
- /* newly shelved windows always become the focused shelf */
- vwm->focused_shelf = vwin;
+ if (!vwin->desktop)
+ vwin->desktop = vwm_desktop_create(vwm, shelf);
+ /* always leave the newly shelved window's desktop focused */
+ vwin->desktop->context->focused_desktop = vwin->desktop;
+ vwm_win_set_focused(vwm, vwin);
+ vwm_win_mru(vwm, vwin);
vwm_win_unmap(vwm, vwin);
}
-/* helper for (idempotently) unfocusing a window, deals with context switching etc... */
+/* helper for (idempotently) unfocusing a window */
void vwm_win_unfocus(vwm_t *vwm, vwm_window_t *vwin)
{
- /* if we're the focused shelved window, cycle the focus to the next shelved window if possible, if there's no more shelf, switch to the desktop */
- /* TODO: there's probably some icky behaviors for focused windows unmapping/destroying in unfocused contexts, we probably jump contexts suddenly. */
- if (vwin == vwm->focused_shelf) {
- VWM_TRACE("unfocusing focused shelf");
- vwm_win_focus_next(vwm, vwin, VWM_DIRECTION_FORWARD, VWM_FENCE_IGNORE);
-
- if (vwin == vwm->focused_shelf) {
- VWM_TRACE("shelf empty, leaving");
- /* no other shelved windows, exit the shelf context */
- vwm_context_focus(vwm, VWM_CONTEXT_DESKTOP);
- vwm->focused_shelf = NULL;
- }
- }
-
/* if we're the focused window cycle the focus to the next window on the desktop if possible */
if (vwin->desktop->focused_window == vwin) {
VWM_TRACE("unfocusing focused window");
@@ -401,7 +386,7 @@ void vwm_win_unfocus(vwm_t *vwm, vwm_window_t *vwin)
}
if (vwin->desktop->focused_window == vwin) {
- VWM_TRACE("desktop empty");
+ VWM_TRACE("unfocused last window on desktop");
vwin->desktop->focused_window = NULL;
}
}
@@ -468,26 +453,23 @@ static void vwm_win_assimilate(vwm_t *vwm, vwm_window_t *vwin)
/* TODO: this is a good place to hook in a window placement algo */
/* on client-requested mapping we place the window */
- if (!vwin->shelved) {
- /* we place the window on the screen containing the the pointer only if that screen is empty,
- * otherwise we place windows on the screen containing the currently focused window */
- scr = vwm_screen_find(vwm, VWM_SCREEN_REL_POINTER);
- if (vwm_screen_is_empty(vwm, scr, vwin->xwindow)) {
- /* focus the new window if it isn't already focused when it's going to an empty screen */
- VWM_TRACE("window \"%s\" is alone on screen \"%i\", focusing", vwin->xwindow->name, scr->screen_number);
- vwm_win_focus(vwm, vwin);
- } else {
- scr = vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, vwm->focused_desktop->focused_window->xwindow);
- }
-
- changes.x = scr->x_org;
- changes.y = scr->y_org;
- } else if (vwm->focused_context == VWM_CONTEXT_SHELF) {
- scr = vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, vwm->focused_shelf->xwindow);
- changes.x = scr->x_org;
- changes.y = scr->y_org;
+ /* we place the window on the screen containing the the pointer only if that screen is empty,
+ * otherwise we place windows on the screen containing the currently focused window */
+ scr = vwm_screen_find(vwm, VWM_SCREEN_REL_POINTER);
+ if (vwm_screen_is_empty(vwm, scr, vwin->xwindow)) {
+ /* focus the new window if it isn't already focused when it's going to an empty screen */
+ VWM_TRACE("window \"%s\" is alone on screen \"%i\", focusing", vwin->xwindow->name, scr->screen_number);
+ vwm_win_focus(vwm, vwin);
+ } else {
+ /* FIXME TODO: there's some situation where we get here but focused_desktop->focused_window == NULL,
+ * which shouldn't be possible; for there to be a non-empty screen, the focused_desktop must have a focused_window.
+ */
+ scr = vwm_screen_find(vwm, VWM_SCREEN_REL_XWIN, vwm->focused_desktop->focused_window->xwindow);
}
+ changes.x = scr->x_org;
+ changes.y = scr->y_org;
+
/* XXX TODO: does this belong here? */
XGetWMNormalHints(VWM_XDISPLAY(vwm), xwin->id, vwin->hints, &vwin->hints_supplied);
XGetWindowAttributes(VWM_XDISPLAY(vwm), xwin->id, &attrs);
@@ -541,7 +523,6 @@ vwm_window_t * vwm_win_manage_xwin(vwm_t *vwm, vwm_xwindow_t *xwin)
vwin->desktop = vwm->focused_desktop;
vwin->autoconfigured = VWM_WIN_AUTOCONF_NONE;
- vwin->shelved = (vwm->focused_context == VWM_CONTEXT_SHELF); /* if we're in the shelf when the window is created, the window is shelved */
vwin->client = xwin->attrs; /* remember whatever the current attributes are */
VWM_TRACE("hints: flags=%lx x=%i y=%i w=%i h=%i minw=%i minh=%i maxw=%i maxh=%i winc=%i hinc=%i basew=%i baseh=%i grav=%x",
@@ -572,9 +553,9 @@ vwm_window_t * vwm_win_manage_xwin(vwm_t *vwm, vwm_xwindow_t *xwin)
/* always raise newly managed windows so we know about them. */
XRaiseWindow(VWM_XDISPLAY(vwm), xwin->id);
- /* if the desktop has no focused window yet, automatically focus the newly managed one, provided we're on the desktop context */
- if (!vwm->focused_desktop->focused_window && vwm->focused_context == VWM_CONTEXT_DESKTOP) {
- VWM_TRACE("Mapped new window \"%s\" is alone on desktop, focusing", xwin->name);
+ /* if the desktop has no focused window yet, automatically focus the newly managed one */
+ if (!vwm->focused_desktop->focused_window) {
+ VWM_TRACE("Mapped new window \"%s\" is alone on desktop \"%s\", focusing", xwin->name, vwm->focused_desktop->name);
vwm_win_focus(vwm, vwin);
}
@@ -595,12 +576,34 @@ _fail:
void vwm_win_migrate(vwm_t *vwm, vwm_window_t *vwin, vwm_desktop_t *desktop)
{
vwm_win_unfocus(vwm, vwin); /* go through the motions of unfocusing the window if it is focused */
- vwin->shelved = 0; /* ensure not shelved */
- vwin->desktop = desktop; /* assign the new desktop */
+ vwin->desktop = desktop; /* assign the new desktop */
vwm_desktop_focus(vwm, desktop); /* currently we always focus the new desktop in a migrate */
vwm_win_focus(vwm, vwin); /* focus the window so borders get updated */
vwm_win_mru(vwm, vwin); /* TODO: is this right? shouldn't the Mod1 release be what's responsible for this? I migrate so infrequently it probably doesn't matter */
- XRaiseWindow(VWM_XDISPLAY(vwm), vwin->xwindow->id); /* ensure the window is raised */
+ XRaiseWindow(VWM_XDISPLAY(vwm), vwin->xwindow->id); /* ensure the window is @ top of stack */
+}
+
+
+/* "send" a window to another desktop, no desktop/context switching occurs. */
+void vwm_win_send(vwm_t *vwm, vwm_window_t *vwin, vwm_desktop_t *desktop)
+{
+ if (desktop == vwin->desktop)
+ return;
+
+ vwm_win_unfocus(vwm, vwin);
+ vwm_win_unmap(vwm, vwin);
+ vwin->desktop = desktop;
+
+ /* XXX: only focus the destination desktop when not the focused context, as
+ * it creates an awkward disconnect for the focused context's focused desktop
+ * to become updated to something else while looking at it without actually
+ * realizing that focus change like a migrate does.
+ */
+ if (vwm->focused_desktop->context != desktop->context)
+ desktop->context->focused_desktop = desktop;
+
+ vwm_win_set_focused(vwm, vwin);
+ XRaiseWindow(VWM_XDISPLAY(vwm), vwin->xwindow->id); /* ensure the window is @ top of stack */
}
diff --git a/src/window.h b/src/window.h
index eef639e..daddf14 100644
--- a/src/window.h
+++ b/src/window.h
@@ -35,7 +35,6 @@ typedef struct _vwm_window_t {
unsigned int autoconfigured:3; /* autoconfigured window states (none/quarter/half/full/all) */
unsigned int mapping:1; /* is the window being mapped? (by vwm) */
unsigned int unmapping:1; /* is the window being unmapped? (by vwm) */
- unsigned int shelved:1; /* is the window shelved? */
} vwm_window_t;
@@ -78,6 +77,7 @@ void vwm_win_unfocus(vwm_t *vwm, vwm_window_t *vwin);
vwm_xwindow_t * vwm_win_unmanage(vwm_t *vwm, vwm_window_t *vwin);
vwm_window_t * vwm_win_manage_xwin(vwm_t *vwm, vwm_xwindow_t *xwin);
void vwm_win_migrate(vwm_t *vwm, vwm_window_t *vwin, vwm_desktop_t *desktop);
+void vwm_win_send(vwm_t *vwm, vwm_window_t *vwin, vwm_desktop_t *desktop);
#endif
diff --git a/src/xwindow.c b/src/xwindow.c
index 86e8e9d..1deaf33 100644
--- a/src/xwindow.c
+++ b/src/xwindow.c
@@ -62,31 +62,15 @@ vwm_xwindow_t * vwm_xwin_lookup(vwm_t *vwm, Window win)
}
-/* determine if a window is mapped (vwm-mapped) according to the current context */
+/* determine if a window is mapped (vwm-mapped) according to the focused context */
int vwm_xwin_is_mapped(vwm_t *vwm, vwm_xwindow_t *xwin)
{
vwm_window_t *vwin = xwin->managed;
- int ret = 0;
if (!xwin->client_mapped || !vwin)
return xwin->client_mapped;
- switch (vwm->focused_context) {
- case VWM_CONTEXT_SHELF:
- if (vwm->focused_shelf == vwin)
- ret = 1;
- break;
-
- case VWM_CONTEXT_DESKTOP:
- if (vwm->focused_desktop == vwin->desktop && !vwin->shelved)
- ret = 1;
- break;
-
- default:
- VWM_BUG("Unsupported context");
- }
-
- return ret;
+ return (vwm->focused_desktop == vwin->desktop);
}
© All Rights Reserved