The i3 FAQ has migrated to https://github.com/i3/i3/discussions. All content here is read-only.
Ask Your Question
1

How to arrange workspaces in a bidimensional manner

asked 2014-03-29 16:50:51 +0000

student gravatar image

In xmonad it is possible to navigate through your workspaces in a bidimensional manner (up/down, left/right): http://xmonad.org/xmonad-docs/xmonad-...

Is there a similar feature in i3wm? If so, how to use it?

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
4

answered 2014-03-30 03:49:56 +0000

TonyC gravatar image

updated 2014-03-30 08:22:18 +0000

You can do this with the new i3ipc library. This script uses the JavaScript version of the library, but the same API is available in many languages. The latest version of this script can be found here.

#!/usr/bin/env gjs

/*
   This example shows how to implement an "n-dimensional" workspace layout,
   where it is possible to navigate through your workspaces by not only the
   "next" and "previous" ones, but also to go "up" and "down" at an arbitrary
   velocity. This is done by generalizing the scalar workspace numbers to
   be interpreted as vectors.

   Usage:
   # Move to the next workspace
   ./n-dimensional-ws-layout.js next
   # Move to the workspace "above" this one
   ./n-dimensional-ws-layout.js up
   # Move two workspaces back (e.g., from 5 to 3)
   ./n-dimensional-ws-layout.js -2
   # Move three workspaces forward and four workspaces down
   ./n-dimensional-ws-layout.js 3,-4

   https://faq.i3wm.org/question/3591/how-to-arrange-workspaces-in-a-bidimensional-manner/
*/

const i3ipc = imports.gi.i3ipc;

let conn = new i3ipc.Connection;

// Add to this number if you want more workspace dimensions (we could figure
// this out from all the workspace names, but I doubt that would be useful to
// anyone at this time).
let MAX_DIMENSIONS = 3;

// Add to this object if you want more workspace aliases.
let movement_aliases = {
    next:       '1',
    previous:   '-1',
    up:         '0,1',
    down:       '0,-1'
};

// Check for aliases
let movement_arg = movement_aliases[ARGV[0]] || ARGV[0] || '';

// Turns a vector string into a vector array
let to_vector = function(str) {
    if (str.indexOf(':') !== -1) {
        str = str.slice(0, str.indexOf(':'));
    }

    return str.split(',').map(function(el) {
        return parseInt(el) || 0;
    });
};

// Adds two vectors in the ordinary way
let add_vectors = function(a, b) {
    let retval = [];
    for (let i = 0; i < MAX_DIMENSIONS; i += 1) {
        retval[i] = (a[i] || 0) + (b[i] || 0);
    }

    return retval;
};

// Checks two vectors for equality in the normal way
let test_vector_equals = function(a, b) {
    for (let i = 0; i < MAX_DIMENSIONS; i += 1) {
        if ((a[i] || 0) !== (b[i] || 0)) {
            return false;
        }
    }

    return true;
};

let workspaces = conn.get_workspaces();

let focused_ws = workspaces.filter(function(ws) {
    return ws.focused;
}).shift();

// This is the vector where we should end up
let next_ws_vector = add_vectors(to_vector(movement_arg), to_vector(focused_ws.name));

let found_next_ws = false;

// Check if the workspace where we want to go already exists and go there if it
// does
workspaces.every(function(ws) {
    if (test_vector_equals(to_vector(ws.name), next_ws_vector)) {
        conn.command('workspace "' + ws.name + '"');
        found_next_ws = true;
        return false;
    }

    return true;
});

// If the workspace where we want to go does not exist, make a new one
if (!found_next_ws) {
    // Pop off the zeros on the end of the array
    while (next_ws_vector.length && !next_ws_vector[next_ws_vector.length - 1]) {
        next_ws_vector.pop();
    }

    conn.command('workspace "' + next_ws_vector.join() + '"');
}
edit flag offensive delete link more

Question Tools

Stats

Asked: 2014-03-29 16:50:51 +0000

Seen: 348 times

Last updated: Mar 30 '14