如何创建Nautilus C扩展

10

我正在尝试用C语言创建一个Nautilus扩展,但是只有一些Python示例和帮助。

几乎没有文档,实际上也没有范例,只有一些完整而且对初学者来说很难理解的扩展。

我需要一个简单的示例代码,它可以在Nautilus的列表视图中创建一个新列。如何编写和编译它。

我尝试过的代码是:

#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,但它不起作用。


这是代码:http://pastebin.com/gyCU2sti。我使用以下命令构建它: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”,但它没有起作用... - Stefano d'Antonio
1个回答

8
您还可以从Nautilus扩展的维基中获取文档,并从archive.org中的副本中获取。 archive.org中的副本使用C语言编写了示例。
编辑:我添加了一个完整的工作示例,以及对您的代码缺失部分的解释。
您需要添加两个接口:
1. 添加接口。对于列提供程序,应该是foo_extension_column_provider_iface_init,并在那里将期望的接口与您的实现关联起来。在这种特殊情况下,是get_columns。 2. 使用上一个接口,您只能获取每个文件的未知值的列。因此,您还必须使用InfoProvider。特别是,接口update_file_info。在该接口中,您可以通过nautilus_file_info_add_string_attribute将属性与每个文件的列相关联。
以下是一个工作示例。请注意,NautilusFileInfoProvider是Nautilus异步IO系统的一部分。因此,如果操作很慢,您将阻止Nautilus。在下面的示例中,我只为每个文件设置了一个固定字符串(“Foo”)。但是,如果您需要收集其他信息,则还应实现update_completehandle参数以及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的命令,该选项用于退出。
如果您想检查是否加载了您的扩展程序,可以按照以下方式使用strace
$ strace -e trace=open nautilus

查看Nautilus正在加载/打开的库和文件。

在扩展中工作时,不要将扩展文件复制到[libdir]/nautilus/extensions-3.0,而是可以创建到您的工作目录的符号链接。如果您正在使用Nautilus 2.x,则改用[libdir]/nautilus/extensions-2.0


第一个链接只有Python示例,第二个链接是我用来编写代码但没有成功的链接。nautilus-sendto不适用于ColumnView,仅适用于上下文菜单,因此即使我从中阅读代码学习,也可能是无用的。 - Stefano d'Antonio
你要求编写和编译。nautilus-sendto已经设置好了工具链,因此,你可以将其用作项目的模板。从你知道它能够工作并且可以检查的东西开始。一旦你设置好了这个,然后开始应用你的更改。 - gpoo
我会试着看一下,但即使是一个简单的插件,也可能太复杂了,无法快速反馈扩展,也没有用处。以前我已经尝试过另一个简单的项目,但为了我所需要的东西,阅读和理解起来太长了。 - Stefano d'Antonio
非常感谢,我会尽快尝试并告诉您! - Stefano d'Antonio
谢谢,你的示例很有效,稍后我会仔细查看代码和我的错误,但是你的回答中只有一个错误:如果你在nautilus已经运行时不使用-q选项调用它,它既不会重新加载自己也不会重新加载扩展,它只会打开你的主目录文件管理器。 - Stefano d'Antonio
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接