summaryrefslogtreecommitdiff
path: root/src/window.c
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2021-01-02 23:27:41 -0800
committerVito Caputo <vcaputo@pengaru.com>2021-01-02 23:27:41 -0800
commitbb59bfd71ec1731587467f64625c7c6818c973dc (patch)
treeaf475dc412cbea3519e5a128641b38057327b247 /src/window.c
parentd08f5671db08de077e271c3e1d3b6b45e11c9ecc (diff)
*: replace the "shelf" with "contexts"
This is unfortunately a bit of a large commit, but it's at least pretty much all on-topic for the generalized "contexts" feature. Rather than waste time trying to split this further into smaller commits, I'm just landing it as-is, now that I've lived with the interaction model long enough to not completely hate it. I fully expect to revisit this in the future. One TODO item in particular I'd like to note is "sending" windows to contexts always creates a new virtual desktop for the sent window in the destination context. What should really happen is the destination context should be checked for an empty desktop, and a new desktop created only when there isn't an empty one to be reused for receiving the sent window. Note this only affects non-migrate sends, as migrates (modified by Shift) explicitly use the existing focused desktop at the destination context. See the README for more information on how contexts work and what's different about the interaction model. It's fairly minimal, most of what you already know how to do should keep working as-is. The only oddity would be Mos1-s no longer "shelves" windows, it's now a modifier to turn "migrates" into "sends", and by itself is a noop now. Colors used for contexts haven't been refined and are enumerated in src/context_colors.def.
Diffstat (limited to 'src/window.c')
-rw-r--r--src/window.c185
1 files changed, 94 insertions, 91 deletions
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 */
}
© All Rights Reserved