Trac is being migrated to new services! Issues can be found in our new YouTrack instance and WIKI pages can be found on our website.

Plugin Actions How-To

This document will explain how to use Plugin Actions to enable your plugins to provide additional functionality to a libpurple client. We will assume that you have completed the Basic C Plugin How-To and have the helloworld.c file in ~/development/pidgin-2.0.2/libpurple/plugins

About Plugin Actions

A Plugin Action allows you to add additional functionality to a libpurple UI. Where the functionality appears depends on the UI. In Pidgin, for example, each plugin's actions appear as a submenu in the Tools menu of the Buddy List window, with the submenu's title being the plugin's name (as described in the initial Hello, World! plugin).

Many plugins choose to use plugin actions to introduce their functionality. The I'dle Mak'er plugin distributed with the Pidgin source code implements its functionality using a combination of plugin actions and the request API. The List Handler plugin, a third-party plugin, does this as well. Plugin actions are a flexible mechanism to introduce new functionality that isn't conversation-specific or may not exactly fit anywhere else.

Your First Plugin Action

Let's open up the helloworld.c file with your favorite editor again. We're going to change it to add a couple new functions as well as a global variable. The comments in the new additions explain what each addition is for.

#define PURPLE_PLUGINS

#include <glib.h>

#include "notify.h"
#include "plugin.h"
#include "version.h"

/* we're adding this here and assigning it in plugin_load because we need
 * a valid plugin handle for our call to purple_notify_message() in the
 * plugin_action_test_cb() callback function */
PurplePlugin *helloworld_plugin = NULL;

/* This function is the callback for the plugin action we added. All we're
 * doing here is displaying a message. When the user selects the plugin
 * action, this function is called. */
static void
plugin_action_test_cb(PurplePluginAction *action)
{
    purple_notify_message(helloworld_plugin, PURPLE_NOTIFY_MSG_INFO,
            "Plugin Actions Test", "This is a plugin actions test :)",
            NULL, NULL, NULL);
}

/* we tell libpurple in the PurplePluginInfo struct to call this function to
 * get a list of plugin actions to use for the plugin.  This function gives
 * libpurple that list of actions. */
static GList *
plugin_actions(PurplePlugin *plugin, gpointer context)
{
    /* some C89 (a.k.a. ANSI C) compilers will warn if any variable declaration
     * includes an initilization that calls a function.  To avoid that, we
     * generally initialize our variables first with constant values like NULL
     * or 0 and assign to them with function calls later */
    GList *list = NULL;
    PurplePluginAction *action = NULL;

    /* The action gets created by specifying a name to show in the UI and a
     * callback function to call. */
    action = purple_plugin_action_new("Plugin Action Test", plugin_action_test_cb);

    /* libpurple requires a GList of plugin actions, even if there is only one
     * action in the list.  We append the action to a GList here. */
    list = g_list_append(list, action);

    /* Once the list is complete, we send it to libpurple. */
    return list;
}

static gboolean
plugin_load(PurplePlugin *plugin)
{
    purple_notify_message(plugin, PURPLE_NOTIFY_MSG_INFO, "Hello World!",
            "This is the Hello World! plugin :)", NULL, NULL, NULL);

    helloworld_plugin = plugin; /* assign this here so we have a valid handle later */

    return TRUE;
}

static PurplePluginInfo info = {
    PURPLE_PLUGIN_MAGIC,
    PURPLE_MAJOR_VERSION,
    PURPLE_MINOR_VERSION,
    PURPLE_PLUGIN_STANDARD,
    NULL,
    0,
    NULL,
    PURPLE_PRIORITY_DEFAULT,

    "core-hello_world",
    "Hello World!",
    "1.1",

    "Hello World Plugin",
    "Hello World Plugin",
    "My Name <email@helloworld.tld>",
    "http://helloworld.tld",


    plugin_load,
    NULL,
    NULL,

    NULL,
    NULL,
    NULL,
    plugin_actions, /* this tells libpurple the address of the function to call
                       to get the list of plugin actions. */
    NULL,
    NULL,
    NULL,
    NULL
};

static void
init_plugin(PurplePlugin *plugin)
{
}

PURPLE_INIT_PLUGIN(hello_world, init_plugin, info)

Compile and Install the Plugin Again

Now that we've modified the source of the plugin, we need to compile it again. Use make helloworld.so (or make -f Makefile.mingw helloworld.dll on Windows) to compile the plugin. Again copy it to the appropriate plugins directory (~/.purple/plugins on UNIX-like systems or %APPDATA%\.purple\plugins on Windows).

If you still have this plugin loaded from the last how-to document, unload it. This step isn't strictly necessary, but will prevent an unwanted dialog from popping up when you start your libpurple client. You will probably want to unload the plugin again after this test is complete.

Now you need to restart your libpurple client, because libpurple doesn't detect updated C plugins when you open the Plugins dialog in your libpurple client; it detects only new ones. Since Hello, World! probably already existed in the plugin list, you need to restart the application to force libpurple to recognize the updated version of the plugin.

Testing the Plugin Action

To test the new plugin action, load the plugin. Now you'll see the familiar popup that appears when plugin_load is called. You can dismiss this dialog. Now go to where your libpurple client shows plugin actions. For the purpose of this test we will assume you are using Pidgin. This means our plugin action will be shown on the Tools menu of the buddy list window, with a submenu called "Hello World!". The sole entry in this submenu is our action, "Plugin Action Test".

Selecting "Plugin Action Test" will display a dialog similar to the one shown at plugin load. If you got this, you have successfully written your first plugin action!

The Other Plugin Actions Function

Libpurple provides one other function to deal with plugin actions, purple_plugin_action_free(). This function will deallocate the memory that was allocated when you created a plugin action. You don't really need to worry about this function, however, because libpurple automatically calls it when appropriate.

Beyond Plugin Actions

Plugin actions are only the tip of the iceberg for plugin functionality. Keep reading the other documents in the C Plugin How-To to learn more about the facilities libpurple provides for plugins to extend its capabilities.

Last modified 16 years ago Last modified on Sep 14, 2007, 1:14:05 AM
All information, including names and email addresses, entered onto this website or sent to mailing lists affiliated with this website will be public. Do not post confidential information, especially passwords!