SDL 2.0
SDL_dbus.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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"
27static const char *dbus_library = "libdbus-1.so.3";
28static void *dbus_handle = NULL;
29static unsigned int screensaver_cookie = 0;
30static SDL_DBusContext dbus;
31
32static int
33LoadDBUSSyms(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
82static void
83UnloadDBUSLibrary(void)
84{
85 if (dbus_handle != NULL) {
86 SDL_UnloadObject(dbus_handle);
87 dbus_handle = NULL;
88 }
89}
90
91static int
92LoadDBUSLibrary(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
111void
112SDL_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
131void
132SDL_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/* Don't do this - bug 3950
143 dbus_shutdown() is a debug feature which closes all global resources in the dbus library. Calling this should be done by the app, not a library, because if there are multiple users of dbus in the process then SDL could shut it down even though another part is using it.
144*/
145#if 0
146 if (dbus.shutdown) {
147 dbus.shutdown();
148 }
149#endif
150 SDL_zero(dbus);
151 UnloadDBUSLibrary();
152}
153
154SDL_DBusContext *
155SDL_DBus_GetContext(void)
156{
157 if(!dbus_handle || !dbus.session_conn){
158 SDL_DBus_Init();
159 }
160
161 if(dbus_handle && dbus.session_conn){
162 return &dbus;
163 } else {
164 return NULL;
165 }
166}
167
168static SDL_bool
169SDL_DBus_CallMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
170{
172
173 if (conn) {
174 DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
175 if (msg) {
176 int firstarg;
177 va_list ap_reply;
178 va_copy(ap_reply, ap); /* copy the arg list so we don't compete with D-Bus for it */
179 firstarg = va_arg(ap, int);
180 if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
181 DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
182 if (reply) {
183 /* skip any input args, get to output args. */
184 while ((firstarg = va_arg(ap_reply, int)) != DBUS_TYPE_INVALID) {
185 /* we assume D-Bus already validated all this. */
186 { void *dumpptr = va_arg(ap_reply, void*); (void) dumpptr; }
187 if (firstarg == DBUS_TYPE_ARRAY) {
188 { const int dumpint = va_arg(ap_reply, int); (void) dumpint; }
189 }
190 }
191 firstarg = va_arg(ap_reply, int);
192 if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_get_args_valist(reply, NULL, firstarg, ap_reply)) {
194 }
195 dbus.message_unref(reply);
196 }
197 }
198 va_end(ap_reply);
199 dbus.message_unref(msg);
200 }
201 }
202
203 return retval;
204}
205
207SDL_DBus_CallMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
208{
210 va_list ap;
211 va_start(ap, method);
212 retval = SDL_DBus_CallMethodInternal(conn, node, path, interface, method, ap);
213 va_end(ap);
214 return retval;
215}
216
218SDL_DBus_CallMethod(const char *node, const char *path, const char *interface, const char *method, ...)
219{
221 va_list ap;
222 va_start(ap, method);
223 retval = SDL_DBus_CallMethodInternal(dbus.session_conn, node, path, interface, method, ap);
224 va_end(ap);
225 return retval;
226}
227
228static SDL_bool
229SDL_DBus_CallVoidMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
230{
232
233 if (conn) {
234 DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
235 if (msg) {
236 int firstarg = va_arg(ap, int);
237 if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
238 if (dbus.connection_send(conn, msg, NULL)) {
239 dbus.connection_flush(conn);
241 }
242 }
243
244 dbus.message_unref(msg);
245 }
246 }
247
248 return retval;
249}
250
252SDL_DBus_CallVoidMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
253{
255 va_list ap;
256 va_start(ap, method);
257 retval = SDL_DBus_CallVoidMethodInternal(conn, node, path, interface, method, ap);
258 va_end(ap);
259 return retval;
260}
261
263SDL_DBus_CallVoidMethod(const char *node, const char *path, const char *interface, const char *method, ...)
264{
266 va_list ap;
267 va_start(ap, method);
268 retval = SDL_DBus_CallVoidMethodInternal(dbus.session_conn, node, path, interface, method, ap);
269 va_end(ap);
270 return retval;
271}
272
274SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
275{
277
278 if (conn) {
279 DBusMessage *msg = dbus.message_new_method_call(node, path, "org.freedesktop.DBus.Properties", "Get");
280 if (msg) {
281 if (dbus.message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
282 DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
283 if (reply) {
284 DBusMessageIter iter, sub;
285 dbus.message_iter_init(reply, &iter);
286 if (dbus.message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
287 dbus.message_iter_recurse(&iter, &sub);
288 if (dbus.message_iter_get_arg_type(&sub) == expectedtype) {
289 dbus.message_iter_get_basic(&sub, result);
291 }
292 }
293 dbus.message_unref(reply);
294 }
295 }
296 dbus.message_unref(msg);
297 }
298 }
299
300 return retval;
301}
302
304SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
305{
306 return SDL_DBus_QueryPropertyOnConnection(dbus.session_conn, node, path, interface, property, expectedtype, result);
307}
308
309
310void
311SDL_DBus_ScreensaverTickle(void)
312{
313 if (screensaver_cookie == 0) { /* no need to tickle if we're inhibiting. */
314 /* org.gnome.ScreenSaver is the legacy interface, but it'll either do nothing or just be a second harmless tickle on newer systems, so we leave it for now. */
315 SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
316 SDL_DBus_CallVoidMethod("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
317 }
318}
319
321SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
322{
323 if ( (inhibit && (screensaver_cookie != 0)) || (!inhibit && (screensaver_cookie == 0)) ) {
324 return SDL_TRUE;
325 } else {
326 const char *node = "org.freedesktop.ScreenSaver";
327 const char *path = "/org/freedesktop/ScreenSaver";
328 const char *interface = "org.freedesktop.ScreenSaver";
329
330 if (inhibit) {
331 const char *app = "My SDL application";
332 const char *reason = "Playing a game";
333 if (!SDL_DBus_CallMethod(node, path, interface, "Inhibit",
334 DBUS_TYPE_STRING, &app, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID,
335 DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
336 return SDL_FALSE;
337 }
338 return (screensaver_cookie != 0) ? SDL_TRUE : SDL_FALSE;
339 } else {
340 if (!SDL_DBus_CallVoidMethod(node, path, interface, "UnInhibit", DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
341 return SDL_FALSE;
342 }
343 screensaver_cookie = 0;
344 }
345 }
346
347 return SDL_TRUE;
348}
349#endif
350
351/* vi: set ts=4 sw=4 expandtab: */
#define SDL_LoadObject
#define SDL_UnloadObject
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
SDL_EventEntry * free
Definition: SDL_events.c:82
GLuint64EXT * result
GLsizei const GLchar *const * path
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
#define NULL
Definition: begin_code.h:167
SDL_bool retval