Skip to content

Add API to register app ID #183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions libportal/portal-helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ XdpPortal *xdp_portal_new (void);
XDP_PUBLIC
XdpPortal *xdp_portal_initable_new (GError **error);

XDP_PUBLIC
void xdp_portal_register (XdpPortal *portal,
const char *app_id,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);

XDP_PUBLIC
gboolean xdp_portal_register_finish (XdpPortal *portal,
GAsyncResult *result,
GError **error);

XDP_PUBLIC
gboolean xdp_portal_running_under_flatpak (void);

Expand Down
111 changes: 111 additions & 0 deletions libportal/portal.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,117 @@ xdp_portal_new (void)
return portal;
}

static void
register_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(GTask) task = user_data;
g_autoptr(GVariant) ret = NULL;
g_autoptr(GError) error = NULL;

ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
result,
&error);
if (error)
g_task_return_error (task, g_steal_pointer (&error));
else
g_task_return_boolean (task, TRUE);
}

/**
* xdp_portal_register:
* @portal: a [class@Portal]
* @app_id: an application ID matching the basename of a desktop file
* @cancellable: (nullable): optional [[email protected]]
* @callback: (scope async): a callback to call when the request is done
* @data: (closure): data to pass to @callback
*
* Registers the application ID with the org.freedesktop.host.Registry portal.
* Doing this when sandboxed is a no-op, but when running on the host, it will
* help associating portal requests with an application.
*
* When the request is done, @callback will be called. You can then
* call [[email protected]_finish] to get the results.
*/
void
xdp_portal_register (XdpPortal *portal,
const char *app_id,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
GVariantBuilder options;
g_autoptr(GError) error = NULL;

g_return_if_fail (XDP_IS_PORTAL (portal));
g_return_if_fail (app_id);
g_return_if_fail (g_strcmp0 (app_id, "") != 0);

task = g_task_new (portal, cancellable, callback, user_data);
g_task_set_source_tag (task, xdp_portal_register);

if (xdp_portal_running_under_flatpak ())
{
g_task_return_boolean (task, TRUE);
return;
}

if (xdp_portal_running_under_snap (&error))
{
g_task_return_boolean (task, TRUE);
return;
}

if (error)
{
g_task_return_error (task, error);
return;
}

g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);

g_dbus_connection_call (portal->bus,
PORTAL_BUS_NAME,
PORTAL_OBJECT_PATH,
"org.freedesktop.host.portal.Registry",
"Register",
g_variant_new ("(sa{sv})", app_id, &options),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
register_cb,
g_object_ref (task));
}

/**
* xdp_portal_register_finish:
* @portal: a [class@Portal]
* @result: a [[email protected]]
* @error: return location for an error
*
* Finishes the registry registration request.
*
* Returns %TRUE if the registration succeeded, or app was sandboxed, in which
* case, the operation was a no-op.
*
* Returns: %TRUE on success
*/
gboolean
xdp_portal_register_finish (XdpPortal *portal,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (XDP_IS_PORTAL (portal), FALSE);
g_return_val_if_fail (g_task_is_valid (result, portal), FALSE);
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
xdp_portal_register, FALSE);

return g_task_propagate_boolean (G_TASK (result), error);
}

/* This function is copied from xdg-desktop-portal */
static int
_xdp_parse_cgroup_file (FILE *f, gboolean *is_snap)
Expand Down
36 changes: 35 additions & 1 deletion portal-test/gtk3/portal-test-win.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,28 @@ settings_changed (XdpSettings* settings, const gchar *namespace, const gchar *ke
}

static void
portal_test_win_init (PortalTestWin *win)
register_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
XdpPortal *portal = XDP_PORTAL (source_object);
g_autoptr(GError) error = NULL;

if (!xdp_portal_register_finish (portal, result, &error))
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Failed to register application ID: %s", error->message);
return;
}

g_debug ("Registered application ID");
}

static void
portal_test_win_realize (GtkWidget *widget)
{
PortalTestWin *win = (PortalTestWin *) widget;
GtkApplication *app = gtk_window_get_application (GTK_WINDOW (win));
const char *status;
g_auto(GStrv) proxies = NULL;
g_autofree char *proxy = NULL;
Expand All @@ -312,6 +332,11 @@ portal_test_win_init (PortalTestWin *win)
g_autoptr(GFile) src = NULL;

win->portal = xdp_portal_new ();
xdp_portal_register (win->portal,
g_application_get_application_id (G_APPLICATION (app)),
NULL,
register_cb,
NULL);

gtk_widget_init_template (GTK_WIDGET (win));

Expand Down Expand Up @@ -357,6 +382,13 @@ portal_test_win_init (PortalTestWin *win)

win->settings = xdp_portal_get_settings (win->portal);
g_signal_connect (win->settings, "changed", G_CALLBACK (settings_changed), win);

GTK_WIDGET_CLASS (portal_test_win_parent_class)->realize (widget);
}

static void
portal_test_win_init (PortalTestWin *win)
{
}

static void
Expand Down Expand Up @@ -1394,6 +1426,8 @@ portal_test_win_class_init (PortalTestWinClass *class)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);

widget_class->realize = portal_test_win_realize;

gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/portal-test/portal-test-win.ui");

Expand Down
11 changes: 10 additions & 1 deletion portal-test/gtk4/application.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { Gio, GLib, GObject, Gtk } = imports.gi;
const { Gio, GLib, GObject, Gtk, Xdp } = imports.gi;

const { PortalTestWindow } = imports.window;
const ByteArray = imports.byteArray;
Expand Down Expand Up @@ -31,12 +31,21 @@ var Application = GObject.registerClass({
}

vfunc_startup() {
this._portal = new Xdp.Portal();
this._portal.register(this.get_application_id(), null, (portal, result) => {
this._portal.register_finish(result);
});

super.vfunc_startup();

if (!this._window)
this._window = new PortalTestWindow(this);
}

getPortal() {
return this._portal;
}

restart() {
const bus = this.get_dbus_connection();

Expand Down
2 changes: 1 addition & 1 deletion portal-test/gtk4/window.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var PortalTestWindow = GObject.registerClass({
super._init({ application });

this._app = application;
this._portal = new Xdp.Portal();
this._portal = application.getPortal();

this._restoreToken = null;

Expand Down
6 changes: 5 additions & 1 deletion portal-test/qt5/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@

#include "portal-test-qt.h"

#define APP_ID "org.freedesktop.PortalTest.Qt5"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

PortalTestQt *portalTest = new PortalTestQt(nullptr);
a.setDesktopFileName(APP_ID);

PortalTestQt *portalTest = new PortalTestQt(&a, nullptr);
portalTest->show();

return a.exec();
Expand Down
2 changes: 2 additions & 0 deletions portal-test/qt5/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ prep = qt5.preprocess(
dependencies: libportal_qt5_dep,
)

install_data('org.freedesktop.PortalTest.Qt5.desktop', install_dir: 'share/applications')

executable('portal-test-qt5',
[src, prep],
include_directories: [top_inc, libportal_inc],
Expand Down
5 changes: 5 additions & 0 deletions portal-test/qt5/org.freedesktop.PortalTest.Qt5.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Desktop Entry]
Name=Portal test (GTK3)
Exec=portal-test-gtk3
Type=Application
DBusActivatable=true
21 changes: 20 additions & 1 deletion portal-test/qt5/portal-test-qt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,30 @@

#include <QStringLiteral>

PortalTestQt::PortalTestQt(QWidget *parent, Qt::WindowFlags f)
PortalTestQt::PortalTestQt(QApplication *app, QWidget *parent, Qt::WindowFlags f)
: QMainWindow(parent, f)
, m_mainWindow(new Ui_PortalTestQt)
, m_app(app)
, m_portal(xdp_portal_new())
{
QString app_id = app->desktopFileName();
xdp_portal_register(m_portal, app_id.toLocal8Bit().constData(), nullptr /*cancellable*/,
[](GObject *source_object, GAsyncResult *result, gpointer user_data)
{
Q_UNUSED(user_data)

XdpPortal *portal = XDP_PORTAL (source_object);
g_autoptr(GError) error = NULL;
if (!xdp_portal_register_finish (portal, result, &error))
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
qWarning ("Failed to register application ID: %s", error->message);
return;
}
qInfo ("Registered application ID");
},
nullptr);

m_mainWindow->setupUi(this);

connect(m_mainWindow->openFileButton, &QPushButton::clicked, [=] (G_GNUC_UNUSED bool clicked) {
Expand Down
3 changes: 2 additions & 1 deletion portal-test/qt5/portal-test-qt.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ class PortalTestQt : public QMainWindow
{
Q_OBJECT
public:
PortalTestQt(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
PortalTestQt(QApplication *app, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
~PortalTestQt();

void updateLastOpenedFile(const QString &file);
private:
static void openedFile(GObject *object, GAsyncResult *result, gpointer data);

Ui_PortalTestQt *m_mainWindow;
QApplication *m_app;
XdpPortal *m_portal;
};

Expand Down
26 changes: 24 additions & 2 deletions portal-test/qt6/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,33 @@

#include "portal-test-qt.h"

#define APP_ID "org.gnome.PortalTest.Qt6"


int main(int argc, char *argv[])
{
QApplication a(argc, argv);
XdpPortal *portal = xdp_portal_new();
xdp_portal_register(portal, APP_ID, nullptr /*cancellable*/,
[](GObject *source_object, GAsyncResult *result, gpointer user_data)
{
Q_UNUSED(user_data)

XdpPortal *portal = XDP_PORTAL (source_object);
g_autoptr(GError) error = NULL;
if (!xdp_portal_register_finish (portal, result, &error))
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
qWarning ("Failed to register application ID: %s", error->message);
return;
}

PortalTestQt *portalTest = new PortalTestQt(nullptr);
qInfo ("Registered application ID");
},
nullptr);


QApplication a(argc, argv);
PortalTestQt *portalTest = new PortalTestQt(portal, nullptr);
portalTest->show();

return a.exec();
Expand Down
2 changes: 2 additions & 0 deletions portal-test/qt6/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ prep = qt6.preprocess(
dependencies: libportal_qt6_dep,
)

install_data('org.freedesktop.PortalTest.Qt6.desktop', install_dir: 'share/applications')

executable('portal-test-qt6',
[src, prep],
include_directories: [top_inc, libportal_inc],
Expand Down
5 changes: 5 additions & 0 deletions portal-test/qt6/org.freedesktop.PortalTest.Qt6.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Desktop Entry]
Name=Portal test (GTK3)
Exec=portal-test-gtk3
Type=Application
DBusActivatable=true
4 changes: 2 additions & 2 deletions portal-test/qt6/portal-test-qt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

#include <QStringLiteral>

PortalTestQt::PortalTestQt(QWidget *parent, Qt::WindowFlags f)
PortalTestQt::PortalTestQt(XdpPortal *portal, QWidget *parent, Qt::WindowFlags f)
: QMainWindow(parent, f)
, m_mainWindow(new Ui_PortalTestQt)
, m_portal(xdp_portal_new())
, m_portal(portal)
{
m_mainWindow->setupUi(this);

Expand Down
2 changes: 1 addition & 1 deletion portal-test/qt6/portal-test-qt.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class PortalTestQt : public QMainWindow
{
Q_OBJECT
public:
PortalTestQt(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
PortalTestQt(XdpPortal *portal, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
~PortalTestQt();

void updateLastOpenedFile(const QString &file);
Expand Down
Loading