Last active
February 11, 2026 10:06
-
-
Save sulincix/0173bc3fa721dec9a223d433896a14be to your computer and use it in GitHub Desktop.
Wayland xdg-desktop-portal screenshot in C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <gio/gio.h> | |
| #include <stdio.h> | |
| /* gcc glib_screenshot.c -o screenshot `pkg-config --cflags --libs gio-2.0 glib-2.0` */ | |
| static GMainLoop *loop; | |
| /* Response signal handler */ | |
| static void | |
| on_response(GDBusProxy *proxy, | |
| gchar *sender_name, | |
| gchar *signal_name, | |
| GVariant *parameters, | |
| gpointer user_data) | |
| { | |
| if (g_strcmp0(signal_name, "Response") == 0) { | |
| guint32 response; | |
| GVariant *results; | |
| g_variant_get(parameters, "(u@a{sv})", &response, &results); | |
| if (response == 0) { | |
| GVariant *uri_variant = g_variant_lookup_value(results, "uri", G_VARIANT_TYPE_STRING); | |
| if (uri_variant) { | |
| const gchar *uri = g_variant_get_string(uri_variant, NULL); | |
| g_print("Screenshot URI: %s\n", uri); | |
| g_variant_unref(uri_variant); | |
| } | |
| } else { | |
| g_print("Failed to take a screenshot.\n"); | |
| } | |
| g_variant_unref(results); | |
| g_main_loop_quit(loop); | |
| } | |
| } | |
| int main() | |
| { | |
| GError *error = NULL; | |
| /* Connect to session bus */ | |
| GDBusConnection *bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error); | |
| if (!bus) { | |
| g_printerr("Failed to connect to session bus: %s\n", error->message); | |
| g_error_free(error); | |
| return 1; | |
| } | |
| /* Create Screenshot proxy */ | |
| GDBusProxy *proxy = g_dbus_proxy_new_sync( | |
| bus, | |
| G_DBUS_PROXY_FLAGS_NONE, | |
| NULL, | |
| "org.freedesktop.portal.Desktop", | |
| "/org/freedesktop/portal/desktop", | |
| "org.freedesktop.portal.Screenshot", | |
| NULL, | |
| &error | |
| ); | |
| if (!proxy) { | |
| g_printerr("Failed to create proxy: %s\n", error->message); | |
| g_error_free(error); | |
| return 1; | |
| } | |
| /* Build options dictionary */ | |
| GVariantBuilder builder; | |
| g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); | |
| g_variant_builder_add(&builder, "{sv}", | |
| "handle_token", | |
| g_variant_new_string("my_unique_token")); | |
| g_variant_builder_add(&builder, "{sv}", | |
| "interactive", | |
| g_variant_new_boolean(FALSE)); | |
| GVariant *parameters = g_variant_new("(sa{sv})", "", &builder); | |
| /* Call Screenshot method */ | |
| GVariant *result = g_dbus_proxy_call_sync( | |
| proxy, | |
| "Screenshot", | |
| parameters, | |
| G_DBUS_CALL_FLAGS_NONE, | |
| -1, | |
| NULL, | |
| &error | |
| ); | |
| if (!result) { | |
| g_printerr("Screenshot call failed: %s\n", error->message); | |
| g_error_free(error); | |
| return 1; | |
| } | |
| /* Extract request object path */ | |
| const gchar *handle; | |
| g_variant_get(result, "(o)", &handle); | |
| g_variant_unref(result); | |
| /* Create Request proxy */ | |
| GDBusProxy *request_proxy = g_dbus_proxy_new_sync( | |
| bus, | |
| G_DBUS_PROXY_FLAGS_NONE, | |
| NULL, | |
| "org.freedesktop.portal.Desktop", | |
| handle, | |
| "org.freedesktop.portal.Request", | |
| NULL, | |
| &error | |
| ); | |
| if (!request_proxy) { | |
| g_printerr("Failed to create request proxy: %s\n", error->message); | |
| g_error_free(error); | |
| return 1; | |
| } | |
| /* Listen for Response signal */ | |
| g_signal_connect(request_proxy, "g-signal", G_CALLBACK(on_response), NULL); | |
| loop = g_main_loop_new(NULL, FALSE); | |
| g_main_loop_run(loop); | |
| /* Cleanup */ | |
| g_object_unref(request_proxy); | |
| g_object_unref(proxy); | |
| g_object_unref(bus); | |
| g_main_loop_unref(loop); | |
| return 0; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <dbus/dbus.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| /* gcc glib_screenshot.c -o screenshot `pkg-config --cflags --libs dbus-1` */ | |
| static void listen_for_response(DBusConnection *conn, const char *request_path); | |
| int main() { | |
| DBusError err; | |
| dbus_error_init(&err); | |
| DBusConnection *conn = dbus_bus_get(DBUS_BUS_SESSION, &err); | |
| if (dbus_error_is_set(&err)) { | |
| fprintf(stderr, "Connection Error: %s\n", err.message); | |
| dbus_error_free(&err); | |
| return 1; | |
| } | |
| if (!conn) return 1; | |
| DBusMessage *msg = dbus_message_new_method_call( | |
| "org.freedesktop.portal.Desktop", | |
| "/org/freedesktop/portal/desktop", | |
| "org.freedesktop.portal.Screenshot", | |
| "Screenshot" | |
| ); | |
| if (!msg) return 1; | |
| const char *parent_window = ""; | |
| DBusMessageIter args; | |
| dbus_message_iter_init_append(msg, &args); | |
| // string parent_window | |
| dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &parent_window); | |
| // a{sv} options | |
| DBusMessageIter dict; | |
| dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &dict); | |
| // handle_token | |
| DBusMessageIter entry; | |
| dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); | |
| const char *key = "handle_token"; | |
| dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); | |
| DBusMessageIter variant; | |
| dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "s", &variant); | |
| const char *token = "mytoken"; | |
| dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &token); | |
| dbus_message_iter_close_container(&entry, &variant); | |
| dbus_message_iter_close_container(&dict, &entry); | |
| dbus_message_iter_close_container(&args, &dict); | |
| DBusPendingCall *pending; | |
| if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) { | |
| fprintf(stderr, "Out Of Memory!\n"); | |
| return 1; | |
| } | |
| if (!pending) return 1; | |
| dbus_connection_flush(conn); | |
| dbus_message_unref(msg); | |
| dbus_pending_call_block(pending); | |
| DBusMessage *reply = dbus_pending_call_steal_reply(pending); | |
| dbus_pending_call_unref(pending); | |
| if (!reply) return 1; | |
| const char *request_path; | |
| if (!dbus_message_get_args(reply, &err, | |
| DBUS_TYPE_OBJECT_PATH, &request_path, | |
| DBUS_TYPE_INVALID)) { | |
| fprintf(stderr, "Reply Error: %s\n", err.message); | |
| dbus_error_free(&err); | |
| return 1; | |
| } | |
| printf("Request path: %s\n", request_path); | |
| dbus_message_unref(reply); | |
| listen_for_response(conn, request_path); | |
| return 0; | |
| } | |
| static void listen_for_response(DBusConnection *conn, const char *request_path) { | |
| DBusError err; | |
| dbus_error_init(&err); | |
| char match[512]; | |
| snprintf(match, sizeof(match), | |
| "type='signal',interface='org.freedesktop.portal.Request',member='Response',path='%s'", | |
| request_path); | |
| dbus_bus_add_match(conn, match, &err); | |
| dbus_connection_flush(conn); | |
| printf("Waiting for Response signal...\n"); | |
| while (1) { | |
| dbus_connection_read_write(conn, 0); | |
| DBusMessage *msg = dbus_connection_pop_message(conn); | |
| if (!msg) { | |
| usleep(100); | |
| continue; | |
| } | |
| if (dbus_message_is_signal(msg, | |
| "org.freedesktop.portal.Request", | |
| "Response")) { | |
| DBusMessageIter args; | |
| if (!dbus_message_iter_init(msg, &args)) { | |
| printf("Signal has no arguments\n"); | |
| } else { | |
| dbus_uint32_t response; | |
| dbus_message_iter_get_basic(&args, &response); | |
| if (response == 0) { | |
| dbus_message_iter_next(&args); | |
| DBusMessageIter dict; | |
| dbus_message_iter_recurse(&args, &dict); | |
| while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { | |
| DBusMessageIter entry; | |
| dbus_message_iter_recurse(&dict, &entry); | |
| const char *key; | |
| dbus_message_iter_get_basic(&entry, &key); | |
| if (strcmp(key, "uri") == 0) { | |
| dbus_message_iter_next(&entry); | |
| DBusMessageIter variant; | |
| dbus_message_iter_recurse(&entry, &variant); | |
| const char *uri; | |
| dbus_message_iter_get_basic(&variant, &uri); | |
| printf("Screenshot URI: %s\n", uri); | |
| } | |
| dbus_message_iter_next(&dict); | |
| } | |
| } else { | |
| printf("Failed to take screenshot\n"); | |
| } | |
| } | |
| dbus_message_unref(msg); | |
| break; | |
| } | |
| dbus_message_unref(msg); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment