问题描述
是否可以镜像一个工作区的活动部分,以使其在当前工作区中作为可移动的窗口可见?
前几天,我在Ubuntu 16.04主机上运行了Windows 10 VM,这花费了很长时间才能完成更新。我一直在Ubuntu上通过Expo(Super
+ S
)来检查它的进度。这让我想到这个问题很可能已经解决了,因为诸如simplescreenrecorder之类的工具可以配置为仅记录屏幕的一部分。但是,我不知道用于Google搜索的正确术语。
我想以浮动窗口(带有实时更新)的形式在下面的300×150屏幕截图中查看,无论哪个工作空间碰巧是最新的。
最佳办法
EDIT
(新答案)
完毕。以下答案现在可以以抛光的形式提供,作为指标,例如Trusty,Xenial,Yakkety和Zesty的ppa:
sudo apt-add-repository ppa:vlijm/windowspy
sudo apt-get update
sudo apt-get install windowspy
指示器(包括预览窗口)现在的果汁含量很低。选项包括设置窗口,设置窗口边框大小/颜色,窗口大小。
同时,我发现密切关注AU窗口很有用。看看是否有任何消息:)
老答案
(第一个第二个粗略概念)
最小化另一个工作区上的窗口表示
令我自己大吃一惊的是,可以有效地做到这一点,无论是通过欺骗还是欺骗手段。具有另一个工作空间上的窗口的更新的表示形式。不适合看电影,绝对足以吸引其他地方的窗户(例如:我的tv-card窗户):
在实践中如何运作
-
将窗口放在前面,按快捷键:(该窗口将最小化)
-
移至另一个工作区,再次按快捷键,将显示该窗口的一个很小的表示,每4秒更新一次:该窗口始终显示在其他窗口的顶部。实际上,窗口为300px(宽度),但可以设置为任何大小。
-
要结束它,请按(再次)快捷键。小窗口将关闭,您将移至原始窗口的视口,该视口将再次最小化。
脚本
-
控制脚本
#!/usr/bin/env python3 import subprocess import os import sys import time # paths imagepath = os.path.join(os.environ["HOME"], ".showcase") wfile = os.path.join(imagepath, "currentwindow") vpfile = os.path.join(imagepath, "last_vp") # setup path if not os.path.exists(imagepath): os.mkdir(imagepath) def get(command): try: return subprocess.check_output(command).decode("utf-8").strip() except subprocess.CalledProcessError: pass def get_vp(): open(vpfile, "wt").write(get(["wmctrl", "-d"]).split()[5]) def run(command): subprocess.Popen(command) def convert_tohex(widxd): return widxd[:2]+((10-len(widxd))*"0")+widxd[2:] def check_windowtype(wid): check = get(["xprop", "-id", wid]) return not any([s in check for s in [ "_NET_WM_WINDOW_TYPE_DOCK", "_NET_WM_WINDOW_TYPE_DESKTOP"]]) def edit_winprops(wid, convert=True): run(["xdotool", "windowminimize", wid]) if convert: widxd = convert_tohex(hex(int(wid))) else: widxd = wid run(["wmctrl", "-i", "-r", widxd, "-b", "add,sticky"]) get_vp() open(os.path.join(imagepath, "currentwindow"), "wt").write(widxd) def initiate_min(): # if not, minmize window, write the file wid = get(["xdotool", "getactivewindow"]) if check_windowtype(wid): edit_winprops(wid) else: pidinfo = [l.split() for l in wlist.splitlines()] match = [l for l in pidinfo if all([ get(["ps", "-p", l[2], "-o", "comm="]) == "VirtualBox", not "Manager" in l])] if match: edit_winprops(match[0][0], convert=False) # windowlist wlist = get(["wmctrl", "-lp"]) if "Window preview" in wlist: # kill the miniwindow pid = get(["pgrep", "-f", "showmin"]) run(["kill", pid]) window = open(wfile).read().strip() viewport = open(vpfile).read().strip() run(["wmctrl", "-o", viewport]) time.sleep(0.3) run(["wmctrl", "-i", "-r", window, "-b", "remove,sticky"]) run(["wmctrl", "-ia", window]) os.remove(wfile) else: # check if windowfile exists wfileexists = os.path.exists(wfile) if wfileexists: # if file exists, try to run miniwindow window = open(wfile).read().strip() if window in wlist: # if the window exists, run! run(["showmin", window]) else: # if not, minmize window, write the file initiate_min() else: # if not, minmize window, write the file initiate_min()
-
窗口表示
#!/usr/bin/env python3 import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, GObject from PIL import Image import os import subprocess import time from threading import Thread import sys wid = sys.argv[1] xsize = 300 imagepath = os.path.join(os.environ["HOME"], ".showcase") if not os.path.exists(imagepath): os.mkdir(imagepath) img_in = os.path.join(imagepath, "image.png") resized = os.path.join(imagepath, "resized.png") def get_img(): subprocess.Popen([ "import", "-window", wid, "-resize", str(xsize), resized ]) get_img() class Splash(Gtk.Window): def __init__(self): Gtk.Window.__init__(self, title="Window preview") maingrid = Gtk.Grid() self.add(maingrid) self.image = Gtk.Image() # set the path to the image below self.resized = resized self.image.set_from_file(self.resized) maingrid.attach(self.image, 0, 0, 1, 1) maingrid.set_border_width(3) self.update = Thread(target=self.update_preview) self.update.setDaemon(True) self.update.start() def update_preview(self): while True: get_img() time.sleep(3) GObject.idle_add( self.image.set_from_file, self.resized, priority=GObject.PRIORITY_DEFAULT ) def miniwindow(): window = Splash() window.set_decorated(False) window.set_resizable(False) window.set_keep_above(True) window.set_wmclass("ShowCase", "showcase") window.connect("destroy", Gtk.main_quit) GObject.threads_init() window.show_all() window.move(70, 50) Gtk.main() miniwindow()
如何使用
-
安装
python3-pil
,xdotool
和wmctrl
sudo apt-get install xdotool wmctrl python3-pil
-
创建目录
~/bin
(如果尚不存在)。 -
将脚本1(控制脚本)复制为
~/bin
中的showcase_control
(无扩展名),并使其可执行。 -
将脚本脚本2(迷你窗口脚本)复制为
~/bin
中的showmin
(无扩展名),并使其可执行。 -
注销并重新登录,然后将以下命令添加到您选择的快捷方式中:
showcase_control
选择:系统设置> “Keyboard”> “Shortcuts”> “Custom Shortcuts”。单击”+”并添加命令:
showcase_control
,它应该可以工作!
-
按键一次即可获取当前窗口
-
移到您想要mini-window的其他工作区
-
再按一次以显示迷你窗口
-
再按一次以返回到原始工作区,(自动)un-minimize原始窗口并关闭迷你-one。
-
缺点?
-
目前的设置为您的处理器增加了一些工作。但是,在我的(非常旧的)系统上,它增加了(平均)appr。我认为是4-5%,我丝毫没有注意到。更新:事实证明
import
可以一步一步地调整图像大小,并获取窗口图像。这意味着处理器负载将大大降低。同时,刷新时间更短(现在为3秒),仍处于较低的”costs”。
Explanation
-
我的出发点是OP提到他想使用该选项来盯着另一个工作区的窗口,等待其中任何一个完成的方式。
-
虽然从字面上看不可能在另一个工作区上有一个窗口的精确(微型)副本,但是一旦有了窗口ID,我们就可以使用
import
-命令为现有窗口创建图像。尽管这两种方法都可以在最小化的窗口或没有焦点的窗口上使用,但是存在一个问题:窗口必须位于当前工作空间上。 -
然后,技巧是临时(使用迷你窗口时)将窗口”sticky”(实际上在所有工作空间中都可用)设置为
wmctrl
,但同时将其最小化。 -
由于所有操作都是自动完成的,因此区别实际上是没有的,因为还返回了初始视口,即自动完成了”un-“粘贴原始窗口并将其最小化的操作。
简而言之:
-
按下快捷键一次:目标窗口变粘,但已最小化
-
再次按下它(大概是在另一个工作区):窗口的一个小型迷你版出现在左上角,每四秒钟更新一次。
-
再次按下该按钮:迷你窗口关闭,桌面移至该窗口的初始工作区,该窗口恢复原状且未最小化。
专门用于VirtualBox
当VBox窗口位于最前面时,表明Ubuntu快捷键已禁用(!),因此需要以另一种方式启动控制脚本。下面简要介绍一下。
选项1
我编辑了控制脚本。现在仅在VirtualBox的情况下:
-
单击桌面上的任意位置,然后按快捷键。之后,只需使用快捷键显示窗口并退出。说明:如果窗口的类型为”desktop”,则使控制脚本退出,因为您不想最小化桌面。现在,如果当前活动的窗口是桌面,则脚本首先查找可能存在的VirtualBox窗口作为目标。
选项2
-
复制下面的图标(右键单击->另存为),将其另存为
minwinicon.png
-
将以下各行复制到一个空文件中,将其另存为
~/.local/share/applications
中的minwin.desktop
:[Desktop Entry] Type=Application Name=Window Spy Exec=showcase_control Icon=/path/to/minwinicon.png StartupNotify=false
您需要注销然后重新登录,以启动器进入本地
~/bin
路径”find”!将图标拖到启动器上以使用它。
第二种解决方案有一个重要的缺点:在启动器中使用它后,它将持续闪烁几秒钟,等待出现一个窗口。在此期间,再次单击不会产生任何效果。可以解决,如here所述,但在此答案中包含该内容确实会使它过长。如果要使用选项二,请查看链接。