summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2020-01-22 18:39:26 +0100
committerCarlos Garnacho <carlosg@gnome.org>2020-07-17 09:33:38 +0200
commit41017d120d480957d7a44ba662f290a6415e840c (patch)
tree925b8b233ef194dcf33dba5af1fc2f0762bd88c2 /src
parentac3eeb8b730eb6959240c4c236385152bb04143c (diff)
downloadtracker-41017d120d480957d7a44ba662f290a6415e840c.tar.gz
portal: Add XDG portal implementation
Diffstat (limited to 'src')
-rw-r--r--src/meson.build3
-rw-r--r--src/portal/meson.build14
-rw-r--r--src/portal/tracker-main.c153
-rw-r--r--src/portal/tracker-portal-utils.c176
-rw-r--r--src/portal/tracker-portal-utils.h31
-rw-r--r--src/portal/tracker-portal.c298
-rw-r--r--src/portal/tracker-portal.h33
7 files changed, 708 insertions, 0 deletions
diff --git a/src/meson.build b/src/meson.build
index 2f9817ece..78f21b9b9 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -16,3 +16,6 @@ subdir('libtracker-sparql')
# Public commandline control tool
subdir('tracker')
+
+# XDG Portal
+subdir('portal')
diff --git a/src/portal/meson.build b/src/portal/meson.build
new file mode 100644
index 000000000..9b801d975
--- /dev/null
+++ b/src/portal/meson.build
@@ -0,0 +1,14 @@
+sources = [
+ 'tracker-main.c',
+ 'tracker-portal.c',
+ 'tracker-portal-utils.c',
+]
+
+executable('tracker-xdg-portal-@0@'.format(tracker_api_major), sources,
+ c_args: tracker_c_args,
+ install: true,
+ install_rpath: tracker_install_rpath,
+ install_dir: get_option('libexecdir'),
+ dependencies: [tracker_sparql_dep],
+ include_directories: [commoninc, configinc, srcinc],
+)
diff --git a/src/portal/tracker-main.c b/src/portal/tracker-main.c
new file mode 100644
index 000000000..e8977fc4b
--- /dev/null
+++ b/src/portal/tracker-main.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2020, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <locale.h>
+
+#include <glib.h>
+#include <glib-unix.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <libtracker-common/tracker-common.h>
+
+#include "tracker-portal.h"
+
+static gboolean version = FALSE;
+
+const char usage_string[] =
+ "xdg-tracker-portal [--version | -v]";
+
+const char about[] =
+ "Tracker XDG portal " PACKAGE_VERSION "\n"
+ "\n"
+ "This program is free software and comes without any warranty.\n"
+ "It is licensed under version 2 or later of the General Public "
+ "License which can be viewed at:\n"
+ "\n"
+ " http://www.gnu.org/licenses/gpl.txt"
+ "\n";
+
+static GOptionEntry entries[] = {
+ { "version", 'v', 0, G_OPTION_ARG_NONE, &version,
+ N_("Version"),
+ NULL
+ },
+};
+
+static int
+print_version (void)
+{
+ puts (about);
+ return 0;
+}
+
+static gboolean
+sigterm_cb (gpointer user_data)
+{
+ g_main_loop_quit (user_data);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+name_acquired_callback (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_debug ("Name '%s' acquired", name);
+ g_main_loop_quit (user_data);
+}
+
+static void
+name_lost_callback (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_critical ("Name '%s' lost", name);
+ exit (EXIT_FAILURE);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GMainLoop *main_loop;
+ g_autoptr(GError) error = NULL;
+ GDBusConnection *connection;
+ g_autoptr(GOptionContext) context = NULL;
+ TrackerPortal *portal;
+
+ setlocale (LC_ALL, "");
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ context = g_option_context_new (NULL);
+ g_option_context_add_main_entries (context, entries, NULL);
+
+ if (!g_option_context_parse (context, &argc, (char***) &argv, &error)) {
+ g_printerr ("%s, %s\n", _("Unrecognized options"), error->message);
+ g_error_free (error);
+ return EXIT_FAILURE;
+ }
+
+ if (version) {
+ print_version ();
+ return EXIT_SUCCESS;
+ }
+
+ connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ if (!connection) {
+ g_printerr ("%s", error->message);
+ return EXIT_FAILURE;
+ }
+
+ main_loop = g_main_loop_new (NULL, FALSE);
+
+ g_bus_own_name_on_connection (connection,
+ "org.freedesktop.portal.Tracker",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ name_acquired_callback,
+ name_lost_callback,
+ g_main_loop_ref (main_loop),
+ (GDestroyNotify) g_main_loop_unref);
+
+ g_main_loop_run (main_loop);
+
+ portal = tracker_portal_new (connection, NULL, &error);
+ if (!portal) {
+ g_printerr ("%s", error->message);
+ return EXIT_FAILURE;
+ }
+
+ g_unix_signal_add (SIGINT, sigterm_cb, main_loop);
+ g_unix_signal_add (SIGTERM, sigterm_cb, main_loop);
+ g_main_loop_run (main_loop);
+
+ g_main_loop_unref (main_loop);
+
+ g_clear_object (&portal);
+
+ return EXIT_FAILURE;
+}
diff --git a/src/portal/tracker-portal-utils.c b/src/portal/tracker-portal-utils.c
new file mode 100644
index 000000000..2582a720e
--- /dev/null
+++ b/src/portal/tracker-portal-utils.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright © 2014 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ *
+ * Code borrowed from xdg-desktop-portal/src/xdp-utils.[ch]
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "tracker-portal-utils.h"
+
+#define DBUS_NAME_DBUS "org.freedesktop.DBus"
+#define DBUS_INTERFACE_DBUS DBUS_NAME_DBUS
+#define DBUS_PATH_DBUS "/org/freedesktop/DBus"
+
+static GKeyFile *
+parse_app_info_from_flatpak_info (int pid, GError **error)
+{
+ g_autofree char *root_path = NULL;
+ int root_fd = -1;
+ int info_fd = -1;
+ struct stat stat_buf;
+ g_autoptr(GError) local_error = NULL;
+ g_autoptr(GMappedFile) mapped = NULL;
+ g_autoptr(GKeyFile) metadata = NULL;
+ g_autofree char *id = NULL;
+
+ root_path = g_strdup_printf ("/proc/%u/root", pid);
+ root_fd = openat (AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
+ if (root_fd == -1) {
+ /* Not able to open the root dir shouldn't happen. Probably the app died and
+ * we're failing due to /proc/$pid not existing. In that case fail instead
+ * of treating this as privileged. */
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Unable to open %s", root_path);
+ return NULL;
+ }
+
+ metadata = g_key_file_new ();
+
+ info_fd = openat (root_fd, ".flatpak-info", O_RDONLY | O_CLOEXEC | O_NOCTTY);
+ close (root_fd);
+ if (info_fd == -1) {
+ if (errno == ENOENT) {
+ /* No file => on the host, return NULL with no error */
+ return NULL;
+ }
+
+ /* Some weird error => failure */
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Unable to open application info file");
+ return NULL;
+ }
+
+ if (fstat (info_fd, &stat_buf) != 0 || !S_ISREG (stat_buf.st_mode)) {
+ /* Some weird fd => failure */
+ close (info_fd);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Unable to open application info file");
+ return NULL;
+ }
+
+ mapped = g_mapped_file_new_from_fd (info_fd, FALSE, &local_error);
+ if (mapped == NULL) {
+ close (info_fd);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Can't map .flatpak-info file: %s", local_error->message);
+ return NULL;
+ }
+
+ if (!g_key_file_load_from_data (metadata,
+ g_mapped_file_get_contents (mapped),
+ g_mapped_file_get_length (mapped),
+ G_KEY_FILE_NONE, &local_error)) {
+ close (info_fd);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Can't load .flatpak-info file: %s", local_error->message);
+ return NULL;
+ }
+
+ close (info_fd);
+
+ return g_steal_pointer (&metadata);
+}
+
+static GKeyFile *
+tracker_connection_lookup_app_info_sync (GDBusConnection *connection,
+ const char *sender,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(GDBusMessage) msg = NULL;
+ g_autoptr(GDBusMessage) reply = NULL;
+ GVariant *body;
+ g_autoptr(GVariantIter) iter = NULL;
+ g_autoptr(GKeyFile) app_info = NULL;
+ const char *key;
+ GVariant *value;
+ g_autoptr(GError) local_error = NULL;
+ guint32 pid = 0;
+
+ msg = g_dbus_message_new_method_call (DBUS_NAME_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "GetConnectionCredentials");
+ g_dbus_message_set_body (msg, g_variant_new ("(s)", sender));
+
+ reply = g_dbus_connection_send_message_with_reply_sync (connection, msg,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ 30000,
+ NULL,
+ cancellable,
+ error);
+ if (reply == NULL)
+ return NULL;
+
+ if (g_dbus_message_get_message_type (reply) == G_DBUS_MESSAGE_TYPE_ERROR) {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find peer app id");
+ return NULL;
+ }
+
+ body = g_dbus_message_get_body (reply);
+
+ g_variant_get (body, "(a{sv})", &iter);
+ while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) {
+ if (strcmp (key, "ProcessID") == 0)
+ pid = g_variant_get_uint32 (value);
+ }
+
+ if (pid == 0) {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't find app PID");
+ return NULL;
+ }
+
+ app_info = parse_app_info_from_flatpak_info (pid, &local_error);
+
+ if (app_info == NULL && local_error) {
+ g_propagate_error (error, g_steal_pointer (&local_error));
+ return NULL;
+ }
+
+ return g_steal_pointer (&app_info);
+}
+
+GKeyFile *
+tracker_invocation_lookup_app_info_sync (GDBusMethodInvocation *invocation,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GDBusConnection *connection = g_dbus_method_invocation_get_connection (invocation);
+ const gchar *sender = g_dbus_method_invocation_get_sender (invocation);
+
+ return tracker_connection_lookup_app_info_sync (connection, sender, cancellable, error);
+}
diff --git a/src/portal/tracker-portal-utils.h b/src/portal/tracker-portal-utils.h
new file mode 100644
index 000000000..dcae4a0e3
--- /dev/null
+++ b/src/portal/tracker-portal-utils.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2014 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexander Larsson <alexl@redhat.com>
+ *
+ * Code borrowed from xdg-desktop-portal/src/xdp-utils.[ch]
+ */
+#ifndef __TRACKER_PORTAL_UTILS_H__
+#define __TRACKER_PORTAL_UTILS_H__
+
+#include <gio/gio.h>
+
+GKeyFile * tracker_invocation_lookup_app_info_sync (GDBusMethodInvocation *invocation,
+ GCancellable *cancellable,
+ GError **error);
+
+#endif /* __TRACKER_PORTAL_UTILS_H__ */
diff --git a/src/portal/tracker-portal.c b/src/portal/tracker-portal.c
new file mode 100644
index 000000000..87c2832e3
--- /dev/null
+++ b/src/portal/tracker-portal.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2020, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#include "config.h"
+
+#include <libtracker-sparql/tracker-sparql.h>
+#include <libtracker-common/tracker-common.h>
+
+#include "tracker-portal.h"
+
+typedef struct _TrackerPortal TrackerPortal;
+typedef struct _TrackerSession TrackerSession;
+
+struct _TrackerSession
+{
+ TrackerSparqlConnection *connection;
+ GDBusConnection *dbus_connection;
+ TrackerEndpoint *endpoint;
+ gchar *object_path;
+};
+
+struct _TrackerPortal
+{
+ GObject parent_instance;
+ GDBusConnection *dbus_connection;
+ guint register_id;
+ GDBusNodeInfo *node_info;
+ GCancellable *cancellable;
+ GArray *sessions;
+ guint64 session_ids;
+};
+
+enum
+{
+ PROP_DBUS_CONNECTION = 1,
+ N_PROPS
+};
+
+static GParamSpec *props[N_PROPS] = { 0 };
+
+static void tracker_portal_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (TrackerPortal, tracker_portal, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, tracker_portal_initable_iface_init))
+
+static const gchar portal_xml[] =
+ "<node>"
+ " <interface name='org.freedesktop.portal.Tracker'>"
+ " <method name='CreateSession'>"
+ " <arg type='s' name='service' direction='in' />"
+ " <arg type='o' name='result' direction='out' />"
+ " </method>"
+ " </interface>"
+ "</node>";
+
+static void
+tracker_portal_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TrackerPortal *portal = TRACKER_PORTAL (object);
+
+ switch (prop_id) {
+ case PROP_DBUS_CONNECTION:
+ portal->dbus_connection = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tracker_portal_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TrackerPortal *portal = TRACKER_PORTAL (object);
+
+ switch (prop_id) {
+ case PROP_DBUS_CONNECTION:
+ g_value_set_object (value, portal->dbus_connection);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tracker_portal_finalize (GObject *object)
+{
+ TrackerPortal *portal = TRACKER_PORTAL (object);
+
+ g_debug ("Finalizing Tracker portal");
+
+ g_clear_pointer (&portal->sessions, g_array_unref);
+
+ if (portal->register_id != 0) {
+ g_dbus_connection_unregister_object (portal->dbus_connection,
+ portal->register_id);
+ portal->register_id = 0;
+ }
+
+ g_clear_object (&portal->dbus_connection);
+ g_clear_pointer (&portal->node_info,
+ g_dbus_node_info_unref);
+
+ G_OBJECT_CLASS (tracker_portal_parent_class)->finalize (object);
+ g_debug ("Tracker portal finalized");
+}
+
+static void
+tracker_portal_class_init (TrackerPortalClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = tracker_portal_set_property;
+ object_class->get_property = tracker_portal_get_property;
+ object_class->finalize = tracker_portal_finalize;
+
+ props[PROP_DBUS_CONNECTION] =
+ g_param_spec_object ("dbus-connection",
+ "DBus connection",
+ "DBus connection",
+ G_TYPE_DBUS_CONNECTION,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class, N_PROPS, props);
+}
+
+static void
+clear_session (gpointer user_data)
+{
+ TrackerSession *session = user_data;
+
+ g_debug ("Closing session '%s'", session->object_path);
+ g_clear_object (&session->endpoint);
+ g_clear_object (&session->connection);
+ g_clear_object (&session->dbus_connection);
+ g_clear_pointer (&session->object_path, g_free);
+}
+
+static void
+tracker_portal_init (TrackerPortal *portal)
+{
+ portal->sessions = g_array_new (FALSE, TRUE, sizeof (TrackerSession));
+ g_array_set_clear_func (portal->sessions, clear_session);
+}
+
+static void
+portal_iface_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ TrackerPortal *portal = user_data;
+
+ if (g_strcmp0 (method_name, "CreateSession") == 0) {
+ g_autofree gchar *uri = NULL;
+ g_autofree gchar *service = NULL;
+ g_autofree gchar *object_path = NULL;
+ g_autofree gchar *session_object_path = NULL;
+ g_autoptr(GDBusConnection) dbus_connection = NULL;
+ g_autoptr(TrackerSparqlConnection) connection = NULL;
+ g_autoptr(TrackerEndpoint) endpoint = NULL;
+ g_autoptr(GError) error = NULL;
+ GBusType bus_type;
+ TrackerSession session;
+
+ g_variant_get (parameters, "(s)", &uri);
+ g_debug ("Creating session for service URI '%s'", uri);
+
+ if (!tracker_util_parse_dbus_uri (uri,
+ &bus_type,
+ &service,
+ &object_path)) {
+ g_debug ("Could not parse URI '%s'", uri);
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Service cannot be parsed");
+ return;
+ }
+
+ dbus_connection = g_bus_get_sync (bus_type, NULL, &error);
+
+ if (!dbus_connection) {
+ g_debug ("Could not get bus connection");
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return;
+ }
+
+ connection = tracker_sparql_connection_bus_new (service, object_path, dbus_connection, &error);
+ if (!connection) {
+ g_debug ("Could not stablish connection to service");
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return;
+ }
+
+ session_object_path = g_strdup_printf ("/org/freedesktop/portal/Tracker/Session_%" G_GUINT64_FORMAT,
+ portal->session_ids++);
+
+ endpoint = TRACKER_ENDPOINT (tracker_endpoint_dbus_new (connection,
+ dbus_connection,
+ session_object_path,
+ NULL,
+ &error));
+ if (!endpoint) {
+ g_debug ("Could not create endpoint");
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return;
+ }
+
+ session = (TrackerSession) {
+ .dbus_connection = g_steal_pointer (&dbus_connection),
+ .connection = g_steal_pointer (&connection),
+ .endpoint = g_steal_pointer (&endpoint),
+ .object_path = g_steal_pointer (&session_object_path),
+ };
+ g_array_append_val (portal->sessions, session);
+
+ g_debug ("Created session object '%s'", session.object_path);
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(o)", session.object_path));
+ } else {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_UNKNOWN_METHOD,
+ "Unknown method '%s'", method_name);
+ }
+}
+
+static gboolean
+tracker_portal_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerPortal *portal = TRACKER_PORTAL (initable);
+
+ portal->node_info = g_dbus_node_info_new_for_xml (portal_xml, error);
+ if (!portal->node_info)
+ return FALSE;
+
+ portal->register_id =
+ g_dbus_connection_register_object (portal->dbus_connection,
+ "/org/freedesktop/portal/Tracker",
+ portal->node_info->interfaces[0],
+ &(GDBusInterfaceVTable) {
+ portal_iface_method_call,
+ NULL,
+ NULL
+ },
+ portal,
+ NULL,
+ error);
+ return TRUE;
+}
+
+static void
+tracker_portal_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = tracker_portal_initable_init;
+}
+
+TrackerPortal *
+tracker_portal_new (GDBusConnection *connection,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return g_initable_new (TRACKER_TYPE_PORTAL, cancellable, error,
+ "dbus-connection", connection,
+ NULL);
+}
diff --git a/src/portal/tracker-portal.h b/src/portal/tracker-portal.h
new file mode 100644
index 000000000..dcf0b4e71
--- /dev/null
+++ b/src/portal/tracker-portal.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg@gnome.org>
+ */
+#ifndef __TRACKER_PORTAL_H__
+#define __TRACKER_PORTAL_H__
+
+#include <gio/gio.h>
+
+#define TRACKER_TYPE_PORTAL tracker_portal_get_type ()
+G_DECLARE_FINAL_TYPE (TrackerPortal, tracker_portal, TRACKER, PORTAL, GObject)
+
+TrackerPortal * tracker_portal_new (GDBusConnection *connection,
+ GCancellable *cancellable,
+ GError **error);
+
+#endif /* __TRACKER_PORTAL_H__ */