С выходом Ubuntu 11.04 оболочка Unity достаточно неожиданно заняла место оболочки по умолчанию. Появление Unity в Ubuntu Netbook Edition, несмотря на медленную скорость работы, было довольно обоснованным: оно позволило эффективно использовать маленькие экраны нетбуков, благодаря, например, вертикальной панели для переключения между запущенными программами. Почему же возникла необходимость переноса Unity на десктопы? Ответить на этот вопрос можно было бы уже сейчас. Однако такой неполный, без готовых примеров, субъективный ответ вряд ли бы удовлетворил пользователя, которому на данный момент пришлось столкнуться с неудобством перехода. Поэтому речь пойдёт о том, как улучшить, а не о том, как и зачем пережить.
Статья ориентирована на разработчиков программного обеспечения для Linux, а также для желающих начать разработку расширений для Firefox. Пользователям же предлагается пройти по ссылке за готовым расширением.
Итак, что нам понадобится:
Собственно, для такого простого расширения хватит. Возможно вам также пригодится расширение Extension Developer.
Теперь нужно создать структуру нашего расширения:
Наше расширение не использует локализацию или настройки, поэтому стандартные директории locale и preferences нам не пригодятся.
Начинается всё с файла install.rdf. В нём принято описывать краткую информацию о расширении: название, описание, версию, авторов, уникальный идентификатор расширения и набор поддерживаемых приложений (одно и то же расширение может работать, например, в Seamonkey и Firefox):
Структура файла должна быть понятна без объяснений. Маленькое уточнение: <em:type>2</em:type> показывает, что этот файл является именно расширением, а не темой оформления, например. {ec8030f7-c20a-464f-9b0e-13a3a9e97384} — код браузера Firefox. Нижний предел версии 4.0 обусловлен тем, что мы будем использовать функции js-ctypes для обмена сообщениями с библиотекой Unity.
Завершив написание install.rdf, можно приступить непосредственно к созданию рабочего кода. Для того, чтобы при создании окна выполнялся наш javascript-код из файла main.xul, нужно описать в файле chrome.manifest процедуру наложения (overlay):
Тут стоит остановиться и вспомнить задачу, которую мы решаем. Наша цель — отобразить полосу загрузки и число активных загрузок в панели Unity. К счастью, Unity предоставляет специальный API для этого. Из этого API нам понадобятся функции:
Расширение готово. Теперь файлы из директории unityfox можно упаковать в zip-архив, изменить расширение файла на .xpi и установить перетаскиванием на окно браузера.
Готовое расширение и список ингредиентов можно найти по адресу addons.mozilla.org/ru/firefox/addon/unityfox. Приятного аппетита!
Текст этой статьи распространяется на условиях лицензии CC BY-SA 3.0
Статья ориентирована на разработчиков программного обеспечения для Linux, а также для желающих начать разработку расширений для Firefox. Пользователям же предлагается пройти по ссылке за готовым расширением.
Итак, что нам понадобится:
- Расширение Restartless Restart. В процессе разработки понадобится часто перезагружать браузер для тестирования расширения
- Архиватор, позволяющий редактировать файлы прямо в архиве, без ручной перепаковки. С этим справляется стандартный архиватор в Ubuntu File-Roller
- Текстовый редактор
Собственно, для такого простого расширения хватит. Возможно вам также пригодится расширение Extension Developer.
Теперь нужно создать структуру нашего расширения:
unityfox -- chrome ---- content ------main.xul -- chrome.manifest -- install.rdf
Наше расширение не использует локализацию или настройки, поэтому стандартные директории locale и preferences нам не пригодятся.
Начинается всё с файла install.rdf. В нём принято описывать краткую информацию о расширении: название, описание, версию, авторов, уникальный идентификатор расширения и набор поддерживаемых приложений (одно и то же расширение может работать, например, в Seamonkey и Firefox):
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>unityfox@mozilla.org</em:id>
<em:version>0.1.3</em:version>
<em:type>2</em:type>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>4.0</em:minVersion>
<em:maxVersion>6.0a1</em:maxVersion>
</Description>
</em:targetApplication>
<em:name>unityfox</em:name>
<em:description>Integration with Ubuntu Unity panel</em:description>
<em:creator>Lockal</em:creator>
</Description>
</RDF>
Структура файла должна быть понятна без объяснений. Маленькое уточнение: <em:type>2</em:type> показывает, что этот файл является именно расширением, а не темой оформления, например. {ec8030f7-c20a-464f-9b0e-13a3a9e97384} — код браузера Firefox. Нижний предел версии 4.0 обусловлен тем, что мы будем использовать функции js-ctypes для обмена сообщениями с библиотекой Unity.
Завершив написание install.rdf, можно приступить непосредственно к созданию рабочего кода. Для того, чтобы при создании окна выполнялся наш javascript-код из файла main.xul, нужно описать в файле chrome.manifest процедуру наложения (overlay):
Это говорит браузеру загружать наш файл main.xul вместе с интерфейсом браузера browser.xul.content unityfox chrome/content/ overlay chrome://browser/content/browser.xul chrome://unityfox/content/main.xul
Тут стоит остановиться и вспомнить задачу, которую мы решаем. Наша цель — отобразить полосу загрузки и число активных загрузок в панели Unity. К счастью, Unity предоставляет специальный API для этого. Из этого API нам понадобятся функции:
- UnityLauncherEntry *unity_launcher_entry_get_for_desktop_id (char *id);
- void unity_launcher_entry_set_count (UnityLauncherEntry *self, gint64 count);
- void unity_launcher_entry_set_count_visible (UnityLauncherEntry *self, gboolean visible);
- void unity_launcher_entry_set_progress (UnityLauncherEntry *self, gdouble progress);
- void unity_launcher_entry_set_progress_visible (UnityLauncherEntry *self, gboolean visible);
<?xml version="1.0"?>
<overlay id="unityfox"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript">
// В расширениях Firefox принято осторожно относиться к глобальной области в xul
if ("undefined" == typeof(unityProgress)) {
var unityProgress = {
setup: function() {
// Загрузим модуль ctypes для обращения к системным библиотекам
Components.utils.import("resource://gre/modules/ctypes.jsm");
// Выполним загрузку библиотеки libunity.so.4
// Нам не нужно, чтобы расширение генерировало ошибки при отсутствии libunity
try {
this.libunity = ctypes.open("libunity.so.4");
} catch(err) { return; }
// Опишем нужные функции libunity
this.getEntry = this.libunity.declare("unity_launcher_entry_get_for_desktop_id",
ctypes.default_abi,
ctypes.voidptr_t,
ctypes.char.ptr);
this.setProgress = this.libunity.declare("unity_launcher_entry_set_progress",
ctypes.default_abi,
ctypes.void_t,
ctypes.voidptr_t,
ctypes.double);
this.setVisibilityP = this.libunity.declare("unity_launcher_entry_set_progress_visible",
ctypes.default_abi,
ctypes.void_t,
ctypes.voidptr_t,
ctypes.int);
this.setVisibilityN = this.libunity.declare("unity_launcher_entry_set_count_visible",
ctypes.default_abi,
ctypes.void_t,
ctypes.voidptr_t,
ctypes.int);
this.setCount = this.libunity.declare("unity_launcher_entry_set_count",
ctypes.default_abi,
ctypes.void_t,
ctypes.voidptr_t,
ctypes.long);
// все основные функции библиотеки libunity работают с UnityLauncherEntry*
this.entry = this.getEntry("firefox.desktop");
this.Cc = Components.classes;
this.Ci = Components.interfaces;
this.IDLM = this.Ci.nsIDownloadManager;
// Обновление панели будет происходить с помощью сервиса download-manager
// Интерфейсы всех встроенных сервисов описаны на https://developer.mozilla.org
this.dlMgr = this.Cc["@mozilla.org/download-manager;1"].getService(this.IDLM);
this.dlMgr.addListener(this);
},
// Функция update вызывается на каждом событии от download-manager
update: function() {
var total = 0, cur = 0, count = 0;
var dls = this.dlMgr.activeDownloads;
while (dls.hasMoreElements()) {
var dl = dls.getNext().QueryInterface(this.Ci.nsIDownload);
// Пропускаем неактивные загрузки и загрузки, время окончания которых неизвестно
if (dl.state != this.IDLM.DOWNLOAD_DOWNLOADING || dl.percentComplete == -1)
continue;
// Считаем общий размер, загруженный размер и число загрузок
total += dl.size;
cur += dl.amountTransferred;
count++;
}
if (total == 0) {
// Если нет загрузок, скрываем счётчик и полосу на панели
this.setVisibilityP(this.entry, 0);
this.setVisibilityN(this.entry, 0);
} else {
// Показываем ход загрузки (от 0 до 1) и число загрузок
this.setProgress(this.entry, cur / total);
this.setCount(this.entry, count);
this.setVisibilityP(this.entry, 1);
this.setVisibilityN(this.entry, 1);
}
},
// Этот объект является nsIDownloadProgressListener по совместительству.
// nsIDownloadManager будет отсылать сообщения нижеописанным функциям
onDownloadStateChange: function() { this.update() },
onStateChange: function() { this.update() },
onProgressChange: function() { this.update() },
onSecurityChange: function() { this.update() }
};
}
// Наконец, инициализируем unityProgress через т. н. анонимное пространство имён
(function() {this.setup();}).apply(unityProgress);
</script>
</overlay>
Расширение готово. Теперь файлы из директории unityfox можно упаковать в zip-архив, изменить расширение файла на .xpi и установить перетаскиванием на окно браузера.
Готовое расширение и список ингредиентов можно найти по адресу addons.mozilla.org/ru/firefox/addon/unityfox. Приятного аппетита!
Текст этой статьи распространяется на условиях лицензии CC BY-SA 3.0