问题描述
我希望能够保存我的应用程序的当前位置,所以当我要打开相同的位置并运行某些东西时,它们会按原样重新排列。
例如,如果我要打开一个 sublime 和三个终端窗口,我希望能够以某种方式保存它。
我不在乎它是应用程序还是命令行工具,只要我可以轻松保存我的应用程序的位置即可。
我是 Moom 的忠实粉丝,但不幸的是它只能在 MacOS 上运行,而在 Ubuntu 上我真的很想念它。它支持更多功能,如果您在我的主要问题之上知道接近它的东西,那也很好。
最佳思路
说明
该脚本于 2017 年 1 月 16 日进行了修补/修复,修复了进程名称与运行应用程序的命令不同的一些应用程序。这可能偶尔会在应用程序上发生。如果有人找到,请发表评论。
用于记住和恢复窗口排列及其相应应用程序的脚本。
下面的脚本可以使用两个选项运行。假设您的窗口排列如下:
要读取(记住)当前窗口排列及其应用程序,请使用以下选项运行脚本:
<script> -read
然后关闭所有窗口:
然后设置最后记住的窗口排列,使用以下选项运行它:
<script> -run
并且最后记住的窗口排列将被恢复:
这也将在重新启动后起作用。
将这两个命令放在两个不同的快捷键下,您可以 “record” 您的窗口排列,关闭您的计算机并在(例如)重新启动后调用相同的窗口排列。
脚本做什么,不做什么
使用选项 -read
运行
-
该脚本使用
wmctrl
列出所有窗口、所有工作区、它们的位置、它们的大小、它们所属的应用程序 -
然后脚本 “converts” 将窗口位置从相对(到当前工作空间,如
wmctrl
的输出)到绝对位置,在您的跨越工作空间上。因此,您要记住的窗口是仅在一个工作区上还是分布在不同的工作区上都没有关系。 -
该脚本然后 “remembers” 当前窗口排列,将其写入主目录中的一个不可见文件。
使用选项 -run
运行
-
脚本读取最后记住的窗口排列;它启动相应的应用程序,将窗口移动到记住的位置,也借助
wmctrl
该脚本不记得可能在窗口中打开的文件,也不记得(例如)在浏览器窗口中打开的网站。
Issues
wmctrl
和 Unity
的组合有一些 bug,举几个例子:
-
由
wmctrl
读取的窗口坐标与定位窗口的命令略有不同,如 here 所述。因此,召回的窗口位置可能与原始位置略有不同。 -
如果窗口边非常靠近
Unity Launcher
或面板,则wmctrl
命令的工作方式有点不可预测。 -
“remembered” 窗口需要完全位于工作区边界内,
wmctrl
放置命令才能正常工作。
某些应用程序默认在新选项卡的同一窗口中打开新窗口(如 gedit
)。我为 gedit
修复了它,但如果您发现更多异常,请提及。
剧本
#!/usr/bin/env python3
import subprocess
import os
import sys
import time
wfile = os.environ["HOME"]+"/.windowlist"
arg = sys.argv[1]
def get(command):
return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")
def check_window(w_id):
w_type = get("xprop -id "+w_id)
if " _NET_WM_WINDOW_TYPE_NORMAL" in w_type:
return True
else:
return False
def get_res():
# get resolution and the workspace correction (vector)
xr = subprocess.check_output(["xrandr"]).decode("utf-8").split()
pos = xr.index("current")
res = [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]
vp_data = subprocess.check_output(["wmctrl", "-d"]).decode("utf-8").split()
curr_vpdata = [int(n) for n in vp_data[5].split(",")]
return [res, curr_vpdata]
app = lambda pid: subprocess.check_output(["ps", "-p", pid, "-o", "comm="]).decode("utf-8").strip()
def read_windows():
res = get_res()
w_list = [l.split() for l in get("wmctrl -lpG").splitlines()]
relevant = [[w[2],[int(n) for n in w[3:7]]] for w in w_list if check_window(w[0]) == True]
for i, r in enumerate(relevant):
relevant[i] = app(r[0])+" "+str((" ").join([str(n) for n in r[1]]))
with open(wfile, "wt") as out:
for l in relevant:
out.write(l+"\n")
def open_appwindow(app, x, y, w, h):
ws1 = get("wmctrl -lp"); t = 0
# fix command for certain apps that open in new tab by default
if app == "gedit":
option = " --new-window"
else:
option = ""
# fix command if process name and command to run are different
if "gnome-terminal" in app:
app = "gnome-terminal"
elif "chrome" in app:
app = "/usr/bin/google-chrome-stable"
subprocess.Popen(["/bin/bash", "-c", app+option])
# fix exception for Chrome (command = google-chrome-stable, but processname = chrome)
app = "chrome" if "chrome" in app else app
while t < 30:
ws2 = [w.split()[0:3] for w in get("wmctrl -lp").splitlines() if not w in ws1]
procs = [[(p, w[0]) for p in get("ps -e ww").splitlines() \
if app in p and w[2] in p] for w in ws2]
if len(procs) > 0:
time.sleep(0.5)
w_id = procs[0][0][1]
cmd1 = "wmctrl -ir "+w_id+" -b remove,maximized_horz"
cmd2 = "wmctrl -ir "+w_id+" -b remove,maximized_vert"
cmd3 = "wmctrl -ir "+procs[0][0][1]+" -e 0,"+x+","+y+","+w+","+h
for cmd in [cmd1, cmd2, cmd3]:
subprocess.call(["/bin/bash", "-c", cmd])
break
time.sleep(0.5)
t = t+1
def run_remembered():
res = get_res()[1]
try:
lines = [l.split() for l in open(wfile).read().splitlines()]
for l in lines:
l[1] = str(int(l[1]) - res[0]); l[2] = str(int(l[2]) - res[1] - 24)
open_appwindow(l[0], l[1], l[2], l[3], l[4])
except FileNotFoundError:
pass
if arg == "-run":
run_remembered()
elif arg == "-read":
read_windows()
如何设置
在开始之前,请确保已安装 wmctrl
:
sudo apt-get install wmctrl
然后:
-
将脚本复制到一个空文件中,将其保存为
recall_windows
中的~/bin
。如有必要,创建目录。如果该目录尚不存在,请在创建目录后运行source ~/.profile
或注销/登录。现在它将位于$PATH
-
使脚本可执行 (!)。
-
现在打开几个窗口,
gedit
,firefox
或其他,并通过运行命令在终端中打开脚本 test-run (不需要路径前缀):recall_windows -read
-
关闭窗户。现在在终端中运行:
recall_windows -run
您的窗口设置现在应该已恢复
如果一切正常,请在快捷键中添加两个命令:选择:系统设置 > “Keyboard” > “Shortcuts” > “Custom Shortcuts”。单击 “+” 并添加命令:
recall_windows -read
和
recall_windows -run
到两个不同的快捷键
次佳思路
我写了一个小库/命令行工具,它允许保存和恢复会话,并且支持不同的监视器设置以及虚拟桌面。
Installation
npm install -g linux-window-session-manager
Usage
将当前会话保存到 ~/.lwsm/sessionData/DEFAULT.json
lwsm save
将当前会话保存到 ~/.lwsm/sessionData/my-session.json
lwsm save my-session
从 ~/.lwsm/sessionData/DEFAULT.json 恢复会话
lwsm restore
从 ~/.lwsm/sessionData/my-session.json 恢复会话
lwsm restore my-session
在开始会话之前优雅地关闭所有正在运行的应用程序
lwsm restore --closeAllOpenWindows
看看:https://github.com/johannesjo/linux-window-session-manager