4 * This library is free software you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * SECTION: e-dbus-server
20 * @include: libebackend/libebackend.h
21 * @short_description: An abstract base class for a D-Bus server
24 #include "e-dbus-server.h"
29 #include <glib-unix.h>
32 #include <libedataserver/libedataserver.h>
34 #include <libebackend/e-module.h>
35 #include <libebackend/e-extensible.h>
36 #include <libebackend/e-backend-enumtypes.h>
38 #define E_DBUS_SERVER_GET_PRIVATE(obj) \
39 (G_TYPE_INSTANCE_GET_PRIVATE \
40 ((obj), E_TYPE_DBUS_SERVER, EDBusServerPrivate))
42 #define INACTIVITY_TIMEOUT 10 /* seconds */
44 struct _EDBusServerPrivate {
50 guint inactivity_timeout_id;
52 gboolean wait_for_client;
53 EDBusServerExitCode exit_code;
65 static guint signals[LAST_SIGNAL];
67 static GHashTable *directories_loaded;
68 G_LOCK_DEFINE_STATIC (directories_loaded);
70 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (
71 EDBusServer, e_dbus_server, G_TYPE_OBJECT,
72 G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
75 dbus_server_bus_acquired_cb (GDBusConnection *connection,
76 const gchar *bus_name,
79 g_signal_emit (server, signals[BUS_ACQUIRED], 0, connection);
83 dbus_server_name_acquired_cb (GDBusConnection *connection,
84 const gchar *bus_name,
87 g_signal_emit (server, signals[BUS_NAME_ACQUIRED], 0, connection);
91 dbus_server_name_lost_cb (GDBusConnection *connection,
92 const gchar *bus_name,
95 g_signal_emit (server, signals[BUS_NAME_LOST], 0, connection);
99 dbus_server_inactivity_timeout_cb (gpointer user_data)
101 EDBusServer *server = E_DBUS_SERVER (user_data);
103 e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_NORMAL);
110 dbus_server_hang_up_cb (gpointer user_data)
112 EDBusServer *server = E_DBUS_SERVER (user_data);
114 g_print ("Received hang up signal.\n");
115 e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_RELOAD);
121 dbus_server_terminate_cb (gpointer user_data)
123 EDBusServer *server = E_DBUS_SERVER (user_data);
125 g_print ("Received terminate signal.\n");
126 e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_NORMAL);
133 dbus_server_finalize (GObject *object)
135 EDBusServerPrivate *priv;
137 priv = E_DBUS_SERVER_GET_PRIVATE (object);
139 g_main_loop_unref (priv->main_loop);
141 if (priv->bus_owner_id > 0)
142 g_bus_unown_name (priv->bus_owner_id);
144 if (priv->hang_up_id > 0)
145 g_source_remove (priv->hang_up_id);
147 if (priv->terminate_id > 0)
148 g_source_remove (priv->terminate_id);
150 if (priv->inactivity_timeout_id > 0)
151 g_source_remove (priv->inactivity_timeout_id);
153 /* Chain up to parent's finalize() method. */
154 G_OBJECT_CLASS (e_dbus_server_parent_class)->finalize (object);
158 dbus_server_constructed (GObject *object)
160 e_dbus_server_load_modules (E_DBUS_SERVER (object));
162 e_extensible_load_extensions (E_EXTENSIBLE (object));
164 /* Chain up to parent's constructed() method. */
165 G_OBJECT_CLASS (e_dbus_server_parent_class)->constructed (object);
169 dbus_server_bus_acquired (EDBusServer *server,
170 GDBusConnection *connection)
172 if (server->priv->use_count == 0 && !server->priv->wait_for_client) {
173 server->priv->inactivity_timeout_id =
174 e_named_timeout_add_seconds (
175 INACTIVITY_TIMEOUT, (GSourceFunc)
176 dbus_server_inactivity_timeout_cb,
182 dbus_server_bus_name_acquired (EDBusServer *server,
183 GDBusConnection *connection)
185 EDBusServerClass *class;
187 class = E_DBUS_SERVER_GET_CLASS (server);
188 g_return_if_fail (class->bus_name != NULL);
190 g_print ("Bus name '%s' acquired.\n", class->bus_name);
194 dbus_server_bus_name_lost (EDBusServer *server,
195 GDBusConnection *connection)
197 EDBusServerClass *class;
199 class = E_DBUS_SERVER_GET_CLASS (server);
200 g_return_if_fail (class->bus_name != NULL);
202 g_print ("Bus name '%s' lost.\n", class->bus_name);
204 e_dbus_server_quit (server, E_DBUS_SERVER_EXIT_NORMAL);
207 static EDBusServerExitCode
208 dbus_server_run_server (EDBusServer *server)
210 EDBusServerClass *class;
212 /* Try to acquire the well-known bus name. */
214 class = E_DBUS_SERVER_GET_CLASS (server);
215 g_return_val_if_fail (
216 class->bus_name != NULL,
217 E_DBUS_SERVER_EXIT_NONE);
219 server->priv->bus_owner_id = g_bus_own_name (
222 G_BUS_NAME_OWNER_FLAGS_REPLACE |
223 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
224 (GBusAcquiredCallback) dbus_server_bus_acquired_cb,
225 (GBusNameAcquiredCallback) dbus_server_name_acquired_cb,
226 (GBusNameLostCallback) dbus_server_name_lost_cb,
227 g_object_ref (server),
228 (GDestroyNotify) g_object_unref);
230 g_main_loop_run (server->priv->main_loop);
232 return server->priv->exit_code;
236 dbus_server_quit_server (EDBusServer *server,
237 EDBusServerExitCode code)
239 /* If we're reloading, voluntarily relinquish our bus
240 * name to avoid triggering a "bus-name-lost" signal. */
241 if (code == E_DBUS_SERVER_EXIT_RELOAD) {
242 g_bus_unown_name (server->priv->bus_owner_id);
243 server->priv->bus_owner_id = 0;
246 server->priv->exit_code = code;
247 g_main_loop_quit (server->priv->main_loop);
251 ignore_log (const gchar *log_domain,
252 GLogLevelFlags log_level,
253 const gchar *message,
256 /* Avoid printing of trivial messages while running test
257 * cases. Only print warnings, criticals and errors. */
258 if ((log_level & (G_LOG_FLAG_FATAL |
260 G_LOG_LEVEL_CRITICAL |
261 G_LOG_LEVEL_WARNING)) != 0)
262 g_log_default_handler (log_domain, log_level, message, user_data);
266 e_dbus_server_class_init (EDBusServerClass *class)
268 GObjectClass *object_class;
270 g_type_class_add_private (class, sizeof (EDBusServerPrivate));
272 object_class = G_OBJECT_CLASS (class);
273 object_class->finalize = dbus_server_finalize;
274 object_class->constructed = dbus_server_constructed;
276 class->bus_acquired = dbus_server_bus_acquired;
277 class->bus_name_acquired = dbus_server_bus_name_acquired;
278 class->bus_name_lost = dbus_server_bus_name_lost;
279 class->run_server = dbus_server_run_server;
280 class->quit_server = dbus_server_quit_server;
283 * EDBusServer::bus-acquired:
284 * @server: the #EDBusServer which emitted the signal
285 * @connection: the #GDBusConnection to the session bus
287 * Emitted when @server acquires a connection to the session bus.
289 signals[BUS_ACQUIRED] = g_signal_new (
291 G_OBJECT_CLASS_TYPE (object_class),
293 G_STRUCT_OFFSET (EDBusServerClass, bus_acquired),
296 G_TYPE_DBUS_CONNECTION);
299 * EDBusServer::bus-name-acquired:
300 * @server: the #EDBusServer which emitted the signal
301 * @connection: the #GDBusConnection to the session bus
303 * Emitted when @server acquires its well-known session bus name.
305 signals[BUS_NAME_ACQUIRED] = g_signal_new (
307 G_OBJECT_CLASS_TYPE (object_class),
309 G_STRUCT_OFFSET (EDBusServerClass, bus_name_acquired),
312 G_TYPE_DBUS_CONNECTION);
315 * EDBusServer::bus-name-lost:
316 * @server: the #EDBusServer which emitted the signal
317 * @connection: the #GDBusconnection to the session bus,
318 * or %NULL if the connection has been closed
320 * Emitted when @server loses its well-known session bus name
321 * or the session bus connection has been closed.
323 signals[BUS_NAME_LOST] = g_signal_new (
325 G_OBJECT_CLASS_TYPE (object_class),
327 G_STRUCT_OFFSET (EDBusServerClass, bus_name_lost),
330 G_TYPE_DBUS_CONNECTION);
333 * EDBusServer::run-server:
334 * @server: the #EDBusServer which emitted the signal
336 * Emitted to request that @server start its main loop and
337 * attempt to acquire its well-known session bus name.
339 * Returns: an #EDBusServerExitCode
341 signals[RUN_SERVER] = g_signal_new (
343 G_OBJECT_CLASS_TYPE (object_class),
345 G_STRUCT_OFFSET (EDBusServerClass, run_server),
347 E_TYPE_DBUS_SERVER_EXIT_CODE, 0);
350 * EDBusServer::quit-server:
351 * @server: the #EDBusServer which emitted the signal
352 * @code: an #EDBusServerExitCode
354 * Emitted to request that @server quit its main loop.
356 signals[QUIT_SERVER] = g_signal_new (
358 G_OBJECT_CLASS_TYPE (object_class),
360 G_STRUCT_OFFSET (EDBusServerClass, quit_server),
363 E_TYPE_DBUS_SERVER_EXIT_CODE);
365 if (g_getenv ("EDS_TESTING") != NULL)
366 g_log_set_default_handler (ignore_log, NULL);
370 e_dbus_server_init (EDBusServer *server)
372 server->priv = E_DBUS_SERVER_GET_PRIVATE (server);
373 server->priv->main_loop = g_main_loop_new (NULL, FALSE);
374 server->priv->wait_for_client = FALSE;
377 server->priv->hang_up_id = g_unix_signal_add (
378 SIGHUP, dbus_server_hang_up_cb, server);
379 server->priv->terminate_id = g_unix_signal_add (
380 SIGTERM, dbus_server_terminate_cb, server);
386 * @server: an #EDBusServer
387 * @wait_for_client: continue running until a client connects
389 * Emits the #EDBusServer::run signal.
391 * By default the @server will start its main loop and attempt to acquire
392 * its well-known session bus name. If the @server's main loop is already
393 * running, the function will immediately return #E_DBUS_SERVER_EXIT_NONE.
394 * Otherwise the function blocks until e_dbus_server_quit() is called.
396 * If @wait_for_client is %TRUE, the @server will continue running until
397 * the first client connection is made instead of quitting on its own if
398 * no client connection is made within the first few seconds.
400 * Returns: the exit code passed to e_dbus_server_quit()
405 e_dbus_server_run (EDBusServer *server,
406 gboolean wait_for_client)
408 EDBusServerExitCode exit_code;
410 g_return_val_if_fail (
411 E_IS_DBUS_SERVER (server),
412 E_DBUS_SERVER_EXIT_NONE);
414 server->priv->wait_for_client = wait_for_client;
416 if (g_main_loop_is_running (server->priv->main_loop))
417 return E_DBUS_SERVER_EXIT_NONE;
419 g_signal_emit (server, signals[RUN_SERVER], 0, &exit_code);
425 * e_dbus_server_quit:
426 * @server: an #EDBusServer
427 * @code: an #EDBusServerExitCode
429 * Emits the #EDBusServer::quit signal with the given @code.
431 * By default the @server will quit its main loop and cause
432 * e_dbus_server_run() to return @code.
437 e_dbus_server_quit (EDBusServer *server,
438 EDBusServerExitCode code)
440 g_return_if_fail (E_IS_DBUS_SERVER (server));
442 g_signal_emit (server, signals[QUIT_SERVER], 0, code);
446 * e_dbus_server_hold:
447 * @server: an #EDBusServer
449 * Increases the use count of @server.
451 * Use this function to indicate that the server has a reason to continue
452 * to run. To cancel the hold, call e_dbus_server_release().
457 e_dbus_server_hold (EDBusServer *server)
459 g_return_if_fail (E_IS_DBUS_SERVER (server));
461 if (server->priv->inactivity_timeout_id > 0) {
462 g_source_remove (server->priv->inactivity_timeout_id);
463 server->priv->inactivity_timeout_id = 0;
466 server->priv->use_count++;
470 * e_dbus_server_release:
471 * @server: an #EDBusServer
473 * Decreates the use count of @server.
475 * When the use count reaches zero, the server will stop running.
477 * Never call this function except to cancel the effect of a previous call
478 * to e_dbus_server_hold().
483 e_dbus_server_release (EDBusServer *server)
485 g_return_if_fail (E_IS_DBUS_SERVER (server));
486 g_return_if_fail (server->priv->use_count > 0);
488 server->priv->use_count--;
490 if (server->priv->use_count == 0) {
491 server->priv->inactivity_timeout_id =
492 e_named_timeout_add_seconds (
493 INACTIVITY_TIMEOUT, (GSourceFunc)
494 dbus_server_inactivity_timeout_cb,
500 * e_dbus_server_load_modules:
501 * @server: an #EDBusServer
503 * This function should be called once during @server initialization to
504 * load all available library modules to extend the @server's functionality.
509 e_dbus_server_load_modules (EDBusServer *server)
511 EDBusServerClass *class;
512 gboolean already_loaded;
513 const gchar *directory;
516 g_return_if_fail (E_IS_DBUS_SERVER (server));
518 class = E_DBUS_SERVER_GET_CLASS (server);
519 g_return_if_fail (class->module_directory != NULL);
521 /* This ensures a module directory is only loaded once. */
522 G_LOCK (directories_loaded);
523 if (directories_loaded == NULL)
524 directories_loaded = g_hash_table_new (NULL, NULL);
525 directory = g_intern_string (class->module_directory);
526 already_loaded = g_hash_table_contains (directories_loaded, directory);
527 g_hash_table_add (directories_loaded, (gpointer) directory);
528 G_UNLOCK (directories_loaded);
533 list = e_module_load_all_in_directory (class->module_directory);
534 g_list_free_full (list, (GDestroyNotify) g_type_module_unuse);