Nemo 插件開發(fā)機(jī)制
這篇文檔介紹文件管理器三種插件開發(fā)機(jī)制,并提供對應(yīng)的簡單示例。
插件分類
右鍵菜單
我們右鍵某個文件,彈出的菜單項(xiàng)有 nemo 自定義的也有插件開發(fā)的。比如文件共享、文件壓縮的功能都是通過插件機(jī)制嵌入到文件管理器的菜單。
這類插件最重要的接口就是 NemoMenuProviderIface,必須實(shí)現(xiàn)這個接口的 iface->get_file_items 函數(shù)。函數(shù)定義:
static GList *sendto_extension_get_file_items (NemoMenuProvider *provider,
GtkWidget *window,
GList *files)
其中 files 列表就是選擇的文件清單,可以只選中一個文件,也可以多個。列表成員 NemoFileInfo,許多工作都是圍繞這個文件清單來做的。
主要工作:創(chuàng)建右鍵菜單項(xiàng) nemo_menu_item_new,這個菜單可能需要子菜單,比如示例 test-sendto 是一個右鍵發(fā)送到可移動設(shè)備的原型程序,所以需要把系統(tǒng)中的可移動設(shè)備列表放在子菜單中。nemo_menu_new 創(chuàng)建子菜單,nemo_menu_item_set_submenu 把它添加到菜單項(xiàng)。
文件屬性頁
右鍵文件,在菜單中選擇屬性,彈出屬性窗口,默認(rèn)有三個tab頁,“基本”,“權(quán)限”,“打開方式”,在這三個之外,我們也可以根據(jù)文件類型、內(nèi)容的不同自定義屬性頁。
這類插件最重要的接口是 NemoPropertyPageProviderIface,必須實(shí)現(xiàn)這個接口的 iface->get_pages 函數(shù),函數(shù)定義:
static GList *
get_property_pages (NemoPropertyPageProvider *provider,
GList *files)
這里的 files 文件也是我們選中的文件清單,列表成員類型NemoFileInfo,比如示例中對于所有 mimetype 是文本文件類型的都新增屬性頁“Text File”,就是通過檢查這個文件的 nemo_file_info_get_mime_type 來做的。
主要工作:調(diào)用 nemo_property_page_new 創(chuàng)建屬性頁。屬性頁是個 Gtk 控件,所以具體內(nèi)容就是使用 gtk 創(chuàng)建就可以了。
詳細(xì)信息列
這個插件與上面兩個略有不同,上面那兩個都是選擇若干文件后右鍵觸發(fā)的,所以都能拿到一個文件清單列表,這個列表里就是一個個 NemoFileInfo,我們可以對這些文件做處理。但是這個插件比較不一樣,沒有選擇的文件。我們打開某個目錄,在列表視圖下所有文件都會新增一列,比如我們示例的文本類型都會增加一個“test column”的屬性,其他文件類型沒有新增屬性這列就為空。
這個插件除了要實(shí)現(xiàn) NemoColumnProviderIface 接口,還得實(shí)現(xiàn) NemoInfoProviderIface 接口,這個接口就可以幫助我們拿到所有文件的信息,根據(jù)自己的需要來設(shè)置文件屬性。
代碼示例
每個插件都需要實(shí)現(xiàn)幾個固定的接口,編譯生成動態(tài)鏈接庫,安裝到 nemo 的 extensions 目錄,這樣 nemo 啟動時才能找到他們。
1、插件加載等接口
/* Extension initialization */
void nemo_module_initialize (GTypeModule *module)
{
sendto_extension_register_type(module);
provider_types[0] = sendto_extension_get_type();
}
void nemo_module_shutdown(void)
{
/* Any module-specific shutdown */
}
void nemo_module_list_types (const GType **types, int *num_types)
{
*types = provider_types;
*num_types = G_N_ELEMENTS (provider_types);
}
2、接口實(shí)現(xiàn): 以屬性頁為例
/* 我們這個插件實(shí)現(xiàn)了什么接口就在這個函數(shù)中注冊
* 這里只實(shí)現(xiàn)了屬性頁,所以只有一個 interface
*/
static void
nemo_txt_properties_page_register_type (GTypeModule *module)
{
GType nemo_txt_type = nemo_txt_properties_page_get_type ();
static const GInterfaceInfo property_page_provider_iface_info = {
(GInterfaceInitFunc) property_page_provider_iface_init,
NULL,
NULL
};
g_type_module_add_interface (module,
nemo_txt_type,
NEMO_TYPE_PROPERTY_PAGE_PROVIDER,
&property_page_provider_iface_info);
}
右鍵菜單
按照上面介紹的,右鍵菜單最重要的接口就是 get_file_items,在接口注冊中添加接口 sendto_extension_menu_provider_iface_init,接口中定義我們要實(shí)現(xiàn)的函數(shù):
iface->get_file_items = sendto_extension_get_file_items;
函數(shù)實(shí)現(xiàn):
/* 右鍵菜單實(shí)現(xiàn)最重要的就是這個函數(shù) */
static GList *sendto_extension_get_file_items (NemoMenuProvider *provider,
GtkWidget *window,
GList *files)
{
GList *items, *iterate;
NemoMenuItem *separator;
NemoMenuItem *item;
show_menu = TRUE;
gchar *uri = NULL;
GFile *object = NULL;
if (!files) {
return NULL;
}
/* 這個 files 就是我們右鍵時選中的文件清單,可以單個也可以多個 */
iterate = files;
while (iterate != NULL) {
NemoFileInfo *file = iterate->data;
uri = nemo_file_info_get_uri (file);
object = g_file_new_for_uri (uri);
gchar *path = g_file_get_path (object);
if (path == NULL) // show_menu 用來控制是否顯示自定義的菜單,這個例子中不存在可移動設(shè)備就不用顯示。
{
show_menu = FALSE;
} else {
g_free (path);
}
g_free (uri);
iterate = iterate->next;
}
item = nemo_menu_item_new ("SendtoExtension::SendtoData",
"NFS Sendto",
"Sendto Data",
"Sendto Description");
g_object_set (G_OBJECT(item), "sensitive", FALSE, NULL);
NemoMenu *sendtoMenu = nemo_menu_new();
nemo_menu_item_set_submenu(item, sendtoMenu);
create_sendto_target (sendtoMenu, files, item);
separator = nemo_menu_item_new_separator ("Sendto Separator");
items = g_list_append (NULL, separator);
items = g_list_append(items, item);
return items;
}
文件屬性頁
屬性頁最重要的接口是 get_pages,接口注冊函數(shù)中定義我們的實(shí)現(xiàn)函數(shù)
static void
property_page_provider_iface_init (NemoPropertyPageProviderIface *iface)
{
iface->get_pages = get_property_pages;
}
函數(shù)實(shí)現(xiàn):
/* 這個函數(shù)最重要,nemo 加載屬性頁時就會調(diào)用這里 */
static GList *
get_property_pages (NemoPropertyPageProvider *provider,
GList *files)
{
GList *pages;
NemoFileInfo *file;
char *mime_type;
/* Only show the property page if 1 file is selected */
if (!files || files->next != NULL) {
return NULL;
}
pages = NULL;
file = NEMO_FILE_INFO (files->data);
mime_type = nemo_file_info_get_mime_type (file);
g_print ("%s %d: mime type %s\n", __func__, __LINE__, mime_type);
if (mime_type != NULL && is_mime_type_supported (mime_type)) {
NemoTxtPropertiesPage *page;
NemoPropertyPage *real_page;
page = g_object_new (nemo_txt_properties_page_get_type (), NULL);
load_location (page, file);
real_page = nemo_property_page_new ("NemoTxtPropertiesPage::property_page",
gtk_label_new (_("Text File")),
GTK_WIDGET (page));
pages = g_list_append (pages, real_page);
}
g_free (mime_type);
return pages;
}
詳細(xì)信息列
這個插件最特殊的就是需要修改文件信息,因?yàn)槲覀円ㄖ莆募行畔?,為了?shí)現(xiàn)這個功能,必須修改文件屬性。這個插件的注冊接口:
static void
nemo_txt_column_register_type (GTypeModule *module)
{
GType nemo_txt_type = nemo_txt_column_get_type ();
static const GInterfaceInfo column_provider_iface_info = {
(GInterfaceInitFunc) nemo_txt_column_provider_iface_init,
NULL,
NULL
};
static const GInterfaceInfo info_provider_iface_info = {
(GInterfaceInitFunc) nemo_txt_info_provider_iface_init,
NULL,
NULL
};
g_type_module_add_interface (module,
nemo_txt_type,
NEMO_TYPE_COLUMN_PROVIDER,
&column_provider_iface_info);
g_type_module_add_interface (module,
nemo_txt_type,
NEMO_TYPE_INFO_PROVIDER,
&info_provider_iface_info);
}
首先介紹 column provider,這個很簡單,我們需要實(shí)現(xiàn) get_columns接口,想增加幾列就在這個函數(shù)中調(diào)用 nemo_column_new 新建列,比較重要的是有個屬性信息,比如例子中自定義 title 屬性,我們在 info provider 中需要用到。
NemoInfoProviderIface 的定義如下:
static void
nemo_txt_info_provider_iface_init (NemoInfoProviderIface *iface) {
iface->update_file_info = nemo_txt_update_file_info;
return;
}
在這個函數(shù)中,我們?yōu)榱朔奖阒皇呛唵蔚呐袛嗳绻俏谋疚募?,就設(shè)置屬性 title 的值為 “test column”
/* Info interfaces */
static NemoOperationResult
nemo_txt_update_file_info (NemoInfoProvider *provider,
NemoFileInfo *file,
GClosure *update_complete,
NemoOperationHandle **handle)
{
char *mime_type;
g_print ("%s %d\n", __func__, __LINE__);
mime_type = nemo_file_info_get_mime_type (file);
g_print ("%s %d: mime type %s\n", __func__, __LINE__, mime_type);
if (mime_type != NULL && is_mime_type_supported (mime_type)) {
nemo_file_info_add_string_attribute (file,
"title", // 對應(yīng)上面的 title
"test column");
}
return NEMO_OPERATION_IN_PROGRESS;
}
插件驗(yàn)證
這三個示例程序,分別編譯成動態(tài)鏈接庫文件,安裝到插件目錄 /usr/lib/x86_64-linux-gnu/nemo/extensions-3.0/,重啟 nemo。
1、如果外接了U盤,右鍵某個文件,就會出現(xiàn) NFS Sendto 菜單,hover 上去出現(xiàn) U 盤子菜單,點(diǎn)擊子菜單觸發(fā)信號,示例程序彈一個 gtk 對話框。
2、如果選擇某個文本文件,右鍵屬性,在屬性頁會新增一個文本文件頁,顯示“文本類型” 和 “File uri” 這兩條信息.
3、進(jìn)入某個空文件目錄,選擇詳細(xì)信息,新建一個文件文檔。右鍵在頂部列表欄中選擇我們自定義的 “Title”,就能看到測試值 “test column”
注意:
測試代碼,沒有任何保護(hù)措施,僅供參考。