![如何在 Unity 启动器中为脚本赋予自己的图标?](https://linux22.com/image/1137972/%E5%A6%82%E4%BD%95%E5%9C%A8%20Unity%20%E5%90%AF%E5%8A%A8%E5%99%A8%E4%B8%AD%E4%B8%BA%E8%84%9A%E6%9C%AC%E8%B5%8B%E4%BA%88%E8%87%AA%E5%B7%B1%E7%9A%84%E5%9B%BE%E6%A0%87%EF%BC%9F.png)
使用 Ubuntu 16.04,如果您创建一个~/.local/share/applications
带有终端应用程序自定义图标的启动器(中的桌面文件)(因此使用Terminal=true
),那么当您启动它时,它将产生一个新的标准终端图标,并且您的自定义图标将在几秒钟内脉动并消失。
在 14.04 中,它按预期工作。(它不会启动新的标准终端图标)。
知道如何改变这种行为吗?我有几个终端应用程序想要从 Unity 启动,但新的行为是有问题的(我记不清哪个是哪个,因为它们都以标准终端图标结尾)...
答案1
为什么它不像你那样工作
正如评论中提到的,原则上一个应用程序只能由启动器中的一个图标表示一次. 一直都是这样。
您所指的可能是 Unity 在确定哪个文件.desktop
最适合代表应用程序窗口方面变得“更聪明”。因此,运行终端窗口的脚本将由 -icon 表示gnome-terminal
:
因此,您设置中过去所做的操作(简单地创建一个启动器,启动您的脚本)不再欺骗 Unity,它会选择现有的gnome-terminal
启动器来代表您的窗口。
糟糕的解决方案
...是通过在启动器中添加一行来推翻 Unity 的选择(适用于 16.04):
StartupWMClass=gnome-terminal-server
...但是之后全部终端窗口,无论是否运行您的脚本,都分组在此图标下。
此外,一般来说,拥有多个.desktop
文件并在其主命令中调用同一个应用程序是一种不好的、不干净的做法。
编辑
如何为正在运行的脚本设置单独的图标
这需要一些诡计和欺骗,但它是可以为在不同的终端窗口中运行的多个脚本设置单独的图标。
实践中如何运作
- 假设您有一个脚本,
somscript.sh
您想要在终端窗口中运行它,并在运行时在 Unity Launcher 中显示其专用图标。 运行命令:
showicon somescript.sh someicon.png
脚本将在新打开的
gnome-terminal
窗口中运行,并显示图标:someicon.png
- 如果窗口关闭,图标将再次从启动器中删除。
一个例子
我想要一个脚本,
/home/jacob/Bureaublad/script.sh
运行,在 Unity 启动器中显示图标:/home/jacob/Thema/icon/ubu.png
运行命令:showicon '/home/jacob/Bureaublad/script.sh' '/home/jacob/Thema/icon/ubu.png'
将会这样做:
现在让我们添加另一个:
showicon '/home/jacob/Bureaublad/script2.sh' '/home/jacob/Thema/icon/banaan.png'
结果:
一旦窗口关闭,图标就会再次被删除。
如何设置
脚本需要
wmctrl
sudo apt-get install wmctrl
如果目录尚不存在,则创建该目录
~/bin
- 将以下脚本复制到一个空文件中,将其另存为
showicon
(无扩展名)~/bin
,然后使其可执行 注销并重新登录,您的设置应该可以正常工作。使用命令进行测试
showicon </path/to/script.sh> </path/to/icon.png>
已经
script.sh
在终端中运行,并显示icon.png
在 Unity 启动器中。
剧本
#!/usr/bin/env python3
import subprocess
import os
import sys
import time
terminal = "gnome-terminal"
key = "com.canonical.Unity.Launcher"
script = sys.argv[1]
icon = sys.argv[2]
curr = os.path.dirname(os.path.realpath(__file__))
scriptname = script.split("/")[-1]
def get(command):
try:
return subprocess.check_output(command).decode("utf-8")
except subprocess.CalledProcessError:
pass
# --- edit Unity launcher section
def current_launcher():
return eval(get(["gsettings", "get", key, "favorites"]))
def set_launcher(desktopfile, arg):
curr_launcher = current_launcher()
last = [i for i, x in enumerate(curr_launcher) if x.startswith("application://")][-1]
new_icon = "application://"+desktopfile
if arg == "a":
if not new_icon in curr_launcher:
curr_launcher.insert(0, new_icon)
subprocess.Popen(["gsettings", "set", key,"favorites",str(curr_launcher)])
elif arg == "r":
curr_launcher.remove(new_icon)
subprocess.Popen(["gsettings", "set", key,"favorites",str(curr_launcher)])
# --- end section
def create_launcher(w, scriptname, icon):
launcher = ["[Desktop Entry]", "Type=Application",
"Exec=wmctrl -ia "+w, "Name="+scriptname, "Icon="+icon,
"StartupNotify=False"]
with open(l_name, "wt") as newlauncher:
for l in launcher:
newlauncher.write(l+"\n")
def getname():
# create unique launcher name
n = 1
while True:
nm = os.path.join(curr, "scriptlauncher_"+str(n)+".desktop")
if os.path.exists(nm):
n += 1
else:
break
return nm
wlist1 = [l.split()[0] for l in get(["wmctrl", "-l"]).splitlines()]
subprocess.Popen(["gnome-terminal", "-e", script])
while True:
time.sleep(1)
wdata = get(["wmctrl", "-l"]).splitlines()
if wdata:
try:
wlist2 = [l.split()[0] for l in wdata]
w = [w for w in wlist2 if not w in wlist1][0]
except IndexError:
pass
else:
# check if the new window belongs to the terminal
if terminal in get(["xprop", "-id", w]):
# create launcher
l_name = getname()
create_launcher(w, scriptname, icon)
set_launcher(l_name, "a")
break
wlist1 = wlist2
while True:
time.sleep(2)
wdata = get(["wmctrl", "-l"])
if wdata:
if not w in wdata:
os.remove(l_name)
set_launcher(l_name, "r")
break
笔记
图标的作用:
- 它代表
gnome-terminal
运行脚本的窗口 单击它时,它会像往常一样升起窗口。执行此操作的命令会自动添加到临时启动器:
wmctrl -ia <window_id>
- 它代表
它能做什么不是:
- 该解决方案的唯一缺点是,由于表示是间接的,因此图标左侧不会显示正在运行的应用程序的通常箭头。
解释
无需过多赘述:
- 该脚本是一个包装器。如果您启动脚本通过
showicon
,的实例在窗口showicon
中运行您的脚本gnome-terminal
,类似于Terminal=true
。 - 随后,
showicon
等待新gnome-terminal
窗口出现并读取其窗口 id。 然后创建一个临时启动器,使用窗口 ID 创建命令以在其行中调出窗口
Exec=
。您在要运行的命令中设置为参数的图标showicon
将自动设置为此临时启动器的图标(在行中定义Icon=
)。这种自动创建的(临时)启动器的示例:
[Desktop Entry] Type=Application Exec=wmctrl -ia 0x04400b7f Name=script2.sh Icon=/home/jacob/Thema/icon/ubu.png StartupNotify=False
使用与这个答案,临时启动器将被添加到 Unity Launcher 的顶部位置,以代表您正在运行的脚本。
- 同时,
showicon
检查窗口是否存在。如果不存在,则临时启动器将从 Unity 启动器中移除,并不再存在根本,showicon
实例将被终止。
答案2
我找到了一个在 Ubuntu 20.04 中有效的简单解决方案。
这适用于您想要使用自己的图标和名称集成到 dock 中而不是仅仅在另一个终端窗口中运行的任何脚本或终端应用程序。
您不需要安装任何东西,一切都在启动器 .desktop 文件中完成。这是我启动终端文本编辑器的示例微。
[Desktop Entry]
Name=Micro
GenericName=Text Editor
Comment=Edit text files in a terminal
Icon=micro
Type=Application
Categories=Utility;TextEditor;Development;
Keywords=text;editor;syntax;terminal;
Exec=gnome-terminal -e "micro %F" -t "Micro" --hide-menubar --name=Micro --class=micro
StartupNotify=true
Terminal=false
MimeType=text/plain;text/x-chdr;text/x-csrc;text/x-c++hdr;text/x-c++src;text/x-java;text/x-dsrc;text/x-pascal;text/x-perl;text/x-python;application/x-php;application/x-httpd-php3;application/x-httpd-php4;application/x-httpd-php5;application/xml;text/html;text/css;text/x-sql;text/x-diff;
需要注意的主要选项是:
- 执行官行
gnome-terminal
使用命令 (-e "YOUR COMMAND"
) 和参数启动-t "Micro" --hide-menubar --name=Micro --class=micro
。这些将使用应用程序的名称(在本例中为 Micro)及其类来设置终端窗口,以便它不会合并到另一个终端类窗口中。 - StartupNotify=true这可以确保如果您将启动器作为收藏,则启动时它会被堆叠,而不是添加额外的图标实例。
- 终端=false使用此功能可以避免弹出额外的终端窗口,除非您确实想看到该窗口。
答案3
另一个不是答案而是解决方案。
我使用快速列表来为最常用的终端会话创建启动器,然后在 gnome-terminal 中为每个启动器创建配置文件,以执行诸如更改其颜色之类的操作,这使得您可以很容易地知道您正在使用哪个服务器。
您可以通过编辑 ~/.local/share/applications/gnome-terminal.desktop 中的 gnome-terminal.desktop 文件来执行此操作。
我的看起来像这样
[Desktop Entry]
Name=Terminal
Comment=Use the command line
Keywords=shell;prompt;command;commandline;
TryExec=gnome-terminal
Exec=gnome-terminal
Icon=utilities-terminal
Type=Application
X-GNOME-DocPath=gnome-terminal/index.html
X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-terminal
X-GNOME-Bugzilla-Component=BugBuddyBugs
X-GNOME-Bugzilla-Version=3.16.2
Categories=GNOME;GTK;System;TerminalEmulator;
StartupNotify=true
X-GNOME-SingleWindow=false
OnlyShowIn=GNOME;Unity;
Actions=New;Item1;Item2
X-Ubuntu-Gettext-Domain=gnome-terminal
[Desktop Action New]
Name=New Terminal
Exec=gnome-terminal
OnlyShowIn=Unity
[Desktop Action Item1]
Name=SSH Shell type 1
Exec=gnome-terminal -e 'ssh item1' --profile 'Item1'
OnlyShowIn=Unity
[Desktop Action Item2]
Name=SSH Shell type 2
Exec=gnome-terminal -e 'ssh item2' --profile 'Item2'
OnlyShowIn=Unity
不久前我还编写了一个脚本,用于自动从 hostsfile 将条目添加到快速列表中,以便任何 ssh 命令都能获得快速列表条目。当快速列表无法自动更新时,我编写了它,但后来放弃了,因为这让它变得笨重,现在它们是即时的,可以通过 cron 作业运行。
答案4
一次性修复方法是编写一个运行脚本的小型可执行程序,并为该可执行程序分配一个唯一的启动器图标。