答案1
令我惊讶的是,它的效果非常好,只要你的桌面上没有太多其他东西。
我用它工作了一段时间,它看起来很奇怪,但奇怪的是好的无需频繁切换工作区。简单易用,令人耳目一新。
在实践中
解决方案实际上与您描述的差不多:
怎么运行的
简短的故事(解释):
当按下快捷键时,脚本会被调用并且参数为
box
:windowbox box
然后脚本:
- 读取最前面窗口的窗口 ID
- 检查它是否是一个“正常”窗口(例如,你不想取消映射你的桌面)
- 查找拥有该窗口的应用程序的进程名称。
.desktop
在相应应用程序的文件中查找相应的图标/usr/share/applications
创建一个唯一命名的
.desktop
文件,其中一行使用Exec=
参数调用脚本(双击时)show
:windowbox show
该.desktop
文件将添加许多附加参数,例如窗口 id、文件的(文件)名称.desktop
。
随后:
然后使该
.desktop
文件成为可执行文件,使其成为可双击的对象。.desktop
双击该文件时,窗口被(重新)映射,该.desktop
文件将从桌面上删除。
如何设置
就像实际上总是那样,当您想使用窗口时,脚本需要
wmctrl
和xdotool
:sudo apt-get install xdotool wmctrl
- 创建目录
~/bin
(~
代表你的主目录) 将下面的脚本复制到一个空文件中,并将其保存为
windowbox
(无扩展名)~/bin
。#!/usr/bin/env python3 import subprocess import sys import os # --- On Unity, there is a (y-wise) deviation in window placement # set to zero for other window managers deviation = 28 # --- args = sys.argv[1:] get = lambda cmd: subprocess.check_output(cmd).decode("utf-8").strip() def find_dtop(): # get the localized path to the Desktop folder home = os.environ["HOME"] dr_file = home+"/.config/user-dirs.dirs" return [home+"/"+ l.split("/")[-1].strip() \ for l in open(dr_file).readlines() \ if l.startswith("XDG_DESKTOP_DIR=")][0].replace('"', "") def check_windowtype(w_id): # check the type of window; only unmap "NORMAL" windows return "_NET_WM_WINDOW_TYPE_NORMAL" in get(["xprop", "-id", w_id]) def get_process(w_id): # get the name of the process, owning the window and window x/y position w_list = get(["wmctrl", "-lpG"]).splitlines() pid = [l for l in w_list if w_id in l][0].split() proc = get(["ps", "-p", pid[2], "-o", "comm="]) xy = (" ").join(pid[3:5]) return (proc, xy) def read_f(f, string, proc): # search for a possible match in a targeted .desktop file try: with open(f) as read: for l in read: if all([l.startswith(string), proc in l]): in_f = True break else: in_f = False except: in_f = False return in_f def get_icon(proc, w_name): # search appropriate icon in /usr/share/applications exceptions = [item for item in [ ["soffice", "libreoffice-main"], ["gnome-terminal", "utilities-terminal"], ["nautilus", "folder"], ] if item[0] in proc] if exceptions: if exceptions == [["soffice", "libreoffice-main"]]: loffice = [ ["Calc", "libreoffice-calc"], ["Writer", "libreoffice-writer"], ["Base", "libreoffice-base"], ["Draw", "libreoffice-draw"], ["Impress", "libreoffice-impress"], ] match = [m[1] for m in loffice if m[0] in w_name] if match: return match[0] else: return exceptions[0][1] else: return exceptions[0][1] else: default = "/usr/share/applications" dtfiles = [default+"/"+f for f in os.listdir(default)] for f in dtfiles: if read_f(f, "Exec=", proc) == True: for l in open(f).readlines(): if l.startswith("Icon="): icon = l.replace("Icon=", "").strip() print(f) break break return icon def create_name(): # create unique (file-) name for boxed window n = 1 while True: name = dtop+"/"+"boxed_"+str(n)+".desktop" if os.path.exists(name): n += 1 else: break return name def convert_wid(w_id): # convert window- id, xdotool format, into wmctrl format w_id = hex(int(w_id)) return w_id[:2]+(10-len(w_id))*"0"+w_id[2:] def create_icon(w_id, w_name, icon, pos): # create the launcher, representing the boxed window boxedwindow = create_name() f_content =[ "[Desktop Entry]", "Name=[WINDOW] "+w_name, "Exec=windowbox show "+w_id+" '"+boxedwindow+"' "+pos, "Icon="+icon, "Type=Application", ] if icon == "generic": f_content.pop(3) with open(boxedwindow, "wt") as boxed: for l in f_content: boxed.write(l+"\n") command = "chmod +x "+"'"+boxedwindow+"'" subprocess.call(["/bin/bash", "-c", command]) if args[0] == "box": dtop = find_dtop() w_id = convert_wid(get(["xdotool", "getactivewindow"])) w_name = get(["xdotool", "getwindowname", w_id]) if check_windowtype(w_id) == True: procdata = get_process(w_id) procname = procdata[0] icon = get_icon(procname, w_name); icon = icon if icon != None else "generic" create_icon(w_id, w_name, icon, procdata[1]) subprocess.call(["xdotool", "windowunmap", w_id]) elif args[0] == "show": w_id = args[1] subprocess.call(["xdotool", "windowmap", w_id]) subprocess.call(["xdotool", "windowmove", "--sync", w_id, args[3], str(int(args[4])-deviation)]) os.remove(args[2])
使脚本可执行
- 要使新创建的目录在中“弹出”
$PATH
,请注销/登录,或运行source ~/.profile
(从终端窗口) 通过以下命令从终端窗口测试运行脚本:
windowbox box
该窗口应该消失,“盒装”窗口应该出现在您的桌面上。
如果一切正常,请将以下命令添加到快捷键:选择屏幕右上角的齿轮图标:
转到System Settings→ Keyboard→ Shortcuts→ Custom Shortcuts。单击+并添加命令:
windowbox box
那就可以了。
重要的提示
脚本使用xdotool
使windowunmap
窗口不可见。桌面上创建的“框”(图标)是隐藏窗口的唯一“大门”。换句话说:不要手动删除桌面文件。如果您这样做,窗口将永远消失。
要做的工作[编辑 20-12:完毕]
该脚本仍需要一些改进:
- 窗口几何形状未按定义恢复。可以很好地修复,但我想向您展示第一个结果。
- 在大多数情况下,方框窗口都有正确的图标。
get_process(w_id)
但是该功能可以进行一些改进。如果在 中未找到作为命令的进程/usr/share/applications
,则文件会有一个通用图标。
使盒状窗口图标的大小与其他图标不同
脚本命名创建的.desktop
文件总是 boxed_1.desktop
等,boxed_2.desktop
取决于创建时的“可用”名称(文件名,而不是显示的名称)。
您可以通过右键单击 > 图标大小来调整文件大小(一般情况下)。好消息是,如果您删除文件并重新创建,系统会记住文件大小。即使您在重新启动后再次创建文件。这意味着如果您曾经调整盒装窗口的大小(例如)1-5,它们将总是当你(脚本)再次创建它们时具有相同的大小!
答案2
您可以使用韓式来实现这一点。
安装 fvwm:
sudo apt-get update sudo apt-get install fvwm
找到一个使用 iconify 功能的主题 - 这里有几个:http://www.jmcunx.com/fvwm_theme.html其中一些看起来像您展示的屏幕截图。
复制主题的文本,然后导航到
~/.fvwm/
(首先显示隐藏文件),然后创建一个文件.fvwm2rc
在文本编辑器(如 gedit)中打开该文件并将主题文本粘贴到其中。
重新启动计算机,选择 fvwm 并登录。