我可以将窗口最小化到Unity上的一个框吗?


17

在Irix的4Dwm上,可以将窗口最小化到一个盒子中(与现代窗口管理器使用的任务栏相反)。我在旧的HPUX上也看到了这一点。

请参阅链接图像中的“控制台”方块:

在此处输入图片说明

是否可以在Ubuntu上通过插件或Unity以外的某些窗口管理器来完成?


奇怪但有趣的问题:)我可以想到这样的事情。该图标很重要,还是通用的?它的表现如何?例如桌面上的图标或最小的“窗口”。
Jacob Vlijm 2015年

@JacobVlijm图标不是通用的。每个应用程序都有其自己的图标作为Unity中最小化窗口的图标)
Artium

也可以在Unity中完成,但是窗口将在桌面上图标化(带有相应应用程序的图标和窗口的名称)。你想打针吗?(这将是一个有趣但充满挑战的工作,在我开始之前最好问问:))
Jacob Vlijm 2015年

1
是的,这可能对我有帮助。我必须处理很多打开的窗口,我认为这种组织它们的方式更好。我对Unity一无所知,因此只能提供测试方面的帮助。
Artium

Answers:


18

令我自己惊讶的是,只要您的桌面上没有太多其他东西,它就可以很好地工作。

我使用了一段时间,这似乎是一种奇怪的方法,但是对于频繁的工作空间切换来说,这是一个足够奇怪的选择。令人耳目一新。

在实践中

该解决方案实际上就是您所描述的:

  • 按下组合键将在一个窗口中将桌面窗口“装箱”:

    在此处输入图片说明

    并带有应用程序外观的图标:

    在此处输入图片说明

  • 双击图标,窗口将重新出现,图标将消失。

怎么运行的

短篇小说(解释):

  • 按下快捷键时,将使用以下参数调用脚本box

    windowbox box
    
  • 脚本然后:

    • 读取最前面窗口的窗口ID
    • 检查它是否是“普通”窗口(例如,您不想取消映射桌面)
    • 查找拥有窗口的应用程序的进程名称。
    • 在相应的应用程序.desktop文件中查找相应的图标/usr/share/applications
    • 创建一个唯一命名的.desktop文件,并在Exec=一行中使用以下参数调用脚本(双击时)show

      windowbox show
      

.desktop文件将添加许多其他自变量参数,例如窗口ID,文件的(file-)名称.desktop

随后:

  • .desktop然后使该文件可执行,以使其成为可双击的对象。

  • .desktop文件被双击,窗口是(重新)映射,将.desktop文件从桌面删除。

如何设定

  1. 几乎像往常一样,当您想在Windows上玩耍时,脚本需要同时wmctrlxdotool

    sudo apt-get install xdotool wmctrl
    
  2. 创建目录~/bin~代表您的主目录)
  3. 将以下脚本复制到一个空文件中,将其另存为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])
  4. 使脚本可执行

  5. 要使新创建的目录在中弹出$PATH,请注销/登录或运行source ~/.profile(从终端窗口)
  6. 通过以下命令从终端窗口中测试脚本:

    windowbox box
    

    该窗口应消失,“装箱”窗口应出现在桌面上。

  7. 如果一切正常,请将以下命令添加到快捷键:选择屏幕右上方的齿轮图标:

    齿轮图标

  8. 进入System Settings→交通Keyboard→交通Shortcuts→交通Custom Shortcuts。单击,+然后添加命令:

    windowbox box
    

那应该做。

重要的提示

脚本使用xdotoolwindowunmap使窗口不可见。在桌面上创建的“框”(图标)是隐藏窗口的唯一“门”。换句话说:不要手动删除桌面文件。如果您这样做,该窗口将永远丢失。

要做的工作[编辑20-12:完成 ]

该脚本仍可以使用一些改进:

  • 窗口几何形状无法按定义恢复。可以很好地解决,但我想我会向您展示第一个结果。
  • 在大多数情况下,带框的窗口都有其正确的图标。但是该功能get_process(w_id)可能需要一些改进。如果未在中找到该过程作为命令/usr/share/applications,则该文件具有通用图标。

给框式窗口图标一个不同于其他图标的大小

脚本会根据创建时的“可用”名称(文件名,而不是显示的名称)始终对创建的.desktop文件命名,等等。 boxed_1.desktopboxed_2.desktop

您可以通过右键单击>图标大小来调整文件的大小(通常)。好消息是,如果删除文件并重新创建文件,则会记住该大小。即使重新启动后再次创建文件。这意味着,如果您曾经调整了框状窗口的大小(例如1-5),则当您(脚本)再次创建它们时,它们将始终具有相同的大小!

在此处输入图片说明


2
我无法抗拒自己,没有留下任何评论,您的回答很不错:)
Ravan

真好!几点评论:1.我用到dtop = "/home/jacob/Bureaublad"桌面的路径(dtop = "/home/" + user + "/Desktop")替换了该行。2.双击还原不起作用。我怀疑source ~/.profile还不足以立即登录/注销以测试此测试。3.可以统一手动调整图标大小(右键单击->调整图标大小),是否可以在其中添加一些参数f_content来设置图标的大小?
Artium

4
当我开始阅读此答案的第一段时,我只知道底部会有一个橙色图标! ;-):P
Fabby 2015年

1
嗨,@ Artium我更新了脚本,它现在有了一些重要的改进,包括更好的图标查找和几何图形恢复,玩得开心!
Jacob Vlijm

1
@Artium我知道,但是尝试使用脚本中的那个,它是通常的文件夹图标,类似于您的图像。可能只是指向相同图标的链接。
Jacob Vlijm

7

您可以使用fvwm完成此操作。

  1. 安装fvwm:

    sudo apt-get update
    sudo apt-get install fvwm
    
  2. 查找使用iconify函数的图标-这里有几个:http ://www.jmcunx.com/fvwm_theme.html 几个看起来像您显示的屏幕截图。

  3. 复制主题文本,然后导航至~/.fvwm/(首先显示隐藏的文件),然后创建一个文件.fvwm2rc

  4. 在文本编辑器(如gedit)中打开该文件,然后将主题文本粘贴到其中。

  5. 重新启动计算机,然后选择fvwm并登录。

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.