I've been able to port over my workspace management from Awesome to i3
using IPC, the config is attached.

The concept was discussed frequently on IRC. Imagine instead of using
workspaces as tags, they are just elements in an array. If you
represent a workspace as a cell on a piece of graph paper, and then
use another piece of paper with one or more cells cut out as a mask to
slide around and view the underlying layer it would be a fair analogy.

Down to the issue I've found. I'm not sure if I'm outracing the IPC
interface, but frequently IPC commands to make the workspaces change
are failing while returning success. So I'll have a monitor where the
workspace is still a scratch one (ie: by output name) instead of it
changing to the workspace intended. No crashing, and often repeating
the operation will make it work.

Second I've run into an issue where Gkrellm cannot dock on the left or
right side of the screen because left/right docking WM hints haven't
been implemented yet. Is this a pending feature?

Thanks.



------------------------------------------------------------------
Russell Adams                            rlad...@adamsinfoserv.com

PGP Key ID:     0x1160DCB3           http://www.adamsinfoserv.com/

Fingerprint:    1723 D8CA 4280 1EC9 557F  66E8 1154 E018 1160 DCB3
set $mod Mod4
font pango:DejaVu Sans Mono 8
mouse_warping none

# Use Mouse+$mod to drag floating windows to their wanted position
floating_modifier $mod

# start a terminal, I use xbindkeys
#bindsym $mod+Shift+Return exec urxvt


# class                 border  backgr. text    indicator
client.focused          #888888 #888888 #000000 #2e9ef4
client.focused_inactive #333333 #222222 #888888 #292d2e
client.unfocused        #333333 #222222 #888888 #292d2e
client.urgent           #2f343a #900000 #ffffff #900000


# reload the configuration file
bindsym $mod+Shift+c reload

# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
bindsym $mod+Shift+r restart
bindsym $mod+Shift+q exit

# Inter-workspace navigation, panning around the 2d plane
bindsym Control+Left  exec --no-startup-id ~/.i3/workspaces.py  -1   0  0
bindsym Control+Right exec --no-startup-id ~/.i3/workspaces.py   1   0  0
bindsym Control+Up    exec --no-startup-id ~/.i3/workspaces.py   0  -1  0
bindsym Control+Down  exec --no-startup-id ~/.i3/workspaces.py   0   1  0

# Inter-workspace navigation, swap planes on third dimension
bindsym Control+Shift+Left  exec --no-startup-id ~/.i3/workspaces.py  0  0 -1
bindsym Control+Shift+Right exec --no-startup-id ~/.i3/workspaces.py  0  0  1

# Intra-workspace navigation
# change focus
bindsym Shift+Left  focus left
bindsym Shift+Down  focus down
bindsym Shift+Up    focus up
bindsym Shift+Right focus right

# Move the window column
bindsym $mod+Shift+Left  move left
bindsym $mod+Shift+Down  move down
bindsym $mod+Shift+Up    move up
bindsym $mod+Shift+Right move right

# split in horizontal orientation
bindsym $mod+Shift+h split h

# split in vertical orientation
bindsym $mod+Shift+v split v

# enter fullscreen mode for the focused container
bindsym $mod+space fullscreen

# change container layout (stacked, tabbed, toggle split)
bindsym $mod+Shift+s layout stacking
bindsym $mod+Shift+w layout tabbed
bindsym $mod+Shift+e layout toggle split

# toggle tiling / floating
bindsym $mod+Shift+space floating toggle

# resize window (you can also use the mouse for that)
mode "resize" {
        # These bindings trigger as soon as you enter the resize mode

        # Pressing left will shrink the window’s width.
        # Pressing right will grow the window’s width.
        # Pressing up will shrink the window’s height.
        # Pressing down will grow the window’s height.
        bindsym j resize shrink width 10 px or 10 ppt
        bindsym k resize grow height 10 px or 10 ppt
        bindsym l resize shrink height 10 px or 10 ppt
        bindsym semicolon resize grow width 10 px or 10 ppt

        # same bindings, but for the arrow keys
        bindsym Left resize shrink width 10 px or 10 ppt
        bindsym Down resize grow height 10 px or 10 ppt
        bindsym Up resize shrink height 10 px or 10 ppt
        bindsym Right resize grow width 10 px or 10 ppt

        # back to normal: Enter or Escape
        bindsym Return mode "default"
        bindsym Escape mode "default"
}

bindsym $mod+r mode "resize"

# Start i3bar to display a workspace bar (plus the system information i3status
# finds out, if available)
bar {
        status_command i3status
}

# Set defaults
workspace  0_0_0 output LVDS1
workspace -1_0_0 output DVI-D-2
workspace  0_0_0 output DVI-I-1
workspace  1_0_0 output DVI-D-1
#!/usr/bin/python3

import struct
import json
import subprocess
import socket
import argparse
import time

# Workspaces in the format of 1:2:3, with negative integers ok.

# List of monitors, with x/y offset from center
centerScreen = "DVI-I-1"
monitors = { "DVI-D-2": (-1, 0), # Left at dock
             "DVI-I-1": ( 0, 0), # Center for docking station
             "DVI-D-1": ( 1, 0), # Right at dock
}

ipcheader = b'i3-ipc'
ipccmds = { 'COMMAND':        0,
            'GET_WORKSPACES': 1,
            'GET_OUTPUTS':    3,
            }

# Obtain socket
socketfile = subprocess.Popen(['/usr/bin/i3','--get-socket'],
                              stdout=subprocess.PIPE).communicate()[0].rstrip()

def socketCommand(mode, command=''):

    i3socket = socket.socket(socket.AF_UNIX)
    i3socket.connect(socketfile)
    i3socket.send( struct.pack("=6sLL" + str(len(command)) + "s", b'i3-ipc', len(command), ipccmds[mode], command.encode()) )
    reply = i3socket.recv(8192)

    data = struct.unpack('=ccccccLL',reply[:14])
    assert b''.join(data[0:6]) == b'i3-ipc'
    size = data[6]

    payload = struct.unpack("=ccccccLL" + str(size) + "s", reply)[8]

    i3socket.close()

    print(command)
    print(json.loads(payload.decode()))
    return json.loads(payload.decode())


def getOutputs():
    """
[{'active': True,
  'current_workspace': '0:0:0',
  'name': 'DVI-I-1',
  'primary': False,
  'rect': {'height': 1080, 'width': 1920, 'x': 1920, 'y': 0}},
 {'active': True,
  'current_workspace': '-1:-1:0',
  'name': 'DVI-D-1',
  'primary': False,
  'rect': {'height': 1080, 'width': 1920, 'x': 3840, 'y': 0}},
 {'active': True,
  'current_workspace': '-1:0:0',
  'name': 'DVI-D-2',
  'primary': False,
  'rect': {'height': 1080, 'width': 1920, 'x': 0, 'y': 0}},
 {'active': False,
  'current_workspace': None,
  'name': 'HDMI-1',
  'primary': False,
  'rect': {'height': 0, 'width': 0, 'x': 0, 'y': 0}}]
"""
    return socketCommand('GET_OUTPUTS')


def getWorkspaces():
    """
[{'focused': True,
  'name': '0:0:0',
  'num': 0,
  'output': 'DVI-I-1',
  'rect': {'height': 1061, 'width': 1920, 'x': 1920, 'y': 0},
  'urgent': False,
  'visible': True},
 {'focused': False,
  'name': '-1:0:0',
  'num': None,
  'output': 'DVI-D-2',
  'rect': {'height': 1061, 'width': 1920, 'x': 0, 'y': 0},
  'urgent': False,
  'visible': True},
 {'focused': False,
  'name': '1:0:0',
  'num': 1,
  'output': 'DVI-D-1',
  'rect': {'height': 1061, 'width': 1920, 'x': 3840, 'y': 0},
  'urgent': False,
  'visible': False},
 {'focused': False,
  'name': '-1:-1:0',
  'num': None,
  'output': 'DVI-D-1',
  'rect': {'height': 1061, 'width': 1920, 'x': 3840, 'y': 0},
  'urgent': False,
  'visible': True}]
"""
    return socketCommand('GET_WORKSPACES')


def changeWorkspaces( dx, dy, dz):

    outputs = getOutputs()
    workspaces = getWorkspaces()
    currentOutput   = [i for i in workspaces if i['focused'] == True ][0]['output']

    # Don't adjust based on data from every screen. Find center position and move it, then set the rest using offsets
    currentCenterWS = [i for i in workspaces if i['output']  == centerScreen and i['visible'] == True][0]['name']

    # Enforce tag format or reset position
    try:
        coords = [int(i) for i in currentCenterWS.strip("'").split('_')]
    except ValueError:
        coords = [0,0,0]

    # Change all outputs to a workspace uniquely named by output temporarily
    for output in monitors:
        socketCommand('COMMAND', "focus output " + output)
        socketCommand('COMMAND', "workspace "    + output)

    # Set each monitor by offset from center and the new delta
    for output in monitors:
        newWS = "{:d}_{:d}_{:d}".format(coords[0] + monitors[output][0] + dx,
                                        coords[1] + monitors[output][1] + dy,
                                        coords[2] + dz)
        socketCommand('COMMAND', "focus output " + output)
        socketCommand('COMMAND', "workspace "    + newWS)
        socketCommand('COMMAND', "move workspace to output " + output)

    # Restore focus
    socketCommand('COMMAND', "focus output " + currentOutput)


# MAIN
parser = argparse.ArgumentParser(description='Change i3 workspaces in a 3d space')
parser.add_argument('x', help='Delta X', nargs=1, type=int, default=0)
parser.add_argument('y', help='Delta Y', nargs=1, type=int, default=0)
parser.add_argument('z', help='Delta Z', nargs=1, type=int, default=0)
options = parser.parse_args()

changeWorkspaces(options.x[0], options.y[0], options.z[0])

Reply via email to