SDL  2.0
SDL_dbus.c
Go to the documentation of this file.
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 /* 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 
154 SDL_DBusContext *
155 SDL_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 
168 static SDL_bool
169 SDL_DBus_CallMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
170 {
171  SDL_bool retval = SDL_FALSE;
172 
173  if (conn) {
174  DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
175  if (msg) {
176  int firstarg = va_arg(ap, int);
177  if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
178  DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
179  if (reply) {
180  firstarg = va_arg(ap, int);
181  if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_get_args_valist(reply, NULL, firstarg, ap)) {
182  retval = SDL_TRUE;
183  }
184  dbus.message_unref(reply);
185  }
186  }
187  dbus.message_unref(msg);
188  }
189  }
190 
191  return retval;
192 }
193 
194 SDL_bool
195 SDL_DBus_CallMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
196 {
198  va_list ap;
199  va_start(ap, method);
200  retval = SDL_DBus_CallMethodInternal(conn, node, path, interface, method, ap);
201  va_end(ap);
202  return retval;
203 }
204 
205 SDL_bool
206 SDL_DBus_CallMethod(const char *node, const char *path, const char *interface, const char *method, ...)
207 {
209  va_list ap;
210  va_start(ap, method);
211  retval = SDL_DBus_CallMethodInternal(dbus.session_conn, node, path, interface, method, ap);
212  va_end(ap);
213  return retval;
214 }
215 
216 static SDL_bool
217 SDL_DBus_CallVoidMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
218 {
219  SDL_bool retval = SDL_FALSE;
220 
221  if (conn) {
222  DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
223  if (msg) {
224  int firstarg = va_arg(ap, int);
225  if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
226  if (dbus.connection_send(conn, msg, NULL)) {
227  dbus.connection_flush(conn);
228  retval = SDL_TRUE;
229  }
230  }
231 
232  dbus.message_unref(msg);
233  }
234  }
235 
236  return retval;
237 }
238 
239 SDL_bool
240 SDL_DBus_CallVoidMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
241 {
243  va_list ap;
244  va_start(ap, method);
245  retval = SDL_DBus_CallVoidMethodInternal(conn, node, path, interface, method, ap);
246  va_end(ap);
247  return retval;
248 }
249 
250 SDL_bool
251 SDL_DBus_CallVoidMethod(const char *node, const char *path, const char *interface, const char *method, ...)
252 {
254  va_list ap;
255  va_start(ap, method);
256  retval = SDL_DBus_CallVoidMethodInternal(dbus.session_conn, node, path, interface, method, ap);
257  va_end(ap);
258  return retval;
259 }
260 
261 SDL_bool
262 SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
263 {
264  SDL_bool retval = SDL_FALSE;
265 
266  if (conn) {
267  DBusMessage *msg = dbus.message_new_method_call(node, path, "org.freedesktop.DBus.Properties", "Get");
268  if (msg) {
269  if (dbus.message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
270  DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
271  if (reply) {
272  DBusMessageIter iter, sub;
273  dbus.message_iter_init(reply, &iter);
274  if (dbus.message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
275  dbus.message_iter_recurse(&iter, &sub);
276  if (dbus.message_iter_get_arg_type(&sub) == expectedtype) {
277  dbus.message_iter_get_basic(&sub, result);
278  retval = SDL_TRUE;
279  }
280  }
281  dbus.message_unref(reply);
282  }
283  }
284  dbus.message_unref(msg);
285  }
286  }
287 
288  return retval;
289 }
290 
291 SDL_bool
292 SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
293 {
294  return SDL_DBus_QueryPropertyOnConnection(dbus.session_conn, node, path, interface, property, expectedtype, result);
295 }
296 
297 
298 void
299 SDL_DBus_ScreensaverTickle(void)
300 {
301  SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
302 }
303 
304 SDL_bool
305 SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
306 {
307  if ( (inhibit && (screensaver_cookie != 0)) || (!inhibit && (screensaver_cookie == 0)) ) {
308  return SDL_TRUE;
309  } else {
310  const char *node = "org.freedesktop.ScreenSaver";
311  const char *path = "/org/freedesktop/ScreenSaver";
312  const char *interface = "org.freedesktop.ScreenSaver";
313 
314  if (inhibit) {
315  const char *app = "My SDL application";
316  const char *reason = "Playing a game";
317  if (!SDL_DBus_CallMethod(node, path, interface, "Inhibit",
318  DBUS_TYPE_STRING, &app, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID,
319  DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
320  return SDL_FALSE;
321  }
322  return (screensaver_cookie != 0) ? SDL_TRUE : SDL_FALSE;
323  } else {
324  if (!SDL_DBus_CallVoidMethod(node, path, interface, "UnInhibit", DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
325  return SDL_FALSE;
326  }
327  screensaver_cookie = 0;
328  }
329  }
330 
331  return SDL_TRUE;
332 }
333 #endif
334 
335 /* vi: set ts=4 sw=4 expandtab: */
GLuint64EXT * result
SDL_EventEntry * free
Definition: SDL_events.c:84
#define SDL_LoadObject
#define SDL_UnloadObject
SDL_bool retval
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:139
GLsizei const GLchar *const * path