2020-10-13 開發(fā)文件管理器插件

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ù)措施,僅供參考。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容