summaryrefslogtreecommitdiff
path: root/src/context.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/context.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/context.c')
-rw-r--r--src/context.c222
1 files changed, 148 insertions, 74 deletions
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);
}
© All Rights Reserved