Как создать расширения наутилуса С - PullRequest
10 голосов
/ 13 марта 2012

Я пытаюсь создать расширение Nautilus в C, но есть только примеры и справки по Python.

Почти нет документации и буквально нет примеров, а есть только полные расширения, которые длинные и трудные для пониманиядля начинающего.

Мне нужен простой пример кода, который создает новый столбец в представлении списка Наутилуса.Как написать и скомпилировать его.

Код, который я пробовал:

#include <libnautilus-extension/nautilus-column-provider.h>

typedef struct _FooExtension FooExtension;
typedef struct _FooExtensionClass FooExtensionClass;

struct _FooExtension
{
    GObject parent_slot;
};

struct _FooExtensionClass
{
    GObjectClass parent_slot;
};

static void foo_extension_class_init    (FooExtensionClass *class);
static void foo_extension_instance_init (FooExtension      *img);

static void foo_extension_class_init(FooExtensionClass *class)
{
}

static void foo_extension_instance_init(FooExtension *img)
{
}

static GType provider_types[1];

static GType foo_extension_type;

static void foo_extension_register_type(GTypeModule *module)
{
    static const GTypeInfo info = {
                sizeof(FooExtensionClass),
                (GBaseInitFunc) NULL,
                (GBaseFinalizeFunc) NULL,
                (GClassInitFunc) foo_extension_class_init,
                NULL,
                NULL,
                sizeof (FooExtension),
                0,
                (GInstanceInitFunc) foo_extension_instance_init,
                };
    foo_extension_type = g_type_module_register_type(module,
                              G_TYPE_OBJECT,
                              "FooExtension",
                              &info, 0);
        /* ... add interfaces ... */
}

GType foo_extension_get_type(void)
{
    return foo_extension_type;
}

static GList *foo_extension_get_columns(NautilusColumnProvider *provider)
{
    NautilusColumn *column;
    GList *ret;
    column = nautilus_column_new("FooExtension::foo_data_column", "FooExtension::foo_data", "Foo Data", "Foo Description");
/*                    _("Foo Data"),
                      _("Information from the Foo Extension"));*/
    ret = g_list_append(NULL, column);
    return ret;
}

void nautilus_module_initialize (GTypeModule  *module)
{
    foo_extension_register_type(module);
    provider_types[0] = foo_extension_get_type();
}

void nautilus_module_shutdown(void)
{
    /* Any module-specific shutdown */
}

void nautilus_module_list_types (const GType **types, int *num_types)
{
    *types = provider_types;
    *num_types = G_N_ELEMENTS (provider_types);
}

, и я построил его с помощью:

gcc-c foo_extension.c -o foo_extension.o -fPIC $(pkg-config libnautilus-extension --libs --cflags)
gcc -shared foo_extension.o -o foo_extension.so $(pkg-config libnautilus-extension --libs --cflags)

, и я скопировалэто в /usr/lib/nautilus/extensions-2.0/, затем я попытался nautilus -q, но это не работает.

1 Ответ

8 голосов
/ 04 мая 2012

Вы также можете получить документацию, указанную в вики Nautilus Extension из копии в archive.org .Копия в archive.org содержит примеры на языке C.

EDIT: Я добавил полный рабочий пример, а также объяснение отсутствующих частей в вашем коде.

Вам не хватает двух вещей:

  1. Добавьте интерфейсы.Для провайдера столбца будет foo_extension_column_provider_iface_init , и там вам нужно связать ссылку, ожидаемую интерфейсами с вашей реализацией.В этом конкретном случае get_columns .
  2. В предыдущем случае вы получите только столбец, но с неизвестным значением для каждого файла.Поэтому вам также необходимо использовать InfoProvider .В частности, интерфейс update_file_info .В этом интерфейсе вы можете связать атрибут для вашего столбца с каждым файлом через nautilus_file_info_add_string_attribute .

Ниже приведен рабочий пример.Осторожно NautilusFileInfoProvider является частью системы асинхронного ввода-вывода Nautilus.Следовательно, если операции выполняются медленно, вы заблокируете Nautilus.В приведенном ниже примере я просто установил фиксированную строку для файла (" Foo ").Однако, если вам нужно собрать другую информацию, вы должны также реализовать аргументы update_complete и handle и интерфейс cancel_update .Проверьте документацию , копию которой можно найти в archive.org

#include <libnautilus-extension/nautilus-column-provider.h>
#include <libnautilus-extension/nautilus-info-provider.h>

typedef struct _FooExtension FooExtension;
typedef struct _FooExtensionClass FooExtensionClass;

typedef struct {
    GClosure *update_complete;
    NautilusInfoProvider *provider;
    NautilusFileInfo *file;
    int operation_handle;
    gboolean cancelled;
} UpdateHandle;

struct _FooExtension
{
    GObject parent_slot;
};

struct _FooExtensionClass
{
    GObjectClass parent_slot;
};

static void foo_extension_class_init    (FooExtensionClass *class);
static void foo_extension_instance_init (FooExtension      *img);
static GList *foo_extension_get_columns (NautilusColumnProvider *provider);
static NautilusOperationResult foo_extension_update_file_info (
                                        NautilusInfoProvider *provider,
                                        NautilusFileInfo *file,
                                        GClosure *update_complete,
                                        NautilusOperationHandle **handle);

/* Interfaces */
static void
foo_extension_column_provider_iface_init (NautilusColumnProviderIface *iface) {
  iface->get_columns = foo_extension_get_columns;
  return;
}

static void
foo_extension_info_provider_iface_init (NautilusInfoProviderIface *iface) {
  iface->update_file_info = foo_extension_update_file_info;
  return;
}

/* Extension */
static void foo_extension_class_init(FooExtensionClass *class)
{
}

static void foo_extension_instance_init(FooExtension *img)
{
}

static GType provider_types[1];

static GType foo_extension_type;

static void foo_extension_register_type(GTypeModule *module)
{
    static const GTypeInfo info = {
                sizeof(FooExtensionClass),
                (GBaseInitFunc) NULL,
                (GBaseFinalizeFunc) NULL,
                (GClassInitFunc) foo_extension_class_init,
                NULL,
                NULL,
                sizeof (FooExtension),
                0,
                (GInstanceInitFunc) foo_extension_instance_init,
                };

    static const GInterfaceInfo column_provider_iface_info = {
        (GInterfaceInitFunc) foo_extension_column_provider_iface_init,
        NULL,
        NULL
    };

    static const GInterfaceInfo info_provider_iface_info = {
        (GInterfaceInitFunc) foo_extension_info_provider_iface_init,
        NULL,
        NULL
    };

    foo_extension_type = g_type_module_register_type(module,
                              G_TYPE_OBJECT,
                              "FooExtension",
                              &info, 0);

    /* ... add interfaces ... */
    g_type_module_add_interface (module,
                                 foo_extension_type,
                                 NAUTILUS_TYPE_COLUMN_PROVIDER,
                                 &column_provider_iface_info);

    g_type_module_add_interface (module,
                                 foo_extension_type,
                                 NAUTILUS_TYPE_INFO_PROVIDER,
                                 &info_provider_iface_info);
}

GType foo_extension_get_type(void)
{
    return foo_extension_type;
}

/* Column interfaces */
static GList *foo_extension_get_columns(NautilusColumnProvider *provider)
{
    NautilusColumn *column;
    GList *ret;
    column = nautilus_column_new ("FooExtension::foo_data_column",
                                  "FooExtension::foo_data",
                                  "Foo Data",
                                  "Foo Description");
    ret = g_list_append(NULL, column);

    return ret;
}

/* Info interfaces */
static NautilusOperationResult
foo_extension_update_file_info (NautilusInfoProvider *provider,
                                NautilusFileInfo *file,
                                GClosure *update_complete,
                                NautilusOperationHandle **handle)
{
    char *data;

    /* Check if we've previously cached the file info */
    data = g_object_get_data (G_OBJECT (file), "foo_extension_data");

    /* get and provide the information associated with the column.
       If the operation is not fast enough, we should use the arguments 
       update_complete and handle for asyncrhnous operation. */
    if (!data) {
        data = g_strdup ("Foo");
    }

    nautilus_file_info_add_string_attribute (file,
                             "FooExtension::foo_data",
                             data);
    return NAUTILUS_OPERATION_COMPLETE;
}

/* Extension initialization */
void nautilus_module_initialize (GTypeModule  *module)
{
    foo_extension_register_type(module);
    provider_types[0] = foo_extension_get_type();
}

void nautilus_module_shutdown(void)
{
    /* Any module-specific shutdown */
}

void nautilus_module_list_types (const GType **types, int *num_types)
{
    *types = provider_types;
    *num_types = G_N_ELEMENTS (provider_types);
}

Чтобы скомпилировать ее:

$ gcc -c foo-extension.c -o foo-extension.o -fPIC $(pkg-config libnautilus-extension --cflags)
$ gcc -shared foo-extension.o -o foo-extension.so $(pkg-config libnautilus-extension --libs)

Для тестирования расширения сначала необходимо остановить всезапустить экземпляр nautilus и перезапустить nautilus.То есть:

$ nautilus -q
$ nautilus 

Обратите внимание, что вы не используете опцию -q , которая используется для quit .

Если вы хотитечтобы проверить, загружает ли Nautilus ваше расширение, вы можете использовать strace следующим образом:

$ strace -e trace=open nautilus

и посмотреть, какие библиотеки и файлы Nautilus загружается / открывается.

Работая в своем расширении, вместо копирования файла расширения в [libdir] /nautilus/extensions-3.0, вы можете создать символическую ссылку на ваш рабочий каталог.Если вы используете Nautilus 2.x, используйте [libdir] /nautilus/extensions-2.0.

...