仅在尚未打开时启动应用程序

我想模仿在Mac OS X上使用Alfred,如果你在搜索后尝试打开一个应用程序,它只会在程序尚未运行时打开一个新窗口,否则它会将焦点设置在当前正在运行该应用程序的实例 无论如何都要更改启动器的默认行为以在打开新窗口之前检查这一点?

4月7日更新:添加了另一个版本,找到了Albert,看到更新和Bonus吼叫!

关于短划线function :您已经问过“ 无论如何都要更改启动器的默认行为,以便在打开新窗口之前检查这一点 ”。 基本答案是,不,作为普通用户,您无法将该行为添加到破折号。 但是,如果有一个统一范围的开发人员愿意实现这一点,那么如果你有决心并愿意学习,你可能会接近他们或自己开发一个。 我的编码技巧非常适中,因此我使用shell脚本和脚本的可用图形前端作为解决方法。

相关信息

原帖:

我写了一个脚本,使用zenity对话和wmctrl来实现你的要求。 请注意,这是一个图形脚本,这意味着它只能在GUI中使用Windows,如果您尝试在tty中启动某些内容,则无法使用。 此外,根据我的理解,阿尔弗雷德完全一样。 您可以创建它的桌面快捷方式或启动它的快捷方式,如此处和此处所述 。

剧本:

 #!/bin/bash # Author: Serg Kolo # Description: A launcher script that checks whether # or not a window of a particular program already exists # If a window of such program is open, bring it to focus # Otherwise - launch a new window # Written for https://askubuntu.com/q/440142/295286 # Date: April 6 , 2015 # MYPROG=$( zenity --entry --title='MY LAUNCHER' --text='Type the name of application to run' ) sleep 0.5 wmctrl -lx | awk '{print $3}' | grep -i "$MYPROG" if [ $? -eq 0 ]; then sleep 1 wmctrl -xa $MYPROG #as an alternative try the line bellow #wmctrl -a $MYPROG exit 1 else $MYPROG & exit 0 fi 

附注:在以前的版本中,脚本使用echo $?来测试先前的表达式是否已成功退出。 根据muru的建议(来自编辑),我将代码更改为更紧凑的版本,所以我建议你看看以前的版本和当前版本。

此外,以前wmctrl -a $MYPROG无法测试google-chrome或chrome-browser; 由于一些愚蠢的原因,一些程序的窗口大小的WM_CLASS属性,而dpkg --get-selections列出的程序是小写的(只需读取man wmctrl并运行wmctrl -lx ,你就会知道)。 添加-ax应该解决这个问题。 该脚本会打开已经打开的铬窗口

另一件事 – wmctlr有点奇怪,因为它有时需要延迟(在另一个脚本中有经验),所以我不得不添加sleep 1行。 以前它会与firefox打开和关闭,但现在可以游泳。

脚本在行动

在下面的动画中,您可以看到在第一次运行脚本时,有一个firefox实例打开,脚本将焦点切换到该窗口; 在第二次测试中,我打开了google-chrome的新实例,该实例之前尚未打开过。 (旁注:如果你对桌面很陌生,顺便说一下,那就是openbox with cairo dock)

根据评论中的建议,删除嵌入式动画,仅发布链接。 请报告是否破损! http://i.stack.imgur.com/puuPZ.gif

4月7日更新

我稍微改进了脚本,使所有程序都列在zenity的下拉输入框中。 现在,用户不必记住每个程序,但可以使用箭头键滚动浏览它们的列表,或者只需打开下拉菜单。 此外,这个改进版本不是通过名称引发窗口,而是通过窗口ID引发窗口,这提供了更好的性能。 注意,我通过.desktop文件的方式是多余的,使用cut命令两次,但由于我的脚本fu到目前为止不是那么好,这就是我所能做的。 欢迎提出改进建议!

 #!/bin/bash # Author: Serg Kolo # Description: Second version of a launcher script that checks whether # or not a window of a particular program already exists # If a window of such program is open, bring it to focus # Otherwise - launch a new window # Written for https://askubuntu.com/q/440142/295286 # Date: April 7 , 2015 # set -x MYPROG=$(zenity --entry --text 'Select program from list' --entry-text $(ls /usr/share/applications/*.desktop | cut -d'/' -f5 | cut -d'.' -f1 | xargs echo)) sleep 0.5 # Do we have a window of such program ? wmctrl -lx| awk '{print $3}' | grep -i $MYPROG if [ $? -eq 0 ]; then sleep 0.5 # if yes, find that window id, and raise it WINID=$(wmctrl -lx | grep -i $MYPROG | awk 'NR==1{print $1}') wmctrl -ia $WINID & # exit 0 else echo $MYPROG | grep -i libreoffice if [ $? -eq 0 ] then MYPROG=$(echo $MYPROG | sed 's/-/ --/g') fi $MYPROG & # exit 0 fi 

在此处输入图像描述

奖金:

我实际上找到了Albert ,这是Alfred的Linux版本,但我自己没有尝试过。 值得一试。 然而,正如雅各布已经指出的那样,它仍然是马车。

有一个名为Gnome-Do的应用程序,它在图形上看起来类似于Alfred,但它没有与此脚本相同的function。

在此处输入图像描述

如果您喜欢这个脚本,请告诉我,如果有任何需要修复的话,如果您发现它有用,请不要忘记给出答案

1.破坏第二个

在您的问题中描述的运行应用程序时,可以用作Dash的替代脚本的脚本下方。

它存在一个与Dash具有相同function的窗口; 如果键入应用程序的一个或多个字符,应用程序将出现在列表中。 按Enter键启动或引发应用程序,具体取决于它是否已在运行。

您可以从快捷键组合中调用它,或者在启动器中设置一个图标,使其类似于Dash(请参见下文)或两者。

在此处输入图像描述

剧本

 #!/usr/bin/env python3 import subprocess import os import getpass import time user = getpass.getuser() get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8") skip = ["%F", "%U", "%f", "%u"]; trim = ["chrome", "chromium", "nautilus"] def apply(command): if "libreoffice" in command: proc = [l.split()[0] for l in get("ps -u "+user).splitlines() if "soffice.bin" in l] module = command.split("--")[-1] time.sleep(0.1) try: ws = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if process in w and module in w.lower()] for process in proc], [])[0] subprocess.call(["wmctrl", "-ia", ws]) except IndexError: subprocess.Popen(["/bin/bash", "-c", command+"&"]) else: check = command.split("/")[-1][:14] proc = [p.split()[0] for p in get("ps -u "+user).splitlines() if check in p] time.sleep(0.5) try: ws = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if process in w] for process in proc], []) if command == "nautilus": real_window = [w for w in ws if "_NET_WM_WINDOW_TYPE_NORMAL" in get("xprop -id "+w)][0] else: real_window = ws[0] subprocess.call(["wmctrl", "-ia", real_window]) except IndexError: subprocess.Popen(["/bin/bash", "-c", command+"&"]) # default directories of .desktop files; globally, locally, LibreOffice- specific when separately installed globally = "/usr/share/applications"; locally = os.environ["HOME"]+"/.local/share/applications"; lo_dir = "/opt/libreoffice4.4/share/xdg" # create list of .desktop files; local ones have preference local_files = [it for it in os.listdir(locally) if it.endswith(".desktop")] global_files = [it for it in os.listdir(globally) if it.endswith(".desktop")] lo_spec = [it for it in os.listdir(lo_dir) if it.endswith(".desktop")] if os.path.exists(lo_dir) else [] for f in [f for f in local_files if f in global_files]: global_files.remove(f) for f in [f for f in local_files if f in lo_spec]: lo_spec.remove(f) dtfiles = [globally+"/"+f for f in global_files]+[locally+"/"+f for f in local_files]+[lo_dir+"/"+f for f in lo_spec] # create list of application names / commands valid = [] for f in dtfiles: content = open(f).read() if all(["NoDisplay=true" not in content,"Exec=" in content]): lines = content.splitlines() name = [l.replace("Name=", "") for l in lines if "Name=" in l][0] command = [l.replace("Exec=", "") for l in lines if all(["Exec=" in l, not "TryExec=" in l])][0] valid.append((name, command)) valid.sort(key=lambda x: x[0]) # create zenity list + window list_items = '"'+'" "'.join([f[0] for f in valid])+'"' proposed = 'zenity --list --text "Type one or more characters... " --column="Application List" '+\ '--title="Dash the Second" --height 450 --width 300 '+list_items try: choice = subprocess.check_output(["/bin/bash", "-c", proposed]).decode("utf-8").strip().split("|")[0] command = [r[1] for r in valid if r[0] == choice][0] # command fixes: for s in skip: command = command.replace(" "+s, "") for t in trim: if t in command: command = t apply(command) except subprocess.CalledProcessError: pass 

如何使用

该脚本需要安装wmctrl

 sudo apt-get install wmctrl 

然后:

  1. 将上面的脚本粘贴到一个空文件中,将其保存为dash_alternative.py
  2. 将其添加到快捷键组合中:选择:系统设置>“键盘”>“快捷方式”>“自定义快捷方式”。 单击“+”并添加命令:

     python3 /path/to/dash_alternative.py 

说明

运行脚本时,它会列出/usr/share/applications表示的所有应用/usr/share/applications 。 它搜索.dektop文件,创建所有应用程序名称的列表(从第一个“Name =”行)和运行应用程序的命令(从第一个“Exec =”行)。

随后,创建Zenity列表,以排序的方式显示所有应用程序。

每当选择一个应用程序时,如果应用程序正在运行,脚本将查看正在运行的进程列表。 如果是,则引发相应的窗口。 如果没有,则打开一个新实例。

笔记

  1. 要在12.04上运行脚本(因为原始问题被标记为12.04只需将shebang更改为#!/usr/bin/env python并通过命令运行它

     python /path/to/dash_alternative.py 
  2. 据我测试,脚本运行正常。 命令及其(非)对应的进程名称(例如LibreOffice <> soffice.bin ),不同的窗口类型( nautilus有几种不同的窗口类型,除了“真正的”窗口),每个应用程序有多个pid( ChromiumGoogle-chrome )可以导致exception,我在上面的例子中修复了。 如果有人遇到问题,请提及。

2.附加:将其设置为运行应用程序的“真实”Dash的替代方案

  1. 如上所述复制并保护脚本
  2. 将下面的图标(右键单击>安全为)保存为dash_alternative.png

    在此处输入图像描述

  3. 将下面的代码复制到一个空文件中,将其保存在~/.local/share/applications作为dash_thesecond.desktop 。 为/path/to/dash_alternative.py (脚本)和/path/to/dash_alternative.png (图标)设置正确的路径

     [Desktop Entry] Name=Dash the Second Exec=python3 /path/to/dash_alternative.py Icon=/path/to/dash_alternative.png Type=Application Hidden=false 
  4. .desktop文件.desktop启动器上:

对于启动器 (屏幕左侧的垂直面板),这已经是默认行为,因为它是任务切换界面。

对于破折号 (单击Ubuntu徽标时打开的大位),无法以这种方式更改行为,而无需对源代码本身进行重大修改。

但是,有些应用程序可能已经这样做了,因为它们的设计就是这样。 但是,所有应用程序都不是,也不一定是以这种方式实现的。

但是,作为另一个function,如果您打开使用Super + W传播的窗口,并开始键入应用程序名称,则该应用程序的窗口将是唯一显示的窗口。