当我点击Unity中的“Lock to launcher”时会发生什么?

在Unity桌面中,当我启动GUI应用程序时,其图标将出现在启动器中(如果它尚未存在)。

现在,当我右键单击此图标时,我会选择Lock to LauncherUnunc from Launcher ,具体取决于应用程序是否已锁定到启动器。

我的问题是:
如果没有.desktop文件,当我点击这两个选项中的一个时会发生什么?

它是否可以自动创建简单的.desktop文件,如果它找不到,在哪种情况下可能发生这种情况,以及固定的启动器项目在哪里得到保存?

如果您将应用程序锁定到启动器/从启动器解锁应用程序,会发生什么

不确定这个答案是否足够深入“引擎盖下”,但这是发生的事情:

您可以通过以下命令获取Unity Launcher的当前内容:

 gsettings get com.canonical.Unity.Launcher favorites 

它将生成一个列表,如下所示:

 ['application://extras-qlequicklisteditor.desktop', 'application://gedit.desktop', 'application://gnome-terminal.desktop', 'application://nautilus.desktop', 'application://firefox.desktop', 'application://thunderbird.desktop', 'application://gnome-screenshot.desktop', 'application://dconf-editor.desktop', 'application://virtualbox.desktop', 'application://gnome-tweak-tool.desktop', 'unity://running-apps', 'unity://devices', 'unity://expo-icon'] 

列表中的提及显然基于相应的.desktop文件的名称。

现在,当您运行GUI应用程序时,右键单击启动器中的图标并选择“ 锁定到启动器” ,当前选择的项目将添加到列表中,而从启动器解锁将从列表中删除该项目。

以编程方式编辑Unity Launcher

重新阅读您的问题下面的(第一个)评论:如上所述,您可以通过命令获取当前的Launcher项目:

  gsettings get com.canonical.Unity.Launcher favorites 

并通过命令设置可能的更改列表:

  gsettings set com.canonical.Unity.Launcher favorites "[item1, item2, etc]" 

然后,您可以编程方式编辑Unity Launcher的内容,如此处所述 。

如果应用程序没有.desktop文件

如果您运行没有现有.desktop文件的GUI应用程序,Unity会在本地创建一个基本的(在~/.local/share/applications ),以可执行文件( application.desktop )命名。 在Exec=行中,您将找到您运行的命令,以调用该应用程序。

如果您要查看以这种方式创建的.desktop文件,它包含以下行:

 X-UnityGenerated=true 

注意

正如@muru所提到的那样(谢谢!),在一些(特殊的,看似似乎)情况下,Unity没有成功创建可执行文件的“缺失” .desktop文件。 然而,我能找到的唯一例子是Tkinter窗口,它在wmctrl -lp的输出中由pid 0拥有。

单击“ 锁定到启动器”选项时会发生什么,Unity将更改启动器collections夹的特定dconf架构并调用几个dbus方法。 程序员和应用程序开发人员的关键是dconf架构的变化。 (雅各布的答案依赖于gsettings ,但是这个想法与gsettings基本相同,只是前端对dconf进行健全性检查)。 在这里,我只想提出一些意见。

旁注:这里,我正在使用没有.desktop文件的自定义python应用程序测试所有内容

Dconf更改

运行dconf watch /将显示这是改变的:

 $ dconf watch / # Lock to launcher /com/canonical/unity/launcher/favorites ['application://gnome-terminal.desktop', 'application://firefox.desktop', 'application://gedit.desktop', 'application://sakura.desktop', 'application://mplab.desktop', 'unity://running-apps', 'application://pyqt_clock_py.desktop', 'unity://devices'] # Unlock from launcher /com/canonical/unity/launcher/favorites ['application://gnome-terminal.desktop', 'application://firefox.desktop', 'application://gedit.desktop', 'application://sakura.desktop', 'application://mplab.desktop', 'unity://running-apps', 'unity://devices'] 

为应用程序创建.desktop文件

最初,检查应用程序是否存在.desktop文件。 如果文件存在 – 很好。 如果不是 – Unity将在org.ayatana.bamf服务上发出对org.ayatana.bamf.control.CreateLocalDesktopFile方法的dbus调用。 这可用于自动创建.desktop文件。 虽然这在dbus-monitor输出中没有显示,但我相信这是Unity可能使用的方法之一。

这是一个小型演示:

 # start custom app in background, app appears on the launcher $> python /home/xieerqi/bin/python/pyqt_clock.py & [1] 16768 # confirm that there is no .desktop file for that app $> qdbus org.ayatana.bamf /org/ayatana/bamf/matcher org.ayatana.bamf.matcher.RunningApplicationsDesktopFiles /usr/share/applications/compiz.desktop /usr/share/applications/firefox.desktop /usr/share/applications/x-terminal-emulator.desktop $> ls .local/share/applications/pyqt_clock_py.desktop ls: cannot access .local/share/applications/pyqt_clock_py.desktop: No such file or directory # I use custom function to find list of running apps by their dbus path $> typeset -f running_apps running_apps() { qdbus org.ayatana.bamf /org/ayatana/bamf/matcher org.ayatana.bamf.matcher.RunningApplications | xargs -I {} bash -c "echo {}; qdbus org.ayatana.bamf {} org.ayatana.bamf.view.Name" } $> running_apps /org/ayatana/bamf/application/0x146bb90 Clock /org/ayatana/bamf/application/1932146384 # that's what we want Firefox Web Browser /org/ayatana/bamf/application/1060483892 MY CUSTOM TERMINAL /org/ayatana/bamf/application/885622223 Compiz /org/ayatana/bamf/application/0x146b8f0 # Use the dbus method to create desktop file $> qdbus org.ayatana.bamf /org/ayatana/bamf/control \ > org.ayatana.bamf.control.CreateLocalDesktopFile /org/ayatana/bamf/application/0x146bb90 # Verify its creation $> ls .local/share/applications/pyqt* .local/share/applications/pyqt_clock_py.desktop # This doesn't however pin the program to launcher # Different call to dbus will be issued $ gsettings get com.canonical.Unity.Launcher favorites ['application://gnome-terminal.desktop', 'application://firefox.desktop', 'application://gedit.desktop', 'application://sakura.desktop', 'application://mplab.desktop', 'unity://running-apps', 'unity://devices'] 

有一种不同的dbus方法,它会破坏文件:

dbus-monitor启示

我已经执行了dbus-monitor --profile命令运行的锁定和解锁操作。 你可以看到几个方法调用(由mc指定)到ca.desrt.dconf.Writer接口和Zeitgeist。

 mc 1461904751 317156 3474 :1.32 /ca/desrt/dconf/Writer/user ca.desrt.dconf.Writer Change mr 1461904751 317976 4520 3473 :1.32 mc 1461904751 320331 3475 :1.32 /org/gnome/zeitgeist/log/activity org.gnome.zeitgeist.Log InsertEvents mc 1461904751 341474 118 :1.93 /org/gnome/zeitgeist/monitor/special org.gnome.zeitgeist.Monitor NotifyInsert mr 1461904751 341576 119 3475 :1.32 mr 1461904751 341927 39 118 :1.93 mr 1461904751 356896 114 3474 :1.32 sig 1461904751 357892 115 /ca/desrt/dconf/Writer/user ca.desrt.dconf.Writer Notify 

如果使用dconf-monitor执行更详细的视图,您将看到对dconf的调用会写入字节序列,并且zeitgeist会记录添加的条目。 我已经多次测试了这些,这些是在每种情况下执行的相同操作。

样本输出formsZeitgeist。

 method call sender=:1.93 -> dest=org.gnome.zeitgeist.SimpleIndexer serial=104 path=/org/gnome/zeitgeist/monitor/special; interface=org.gnome.zeitgeist.Monitor; member=NotifyInsert struct { int64 1461904249994 int64 1461904249994 } array [ struct { array [ string "14288" string "1461904249994" string "http://www.zeitgeist-project.com/ontologies/2010/01/27/zg#AccessEvent" string "http://www.zeitgeist-project.com/ontologies/2010/01/27/zg#UserActivity" string "application://compiz.desktop" string "" ] array [ array [ string "application://pyqt_clock_py.desktop" string "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Software" string "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#SoftwareItem" string "" string "application/x-desktop" string "Clock" string "unknown" string "application://pyqt_clock_py.desktop" string "" ] ] array [ ] } ] 

Unity源代码:

处理它的特定代码在Unity源代码的launcher/ApplicationLauncherIcon.cpp中定义

 /* (Un)Stick to Launcher */ glib::Object menu_item(dbusmenu_menuitem_new()); const char* label = !IsSticky() ? _("Lock to Launcher") : _("Unlock from Launcher"); dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, label); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true); 

但实际的工作是由unity-shared/BamfApplicationManager.cpp

 bool Application::SetSticky(bool const& param) { bool is_sticky = GetSticky(); if (param == is_sticky) return false; // unchanged bamf_view_set_sticky(bamf_view_, param); return true; // value updated } 

那我们离开了哪里?

了解对dconf所做的更改以及启动程序的特定行为可以帮助我们扩展其function。 我和雅各布的例子包括:

  • 将Launcher设置为输入文件
  • 重新排序以使活动应用程序顶部或底部项目
  • 从用户到用户克隆启动器设置
  • 每个工作区创建唯一的启动器

dbus方法用于创建.desktop文件的特殊用途允许自动创建自定义编写应用程序的快捷方式,稍后可以使用Jacob描述的gsettings方法将其锁定到启动gsettings