SDL  2.0
SDL_dbus.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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_iter_init_append);
61  SDL_DBUS_SYM(message_iter_open_container);
62  SDL_DBUS_SYM(message_iter_append_basic);
63  SDL_DBUS_SYM(message_iter_close_container);
64  SDL_DBUS_SYM(message_get_args);
65  SDL_DBUS_SYM(message_get_args_valist);
66  SDL_DBUS_SYM(message_iter_init);
67  SDL_DBUS_SYM(message_iter_next);
68  SDL_DBUS_SYM(message_iter_get_basic);
69  SDL_DBUS_SYM(message_iter_get_arg_type);
70  SDL_DBUS_SYM(message_iter_recurse);
71  SDL_DBUS_SYM(message_unref);
72  SDL_DBUS_SYM(threads_init_default);
73  SDL_DBUS_SYM(error_init);
74  SDL_DBUS_SYM(error_is_set);
75  SDL_DBUS_SYM(error_free);
76  SDL_DBUS_SYM(get_local_machine_id);
77  SDL_DBUS_SYM(free);
78  SDL_DBUS_SYM(free_string_array);
79  SDL_DBUS_SYM(shutdown);
80 
81  #undef SDL_DBUS_SYM
82  #undef SDL_DBUS_SYM2
83 
84  return 0;
85 }
86 
87 static void
88 UnloadDBUSLibrary(void)
89 {
90  if (dbus_handle != NULL) {
91  SDL_UnloadObject(dbus_handle);
92  dbus_handle = NULL;
93  }
94 }
95 
96 static int
97 LoadDBUSLibrary(void)
98 {
99  int retval = 0;
100  if (dbus_handle == NULL) {
101  dbus_handle = SDL_LoadObject(dbus_library);
102  if (dbus_handle == NULL) {
103  retval = -1;
104  /* Don't call SDL_SetError(): SDL_LoadObject already did. */
105  } else {
106  retval = LoadDBUSSyms();
107  if (retval < 0) {
108  UnloadDBUSLibrary();
109  }
110  }
111  }
112 
113  return retval;
114 }
115 
116 void
117 SDL_DBus_Init(void)
118 {
119  static SDL_bool is_dbus_available = SDL_TRUE;
120  if (!is_dbus_available) {
121  return; /* don't keep trying if this fails. */
122  }
123 
124  if (!dbus.session_conn) {
125  DBusError err;
126 
127  if (LoadDBUSLibrary() == -1) {
128  is_dbus_available = SDL_FALSE; /* can't load at all? Don't keep trying. */
129  return; /* oh well */
130  }
131 
132  if (!dbus.threads_init_default()) {
133  is_dbus_available = SDL_FALSE;
134  return;
135  }
136 
137  dbus.error_init(&err);
138  /* session bus is required */
139 
140  dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
141  if (dbus.error_is_set(&err)) {
142  dbus.error_free(&err);
143  SDL_DBus_Quit();
144  is_dbus_available = SDL_FALSE;
145  return; /* oh well */
146  }
147  dbus.connection_set_exit_on_disconnect(dbus.session_conn, 0);
148 
149  /* system bus is optional */
150  dbus.system_conn = dbus.bus_get_private(DBUS_BUS_SYSTEM, &err);
151  if (!dbus.error_is_set(&err)) {
152  dbus.connection_set_exit_on_disconnect(dbus.system_conn, 0);
153  }
154 
155  dbus.error_free(&err);
156  }
157 }
158 
159 void
160 SDL_DBus_Quit(void)
161 {
162  if (dbus.system_conn) {
163  dbus.connection_close(dbus.system_conn);
164  dbus.connection_unref(dbus.system_conn);
165  }
166  if (dbus.session_conn) {
167  dbus.connection_close(dbus.session_conn);
168  dbus.connection_unref(dbus.session_conn);
169  }
170 /* Don't do this - bug 3950
171  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.
172 */
173 #if 0
174  if (dbus.shutdown) {
175  dbus.shutdown();
176  }
177 #endif
178  SDL_zero(dbus);
179  UnloadDBUSLibrary();
180 }
181 
182 SDL_DBusContext *
183 SDL_DBus_GetContext(void)
184 {
185  if (!dbus_handle || !dbus.session_conn) {
186  SDL_DBus_Init();
187  }
188 
189  return (dbus_handle && dbus.session_conn) ? &dbus : NULL;
190 }
191 
192 static SDL_bool
193 SDL_DBus_CallMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
194 {
196 
197  if (conn) {
198  DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
199  if (msg) {
200  int firstarg;
201  va_list ap_reply;
202  va_copy(ap_reply, ap); /* copy the arg list so we don't compete with D-Bus for it */
203  firstarg = va_arg(ap, int);
204  if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
205  DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
206  if (reply) {
207  /* skip any input args, get to output args. */
208  while ((firstarg = va_arg(ap_reply, int)) != DBUS_TYPE_INVALID) {
209  /* we assume D-Bus already validated all this. */
210  { void *dumpptr = va_arg(ap_reply, void*); (void) dumpptr; }
211  if (firstarg == DBUS_TYPE_ARRAY) {
212  { const int dumpint = va_arg(ap_reply, int); (void) dumpint; }
213  }
214  }
215  firstarg = va_arg(ap_reply, int);
216  if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_get_args_valist(reply, NULL, firstarg, ap_reply)) {
217  retval = SDL_TRUE;
218  }
219  dbus.message_unref(reply);
220  }
221  }
222  va_end(ap_reply);
223  dbus.message_unref(msg);
224  }
225  }
226 
227  return retval;
228 }
229 
230 SDL_bool
231 SDL_DBus_CallMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
232 {
234  va_list ap;
235  va_start(ap, method);
236  retval = SDL_DBus_CallMethodInternal(conn, node, path, interface, method, ap);
237  va_end(ap);
238  return retval;
239 }
240 
241 SDL_bool
242 SDL_DBus_CallMethod(const char *node, const char *path, const char *interface, const char *method, ...)
243 {
245  va_list ap;
246  va_start(ap, method);
247  retval = SDL_DBus_CallMethodInternal(dbus.session_conn, node, path, interface, method, ap);
248  va_end(ap);
249  return retval;
250 }
251 
252 static SDL_bool
253 SDL_DBus_CallVoidMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
254 {
256 
257  if (conn) {
258  DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
259  if (msg) {
260  int firstarg = va_arg(ap, int);
261  if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
262  if (dbus.connection_send(conn, msg, NULL)) {
263  dbus.connection_flush(conn);
264  retval = SDL_TRUE;
265  }
266  }
267 
268  dbus.message_unref(msg);
269  }
270  }
271 
272  return retval;
273 }
274 
275 SDL_bool
276 SDL_DBus_CallVoidMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
277 {
279  va_list ap;
280  va_start(ap, method);
281  retval = SDL_DBus_CallVoidMethodInternal(conn, node, path, interface, method, ap);
282  va_end(ap);
283  return retval;
284 }
285 
286 SDL_bool
287 SDL_DBus_CallVoidMethod(const char *node, const char *path, const char *interface, const char *method, ...)
288 {
290  va_list ap;
291  va_start(ap, method);
292  retval = SDL_DBus_CallVoidMethodInternal(dbus.session_conn, node, path, interface, method, ap);
293  va_end(ap);
294  return retval;
295 }
296 
297 SDL_bool
298 SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
299 {
301 
302  if (conn) {
303  DBusMessage *msg = dbus.message_new_method_call(node, path, "org.freedesktop.DBus.Properties", "Get");
304  if (msg) {
305  if (dbus.message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
306  DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
307  if (reply) {
308  DBusMessageIter iter, sub;
309  dbus.message_iter_init(reply, &iter);
310  if (dbus.message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
311  dbus.message_iter_recurse(&iter, &sub);
312  if (dbus.message_iter_get_arg_type(&sub) == expectedtype) {
313  dbus.message_iter_get_basic(&sub, result);
314  retval = SDL_TRUE;
315  }
316  }
317  dbus.message_unref(reply);
318  }
319  }
320  dbus.message_unref(msg);
321  }
322  }
323 
324  return retval;
325 }
326 
327 SDL_bool
328 SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
329 {
330  return SDL_DBus_QueryPropertyOnConnection(dbus.session_conn, node, path, interface, property, expectedtype, result);
331 }
332 
333 
334 void
335 SDL_DBus_ScreensaverTickle(void)
336 {
337  if (screensaver_cookie == 0) { /* no need to tickle if we're inhibiting. */
338  /* 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. */
339  SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
340  SDL_DBus_CallVoidMethod("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
341  }
342 }
343 
344 SDL_bool
345 SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
346 {
347  if ( (inhibit && (screensaver_cookie != 0)) || (!inhibit && (screensaver_cookie == 0)) ) {
348  return SDL_TRUE;
349  } else {
350  const char *node = "org.freedesktop.ScreenSaver";
351  const char *path = "/org/freedesktop/ScreenSaver";
352  const char *interface = "org.freedesktop.ScreenSaver";
353 
354  if (inhibit) {
355  const char *app = "My SDL application";
356  const char *reason = "Playing a game";
357  if (!SDL_DBus_CallMethod(node, path, interface, "Inhibit",
358  DBUS_TYPE_STRING, &app, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID,
359  DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
360  return SDL_FALSE;
361  }
362  return (screensaver_cookie != 0) ? SDL_TRUE : SDL_FALSE;
363  } else {
364  if (!SDL_DBus_CallVoidMethod(node, path, interface, "UnInhibit", DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
365  return SDL_FALSE;
366  }
367  screensaver_cookie = 0;
368  }
369  }
370 
371  return SDL_TRUE;
372 }
373 #endif
374 
375 /* 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:89
GLuint64EXT * result
GLsizei const GLchar *const * path
#define SDL_zero(x)
Definition: SDL_stdinc.h:426
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define NULL
Definition: begin_code.h:163
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF base if bpp PF set rept prefetch_distance PF set OFFSET endr endif endm macro preload_leading_step2 base if bpp ifc DST PF PF else if bpp lsl PF PF lsl PF sub
SDL_bool retval