На рабочем столе Unity, когда я запускаю приложение GUI, его значок появляется в панели запуска (если он еще не существует).
Теперь, когда я нажимаю правой кнопкой мыши этот значок, я либо получаю вариант Lock to Launcher или Unlock from Launcher, в зависимости от того, было ли приложение уже заблокировано для запуска или нет.
Мой вопрос: что происходит под капотом, когда я нажимаю один из этих двух вариантов, если Нет .desktop файл существует?
Может ли он автоматически создавать простые файлы .desktop, если он не может найти его, при каких условиях это может произойти, и где сохраняются сохраненные элементы пусковой установки?
Что происходит, когда вы нажимаете Lock To Launcher, это означает, что Unity изменит конкретную схему dconf для избранных Launcher и вызовет пару методов dbus. Ключом для программистов и разработчиков приложений является изменение схемы dconf. (Ответ Джейкоба полагается на gsettings, однако идея по существу такая же, как и gsettings - это просто передняя часть с проверкой работоспособности для dconf). Здесь я просто хочу представить несколько сделанных замечаний.
Боковое замечание: здесь я тестирую все с помощью специального приложения python, у которого нет файла .desktop
Запуск 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 для приложения. Если файл существует - хорошо. Если нет - Unity выдает dbus вызов метода org.ayatana.bamf.control.CreateLocalDesktopFile в службе org.ayatana.bamf. Это можно использовать для автоматизации создания файла .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 --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 записывает добавленную запись. Я проверил это несколько раз, и это те же самые действия, которые выполняются в каждом случае.
Пример формы вывода 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 [
]
}
]
Конкретный код, который обрабатывается, который определен в launcher/ApplicationLauncherIcon.cpp исходного кода Unity
/* (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, и конкретное поведение пусковой установки могут помочь нам расширить ее функциональность. Примеры этого из меня и Якоба включают:
Настройка Launcher из входного файла Переупорядочение, чтобы сделать активный верхний или нижний элемент приложения Cloning launcher от пользователя к пользователю Создание уникальной пусковой установки на рабочее пространствоОсобая полезность метода dbus для создания файлов .desktop позволяет автоматизировать создание ярлыков для специально написанных приложений, которые позже могут быть заблокированы для запуска с использованием метода gsettings, описанного Джейкобом.