Интеграция своих приложений с Unity Launcher

/www/pages/modesco/ubuntovod

Приветствую всех!

Уже достаточно давно появилась разработка небезызвестной компании Canonical — Unity. Вызвала она крайне неоднозначные эмоции у всех пользователей. Но разработчики ПО нашли ее интересной и стараются интегрировать свои приложения в Unity, а Unity в свои приложения. Не будем же отставать и мы. 
Я хотел бы поговорить с вами об одной из интереснейших возможностей Unity — Unity Launcher. Эта панель, которую мы можем наблюдать в левой части экрана. Но панель это не простая, мы можем интегрировать в нее приложения, а именно можем выводить следующую информацию: шкалу, отображающую какой-либо процесс, количество чего-либо и можем привлекать внимание пользователей.
Я постараюсь подробно описать API и показать примеры на C/C++ и Python.

Приступим к делу.
Для начала создаем нашу экспериментальную площадку. Для этого сначала создаем файл UnityTest.cpp, в котором будет наш исходный код.
Теперь установим необходимый пакет — libunity-dev (sudo apt-get install libunity-dev).
Можно приступать к разработке.
За иконку в Unity Launcher отвечает тип данных UnityLauncherEntry. Увы, насколько мне известно, нету метода, с помощь которого можно было бы получить текущую иконку в Launcher. Иконка получается по названию файла запуска. Для меня это показалось несколько необычным, непривычным, но позже я понял, что ничего сверхъестественного в этом нет. Основной метод для получения иконки:

1
UnityLauncherEntry* unity_launcher_entry_get_for_desktop_id (const gchar* desktop_id)

Где desktop_id — название файла запуска.

Примечание:
Опытным путем было установлено, что если иконки текущего приложения нету, не существует, то при запуске приложения она будет временно создана с именем: «Имя_приложения.desktop» (если ошибаюсь, то прошу поправить). Я советую самому создавать данную кнопку запуска, причем давать имя файлу по правилу, описанному ранее («Имя_приложения.desktop»).

Следующие методы нужны для работы с шкалой, которая будет отображена поверх иконки в Launcher:

1
2
3
4
void unity_launcher_entry_set_progress (UnityLauncherEntry* self, gdouble value)
void unity_launcher_entry_set_progress_visible (UnityLauncherEntry* self, gboolean value)
gdouble unity_launcher_entry_get_progress (UnityLauncherEntry* self)
gboolean unity_launcher_entry_get_progress_visible (UnityLauncherEntry* self)

Где self — ранее полученная иконка.
В первом методе value может принимать значение от 0 до 1, которое показывает количество процентов на шкале.
Во втором методе value может принимать значения true и false, которые показывают, отображена ли сейчас шкала.
Третий и четвертый методы действуют обратно первому и второму, то есть получают значения.

Следующие методы нужны для работы с количеством чего-либо на нашей иконке:

1
2
3
4
void unity_launcher_entry_set_count (UnityLauncherEntry* self, gint64 value);
gint64 unity_launcher_entry_get_count (UnityLauncherEntry* self);
gboolean unity_launcher_entry_get_count_visible (UnityLauncherEntry* self);
void unity_launcher_entry_set_count_visible (UnityLauncherEntry* self, gboolean value);

Где self — ранее полученная иконка.
В первом методе value может принимать любое численное значение, которое будет отображено поверх иконки.
Второй метод действует обратно первому.
Третий и четвертый методы работают сходно аналогичным методам для работы со шкалой.

Следующие два метода служат для привлечения внимания пользователя:

1
2
void unity_launcher_entry_set_urgent (UnityLauncherEntry* self, gboolean value);
gboolean unity_launcher_entry_get_urgent (UnityLauncherEntry* self);

Где self — ранее полученная иконка.
value — статус приложения. True — активный режим для назойливого привлечения внимания пользователя, False — обычный режим.

Два последних метода служат для подключения своего меню к иконке:

1
2
void unity_launcher_entry_set_quicklist (UnityLauncherEntry* self, DbusmenuMenuitem* value)
DbusmenuMenuitem* unity_launcher_entry_get_quicklist (UnityLauncherEntry* self)

А теперь пример с подробными комментариями, который нужно скопировать в файл UnityTest.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//Подключаем заголовок unity
#include <unity.h>
//Подключаем заголовок dbusmenu. Нужно для создания своего меню.
#include <libdbusmenu-glib/dbusmenu-glib.h>
//Если не нужно GTK+, то можно использовать простой glib
//#include <glib.h>
//Подключаем GTK+
#include <gtk/gtk.h>
 
//Наша иконка
UnityLauncherEntry* launcher;
 
//Данный метод будет вызываться при клике на одну единственную кнопку в нашем окне
int onclick(GtkWidget* widget, gpointer data)
{
	//Меняем статус приложения на противоположный
	unity_launcher_entry_set_urgent(launcher, !unity_launcher_entry_get_urgent(launcher));
	//unity_launcher_entry_set_urgent(UNITY_LAUNCHER_ENTRY(data), !unity_launcher_entry_get_urgent(UNITY_LAUNCHER_ENTRY(data)));
}
//Данный метод будет вызываться при фокусе окна
int onfocus(GtkWidget* widget, gpointer data)
{
	//При фокусе окна делаем статус приложения обычным
	unity_launcher_entry_set_urgent(launcher, false);
	//unity_launcher_entry_set_urgent(UNITY_LAUNCHER_ENTRY(data), false);
}
 
int main(int argc, char *argv[])
{
	//Инициализируем GTK+
	gtk_init(&amp;argc, &amp;argv); //g_type_init();
	//Создаем наше окно
	GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	//Ставим заголовок
	gtk_window_set_title(GTK_WINDOW(window), "Unity Test");
	//Колбек на завершение приложения
	g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
	//Ищем нашу иконку
	launcher = unity_launcher_entry_get_for_desktop_id("UnityTest.desktop");
	//Рисуем шкалу в 50 процентов
	unity_launcher_entry_set_progress_visible(launcher, true);
	unity_launcher_entry_set_progress(launcher, 0.5);
	//Ставим количество чего-нибудь в 50
	unity_launcher_entry_set_count_visible(launcher, true);
	unity_launcher_entry_set_count(launcher, 50);
	//Создаем главное меню. Оно не будет отображено, нужно лишь как связывающее звено между другими пунктами меню
	DbusmenuMenuitem* menu = dbusmenu_menuitem_new();
	//Данные пункты будут отображены в меню
	DbusmenuMenuitem* menu1 = dbusmenu_menuitem_new();
	dbusmenu_menuitem_property_set(menu1, "label", "test1");
	DbusmenuMenuitem* menu2 = dbusmenu_menuitem_new();
	dbusmenu_menuitem_property_set(menu2, "label", "test2");
	//Подключаем их к главному меню
	dbusmenu_menuitem_child_append(menu, menu1);
	dbusmenu_menuitem_child_append(menu, menu2);
	//При клике на пункты меню мы будем менять статус приложения
	g_signal_connect(menu1, "item_activated", G_CALLBACK(onclick), launcher);
	g_signal_connect(menu2, "item_activated", G_CALLBACK(onclick), launcher);
	//Приклеиваем наше меню к меню иконки
	unity_launcher_entry_set_quicklist(launcher, menu);
	//Создать кнопку, при нажатии на которую будем менять статус нашего приложения
	GtkWidget* button = gtk_button_new_with_label("Привлечь внимание!");
	gtk_container_add(GTK_CONTAINER(window), button);
	g_signal_connect(button, "clicked", G_CALLBACK(onclick), launcher);
	//Ставим колбек на фокус окна
	g_signal_connect(window, "focus-in-event", G_CALLBACK(onfocus), NULL);
	//Показываем наше окно
	gtk_widget_show_all(window);
	//Запускаем главный цикл
	gtk_main();
	/*GMainLoop* loop = g_main_loop_new(NULL, false);
	g_main_loop_run(loop);*/
}

Собрать можно следующей командой:
g++ `pkg-config unity gtk+-2.0 dbusmenu-glib-0.4 --cflags --libs` UnityTest.cpp -o UnityTest

Также имеется возможность использовать интеграцию с Unity Launcher в Python-приложениях. Вот небольшой пример, который добавляет несколько пунктов меню в иконку Chromium:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from gi.repository import Unity, GObject, Dbusmenu
 
launcher = Unity.LauncherEntry.get_for_desktop_id("chromium-browser.desktop")
 
launcher.set_property("count_visible", True)
launcher.set_property("count", 50)
 
launcher.set_property("progress_visible", True)
launcher.set_property("progress", 0.5)
 
menu = Dbusmenu.Menuitem.new()
menu1 = Dbusmenu.Menuitem.new()
menu1.property_set("label", "Test1")
menu2 = Dbusmenu.Menuitem.new()
menu2.property_set("label", "Test2")
menu.child_append(menu1)
menu.child_append(menu2)
launcher.set_property("quicklist", menu)
 
GObject.MainLoop().run()

Пробуем, адаптируем, развиваем!

Источник: habrahabr.ru.

У вас болят зубы? Или вообще выпадывают? Сожалею, но тогда вам срочно нужна Имплантация зубов. Эти и другие услуги есть на сайте implantolog.net.