src/core/linux/SDL_dbus.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 03 Jan 2018 10:03:25 -0800
changeset 11811 5d94cb6b24d3
parent 11043 5be3faa49e54
child 11839 971881e55d61
permissions -rw-r--r--
Updated copyright for 2018
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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(free_string_array);
    74     SDL_DBUS_SYM(shutdown);
    75 
    76     #undef SDL_DBUS_SYM
    77     #undef SDL_DBUS_SYM2
    78 
    79     return 0;
    80 }
    81 
    82 static void
    83 UnloadDBUSLibrary(void)
    84 {
    85     if (dbus_handle != NULL) {
    86         SDL_UnloadObject(dbus_handle);
    87         dbus_handle = NULL;
    88     }
    89 }
    90 
    91 static int
    92 LoadDBUSLibrary(void)
    93 {
    94     int retval = 0;
    95     if (dbus_handle == NULL) {
    96         dbus_handle = SDL_LoadObject(dbus_library);
    97         if (dbus_handle == NULL) {
    98             retval = -1;
    99             /* Don't call SDL_SetError(): SDL_LoadObject already did. */
   100         } else {
   101             retval = LoadDBUSSyms();
   102             if (retval < 0) {
   103                 UnloadDBUSLibrary();
   104             }
   105         }
   106     }
   107 
   108     return retval;
   109 }
   110 
   111 void
   112 SDL_DBus_Init(void)
   113 {
   114     if (!dbus.session_conn && LoadDBUSLibrary() != -1) {
   115         DBusError err;
   116         dbus.error_init(&err);
   117         dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
   118         if (!dbus.error_is_set(&err)) {
   119             dbus.system_conn = dbus.bus_get_private(DBUS_BUS_SYSTEM, &err);
   120         }
   121         if (dbus.error_is_set(&err)) {
   122             dbus.error_free(&err);
   123             SDL_DBus_Quit();
   124             return;  /* oh well */
   125         }
   126         dbus.connection_set_exit_on_disconnect(dbus.system_conn, 0);
   127         dbus.connection_set_exit_on_disconnect(dbus.session_conn, 0);
   128     }
   129 }
   130 
   131 void
   132 SDL_DBus_Quit(void)
   133 {
   134     if (dbus.system_conn) {
   135         dbus.connection_close(dbus.system_conn);
   136         dbus.connection_unref(dbus.system_conn);
   137     }
   138     if (dbus.session_conn) {
   139         dbus.connection_close(dbus.session_conn);
   140         dbus.connection_unref(dbus.session_conn);
   141     }
   142     if (dbus.shutdown) {
   143         dbus.shutdown();
   144     }
   145     SDL_zero(dbus);
   146     UnloadDBUSLibrary();
   147 }
   148 
   149 SDL_DBusContext *
   150 SDL_DBus_GetContext(void)
   151 {
   152     if(!dbus_handle || !dbus.session_conn){
   153         SDL_DBus_Init();
   154     }
   155     
   156     if(dbus_handle && dbus.session_conn){
   157         return &dbus;
   158     } else {
   159         return NULL;
   160     }
   161 }
   162 
   163 static SDL_bool
   164 SDL_DBus_CallMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
   165 {
   166     SDL_bool retval = SDL_FALSE;
   167 
   168     if (conn) {
   169         DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
   170         if (msg) {
   171             int firstarg = va_arg(ap, int);
   172             if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
   173                 DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
   174                 if (reply) {
   175                     firstarg = va_arg(ap, int);
   176                     if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_get_args_valist(reply, NULL, firstarg, ap)) {
   177                         retval = SDL_TRUE;
   178                     }
   179                     dbus.message_unref(reply);
   180                 }
   181             }
   182             dbus.message_unref(msg);
   183         }
   184     }
   185 
   186     return retval;
   187 }
   188 
   189 SDL_bool
   190 SDL_DBus_CallMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
   191 {
   192     SDL_bool retval;
   193     va_list ap;
   194     va_start(ap, method);
   195     retval = SDL_DBus_CallMethodInternal(conn, node, path, interface, method, ap);
   196     va_end(ap);
   197     return retval;
   198 }
   199 
   200 SDL_bool
   201 SDL_DBus_CallMethod(const char *node, const char *path, const char *interface, const char *method, ...)
   202 {
   203     SDL_bool retval;
   204     va_list ap;
   205     va_start(ap, method);
   206     retval = SDL_DBus_CallMethodInternal(dbus.session_conn, node, path, interface, method, ap);
   207     va_end(ap);
   208     return retval;
   209 }
   210 
   211 static SDL_bool
   212 SDL_DBus_CallVoidMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
   213 {
   214     SDL_bool retval = SDL_FALSE;
   215 
   216     if (conn) {
   217         DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
   218         if (msg) {
   219             int firstarg = va_arg(ap, int);
   220             if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
   221                 if (dbus.connection_send(conn, msg, NULL)) {
   222                     dbus.connection_flush(conn);
   223                     retval = SDL_TRUE;
   224                 }
   225             }
   226 
   227             dbus.message_unref(msg);
   228         }
   229     }
   230 
   231     return retval;
   232 }
   233 
   234 SDL_bool
   235 SDL_DBus_CallVoidMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
   236 {
   237     SDL_bool retval;
   238     va_list ap;
   239     va_start(ap, method);
   240     retval = SDL_DBus_CallVoidMethodInternal(conn, node, path, interface, method, ap);
   241     va_end(ap);
   242     return retval;
   243 }
   244 
   245 SDL_bool
   246 SDL_DBus_CallVoidMethod(const char *node, const char *path, const char *interface, const char *method, ...)
   247 {
   248     SDL_bool retval;
   249     va_list ap;
   250     va_start(ap, method);
   251     retval = SDL_DBus_CallVoidMethodInternal(dbus.session_conn, node, path, interface, method, ap);
   252     va_end(ap);
   253     return retval;
   254 }
   255 
   256 SDL_bool
   257 SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
   258 {
   259     SDL_bool retval = SDL_FALSE;
   260 
   261     if (conn) {
   262         DBusMessage *msg = dbus.message_new_method_call(node, path, "org.freedesktop.DBus.Properties", "Get");
   263         if (msg) {
   264             if (dbus.message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
   265                 DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
   266                 if (reply) {
   267                     DBusMessageIter iter, sub;
   268                     dbus.message_iter_init(reply, &iter);
   269                     if (dbus.message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
   270                         dbus.message_iter_recurse(&iter, &sub);
   271                         if (dbus.message_iter_get_arg_type(&sub) == expectedtype) {
   272                             dbus.message_iter_get_basic(&sub, result);
   273                             retval = SDL_TRUE;
   274                         }
   275                     }
   276                     dbus.message_unref(reply);
   277                 }
   278             }
   279             dbus.message_unref(msg);
   280         }
   281     }
   282 
   283     return retval;
   284 }
   285 
   286 SDL_bool
   287 SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
   288 {
   289     return SDL_DBus_QueryPropertyOnConnection(dbus.session_conn, node, path, interface, property, expectedtype, result);
   290 }
   291 
   292 
   293 void
   294 SDL_DBus_ScreensaverTickle(void)
   295 {
   296     SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
   297 }
   298 
   299 SDL_bool
   300 SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
   301 {
   302     if ( (inhibit && (screensaver_cookie != 0)) || (!inhibit && (screensaver_cookie == 0)) ) {
   303         return SDL_TRUE;
   304     } else {
   305         const char *node = "org.freedesktop.ScreenSaver";
   306         const char *path = "/org/freedesktop/ScreenSaver";
   307         const char *interface = "org.freedesktop.ScreenSaver";
   308 
   309         if (inhibit) {
   310             const char *app = "My SDL application";
   311             const char *reason = "Playing a game";
   312             if (!SDL_DBus_CallMethod(node, path, interface, "Inhibit",
   313                     DBUS_TYPE_STRING, &app, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID,
   314                     DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
   315                 return SDL_FALSE;
   316             }
   317             return (screensaver_cookie != 0) ? SDL_TRUE : SDL_FALSE;
   318         } else {
   319             if (!SDL_DBus_CallVoidMethod(node, path, interface, "UnInhibit", DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
   320                 return SDL_FALSE;
   321             }
   322             screensaver_cookie = 0;
   323         }
   324     }
   325 
   326     return SDL_TRUE;
   327 }
   328 #endif
   329 
   330 /* vi: set ts=4 sw=4 expandtab: */