当前位置: 首页>>技术教程>>正文


有没有办法存储当前的桌面布局?

,

问题描述

我希望能够保存我的应用程序的当前位置,所以当我要打开相同的位置并运行某些东西时,它们会按原样重新排列。

例如,如果我要打开一个 sublime 和三个终端窗口,我希望能够以某种方式保存它。

我不在乎它是应用程序还是命令行工具,只要我可以轻松保存我的应用程序的位置即可。

我是 Moom 的忠实粉丝,但不幸的是它只能在 MacOS 上运行,而在 Ubuntu 上我真的很想念它。它支持更多功能,如果您在我的主要问题之上知道接近它的东西,那也很好。

最佳思路

说明

该脚本于 2017 年 1 月 16 日进行了修补/修复,修复了进程名称与运行应用程序的命令不同的一些应用程序。这可能偶尔会在应用程序上发生。如果有人找到,请发表评论。


用于记住和恢复窗口排列及其相应应用程序的脚本。

下面的脚本可以使用两个选项运行。假设您的窗口排列如下:

要读取(记住)当前窗口排列及其应用程序,请使用以下选项运行脚本:

<script> -read

然后关闭所有窗口:

然后设置最后记住的窗口排列,使用以下选项运行它:

<script> -run

并且最后记住的窗口排列将被恢复:

这也将在重新启动后起作用。

将这两个命令放在两个不同的快捷键下,您可以 “record” 您的窗口排列,关闭您的计算机并在(例如)重新启动后调用相同的窗口排列。

脚本做什么,不做什么

使用选项 -read 运行

  • 该脚本使用 wmctrl 列出所有窗口、所有工作区、它们的位置、它们的大小、它们所属的应用程序

  • 然后脚本 “converts” 将窗口位置从相对(到当前工作空间,如 wmctrl 的输出)到绝对位置,在您的跨越工作空间上。因此,您要记住的窗口是仅在一个工作区上还是分布在不同的工作区上都没有关系。

  • 该脚本然后 “remembers” 当前窗口排列,将其写入主目录中的一个不可见文件。

使用选项 -run 运行

  • 脚本读取最后记住的窗口排列;它启动相应的应用程序,将窗口移动到记住的位置,也借助 wmctrl

该脚本不记得可能在窗口中打开的文件,也不记得(例如)在浏览器窗口中打开的网站。

Issues

wmctrlUnity 的组合有一些 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

然后:

  1. 将脚本复制到一个空文件中,将其保存为 recall_windows 中的 ~/bin 。如有必要,创建目录。如果该目录尚不存在,请在创建目录后运行 source ~/.profile 或注销/登录。现在它将位于 $PATH

  2. 使脚本可执行 (!)。

  3. 现在打开几个窗口, geditfirefox 或其他,并通过运行命令在终端中打开脚本 test-run (不需要路径前缀):

    recall_windows -read
    
  4. 关闭窗户。现在在终端中运行:

    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

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/12609.html,未经允许,请勿转载。