#include "arc/linux/dbus/dbus.h" #include "arc/linux/dbus/helpers.h" #include #include static const char *handleCStr = "ARC_Controller"; static const char *sessionHandleCStr = "arc_controller"; static const char *busNameCStr = "org.freedesktop.portal.Desktop"; static const char *requestInterfaceCStr = "org.freedesktop.portal.Request"; static const char *shortcutInterfaceCStr = "org.freedesktop.portal.GlobalShortcuts"; static const char *objectPathCStr = "/org/freedesktop/portal/desktop"; typedef struct ARC_DBus { DBusConnection *connection; DBusError error; const char *handle; } ARC_DBus; typedef struct ARC_DBusShortcut { const char *id; const char *description; const char *preferredTrigger; } ARC_DBusShortcut; void ARC_DBus_Create(ARC_DBus **dbus){ *dbus = (ARC_DBus *)malloc(sizeof(ARC_DBus)); dbus_error_init(&((*dbus)->error)); (*dbus)->connection = dbus_bus_get(DBUS_BUS_SESSION, &((*dbus)->error)); if((*dbus)->connection == NULL){ printf("Connection to D-Bus failed %s\n", ((*dbus)->error).message); dbus_error_free(&((*dbus)->error)); free(*dbus); *dbus = NULL; return; } } void ARC_DBus_Destroy(ARC_DBus *dbus){ dbus_error_free(&(dbus->error)); dbus_connection_unref(dbus->connection); free(dbus); } //Docs: https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Request.html#org-freedesktop-portal-request-response void ARC_DBus_RequestResponse(){ //create the create session message DBusMessage *message = dbus_message_new_method_call(busNameCStr, objectPathCStr, requestInterfaceCStr, "Response"); if(!message){ //TODO: arc errno stuff here printf("Message creation failed\n"); return; } //initialize the message arguments DBusMessageIter arguments; dbus_message_iter_init_append(message, &arguments); } //Docs: https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.GlobalShortcuts.html#org-freedesktop-portal-globalshortcuts-createsession void ARC_DBus_InitSession(ARC_DBus *dbus){ //create the create session message DBusMessage *message = dbus_message_new_method_call(busNameCStr, objectPathCStr, shortcutInterfaceCStr, "CreateSession"); if(!message){ //TODO: arc errno stuff here printf("Message creation failed\n"); return; } //initialize the message arguments DBusMessageIter arguments; dbus_message_iter_init_append(message, &arguments); //create the dictionary to add the message arguments to and make sure it can open DBusMessageIter dictonaryIter; if(!dbus_message_iter_open_container(&arguments, DBUS_TYPE_ARRAY, "{sv}", &dictonaryIter)){ printf("Failed to append array to the message\n"); return; } //init variable container for handle and session handle ARC_DBusHelper_AddStringVarientStringToMessageIterDictionary(&dictonaryIter, "handle_token" , handleCStr); ARC_DBusHelper_AddStringVarientStringToMessageIterDictionary(&dictonaryIter, "session_handle_token", sessionHandleCStr); //close to be able to send the message dbus_message_iter_close_container(&arguments, &dictonaryIter); //send the message and store the handle response in a reply message DBusMessage *reply = dbus_connection_send_with_reply_and_block(dbus->connection, message, -1, &(dbus->error)); if(reply == NULL){ //TODO: arc errno stuff here printf("ERROR: %s\n", dbus->error.message); } //wait until message queue is empty then clean up the message dbus_connection_flush(dbus->connection); dbus_message_unref(message); //get the reply message iterator and make sure it stores an object (this will be a handle on success) DBusMessageIter replyIter; dbus_message_iter_init(reply, &replyIter); if(dbus_message_iter_get_arg_type(&replyIter) != 'o'){ //TODO: arc errno stuff here printf("object expected, but recieved something else, '%c'\n", (char)dbus_message_iter_get_arg_type(&replyIter)); return; } //store the handle from the iterator into the dbus type //TODO: probably want to warn if dbus->handle already stores something dbus_message_iter_get_basic(&replyIter, &(dbus->handle)); //request response shit? // dbus_connection_read_write(dbus->connection, 0); // // DBusMessage *message = dbus_connection_pop_message(dbus->connection); // if(message == NULL){ // continue; // } //cleanup dbus_message_unref(reply); } //Docs: https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.GlobalShortcuts.html#org-freedesktop-portal-globalshortcuts-bindshortcuts //NOTE: this is a vector of ARC_DBusShortcut void ARC_DBus_BindShortcuts(ARC_DBus *dbus, ARC_Vector *dbusShortcutVector){ //create the create session message DBusMessage *message = dbus_message_new_method_call(busNameCStr, objectPathCStr, shortcutInterfaceCStr, "BindShortcuts"); if(!message){ //TODO: arc errno stuff here printf("Message creation failed\n"); return; } //initialize the message arguments DBusMessageIter arguments; dbus_message_iter_init_append(message, &arguments); /* ~ session handle ~ */ dbus_message_iter_append_basic(&arguments, DBUS_TYPE_OBJECT_PATH, &(dbus->handle)); /* ~ shortcuts ~ */ //create the dictionary to add the message arguments to and make sure it can open DBusMessageIter shortcutsIter; if(!dbus_message_iter_open_container(&arguments, DBUS_TYPE_ARRAY, "(sa{sv})", &shortcutsIter)){ printf("Failed to append array to the message\n"); return; } //add all the shortcuts from the vector to the shortcuts for(uint32_t index = 0; index < ARC_Vector_GetSize(dbusShortcutVector); index++){ DBusMessageIter shortcutStructIter; if(!dbus_message_iter_open_container(&shortcutsIter, DBUS_TYPE_STRUCT, NULL, &shortcutStructIter)){ printf("Failed to append array to the message\n"); return; } ARC_DBusShortcut *shortcut = ARC_Vector_Get(dbusShortcutVector, index); dbus_message_iter_append_basic(&shortcutStructIter, DBUS_TYPE_STRING, &shortcut->id); DBusMessageIter shortcutItemIter; if(!dbus_message_iter_open_container(&shortcutStructIter, DBUS_TYPE_ARRAY, "{sv}", &shortcutItemIter)){ printf("Failed to append array to the message\n"); return; } //add the shortcut to the dictionary ARC_DBusHelper_AddStringVarientStringToMessageIterDictionary(&shortcutItemIter, shortcut->description, shortcut->preferredTrigger); //close to be able to send the message dbus_message_iter_close_container(&shortcutStructIter, &shortcutItemIter); dbus_message_iter_close_container(&shortcutsIter, &shortcutStructIter); } //close to be able to send the message dbus_message_iter_close_container(&arguments, &shortcutsIter); /* ~ parent window ~ */ const char *parentWindow = ""; dbus_message_iter_append_basic(&arguments, DBUS_TYPE_STRING, &parentWindow); /* ~ options ~ */ DBusMessageIter optionsIter; if(!dbus_message_iter_open_container(&arguments, DBUS_TYPE_ARRAY, "{sv}", &optionsIter)){ printf("Failed to append array to the message\n"); return; } dbus_message_iter_close_container(&arguments, &optionsIter); //send the message and store the handle response in a reply message DBusMessage *reply = dbus_connection_send_with_reply_and_block(dbus->connection, message, -1, &(dbus->error)); if(reply == NULL){ //TODO: arc errno stuff here printf("ERROR: %s\n", dbus->error.message); } //wait until message queue is empty then clean up the message dbus_connection_flush(dbus->connection); dbus_message_unref(message); //get the reply message iterator and make sure it stores an object (this will be a handle on success) DBusMessageIter replyIter; dbus_message_iter_init(reply, &replyIter); if(dbus_message_iter_get_arg_type(&replyIter) != 'o'){ //TODO: arc errno stuff here printf("object expected, but recieved something else, '%c'\n", (char)dbus_message_iter_get_arg_type(&replyIter)); return; } //get the request handle. not sure what to do with this yet... const char *requestHandle; dbus_message_iter_get_basic(&replyIter, &requestHandle); printf("Request Handle: %s\n", requestHandle); //cleanup dbus_message_unref(reply); } //NOTE: https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.GlobalShortcuts.html#org-freedesktop-portal-globalshortcuts-listshortcuts void ARC_DBus_ListShortcuts(ARC_DBus *dbus){ //create the create session message DBusMessage *message = dbus_message_new_method_call(busNameCStr, objectPathCStr, shortcutInterfaceCStr, "ListShortcuts"); if(!message){ //TODO: arc errno stuff here printf("Message creation failed\n"); return; } //initialize the message arguments DBusMessageIter arguments; dbus_message_iter_init_append(message, &arguments); /* ~ session handle ~ */ dbus_message_iter_append_basic(&arguments, DBUS_TYPE_OBJECT_PATH, &(dbus->handle)); /* ~ options ~ */ DBusMessageIter optionsIter; if(!dbus_message_iter_open_container(&arguments, DBUS_TYPE_ARRAY, "{sv}", &optionsIter)){ printf("Failed to append array to the message\n"); return; } dbus_message_iter_close_container(&arguments, &optionsIter); //send the message and store the handle response in a reply message DBusMessage *reply = dbus_connection_send_with_reply_and_block(dbus->connection, message, -1, &(dbus->error)); if(reply == NULL){ //TODO: arc errno stuff here printf("ERROR: %s\n", dbus->error.message); } //wait until message queue is empty then clean up the message dbus_connection_flush(dbus->connection); dbus_message_unref(message); /* //get the reply message iterator and make sure it stores an object (this will be a handle on success) DBusMessageIter replyIter; dbus_message_iter_init(reply, &replyIter); if(dbus_message_iter_get_arg_type(&replyIter) != 'o'){ //TODO: arc errno stuff here printf("object expected, but recieved something else, '%c'\n", (char)dbus_message_iter_get_arg_type(&replyIter)); return; } //get the request handle. not sure what to do with this yet... const char *requestHandle; dbus_message_iter_get_basic(&replyIter, &requestHandle); printf("Request Handle: %s\n", requestHandle); */ //cleanup dbus_message_unref(reply); } ARC_DBusShortcut *ARC_DBusShortcut_CreateAndReturn(const char *id, const char *description, const char *preferredTrigger){ ARC_DBusShortcut *shortcut = (ARC_DBusShortcut *)malloc(sizeof(ARC_DBusShortcut)); *shortcut = (ARC_DBusShortcut){ id, description, preferredTrigger }; return shortcut; }