Skip to content

Instantly share code, notes, and snippets.

@Phyks
Last active February 22, 2021 22:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Phyks/4fbc2572dcc5eed96caa to your computer and use it in GitHub Desktop.
Save Phyks/4fbc2572dcc5eed96caa to your computer and use it in GitHub Desktop.
Enhanced back_and_forth for workspaces in i3.
#!/usr/bin/env python3
"""
Enhanced version of the workspace_back_and_forth of i3. Support a history of up
to 20 previously focused workspaces. See
https://www.reddit.com/r/i3wm/comments/40ncsn/window_back_and_forth_stack/
How to use:
* Put this file somewhere in your `$PATH`.
* In your `.i3/config` file, run the server on startup:
```
exec_always --no-startup-id "python workspace_back_and_forth_enhanced.py"
```
* In your `.i3/config`, use the program to manage workspace change, e.g.:
```
bindsym $mod+agrave exec "echo 10 | socat - UNIX-CONNECT:$XDG_RUNTIME_DIR/i3/i3-back-and-forth-enhanced.sock"
```
* Enjoy!
This script is under an MIT license and has been written by Phyks (Lucas
Verney - http://phyks.me/).
"""
import i3ipc
import os
import socket
from collections import deque
WORKSPACES_STACK = deque(maxlen=20)
# Create the Connection object that can be used to send commands and
# subscribe to events.
i3 = i3ipc.Connection()
def move_with_back_and_forth(target_workspace):
"""
Move to target workspace, handling enhanced back and forth.
"""
current_workspace = [
i
for i in i3.get_workspaces() if i.focused
][0].name
current_workspace = current_workspace.strip()
target_workspace = target_workspace.strip()
if target_workspace != current_workspace:
# Not on the target workspace, no back and forth move
# Push actual workspace and move
WORKSPACES_STACK.append(current_workspace)
return i3.command("workspace %s" % (target_workspace,))
# Else, try to use back and forth
try:
return i3.command("workspace %s" % (WORKSPACES_STACK.pop(),))
except IndexError:
# Stack is empty, do nothing
return
def listen_socket(sock):
"""
Socket listener
"""
while True:
# Wait for a connection
connection, client = sock.accept()
try:
while True:
chunk = connection.recv(16)
if chunk:
data = chunk.decode("utf-8")
move_with_back_and_forth(data)
else:
# No more data
break
finally:
# Close the connection
connection.close()
def main():
"""
Main
"""
# Find Unix socket dir
socket_dir = os.path.join(os.getenv("XDG_RUNTIME_DIR", "/tmp"), "i3")
if not os.path.isdir(socket_dir):
os.mkdir(socket_dir)
# Make sure socket does not already exists
socket_address = os.path.join(socket_dir,
"i3-back-and-forth-enhanced.sock")
try:
os.unlink(socket_address)
except OSError:
if os.path.exists(socket_address):
raise
# Create the socket
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(socket_address)
sock.listen(1)
# Start listener on socket
try:
listen_socket(sock)
finally:
sock.close()
try:
os.unlink(socket_address)
except OSError:
pass
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
raise
pass
except:
raise
pass
@olayad
Copy link

olayad commented May 5, 2020

Can you comment on what version you are using with i3ipc?
I am currently getting TypeError: 'WorkspaceReply' object is not subscriptable when trying to iterate over the list returned by get_workspaces().

It seems the script could be fixed following this issue.

>>> import i3ipc
>>> i3 = i3ipc.Connection()
>>> ws = i3.get_workspaces()
>>> ws
[<i3ipc.replies.WorkspaceReply object at 0x7f2ead288370>, <i3ipc.replies.WorkspaceReply object at 0x7f2ead288c40>, <i3ipc.replies.WorkspaceReply object at 0x7f2eace422b0>, <i3ipc.replies.WorkspaceReply object at 0x7f2eace423a0>, <i3ipc.replies.WorkspaceReply object at 0x7f2eace42430>, <i3ipc.replies.WorkspaceReply object at 0x7f2eace424c0>]
>>> ws[0]["focused"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'WorkspaceReply' object is not subscriptable
>>> ws[0].focused
True
$ pip3 show i3ipc
Name: i3ipc
Version: 2.2.1
Summary: An improved Python library to control i3wm and sway
Home-page: https://github.com/altdesktop/i3ipc-python
Author: Tony Crisci
Author-email: tony@dubstepdish.com
License: BSD
Location: /home/mi/.local/lib/python3.8/site-packages
Requires: python-xlib
Required-by: 

@Phyks
Copy link
Author

Phyks commented May 5, 2020

Indeed, I updated the script on my side but completely forgot about this gist. I'll update a fixed version of the script right away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment