platform-nix-dbus.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright (c) 2015 Hugh Bailey <[email protected]>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <assert.h>
  17. #include <gio/gio.h>
  18. #include "bmem.h"
  19. /* NOTE: This is basically just the VLC implementation from its d-bus power
  20. * management inhibition code. Credit is theirs for this. */
  21. enum service_type {
  22. FREEDESKTOP_SS, /* freedesktop screensaver (KDE >= 4, GNOME >= 3.10) */
  23. FREEDESKTOP_PM, /* freedesktop power management (KDE, gnome <= 2.26) */
  24. MATE_SM, /* MATE (>= 1.0) session manager */
  25. GNOME_SM, /* GNOME 2.26 - 3.4 sessopm mamager */
  26. };
  27. struct service_info {
  28. const char *name;
  29. const char *path;
  30. const char *interface;
  31. const char *uninhibit;
  32. };
  33. static const struct service_info services[] = {
  34. [FREEDESKTOP_SS] =
  35. {
  36. .name = "org.freedesktop.ScreenSaver",
  37. .path = "/ScreenSaver",
  38. .interface = "org.freedesktop.ScreenSaver",
  39. .uninhibit = "UnInhibit",
  40. },
  41. [FREEDESKTOP_PM] =
  42. {
  43. .name = "org.freedesktop.PowerManagement.Inhibit",
  44. .path = "/org/freedesktop/PowerManagement",
  45. .interface = "org.freedesktop.PowerManagement.Inhibit",
  46. .uninhibit = "UnInhibit",
  47. },
  48. [MATE_SM] =
  49. {
  50. .name = "org.mate.SessionManager",
  51. .path = "/org/mate/SessionManager",
  52. .interface = "org.mate.SessionManager",
  53. .uninhibit = "Uninhibit",
  54. },
  55. [GNOME_SM] =
  56. {
  57. .name = "org.gnome.SessionManager",
  58. .path = "/org/gnome/SessionManager",
  59. .interface = "org.gnome.SessionManager",
  60. .uninhibit = "Uninhibit",
  61. },
  62. };
  63. static const size_t num_services =
  64. (sizeof(services) / sizeof(struct service_info));
  65. struct dbus_sleep_info {
  66. const struct service_info *service;
  67. GDBusConnection *c;
  68. uint32_t cookie;
  69. enum service_type type;
  70. };
  71. void dbus_sleep_info_destroy(struct dbus_sleep_info *info)
  72. {
  73. if (info) {
  74. g_clear_object(&info->c);
  75. bfree(info);
  76. }
  77. }
  78. struct dbus_sleep_info *dbus_sleep_info_create(void)
  79. {
  80. struct dbus_sleep_info *info = bzalloc(sizeof(*info));
  81. g_autoptr(GError) error = NULL;
  82. info->c = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
  83. if (!info->c) {
  84. blog(LOG_ERROR, "Could not create dbus connection: %s",
  85. error->message);
  86. bfree(info);
  87. return NULL;
  88. }
  89. for (size_t i = 0; i < num_services; i++) {
  90. const struct service_info *service = &services[i];
  91. g_autoptr(GVariant) reply = NULL;
  92. if (!service->name)
  93. continue;
  94. reply = g_dbus_connection_call_sync(
  95. info->c, "org.freedesktop.DBus",
  96. "/org/freedesktop/DBus", "org.freedesktop.DBus",
  97. "GetNameOwner", g_variant_new("(s)", service->name),
  98. NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, NULL, NULL);
  99. if (reply != NULL) {
  100. blog(LOG_DEBUG, "Found dbus service: %s",
  101. service->name);
  102. info->service = service;
  103. info->type = (enum service_type)i;
  104. return info;
  105. }
  106. }
  107. dbus_sleep_info_destroy(info);
  108. return NULL;
  109. }
  110. void dbus_inhibit_sleep(struct dbus_sleep_info *info, const char *reason,
  111. bool active)
  112. {
  113. g_autoptr(GVariant) reply = NULL;
  114. g_autoptr(GError) error = NULL;
  115. const char *method;
  116. GVariant *params;
  117. if (active == !!info->cookie)
  118. return;
  119. method = active ? "Inhibit" : info->service->uninhibit;
  120. if (active) {
  121. const char *program = "libobs";
  122. uint32_t flags = 0xC;
  123. uint32_t xid = 0;
  124. assert(info->cookie == 0);
  125. switch (info->type) {
  126. case MATE_SM:
  127. case GNOME_SM:
  128. params = g_variant_new("(s@usu)", program,
  129. g_variant_new_uint32(xid),
  130. reason, flags);
  131. break;
  132. default:
  133. params = g_variant_new("(ss)", program, reason);
  134. }
  135. } else {
  136. assert(info->cookie != 0);
  137. params = g_variant_new("(u)", info->cookie);
  138. }
  139. reply = g_dbus_connection_call_sync(
  140. info->c, info->service->name, info->service->path,
  141. info->service->interface, method, params, NULL,
  142. G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
  143. if (error != NULL) {
  144. blog(LOG_ERROR, "Failed to call %s: %s", method,
  145. error->message);
  146. return;
  147. }
  148. if (active)
  149. g_variant_get(reply, "(u)", &info->cookie);
  150. else
  151. info->cookie = 0;
  152. }