当它丢失焦点时,我可以自动将特定应用程序的窗口发送到最低的z位置吗?

我在两个应用程序中完成了大部分工作:我的Web浏览器和编辑器。 我经常使用Alt-Tab在它们之间来回切换。 我也有一个IM客户端(Hipchat)一直打开,但与其他两个应用程序相比,我很少与它进行交互。

一个反复出现的烦恼是,在我与Hipchat窗口和Alt-Tab交互(比如说)我的编辑器之后,我的肌肉记忆被调整为期望另一个Alt-Tab关注我的浏览器,但我最终再次使用Hipchat。

是否有任何方法可以使Hipchat被发送到堆栈或新近度列表的底部或者它是什么,在它以任何方式失去焦点之后?

你问的实际上是允许特定应用程序的窗口出现在第一个或最后一个位置,z-方式。

当gedit窗口(在此示例中)失去焦点时,它将被发送到最后一个poition(z-方式,在半透明终端窗口下方)而不是仅下降一个位置

在此处输入图像描述 在此处输入图像描述


Z-窗口的位置

虽然可以做到,但我们仍然必须克服一些严重的并发症; 当窗口被发送到最后一个位置时,您将希望保持所有其他窗口的z顺序。 但是,目前没有工具可以为我们提供这种z-order的窗口。 xdotoolwmctrl都没有提供任何关于此的信息。

然而,我们可以做的是跟踪(所有)窗口的焦点历史。 由于如果另一个窗口获得焦点,窗口会下降一个位置,如果我们运行后台脚本来观察窗口的焦点历史,我们可以得出窗口的z顺序。

解决方案有两个小背景脚本

下面的解决方案存在两个小的后台脚本,可以同时运行。

  1. 用于跟踪焦点历史记录的脚本: focus_history.py
  2. 如果失去焦点, set_z.py目标应用程序窗口发送到最后位置的脚本: set_z.py

脚本1

focus-history.py

 #!/usr/bin/env python3 import subprocess import time import os rootdata = os.environ["HOME"]+"/.focus_history" open(rootdata, "wt").write("This is an empty line") def current_windows(): try: return subprocess.check_output(["wmctrl", "-lp"]).decode("utf-8") except subprocess.CalledProcessError: pass def convert_format(w_id): return w_id[:2]+(10-len(w_id))*"0"+w_id[2:] def read_data(): return open(rootdata).read().splitlines() def get_top(wlist): try: top = convert_format( [l.split("#")[-1].strip() for l in subprocess.check_output( ["xprop", "-root"] ).decode("utf-8").splitlines() \ if "_NET_ACTIVE_WINDOW(WINDOW)" in l][0]) return [l for l in wlist if top in l][0] except IndexError: pass if __name__ == "__main__": while True: time.sleep(1) wdata = current_windows() if wdata != None: wlist = wdata.splitlines() # get frontmost window (as in wmctrl -lG) top = get_top(wlist) oldlist = read_data() if not any([top == oldlist[0], top == None]): # clean up closed windows [oldlist.remove(l) for l in oldlist if not l.split()[0] in wdata] # remove possible other mentions of the active window [oldlist.remove(l) for l in oldlist if l.startswith(top.split()[0])] open(rootdata, "wt").write(("\n").join([top]+oldlist)) 

脚本2

 #!/usr/bin/python3 import subprocess import time import focus_history # --- set the process name of your application below proc = "gedit" # --- focus_hist = focus_history.rootdata def get(val): try: return subprocess.check_output(val).decode("utf-8").strip() except subprocess.CalledProcessError: pass def front_w(): get_front = str(hex(int(get(["xdotool", "getactivewindow"])))) return get_front[:2]+(10-len(get_front))*"0"+get_front[2:] while True: time.sleep(1) pid = get(["pgrep", proc]) front1 = "" while pid: time.sleep(1) frontpid = get(["xdotool", "getactivewindow", "getwindowpid"]) front2 = frontpid == pid if front2 != front1: if front2 == False: zdata = [l for l in open(focus_hist).read().splitlines()] wins = list(reversed([l.split()[0] for l in zdata if not pid in l])) for w in wins+[front_w()]: cmd = ["xdotool", "windowraise", w] subprocess.call(cmd) pid = get(["pgrep", proc]) front1 = front2 

如何设置

  1. 该脚本使用wmctrlxdotool

     sudo apt-get install wmctrl xdotool 
  2. 将脚本1复制到一个空文件中,将其保存(完全!)为focus_history.py

  3. 将脚本2复制到空文件中,将其作为set_z.py保存在与脚本1 完全相同的目录中。

    在脚本的head部分,在行中:

     proc = "gedit" 

    "gedit"替换为应用程序的进程名称(引号之间)

  4. 测试运行脚本: 在打开任何(附加)窗口之前 ,通过以下命令启动脚本1:

     python3 /path/to/focus_history.py & python3 /path/to/set_z.py 

    [该脚本将识别至少聚焦一次的窗口。 如果脚本在登录时运行则会出现这种情况]

    如上所述,脚本应位于同一级别的同一目录中。

  5. 现在开始打开窗口,看看它的行为方式。 如果失去焦点,您的应用程序应移至(非常)背景。

  6. 如果一切正常,请将其添加到启动应用程序:Dash>启动应用程序>添加。 添加命令:

     /bin/bash -c "sleep 15 && python3 /path/to/focus_history.py & python3 /path/to/set_z.py" 

笔记

  • 设置假定您打开了目标应用程序的单个窗口。 从你的问题来看,我理解是这样的。

另外

或者,您可以设置快捷键以引发特定应用程序的窗口(如果存在),如此处所述。

然而,这将需要另一个快捷方式返回到第一个应用程序的窗口,

除非…,

您将设置一个快捷方式在两个应用程序之间切换。 然而,这将超出这个问题的范围……