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


16

我想模仿在Mac OS X上使用Alfred的情况,如果您尝试在搜索后打开某个应用程序,则只有在该程序尚未运行时,它才会打开一个新窗口,否则它将把重点放在该应用程序当前正在运行的实例。无论如何,是否需要更改启动器的默认行为以在打开新窗口之前进行检查?


同样@pidge做到这一点并不困难,但也会影响右键单击“打开方式”的行为。我猜这是不可接受的副作用。
Jacob Vlijm

1
我认为您应该能够创建一个脚本,该脚本可以检查特定进程是否已在运行,并决定启动新进程还是将重点放在现有窗口上。不幸的是,我在脚本方面还不是很出色...但是@JacobVlijm是一个有各种用途的脚本的人;)但是,您必须用相应的脚本替换所有原始启动器。不确定是否要/可以做到-我不会...
字节指挥官

2
如果您使用脚本路径,则可以将此脚本用作起点。我最初是为LXDE / Openbox编写的,但它也应在Unity中工作。有关脚本及其用法的更多信息,请参见此处
Glutanimate 2015年

1
@ByteCommander正是我所想到的。您甚至可以脚本替换.desktop文件中的命令。.desktop但是,如果替换文件中的命令,则右键单击“打开方式”选项会损坏。
Jacob Vlijm

1
适用于哪个桌面环境?
2015年

Answers:


6

4月7日更新:添加了另一个版本并找到了阿尔伯特,请参见更新和以下内容!

关于破折号功能:您询问“ 是否有必要更改启动器的默认行为以在打开新窗口之前进行检查 ”。基本答案是,不,作为普通用户,您无法将这种行为添加到破折号中。但是,如果有一个统一范围的开发人员愿意实现这一目标,那么如果您有决心并愿意学习,则可以与他们联系或自己开发。我的编码技巧非常谦虚,因此我使用外壳脚本和脚本的可用图形前端作为解决方法。

相关信息

原始帖子:

我编写了一个脚本,该脚本使用zenity对话和wmctrl来实现您的要求。请注意,这是一个图形脚本,这意味着它将仅在GUI中的Windows上运行,并且如果您尝试在tty中启动某些内容则将不起作用。此外,据我了解,阿尔弗雷德(Alfred)也做同样的事情。您可以为其创建桌面快捷方式,也可以为其创建启动器快捷方式,如此此处所述

剧本:

#!/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 /ubuntu//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的建议(来自edit),我将代码更改为更紧凑的版本,因此我建议您看一下以前的版本和当前版本。

另外,以前wmctrl -a $MYPROG无法测试google-chrome或Chrome浏览器。由于某些愚蠢的原因,某些程序的窗口的WM_CLASS属性为大写,而列出的程序为dpkg --get-selections小写字母(只需读取man wmctrl并运行wmctrl -lx,您就会知道)。添加-ax应该可以解决这个问题。该脚本会按原样打开已经打开的铬窗口

另一件事-wmctlr有点奇怪,因为有时需要延迟(在其他脚本中有使用经验),所以我不得不添加 sleep 1一行。以前,使用Firefox可以打开和关闭它,但是现在可以轻松使用了。

实际脚本

在动画下面,您可以看到在脚本的第一次运行中,有一个打开的firefox实例,脚本将焦点切换到该窗口。在第二个测试中,我打开了以前未打开的google-chrome新实例。(附带说明:顺便说一句,如果您对台式机比较了解,那就是带有cairo扩展坞的openbox)

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

4月7日更新

我对脚本进行了一些改进,以使所有程序都在zenity的下拉输入框中列出。现在,用户不必记住每个程序,只需使用箭头键滚动浏览它们的列表或打开下拉菜单即可。此外,此改进的版本不是通过名称而是通过窗口ID来引发窗口,从而提供了更好的性能。请注意,我遍历.desktop文件的方式有点多余,两次使用cut命令,但是由于到目前为止我的script-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 /ubuntu//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,但是它没有与此脚本相同的功能。

在此处输入图片说明

让我知道您是否喜欢此脚本,是否有任何需要修复的内容,如果发现有用的话,别忘了对答案进行投票


顺便说一句,请注意我是如何键入程序名称的-完全与中列出的相同dpkg --get-selectons。通过键入“ writer”启动libreoffice writer无法正常工作,但是您可以在〜/ bin,/ bin或/ usr / bin文件夹中对其进行符号链接,也可以在.bashrc或.profile中使用别名。
Sergiy Kolodyazhnyy 2015年

还要注意,您将需要安装wmctl,它不是默认设置,但是非常方便。我还用它来使这个
谢尔盖Kolodyazhnyy

您可以用链接到动画的图像替换动画吗?我的浏览器一直在“加载”页面,所以我无法刷新它。(并且动画不会运行:))
Jacob Vlijm 2015年

谢谢!该链接在Chrome(而不是Firefox)中可以正常工作。
Jacob Vlijm

@JacobVlijm Ugh,确实如此。不知道为什么firefox拒绝播放。这只是我最初上传的内容的imgur链接
Sergiy Kolodyazhnyy 2015年

5

1.短跑第二

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

它存在一个具有与Dash相同功能的窗口。如果键入应用程序的一个或多个字符,则该应用程序将出现在列表中。按此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。它搜索.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)可能会导致异常,我在示例中对此进行了修复以上。如果有人遇到问题,请提及。

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

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

    在此处输入图片说明

  3. 将下面的代码复制到一个空文件中,另存~/.local/share/applicationsdash_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文件拖到启动器上:


1
很高兴知道有一整个.desktop文件文件夹!我想知道如何通过名称而不是命令列出本机和apt安装的应用程序。那里好工作!
Sergiy Kolodyazhnyy 2015年

@Serg谢谢!而你也一样 :)。还有一个.desktop文件本地目录: ~/.local/share/applications。我以为可以将搜索范围限制为全局安装的应用程序。
Jacob Vlijm

雅各,我不知道蟒蛇,但也许将是对你有用的将其变成一个统一的范围提高你的脚本。我的理解是,这是完全改变OP想要的仪表板功能的唯一方法
Sergiy Kolodyazhnyy 2015年

@Serg谢谢!那是一个有趣的帖子,一定会很好看的!
Jacob Vlijm

0

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

对于破折号(单击Ubuntu徽标时会打开的较大部分),如果不对源代码本身进行重大修改,则无法以这种方式更改行为。

但是,某些应用可能已经这样做了,因为它们被设计为以这种方式运行。但是,并非所有应用程序都应该以这种方式实现,也不一定必须如此。

但是,另一个功能是,如果打开用Super+ 展开的窗口W并开始输入应用程序名称,则仅显示该应用程序的窗口。


我实际上已经找到了OP想要的Linux版本,请参阅我的博文,奖金部分。显然有人想到了将Alfred带到Linux的想法
Sergiy Kolodyazhnyy 2015年

1
@Serg,请尝试阿尔伯特;Albert仍然有“ LibreOffice错误”,“ Chromium错误”和“ Chrome错误”。甚至“文件错误” ... Albert总是总是打开这些应用程序的新实例。LibreOffice根本不起作用。此外,在链接下方的评论中,您可以找到许多问题。
Jacob Vlijm

@Serg不,您找到了解决方法,方法是添加一个在后台运行的附加软件,这提供了完全不同的用户体验,并且需要重新培训如何查找应用程序。问题是如何在Unity仪表板中进行这项工作。您也许可以在Unity本身之外获得类似的功能,但是更改Unity来做到这一点的唯一方法是更改​​源代码。
dobey 2015年

@dobey好吧,是的;更改破折号功能超出了我们的能力范围,因此。。.gotta与我们拥有的权利有关,对吗?除非有一个开发人员愿意用这种功能编写统一范围。。。
Sergiy Kolodyazhnyy 2015年
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.