SDL_dbus.c 10 KB

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