# Thunar Extensions Reference Manual

Version &version;
&date;
2005 Benedikt Meurer

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. The complete license text is available from the Free Software Foundation.

Benedikt Meurer

    benny@xfce.org

os-cillation System development Software developer

## Overview

The Thunar Extension Framework (thunarx) provides developers with an easy way to extend the basic functionality provided by the Thunar File Manager. The thunarx library includes interfaces that can be implemented by extensions for various purposes.

It is based on the GLib Dynamic Type System and loads the extensions on demand to reduce the system resources allocated for the file manager process.

### Goals

The Thunar Extension Framework was developed with the following goals in mind:

1. It should be easy to extend the functionality of the file manager in certain ways.
2. The internals of the file manager should be hidden from the extensions to be able to maintain API/ABI compatibility for extensions over various major releases of the file manager.
3. Provide basic compatibility with the Nautilus Extension Framework, so vendors don't need to write several versions of their extensions for the various file managers. With the current implementation it should be easy to write a small wrapper library for generic extensions that can be loaded into both Thunar and Nautilus.
4. Extensions should not be loaded into memory until they are actually required to save system resources. This differs from the way Nautilus handles extensions and therefore people that already know how to write Nautilus extensions must be careful when writing extensions for Thunar, because Thunar actually unloads the extension when it's no longer needed. The GTypePlugin and GTypeModule sections in the GObject Reference Manual provide details about the handling of dynamic type plugins.
5. Permit developers to write extensions in languages other than C.

## Writing Extensions

This section explains the basic steps required to write an extension for the Thunar File Manager using the C language interface. It is just a short introduction and not meant to provide extensive details about the internal workings of the file manager.

### Basic Concepts

#### Extensions and Providers

Thunar Extensions are shared libraries that extend the basic functionality provided by the Thunar File Manager. An extension exports one or more GObjects, called providers, to Thunar.

Providers implement one or more of the GInterfaces included with the thunarx library. The currently exported interfaces include the ThunarxMenuProvider for adding context menu items to the file views, the ThunarxPropertyPageProvider for adding pages to the file properties dialog, the ThunarxPreferencesProvider for adding actions to the preferences section of the main menu, and the ThunarxRenamerProvider for adding renamers to the bulk rename dialog.

#### ThunarxFileInfo

Thunar passes file references to the provider using ThunarxFileInfo objects. The ThunarxFileInfo interface provides access to the file information that Thunar has already read - mime type, URI, name, etc. Extensions should use the data from the ThunarxFileInfo rather than reading it themselves, to prevent excessive I/O.

There is exactly one ThunarxFileInfo per file, and it is kept around for as long as Thunar is interested in the file. Extensions can use this information to manage lifecycles of its own data - e.g. when the ThunarxFileInfo goes away, it is safe for the extension to forget any private data for that file.

#### Names

Most objects created by the extensions need names, e.g. the GtkActions returned from the ThunarxMenuProviders. These names must be namespaced with the name of the extension. For example the main action returned from the TexOpenTerminal extension (which can be found in the `examples/tex-open-terminal` subdirectory of the Thunar distribution) should be called `TexOpenTerminal::open-terminal`. The namespace must be global among the providers exported by a certain extension.

#### Types

Thunar extensions are loaded as GTypeModules. This means that all GTypes created by the extension must be registered with the GTypeModule, using `thunarx_provider_plugin_register_type()` function (or one of the convenience macros like `THUNARX_DEFINE_TYPE()`) rather than `g_type_register_static()`. All types exported by an extension must be registered in `thunar_extension_initialize()`.

### Getting Started

Providers are ThunarxProviderPlugins loaded from shared libraries installed in `$libdir/thunarx-1/`. The shared libraries are linked against the thunarx-1 library.

The extensions must provide three public functions, `thunar_extension_initialize()`, `thunar_extension_shutdown()` and `thunar_extension_list_types()`.

`thunar_extension_initialize()` is passed a ThunarxProviderPlugin object, and is responsible to register all GTypes required by the extension. `thunar_extension_shutdown()` should perform any extension-specific shutdown required prior to unloading the extension. `thunar_extension_list_types()` returns an array of GTypes that represent the types of the providers exported by the extension. Thunar will instantiate objects of those types when needed.

Basic Structure of an extension

    #include <gmodule.h>
    #include <thunarx/thunarx.h>

    static GType type_list[1];

    static void
    foo_extension_register_type (ThunarxProviderPlugin *plugin)
    {
      static const GTypeInfo info =
      {
        sizeof (FooExtensionClass),
        NULL,
        NULL,
        (GClassInitFunc) foo_extension_class_init,
        NULL,
        NULL,
        sizeof (FooExtension),
        0,
        (GInstanceInitFunc) foo_extension_init,
        NULL,
      };

      type_list[0] = thunarx_provider_plugin_register_type (plugin,
                                                            G_TYPE_OBJECT,
                                                            "FooExtension",
                                                            &info, 0);

      /* implement the desired provider interfaces */
    }

    static GType
    foo_extension_get_type (void)
    {
      return type_list[0];
    }

    G_MODULE_EXPORT void
    thunar_extension_initialize (ThunarxProviderPlugin *plugin)
    {
      const gchar *mismatch;

      /* verify the versions */
      mismatch = thunarx_check_version (THUNARX_MAJOR_VERSION,
                                        THUNARX_MINOR_VERSION,
                                        THUNARX_MICRO_VERSION);
      if (G_UNLIKELY (mismatch != NULL))
        {
          g_warning ("Version mismatch: %s", mismatch);
          return;
        }

      foo_extension_register_type (plugin);
    }

    G_MODULE_EXPORT void
    thunar_extension_shutdown (void)
    {
      /* any extension-specific shutdown */
    }

    G_MODULE_EXPORT void
    thunar_extension_list_types (const GType **types,
                                 gint         *n_types)
    {
      *types = type_list;
      *n_types = G_N_ELEMENTS (type_list);
    }

You should check the TexOpenTerminal extension, which is included in the Thunar distribution in the `examples/tex-open-terminal` directory, for a more complete example of how to write a Thunar extension.

#### Compiling Thunar Extensions

To compile a Thunar extension, you need to tell the compiler where to find the thunarx header files and library. This is done with the `pkg-config` utility.

The following interactive shell session demonstrates how `pkg-config` is used (the actual output on your system will be different):

    $ pkg-config --cflags thunarx-1
    -DXTHREADS -DXUSE_MTSAFE_API -I/opt/local/include/thunarx-1 -I/usr/local/include/atk-1.0 \
    -I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include -I/usr/X11R6/include/gtk-2.0 \
    -I/usr/X11R6/lib/gtk-2.0/include -I/usr/X11R6/include -I/usr/X11R6/include/pango-1.0 \
    -I/usr/local/include/freetype2 -I/usr/local/include
    $ pkg-config --libs thunarx-1
    -Wl,--rpath -Wl,/usr/local/lib -L/usr/local/lib -L/usr/X11R6/lib -L/opt/local/lib -lthunarx-1

The easiest way to compile an extension is to use the backticks feature of the shell. If you enclose a command in backticks (not single quotes), then its output will be substituted into the command line before execution. So to compile an extension, you would type the following:

    $ gcc -shared -fPIC -DPIC `pkg-config --cflags --libs thunarx-1` foo.c -o foo.so

#### Installing Thunar Extensions

To determine the directory where extensions must be installed on your local system, you can use the following command (as mentioned above, the output will be different on your system):

    $ pkg-config --variable=extensionsdir thunarx-1
    /opt/local/lib/thunarx-1

For example, to install the extension `foo.so` on your system, you would type the following:

    $ install -d `pkg-config --variable=extensionsdir thunarx-1`
    $ install -c -m 0755 foo.so `pkg-config --variable=extensionsdir thunarx-1`/foo.so

### Advanced topics

This section provides a short introduction to some of the advanced topics in the Thunar Extension Framework.

#### Memory-Resident Extensions

Some extensions may not play well with Thunar's on-demand loading and unloading of extensions. For example, an extension that uses a desktop library, which in turn registers additional static GTypes will not work after being loaded and unloaded for the first time. For these kind of extensions, Thunar provides the option to make extensions memory resident, which means the extension will be loaded once and afterwards will never be unloaded again until Thunar exits.

Such extensions must set the `resident` property of the provider plugin in its `thunar_extension_initialize()` function to `TRUE`, using the `thunarx_provider_plugin_set_resident()` method.

Making an extension memory resident

    G_MODULE_EXPORT void
    thunar_extension_initialize (ThunarxProviderPlugin *plugin)
    {
      /* setup the types for the extension */
      ...

      /* ensure that the extension will never be unloaded */
      thunarx_provider_plugin_set_resident (plugin, TRUE);
    }

## Fundamentals

&thunarx-version-information;

## Abstraction Layer

In order to hide the internals of the file manager from the extensions, the thunarx library provides an abstraction layer, which includes interfaces accessible to the extension, that are implemented by the file manager at runtime.

Currently the abstraction layer consists of the interface ThunarxFileInfo, which provides extensions with a way to access information about a file handled within the file manager, the class ThunarxPropertyPage, which is the base class for widgets that can be added to the properties dialog by extensions, the interface ThunarxProviderPlugin, which hides the details of dynamic type registration from the extensions, and the class ThunarxRenamer, which is the abstract base class for renamers that can be used in the bulk rename dialog provided by Thunar to rename multiple files at once.

&ThunarxFileInfo; &ThunarxPropertyPage; &ThunarxProviderPlugin; &ThunarxRenamer;

## Providers

The extensions interact with the file manager by implementing so called providers. This is a concept adopted from the Nautilus Extension Framework.

Providers are interfaces in the thunarx library that describe the functionality provided by a certain extension. For example, when the file manager pops up the file context menu, it'll first lookup all extensions that implement the interface ThunarxMenuProvider ask those extensions for the list of additional actions.

&ThunarxMenuProvider; &ThunarxPropertyPageProvider; &ThunarxPreferencesProvider; &ThunarxRenamerProvider;

## Using Thunar extensions in applications

&ThunarxProviderFactory;

Index