portal.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* portal.c
  2. *
  3. * Copyright 2021 Georges Basile Stavracas Neto <[email protected]>
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * SPDX-License-Identifier: GPL-2.0-or-later
  19. */
  20. #include "portal.h"
  21. #include "pipewire.h"
  22. #include <util/dstr.h>
  23. struct portal_signal_call {
  24. GCancellable *cancellable;
  25. portal_signal_callback callback;
  26. gpointer user_data;
  27. char *request_path;
  28. guint signal_id;
  29. gulong cancelled_id;
  30. };
  31. #define REQUEST_PATH "/org/freedesktop/portal/desktop/request/%s/obs%u"
  32. #define SESSION_PATH "/org/freedesktop/portal/desktop/session/%s/obs%u"
  33. static GDBusConnection *connection = NULL;
  34. static void ensure_connection(void)
  35. {
  36. g_autoptr(GError) error = NULL;
  37. if (!connection) {
  38. connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
  39. if (error) {
  40. blog(LOG_WARNING,
  41. "[portals] Error retrieving D-Bus connection: %s",
  42. error->message);
  43. return;
  44. }
  45. }
  46. }
  47. char *get_sender_name(void)
  48. {
  49. char *sender_name;
  50. char *aux;
  51. ensure_connection();
  52. sender_name =
  53. bstrdup(g_dbus_connection_get_unique_name(connection) + 1);
  54. /* Replace dots by underscores */
  55. while ((aux = strstr(sender_name, ".")) != NULL)
  56. *aux = '_';
  57. return sender_name;
  58. }
  59. GDBusConnection *portal_get_dbus_connection(void)
  60. {
  61. ensure_connection();
  62. return connection;
  63. }
  64. void portal_create_request_path(char **out_path, char **out_token)
  65. {
  66. static uint32_t request_token_count = 0;
  67. request_token_count++;
  68. if (out_token) {
  69. struct dstr str;
  70. dstr_init(&str);
  71. dstr_printf(&str, "obs%u", request_token_count);
  72. *out_token = str.array;
  73. }
  74. if (out_path) {
  75. char *sender_name;
  76. struct dstr str;
  77. sender_name = get_sender_name();
  78. dstr_init(&str);
  79. dstr_printf(&str, REQUEST_PATH, sender_name,
  80. request_token_count);
  81. *out_path = str.array;
  82. bfree(sender_name);
  83. }
  84. }
  85. void portal_create_session_path(char **out_path, char **out_token)
  86. {
  87. static uint32_t session_token_count = 0;
  88. session_token_count++;
  89. if (out_token) {
  90. struct dstr str;
  91. dstr_init(&str);
  92. dstr_printf(&str, "obs%u", session_token_count);
  93. *out_token = str.array;
  94. }
  95. if (out_path) {
  96. char *sender_name;
  97. struct dstr str;
  98. sender_name = get_sender_name();
  99. dstr_init(&str);
  100. dstr_printf(&str, SESSION_PATH, sender_name,
  101. session_token_count);
  102. *out_path = str.array;
  103. bfree(sender_name);
  104. }
  105. }
  106. static void portal_signal_call_free(struct portal_signal_call *call)
  107. {
  108. if (call->signal_id)
  109. g_dbus_connection_signal_unsubscribe(
  110. portal_get_dbus_connection(), call->signal_id);
  111. if (call->cancelled_id > 0)
  112. g_signal_handler_disconnect(call->cancellable,
  113. call->cancelled_id);
  114. g_clear_pointer(&call->request_path, bfree);
  115. bfree(call);
  116. }
  117. static void on_cancelled_cb(GCancellable *cancellable, void *data)
  118. {
  119. UNUSED_PARAMETER(cancellable);
  120. struct portal_signal_call *call = data;
  121. blog(LOG_INFO, "[portals] Request cancelled");
  122. g_dbus_connection_call(
  123. portal_get_dbus_connection(), "org.freedesktop.portal.Desktop",
  124. call->request_path, "org.freedesktop.portal.Request", "Close",
  125. NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
  126. portal_signal_call_free(call);
  127. }
  128. static void on_response_received_cb(GDBusConnection *connection,
  129. const char *sender_name,
  130. const char *object_path,
  131. const char *interface_name,
  132. const char *signal_name,
  133. GVariant *parameters, void *user_data)
  134. {
  135. UNUSED_PARAMETER(connection);
  136. UNUSED_PARAMETER(sender_name);
  137. UNUSED_PARAMETER(object_path);
  138. UNUSED_PARAMETER(interface_name);
  139. UNUSED_PARAMETER(signal_name);
  140. struct portal_signal_call *call = user_data;
  141. if (call->callback)
  142. call->callback(parameters, call->user_data);
  143. portal_signal_call_free(call);
  144. }
  145. void portal_signal_subscribe(const char *path, GCancellable *cancellable,
  146. portal_signal_callback callback,
  147. gpointer user_data)
  148. {
  149. struct portal_signal_call *call;
  150. call = bzalloc(sizeof(struct portal_signal_call));
  151. call->request_path = bstrdup(path);
  152. call->callback = callback;
  153. call->user_data = user_data;
  154. call->cancellable = cancellable ? g_object_ref(cancellable) : NULL;
  155. call->cancelled_id =
  156. cancellable
  157. ? g_signal_connect(cancellable, "cancelled",
  158. G_CALLBACK(on_cancelled_cb), call)
  159. : 0;
  160. call->signal_id = g_dbus_connection_signal_subscribe(
  161. portal_get_dbus_connection(), "org.freedesktop.portal.Desktop",
  162. "org.freedesktop.portal.Request", "Response",
  163. call->request_path, NULL, G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
  164. on_response_received_cb, call, NULL);
  165. }