i3: 对换两个显示器上的工作区

最近用 i3 实现了一个在我脑中转了很久的念头――对换两个显示器上的工作区。比如:Firefox 在笔记本显示器上,Emacs 在外接显示器上,按一个快捷键,将 Emacs 放到笔记本显示器上,将 Firefox 放到外接显示器上。

1 配置

  • 确保安装了 i3python2.7
  • 学会 i3 的基本操作和配置方法:http://i3wm.org/docs/userguide.html
  • 安装 i3-py: sudo pip install i3-py
  • 下载脚本: swap-workspace.py
  • swap-workspace.py 执行权限: chmod a+x swap-workspace
  • 在 i3 的配置文件(/home/yourname/.i3/config)里添加:
    # swap workspaces
    bindsym $mod+Shift+s exec /path/to/i3-scripts/swap-workspace.py
    
  • 重新加载 i3: Mod+Shift+r (Mod 是什么可以自己设定,我用的是 Windows 键)
  • Mod+Shift+s 对换两个显示器上的工作区

2 HACK 记录

看到陈斌的一个 知乎回答 之后,我决定试一下 i3 ―― 颇为知名的 Linux 桌面管理器。稍微过了一下 官网教程 (基本只看了第一节,即 Default keybindings )就上手了,简单实用。

熟悉了一天之后,突然心血来潮,想要实现 “对换两个显示器上的工作区” 这个功能。Google 一下之后,发现官方的文档里有一篇是讲这个的: http://i3wm.org/docs/user-contributed/swapping-workspaces.html

根据文章,把以下代码保存到 swap-workspace.py

#!/usr/bin/python2.7

import i3
outputs = i3.get_outputs()

# set current workspace to output 0
i3.workspace(outputs[0]['current_workspace'])

# ..and move it to the other output.
# outputs wrap, so the right of the right is left ;)
i3.command('move', 'workspace to output right')

# rinse and repeat
i3.workspace(outputs[1]['current_workspace'])
i3.command('move', 'workspace to output right')

运行之,不好使,返回以下错误:

Traceback (most recent call last):
  File "swap-workspace.py", line 14, in <module>
    i3.workspace(outputs[1]['current_workspace'])
  File "/usr/local/lib/python2.7/dist-packages/i3.py", line 404, in function
    msg_full = ' '.join([message] + list(args)  + list(args2))
TypeError: sequence item 1: expected string, NoneType found

仔细读了代码,然后开 python 的 REPL 实验了一下,发现在我的电脑上, outputs 有四个(而不是两个):

>>> import i3
>>> outputs = i3.get_outputs()
>>> outputs
[{u'active': True, u'current_workspace': u'4', u'name': u'LVDS1', u'rect': {u'y': 0, u'x': 0, u'height': 768, u'width': 1360}, u'primary': True}, {u'active': False, u'current_workspace': None, u'name': u'VGA1', u'rect': {u'y': 0, u'x': 0, u'height': 0, u'width': 0}, u'primary': False}, {u'active': True, u'current_workspace': u'2', u'name': u'HDMI1', u'rect': {u'y': 0, u'x': 1360, u'height': 1080, u'width': 1920}, u'primary': False}, {u'active': False, u'current_workspace': None, u'name': u'DP1', u'rect': {u'y': 0, u'x': 0, u'height': 0, u'width': 0}, u'primary': False}]
>>> len(outputs)
4

根据这些信息,修改代码如下:

for output in i3.get_outputs():
    if output['active']:
        i3.workspace(output['current_workspace'])
        i3.command('move', 'workspace to output right')

试了一下,可以用了!

但是这样写的话,一旦遇到三屏(或更多),就会出错,还是限定脚本只能用于双屏吧:

#!/usr/bin/python2.7
# Swap workspaces on two monitors
import i3

# collect active outputs
to_be_swapped = [output for output in i3.get_outputs() if output['active']]
# only swap when there are two active outputs
if len(to_be_swapped) == 2:
    for output in to_be_swapped:
        i3.workspace(output['current_workspace'])
        i3.command('move', 'workspace to output right')

觉得自己以后还会写 i3 的脚本,于是建了个 Github repo: https://github.com/RenWenshan/i3-scripts

Leave a Reply