1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
<refentry id="totem-plugins">
<refmeta>
<refentrytitle role="top_of_page" id="totem-plugins.top_of_page">Writing Totem Plugins</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>Totem</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Writing Totem Plugins</refname>
<refpurpose>brief tutorial on writing Totem plugins</refpurpose>
</refnamediv>
<refsect1>
<title>Introduction</title>
<para>Totem is extensible by means of small, dynamically-loadable plugins, which add functionality wanted by some but not others.</para>
<refsect2>
<title>Locations</title>
<para>Totem plugins can either be installed in the system path
(e.g. <filename class="directory">/usr/lib/totem/plugins/</filename>), or in a user's home directory
(e.g. <filename class="directory">~/.local/share/totem/plugins/</filename>). In either case, each plugin resides in a
subdirectory named after the plugin itself.</para>
<para>In addition, each plugin needs a <filename class="extension">.plugin</filename> index file, residing inside the plugin
directory. This gives the code name of the plugin, as well as some metadata about the plugin such as its human-readable
name, description and author.</para>
<example>
<title>Example Plugin Directory</title>
<para>A system-installed plugin called <literal>subtitle-downloader</literal> would reside in
<filename class="directory">/usr/lib/totem/plugins/subtitle-downloader</filename>, and would (at a
minimum) have the following files:
<itemizedlist>
<listitem><filename>subtitle-downloader.plugin</filename></listitem>
<listitem><filename>libsubtitle-downloader.so</filename></listitem>
</itemizedlist>
</para>
<para>If installed in a user's home directory, it would reside in
<filename class="extension">~/.local/share/totem/plugins/subtitle-downloader</filename> and have the same
files.</para>
</example>
</refsect2>
<refsect2>
<title>The <filename class="extension">.plugin</filename> File</title>
<para>The file should use the following template:
<programlisting>[Plugin]
Module=<replaceable>plugin-name</replaceable>
IAge=<replaceable>plugin interface age (starting at 1)</replaceable>
Builtin=<replaceable><literal>true</literal> or <literal>false</literal></replaceable>
Name=<replaceable>Human-Readable Plugin Name</replaceable>
Description=<replaceable>Simple sentence describing the plugin's functionality.</replaceable>
Authors=<replaceable>Plugin Author Name</replaceable>
Copyright=Copyright © <replaceable>year</replaceable> <replaceable>Copyright Holder</replaceable>
Website=<replaceable>http://plugin/website/</replaceable></programlisting>
Most of the values in the template are fairly self-explanatory. One thing to note is that the plugin name should be
in lowercase, and contain no spaces. The plugin interface age should start at <literal>1</literal>, and only be
incremented when the binary interface of the plugin (as used by Totem) changes. If the plugin does not have its own
website, Totem's website (<literal>https://wiki.gnome.org/Apps/Videos</literal>) can be used.</para>
<para>The library file containing the plugin's code should be named
<filename>lib<replaceable>plugin-name</replaceable>.so</filename> (for C, or other compiled language, plugins) or
<filename><replaceable>pluginname</replaceable>.py</filename> (for Python plugins).</para>
</refsect2>
<refsect2>
<title>Writing a Plugin</title>
<para>Writing a plugin in C is a matter of creating a new <type><link linkend="GObject">GObject</link></type> which inherits
from <type><link linkend="PeasExtensionBase">PeasExtensionBase</link></type> and which implements
<type><link linkend="PeasActivatable">PeasActivatable</link></type>. The following code will create a simple plugin
called <literal>foobar</literal>:
<example>
<title>Example Plugin Code</title>
<programlisting>
#define TOTEM_TYPE_FOOBAR_PLUGIN (totem_foobar_plugin_get_type ())
#define TOTEM_FOOBAR_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TOTEM_TYPE_FOOBAR_PLUGIN, TotemFoobarPlugin))
#define TOTEM_FOOBAR_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TOTEM_TYPE_FOOBAR_PLUGIN, TotemFoobarPluginClass))
#define TOTEM_IS_FOOBAR_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TOTEM_TYPE_FOOBAR_PLUGIN))
#define TOTEM_IS_FOOBAR_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TOTEM_TYPE_FOOBAR_PLUGIN))
#define TOTEM_FOOBAR_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TOTEM_TYPE_FOOBAR_PLUGIN, TotemFoobarPluginClass))
typedef struct {
/* Plugin private member variables */
} TotemFoobarPluginPrivate;
TOTEM_PLUGIN_REGISTER (TOTEM_TYPE_FOOBAR_PLUGIN, TotemFoobarPlugin, totem_foobar_plugin);
static void
impl_activate (PeasActivatable *plugin)
{
TotemFoobarPlugin *self = TOTEM_FOOBAR_PLUGIN (plugin);
TotemFoobarPluginPrivate *priv = self->priv;
TotemObject *totem = g_object_get_data (G_OBJECT (plugin), "object");
/* Initialise resources, connect to events, create menu items and UI, etc., here.
* Note that impl_activate() and impl_deactivate() can be called multiple times in one
* Totem instance, though impl_activate() will always be followed by impl_deactivate() before
* it is called again. Similarly, impl_deactivate() cannot be called twice in succession. */
}
static void
impl_deactivate (PeasActivatable *plugin)
{
TotemFoobarPlugin *self = TOTEM_FOOBAR_PLUGIN (plugin);
/* Destroy resources created in impl_activate() here. e.g. Disconnect from signals
* and remove menu entries and UI. */
}</programlisting>
</example></para>
<para>Once resources have been created, and the plugin has been connected to Totem's UI in the <function>impl_activate</function>
function, the plugin is free to go about its tasks as appropriate. If the user deactivates the plugin, or Totem decides
to deactivate it, the <function>impl_deactivate</function> will be called. The plugin should free any resources
grabbed or allocated in the <function>impl_activate</function> function, and remove itself from the Totem
interface.</para>
<para>Note that plugins can be activated and deactivated (e.g. from Totem's plugin manager) many times during one Totem session,
so the <function>impl_activate</function> and <function>impl_deactivate</function> functions must be able to cope with
this.</para>
<para>Any of the API documented in the rest of the Totem API reference can be used by plugins. Python plugins are written in
the same way as C plugins, and are similarly implemented as classes derived from
<type><link linkend="PeasExtensionBase">PeasExtensionBase</link></type> and implementing
<type><link linkend="PeasActivatable">PeasActivatable</link></type>.</para>
</refsect2>
</refsect1>
</refentry>
|