~ubuntu-branches/ubuntu/precise/telepathy-mission-control-5/precise

« back to all changes in this revision

Viewing changes to mission-control-plugins/loader.c

Tags: upstream-5.5.0
ImportĀ upstreamĀ versionĀ 5.5.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Loader for plugins that use mission-control-plugins
 
2
 *
 
3
 * Copyright (C) 2009 Nokia Corporation
 
4
 * Copyright (C) 2009 Collabora Ltd.
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2.1 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful, but
 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this library; if not, write to the Free Software
 
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 
19
 * 02110-1301 USA
 
20
 *
 
21
 */
 
22
 
 
23
#include <gmodule.h>
 
24
#include <mission-control-plugins/mission-control-plugins.h>
 
25
#include <mission-control-plugins/debug-internal.h>
 
26
 
 
27
static gboolean debugging = FALSE;
 
28
 
 
29
void
 
30
mcp_set_debug (gboolean debug)
 
31
{
 
32
  debugging = debug;
 
33
}
 
34
 
 
35
gboolean
 
36
_mcp_is_debugging (void)
 
37
{
 
38
  return debugging;
 
39
}
 
40
 
 
41
void
 
42
_mcp_debug (const gchar *format, ...)
 
43
{
 
44
  if (debugging)
 
45
    {
 
46
      va_list args;
 
47
 
 
48
      va_start (args, format);
 
49
      g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args);
 
50
      va_end (args);
 
51
    }
 
52
}
 
53
 
 
54
static GList *plugins = NULL;
 
55
 
 
56
/**
 
57
 * mcp_add_object:
 
58
 * @object: an object implementing one or more plugin interfaces
 
59
 *
 
60
 * As currently implemented, these objects are never unreferenced.
 
61
 *
 
62
 * Add an object to the list of plugin objects.
 
63
 */
 
64
void
 
65
mcp_add_object (gpointer object)
 
66
{
 
67
  g_return_if_fail (G_IS_OBJECT (object));
 
68
 
 
69
  plugins = g_list_prepend (plugins, g_object_ref (object));
 
70
}
 
71
 
 
72
/**
 
73
 * mcp_plugin_ref_nth_object:
 
74
 * @n: object number, starting from 0
 
75
 *
 
76
 * Implemented by each plugin (not implemented in this library!) as a hook
 
77
 * point; it will be called repeatedly with an increasing argument, and must
 
78
 * return a GObject reference each time, until it returns NULL.
 
79
 *
 
80
 * As currently implemented, these objects are never unreferenced.
 
81
 *
 
82
 * Returns: a new reference to a #GObject, or NULL if @n is at least the number
 
83
 *  of objects supported by this plugin
 
84
 */
 
85
 
 
86
/**
 
87
 * mcp_read_dir:
 
88
 * @path: full path to a plugins directory
 
89
 *
 
90
 * Read plugins from the given path. Any file with suffix G_MODULE_SUFFIX is
 
91
 * considered as a potential plugin, and loaded; if it contains the symbol
 
92
 * mcp_plugin_ref_nth_object(), it's made resident, then that symbol is called
 
93
 * as a function.
 
94
 */
 
95
void
 
96
mcp_read_dir (const gchar *path)
 
97
{
 
98
  GError *error = NULL;
 
99
  GDir *dir = g_dir_open (path, 0, &error);
 
100
  const gchar *entry;
 
101
 
 
102
  if (dir == NULL)
 
103
    {
 
104
      DEBUG ("could not load plugins from %s: %s", path, error->message);
 
105
      g_error_free (error);
 
106
      return;
 
107
    }
 
108
 
 
109
  for (entry = g_dir_read_name (dir);
 
110
      entry != NULL;
 
111
      entry = g_dir_read_name (dir))
 
112
    {
 
113
      gchar *full_path;
 
114
      GModule *module;
 
115
 
 
116
      if (!g_str_has_prefix (entry, "mcp-"))
 
117
        {
 
118
          DEBUG ("%s isn't a plugin (doesn't start with mcp-)", entry);
 
119
          continue;
 
120
        }
 
121
 
 
122
      if (!g_str_has_suffix (entry, "." G_MODULE_SUFFIX))
 
123
        {
 
124
          DEBUG ("%s is not a loadable module", entry);
 
125
          continue;
 
126
        }
 
127
 
 
128
      full_path = g_build_filename (path, entry, NULL);
 
129
 
 
130
      module = g_module_open (full_path, G_MODULE_BIND_LOCAL);
 
131
 
 
132
      if (module != NULL)
 
133
        {
 
134
          gpointer symbol;
 
135
 
 
136
          if (g_module_symbol (module, MCP_PLUGIN_REF_NTH_OBJECT_SYMBOL,
 
137
                &symbol))
 
138
            {
 
139
              GObject *(* ref_nth) (guint) = symbol;
 
140
              guint n = 0;
 
141
              GObject *object;
 
142
 
 
143
              /* In practice, approximately no GModules can safely be unloaded.
 
144
               * For those that can, if there's ever a need for it, we can add
 
145
               * an API for "please don't make me resident". */
 
146
              g_module_make_resident (module);
 
147
 
 
148
              for (object = ref_nth (n);
 
149
                  object != NULL;
 
150
                  object = ref_nth (++n))
 
151
                {
 
152
                  mcp_add_object (object);
 
153
                  g_object_unref (object);
 
154
                }
 
155
 
 
156
              DEBUG ("%u plugin object(s) found in %s", n, entry);
 
157
            }
 
158
          else
 
159
            {
 
160
              DEBUG ("%s does not have symbol %s", entry,
 
161
                  MCP_PLUGIN_REF_NTH_OBJECT_SYMBOL);
 
162
              g_module_close (module);
 
163
            }
 
164
        }
 
165
 
 
166
      g_free (full_path);
 
167
    }
 
168
 
 
169
  g_dir_close (dir);
 
170
}
 
171
 
 
172
/**
 
173
 * mcp_list_objects:
 
174
 *
 
175
 * Return a list of objects that might implement plugin interfaces.
 
176
 *
 
177
 * Returns: a constant list of plugin objects
 
178
 */
 
179
const GList *
 
180
mcp_list_objects (void)
 
181
{
 
182
  return plugins;
 
183
}