src/core/linux/SDL_dbus.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 28 May 2017 07:11:52 -0400
changeset 11042 303c875e47f0
parent 11041 5aebcca5ff18
child 11043 5be3faa49e54
permissions -rw-r--r--
linux: Simplify D-Bus interface, remove lots of boilerplate.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 #include "SDL_dbus.h"
    23 
    24 #if SDL_USE_LIBDBUS
    25 /* we never link directly to libdbus. */
    26 #include "SDL_loadso.h"
    27 static const char *dbus_library = "libdbus-1.so.3";
    28 static void *dbus_handle = NULL;
    29 static unsigned int screensaver_cookie = 0;
    30 static SDL_DBusContext dbus;
    31 
    32 static int
    33 LoadDBUSSyms(void)
    34 {
    35     #define SDL_DBUS_SYM2(x, y) \
    36         if (!(dbus.x = SDL_LoadFunction(dbus_handle, #y))) return -1
    37         
    38     #define SDL_DBUS_SYM(x) \
    39         SDL_DBUS_SYM2(x, dbus_##x)
    40 
    41     SDL_DBUS_SYM(bus_get_private);
    42     SDL_DBUS_SYM(bus_register);
    43     SDL_DBUS_SYM(bus_add_match);
    44     SDL_DBUS_SYM(connection_open_private);
    45     SDL_DBUS_SYM(connection_set_exit_on_disconnect);
    46     SDL_DBUS_SYM(connection_get_is_connected);
    47     SDL_DBUS_SYM(connection_add_filter);
    48     SDL_DBUS_SYM(connection_try_register_object_path);
    49     SDL_DBUS_SYM(connection_send);
    50     SDL_DBUS_SYM(connection_send_with_reply_and_block);
    51     SDL_DBUS_SYM(connection_close);
    52     SDL_DBUS_SYM(connection_unref);
    53     SDL_DBUS_SYM(connection_flush);
    54     SDL_DBUS_SYM(connection_read_write);
    55     SDL_DBUS_SYM(connection_dispatch);
    56     SDL_DBUS_SYM(message_is_signal);
    57     SDL_DBUS_SYM(message_new_method_call);
    58     SDL_DBUS_SYM(message_append_args);
    59     SDL_DBUS_SYM(message_append_args_valist);
    60     SDL_DBUS_SYM(message_get_args);
    61     SDL_DBUS_SYM(message_get_args_valist);
    62     SDL_DBUS_SYM(message_iter_init);
    63     SDL_DBUS_SYM(message_iter_next);
    64     SDL_DBUS_SYM(message_iter_get_basic);
    65     SDL_DBUS_SYM(message_iter_get_arg_type);
    66     SDL_DBUS_SYM(message_iter_recurse);
    67     SDL_DBUS_SYM(message_unref);
    68     SDL_DBUS_SYM(error_init);
    69     SDL_DBUS_SYM(error_is_set);
    70     SDL_DBUS_SYM(error_free);
    71     SDL_DBUS_SYM(get_local_machine_id);
    72     SDL_DBUS_SYM(free);
    73     SDL_DBUS_SYM(shutdown);
    74 
    75     #undef SDL_DBUS_SYM
    76     #undef SDL_DBUS_SYM2
    77 
    78     return 0;
    79 }
    80 
    81 static void
    82 UnloadDBUSLibrary(void)
    83 {
    84     if (dbus_handle != NULL) {
    85         SDL_UnloadObject(dbus_handle);
    86         dbus_handle = NULL;
    87     }
    88 }
    89 
    90 static int
    91 LoadDBUSLibrary(void)
    92 {
    93     int retval = 0;
    94     if (dbus_handle == NULL) {
    95         dbus_handle = SDL_LoadObject(dbus_library);
    96         if (dbus_handle == NULL) {
    97             retval = -1;
    98             /* Don't call SDL_SetError(): SDL_LoadObject already did. */
    99         } else {
   100             retval = LoadDBUSSyms();
   101             if (retval < 0) {
   102                 UnloadDBUSLibrary();
   103             }
   104         }
   105     }
   106 
   107     return retval;
   108 }
   109 
   110 void
   111 SDL_DBus_Init(void)
   112 {
   113     if (!dbus.session_conn && LoadDBUSLibrary() != -1) {
   114         DBusError err;
   115         dbus.error_init(&err);
   116         dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
   117         if (!dbus.error_is_set(&err)) {
   118             dbus.system_conn = dbus.bus_get_private(DBUS_BUS_SYSTEM, &err);
   119         }
   120         if (dbus.error_is_set(&err)) {
   121             dbus.error_free(&err);
   122             SDL_DBus_Quit();
   123             return;  /* oh well */
   124         }
   125         dbus.connection_set_exit_on_disconnect(dbus.system_conn, 0);
   126         dbus.connection_set_exit_on_disconnect(dbus.session_conn, 0);
   127     }
   128 }
   129 
   130 void
   131 SDL_DBus_Quit(void)
   132 {
   133     if (dbus.system_conn) {
   134         dbus.connection_close(dbus.system_conn);
   135         dbus.connection_unref(dbus.system_conn);
   136     }
   137     if (dbus.session_conn) {
   138         dbus.connection_close(dbus.session_conn);
   139         dbus.connection_unref(dbus.session_conn);
   140     }
   141     if (dbus.shutdown) {
   142         dbus.shutdown();
   143     }
   144     SDL_zero(dbus);
   145     UnloadDBUSLibrary();
   146 }
   147 
   148 SDL_DBusContext *
   149 SDL_DBus_GetContext(void)
   150 {
   151     if(!dbus_handle || !dbus.session_conn){
   152         SDL_DBus_Init();
   153     }
   154     
   155     if(dbus_handle && dbus.session_conn){
   156         return &dbus;
   157     } else {
   158         return NULL;
   159     }
   160 }
   161 
   162 static SDL_bool
   163 SDL_DBus_CallMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
   164 {
   165     SDL_bool retval = SDL_FALSE;
   166 
   167     if (conn) {
   168         DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
   169         if (msg) {
   170             int firstarg = va_arg(ap, int);
   171             if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
   172                 DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
   173                 if (reply) {
   174                     firstarg = va_arg(ap, int);
   175                     if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_get_args_valist(reply, NULL, firstarg, ap)) {
   176                         retval = SDL_TRUE;
   177                     }
   178                     dbus.message_unref(reply);
   179                 }
   180             }
   181             dbus.message_unref(msg);
   182         }
   183     }
   184 
   185     return retval;
   186 }
   187 
   188 SDL_bool
   189 SDL_DBus_CallMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
   190 {
   191     SDL_bool retval;
   192     va_list ap;
   193     va_start(ap, method);
   194     retval = SDL_DBus_CallMethodInternal(conn, node, path, interface, method, ap);
   195     va_end(ap);
   196     return retval;
   197 }
   198 
   199 SDL_bool
   200 SDL_DBus_CallMethod(const char *node, const char *path, const char *interface, const char *method, ...)
   201 {
   202     SDL_bool retval;
   203     va_list ap;
   204     va_start(ap, method);
   205     retval = SDL_DBus_CallMethodInternal(dbus.session_conn, node, path, interface, method, ap);
   206     va_end(ap);
   207     return retval;
   208 }
   209 
   210 static SDL_bool
   211 SDL_DBus_CallVoidMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
   212 {
   213     SDL_bool retval = SDL_FALSE;
   214 
   215     if (conn) {
   216         DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
   217         if (msg) {
   218             int firstarg = va_arg(ap, int);
   219             if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
   220                 if (dbus.connection_send(conn, msg, NULL)) {
   221                     dbus.connection_flush(conn);
   222                     retval = SDL_TRUE;
   223                 }
   224             }
   225 
   226             dbus.message_unref(msg);
   227         }
   228     }
   229 
   230     return retval;
   231 }
   232 
   233 SDL_bool
   234 SDL_DBus_CallVoidMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
   235 {
   236     SDL_bool retval;
   237     va_list ap;
   238     va_start(ap, method);
   239     retval = SDL_DBus_CallVoidMethodInternal(conn, node, path, interface, method, ap);
   240     va_end(ap);
   241     return retval;
   242 }
   243 
   244 SDL_bool
   245 SDL_DBus_CallVoidMethod(const char *node, const char *path, const char *interface, const char *method, ...)
   246 {
   247     SDL_bool retval;
   248     va_list ap;
   249     va_start(ap, method);
   250     retval = SDL_DBus_CallVoidMethodInternal(dbus.session_conn, node, path, interface, method, ap);
   251     va_end(ap);
   252     return retval;
   253 }
   254 
   255 SDL_bool
   256 SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
   257 {
   258     SDL_bool retval = SDL_FALSE;
   259 
   260     if (conn) {
   261         DBusMessage *msg = dbus.message_new_method_call(node, path, "org.freedesktop.DBus.Properties", "Get");
   262         if (msg) {
   263             if (dbus.message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
   264                 DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
   265                 if (reply) {
   266                     DBusMessageIter iter, sub;
   267                     dbus.message_iter_init(reply, &iter);
   268                     if (dbus.message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
   269                         dbus.message_iter_recurse(&iter, &sub);
   270                         if (dbus.message_iter_get_arg_type(&sub) == expectedtype) {
   271                             dbus.message_iter_get_basic(&sub, result);
   272                             retval = SDL_TRUE;
   273                         }
   274                     }
   275                     dbus.message_unref(reply);
   276                 }
   277             }
   278             dbus.message_unref(msg);
   279         }
   280     }
   281 
   282     return retval;
   283 }
   284 
   285 SDL_bool
   286 SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
   287 {
   288     return SDL_DBus_QueryPropertyOnConnection(dbus.session_conn, node, path, interface, property, expectedtype, result);
   289 }
   290 
   291 
   292 void
   293 SDL_DBus_ScreensaverTickle(void)
   294 {
   295     SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
   296 }
   297 
   298 SDL_bool
   299 SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
   300 {
   301     if ( (inhibit && (screensaver_cookie != 0)) || (!inhibit && (screensaver_cookie == 0)) ) {
   302         return SDL_TRUE;
   303     } else {
   304         const char *node = "org.freedesktop.ScreenSaver";
   305         const char *path = "/org/freedesktop/ScreenSaver";
   306         const char *interface = "org.freedesktop.ScreenSaver";
   307 
   308         if (inhibit) {
   309             const char *app = "My SDL application";
   310             const char *reason = "Playing a game";
   311             if (!SDL_DBus_CallMethod(node, path, interface, "Inhibit",
   312                     DBUS_TYPE_STRING, &app, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID,
   313                     DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
   314                 return SDL_FALSE;
   315             }
   316             return (screensaver_cookie != 0) ? SDL_TRUE : SDL_FALSE;
   317         } else {
   318             if (!SDL_DBus_CallVoidMethod(node, path, interface, "UnInhibit", DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
   319                 return SDL_FALSE;
   320             }
   321             screensaver_cookie = 0;
   322         }
   323     }
   324 
   325     return SDL_TRUE;
   326 }
   327 #endif
   328 
   329 /* vi: set ts=4 sw=4 expandtab: */