portal.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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, "[portals] Error retrieving D-Bus connection: %s", error->message);
  41. return;
  42. }
  43. }
  44. }
  45. char *get_sender_name(void)
  46. {
  47. char *sender_name;
  48. char *aux;
  49. ensure_connection();
  50. sender_name = bstrdup(g_dbus_connection_get_unique_name(connection) + 1);
  51. /* Replace dots by underscores */
  52. while ((aux = strstr(sender_name, ".")) != NULL)
  53. *aux = '_';
  54. return sender_name;
  55. }
  56. GDBusConnection *portal_get_dbus_connection(void)
  57. {
  58. ensure_connection();
  59. return connection;
  60. }
  61. void portal_create_request_path(char **out_path, char **out_token)
  62. {
  63. static uint32_t request_token_count = 0;
  64. request_token_count++;
  65. if (out_token) {
  66. struct dstr str;
  67. dstr_init(&str);
  68. dstr_printf(&str, "obs%u", request_token_count);
  69. *out_token = str.array;
  70. }
  71. if (out_path) {
  72. char *sender_name;
  73. struct dstr str;
  74. sender_name = get_sender_name();
  75. dstr_init(&str);
  76. dstr_printf(&str, REQUEST_PATH, sender_name, request_token_count);
  77. *out_path = str.array;
  78. bfree(sender_name);
  79. }
  80. }
  81. void portal_create_session_path(char **out_path, char **out_token)
  82. {
  83. static uint32_t session_token_count = 0;
  84. session_token_count++;
  85. if (out_token) {
  86. struct dstr str;
  87. dstr_init(&str);
  88. dstr_printf(&str, "obs%u", session_token_count);
  89. *out_token = str.array;
  90. }
  91. if (out_path) {
  92. char *sender_name;
  93. struct dstr str;
  94. sender_name = get_sender_name();
  95. dstr_init(&str);
  96. dstr_printf(&str, SESSION_PATH, sender_name, session_token_count);
  97. *out_path = str.array;
  98. bfree(sender_name);
  99. }
  100. }
  101. static void portal_signal_call_free(struct portal_signal_call *call)
  102. {
  103. if (call->signal_id)
  104. g_dbus_connection_signal_unsubscribe(portal_get_dbus_connection(), call->signal_id);
  105. if (call->cancelled_id > 0)
  106. g_signal_handler_disconnect(call->cancellable, call->cancelled_id);
  107. g_clear_pointer(&call->request_path, bfree);
  108. bfree(call);
  109. }
  110. static void on_cancelled_cb(GCancellable *cancellable, void *data)
  111. {
  112. UNUSED_PARAMETER(cancellable);
  113. struct portal_signal_call *call = data;
  114. blog(LOG_INFO, "[portals] Request cancelled");
  115. g_dbus_connection_call(portal_get_dbus_connection(), "org.freedesktop.portal.Desktop", call->request_path,
  116. "org.freedesktop.portal.Request", "Close", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
  117. NULL, NULL);
  118. portal_signal_call_free(call);
  119. }
  120. static void on_response_received_cb(GDBusConnection *connection, const char *sender_name, const char *object_path,
  121. const char *interface_name, const char *signal_name, GVariant *parameters,
  122. void *user_data)
  123. {
  124. UNUSED_PARAMETER(connection);
  125. UNUSED_PARAMETER(sender_name);
  126. UNUSED_PARAMETER(object_path);
  127. UNUSED_PARAMETER(interface_name);
  128. UNUSED_PARAMETER(signal_name);
  129. struct portal_signal_call *call = user_data;
  130. if (call->callback)
  131. call->callback(parameters, call->user_data);
  132. portal_signal_call_free(call);
  133. }
  134. void portal_signal_subscribe(const char *path, GCancellable *cancellable, portal_signal_callback callback,
  135. gpointer user_data)
  136. {
  137. struct portal_signal_call *call;
  138. call = bzalloc(sizeof(struct portal_signal_call));
  139. call->request_path = bstrdup(path);
  140. call->callback = callback;
  141. call->user_data = user_data;
  142. call->cancellable = cancellable ? g_object_ref(cancellable) : NULL;
  143. call->cancelled_id = cancellable ? g_signal_connect(cancellable, "cancelled", G_CALLBACK(on_cancelled_cb), call)
  144. : 0;
  145. call->signal_id = g_dbus_connection_signal_subscribe(
  146. portal_get_dbus_connection(), "org.freedesktop.portal.Desktop", "org.freedesktop.portal.Request",
  147. "Response", call->request_path, NULL, G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, on_response_received_cb, call,
  148. NULL);
  149. }