当我在 Unity 中单击“锁定到启动器”时内部会发生什么?

当我在 Unity 中单击“锁定到启动器”时内部会发生什么?

在 Unity 桌面中,当我启动 GUI 应用程序时,它的图标就会出现在启动器中(如果它还不存在)。

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

我的问题是:
如果不存在文件,当我单击这两个选项之一时,会发生什么情况.desktop

.desktop如果找不到简单文件,它能自动创建吗?在什么情况下会发生这种情况?固定的启动器项保存在哪里?

答案1

如果你将应用程序锁定/解锁到启动器会发生什么情况

不确定这个答案是否足够深刻,但这是发生的事情:

您可以通过以下命令获取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 应用程序时,右键单击启动器中的图标并选择Lock to Launcher,当前选定的项目将添加到列表中,而Unlock from Launcher将从列表中删除该项目。

通过编程方式编辑 Unity Launcher

重新阅读你问题下面的(第一条)评论:正如提到的那样,你可以得到使用以下命令删除当前启动器项目:

 gsettings get com.canonical.Unity.Launcher favorites

以下命令可能改变的列表:

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

当然,您也可以通过编程方式编辑 Unity Launcher 的内容,就像这样做一样这里

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

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

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

X-UnityGenerated=true

笔记

正如 @muru (谢谢!) 所述,在少数情况下 (似乎是例外),Unity 无法成功创建可执行文件的“缺失”文件。然而,我能找到的唯一示例是 Tkinter 窗口的情况,它在 的输出中.desktop归 拥有。pid 0wmctrl -lp

答案2

单击Lock To Launcher选项时,Unity 将更改dconf启动器收藏夹的特定架构并调用几个dbus方法。对于程序员和应用程序开发人员来说,关键是架构的变化dconf。(Jacob 的回答依赖于,但这个想法本质上与只是带有健全性检查的前端gsettings相同)。在这里,我只想提出一些观察结果。gsettingsdconf

附注:在这里,我使用没有.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 将发出对服务方法dbus的调用。这可用于自动创建文件。虽然这不会显示在输出中,但我相信这是 Unity 可能使用的方法之一。org.ayatana.bamf.control.CreateLocalDesktopFileorg.ayatana.bamf.desktopdbus-monitor

这是一个小演示:

# 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 启示

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

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 记录添加的条目。我已经测试了几次,每次执行的操作都相同。

Zeitgeist 的示例输出。

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 源代码:

launcher/ApplicationLauncherIcon.cppUnity 源代码中定义了处理该问题的具体代码

/* (Un)Stick to Launcher */
  glib::Object<DbusmenuMenuitem> 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和具体行为可以帮助我们扩展其功能。我和 Jacob 举的例子包括:

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

相关内容