Skip to content

Instantly share code, notes, and snippets.

@LowByteFox
Last active August 7, 2026 05:07
Show Gist options
  • Select an option

  • Save LowByteFox/f392bae6e57eb68d04887310a5caa7c2 to your computer and use it in GitHub Desktop.

Select an option

Save LowByteFox/f392bae6e57eb68d04887310a5caa7c2 to your computer and use it in GitHub Desktop.
libportal file open dialog example
#if 0
set -e
cc -D _GNU_SOURCE -g $(pkg-config --cflags libportal) portal.c -o /tmp/portal $(pkg-config --libs libportal)
/tmp/portal
#endif
/* libportal is licensed under LGPL-3.0-only :/, dynamic linking recommended */
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <libportal/portal.h>
static bool done = false;
static void open_file(XdpPortal *portal);
static void open_files(XdpPortal *portal);
static void save_file(XdpPortal *portal);
static void _files(GObject *src, GAsyncResult *res, gpointer data);
static void _save_file(GObject *src, GAsyncResult *res, gpointer data);
int main()
{
GError *err;
GMainContext *loop = g_main_context_default();
XdpPortal *portal = xdp_portal_initable_new(&err);
if (!portal) {
fprintf(stderr, "error: %s\n", err->message);
return 1;
}
save_file(portal);
while (g_main_context_pending(loop) || !done) {
/* set this to false to not block */
g_main_context_iteration(loop, true);
}
g_object_unref(portal);
g_main_context_unref(loop);
return 0;
}
static void open_file(XdpPortal *portal)
{
GVariantBuilder *a1;
GVariantBuilder *a2;
a1 = g_variant_builder_new(G_VARIANT_TYPE("a(us)"));
a2 = g_variant_builder_new(G_VARIANT_TYPE("a(sa(us))"));
g_variant_builder_add(a1, "(us)", 0, "*.opng");
g_variant_builder_add(a2, "(s@a(us))", "Model", g_variant_builder_end(a1));
GVariant *filters = g_variant_builder_end(a2);
xdp_portal_open_file(portal, NULL, "Open File", filters, NULL, NULL,
XDP_OPEN_FILE_FLAG_NONE, NULL, _files, portal);
}
static void save_file(XdpPortal *portal)
{
GVariantBuilder *a1;
GVariantBuilder *a2;
a1 = g_variant_builder_new(G_VARIANT_TYPE("a(us)"));
a2 = g_variant_builder_new(G_VARIANT_TYPE("a(sa(us))"));
g_variant_builder_add(a1, "(us)", 0, "*.opng");
g_variant_builder_add(a2, "(s@a(us))", "Model", g_variant_builder_end(a1));
GVariant *filters = g_variant_builder_end(a2);
xdp_portal_save_file(portal, NULL, "Save File", "model.opng", NULL, NULL, filters,
NULL, NULL, 0, NULL, _save_file, portal);
}
static void open_files(XdpPortal *portal)
{
GVariantBuilder *a1;
GVariantBuilder *a2;
a1 = g_variant_builder_new(G_VARIANT_TYPE("a(us)"));
a2 = g_variant_builder_new(G_VARIANT_TYPE("a(sa(us))"));
g_variant_builder_add(a1, "(us)", 1, "image/avif");
g_variant_builder_add(a1, "(us)", 0, "*.jxl");
g_variant_builder_add(a1, "(us)", 1, "image/webp");
g_variant_builder_add(a1, "(us)", 0, "*.qoi");
g_variant_builder_add(a1, "(us)", 1, "image/png");
g_variant_builder_add(a1, "(us)", 1, "image/bmp");
g_variant_builder_add(a1, "(us)", 1, "image/jpeg");
g_variant_builder_add(a1, "(us)", 0, "*.tga");
g_variant_builder_add(a1, "(us)", 0, "*.psd");
g_variant_builder_add(a1, "(us)", 0, "*.dds");
g_variant_builder_add(a1, "(us)", 1, "image/gif");
g_variant_builder_add(a1, "(us)", 1, "image/png");
g_variant_builder_add(a1, "(us)", 0, "*.opng");
g_variant_builder_add(a2, "(s@a(us))", "Images", g_variant_builder_end(a1));
GVariant *filters = g_variant_builder_end(a2);
xdp_portal_open_file(portal, NULL, "Open Files", filters, NULL, NULL,
XDP_OPEN_FILE_FLAG_MULTIPLE, NULL, _files, portal);
}
static void _files(GObject *src, GAsyncResult *ares, gpointer data)
{
GError *err = NULL;
XdpPortal *portal = data;
GVariant *res = xdp_portal_open_file_finish(portal, ares, &err);
if (err) {
fprintf(stderr, "error: %s\n", err->message);
exit(1);
}
GVariant *uris = g_variant_lookup_value(res, "uris", NULL);
size_t count = g_variant_n_children(uris);
for (int i = 0; i < count; i++) {
GVariant *uri = g_variant_get_child_value(uris, i);
printf("%s\n", g_variant_get_string(uri, NULL));
g_variant_unref(uri);
}
g_variant_unref(uris);
g_variant_unref(res);
done = true;
}
static void _save_file(GObject *src, GAsyncResult *ares, gpointer data)
{
GError *err = NULL;
XdpPortal *portal = data;
GVariant *res = xdp_portal_save_file_finish(portal, ares, &err);
if (err) {
fprintf(stderr, "error: %s\n", err->message);
exit(1);
}
GVariant *uris = g_variant_lookup_value(res, "uris", NULL);
size_t count = g_variant_n_children(uris);
for (int i = 0; i < count; i++) {
GVariant *uri = g_variant_get_child_value(uris, i);
printf("%s\n", g_variant_get_string(uri, NULL));
g_variant_unref(uri);
}
g_variant_unref(uris);
g_variant_unref(res);
done = true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment