Squashed 'deps/nostalgia/' changes from dd5d1bfb..976550ef

976550ef [nostalgia/sample_project] Add missing type descriptors
1fb0a866 [nostalgia/core] Fix CompactPalette TypeName and TypeVersion
eb46aeeb [nfde] Fix compiler warnings on Gtk build
9244b735 [nostalgia] Fix non-Linux non-Apple systems not to build GLFW for Wayland
3fba36b4 [nfde] Make only option BUILD_SHARED_LIBS if not already set
6ddb6b42 Merge commit '5461f6700dac79e9e71e3966f8a1270706c385ba'
5461f670 Squashed 'deps/nfde/' changes from 28ade5a5c..5786fabce
1ecc7aa7 Merge commit '26c8cc348eacea01237cd64e1a68d0df8141e848'
26c8cc34 Squashed 'deps/glfw/' changes from 7d5a16ce7..7b6aead9f
fc25c12d Merge commit 'ae51a422787bc3b720ff1748c0219c8f33363427'
ae51a422 Squashed 'deps/imgui/' changes from f33737806..2db79d086
6c71e1e2 [nostalgia/core/studio,studio] Give TileSheetEditor Ctrl-A and Ctrl-G for selection
2ede01e7 [nostalgia/core/studio] Fix build
deacd4ab [nostalgia/core/studio] Fix PaletteEditor add/remove color commands

git-subtree-dir: deps/nostalgia
git-subtree-split: 976550ef6fa269cf1e367e880f148b0ad7b1b163
This commit is contained in:
2024-05-31 20:54:46 -05:00
parent e3cd379bb4
commit 60789230be
374 changed files with 61191 additions and 26808 deletions

View File

@ -14,19 +14,26 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/random.h> // for the random token string
#include <unistd.h> // for access()
#include <unistd.h> // for access()
#if !defined(__has_include) || !defined(__linux__)
#include <sys/random.h> // for getrandom() - the random token string
#elif __has_include(<sys/random.h>)
#include <sys/random.h>
#else // for GLIBC < 2.25
#include <sys/syscall.h>
#define getrandom(buf, sz, flags) syscall(SYS_getrandom, buf, sz, flags)
#endif
#include "nfd.h"
/*
Define NFD_PORTAL_AUTO_APPEND_FILE_EXTENSION to 0 if you don't want the file extension to be
appended when missing. Linux programs usually doesn't append the file extension, but for consistency
with other OSes we append it by default.
Define NFD_APPEND_EXTENSION if you want the file extension to be appended when missing. Linux
programs usually don't append the file extension, but for consistency with other OSes you might want
to append it. However, when using portals, the file overwrite prompt and the Flatpak sandbox won't
know that we appended an extension, so they will not check or whitelist the correct file. Enabling
NFD_APPEND_EXTENSION is not recommended for portals.
*/
#ifndef NFD_PORTAL_AUTO_APPEND_FILE_EXTENSION
#define NFD_PORTAL_AUTO_APPEND_FILE_EXTENSION 1
#endif
namespace {
@ -70,7 +77,10 @@ struct DBusMessage_Guard {
DBusConnection* dbus_conn;
/* current D-Bus error */
DBusError dbus_err;
/* current error (may be a pointer to the D-Bus error message above, or a pointer to some string
/* current non D-Bus error */
constexpr size_t OWNED_ERR_LEN = 1024;
char owned_err[OWNED_ERR_LEN]{};
/* current error (may be a pointer to dbus_err.message, owned_err, or a pointer to some string
* literal) */
const char* err_ptr = nullptr;
/* the unique name of our connection, used for the Request handle; owned by D-Bus so we don't free
@ -81,6 +91,14 @@ void NFDi_SetError(const char* msg) {
err_ptr = msg;
}
void NFDi_SetFormattedError(const char* format, ...) {
va_list args;
va_start(args, format);
vsnprintf(owned_err, OWNED_ERR_LEN, format, args);
va_end(args);
err_ptr = owned_err;
}
template <typename T>
T* copy(const T* begin, const T* end, T* out) {
for (; begin != end; ++begin) {
@ -112,6 +130,10 @@ constexpr const char* STR_CURRENT_FOLDER = "current_folder";
constexpr const char* STR_CURRENT_FILE = "current_file";
constexpr const char* STR_ALL_FILES = "All files";
constexpr const char* STR_ASTERISK = "*";
constexpr const char* DBUS_DESTINATION = "org.freedesktop.portal.Desktop";
constexpr const char* DBUS_PATH = "/org/freedesktop/portal/desktop";
constexpr const char* DBUS_FILECHOOSER_IFACE = "org.freedesktop.portal.FileChooser";
constexpr const char* DBUS_REQUEST_IFACE = "org.freedesktop.portal.Request";
template <bool Multiple, bool Directory>
void AppendOpenFileQueryTitle(DBusMessageIter&);
@ -462,7 +484,7 @@ void AppendSaveFileQueryDictEntryCurrentName(DBusMessageIter& sub_iter, const ch
dbus_message_iter_close_container(&sub_iter, &sub_sub_iter);
}
void AppendSaveFileQueryDictEntryCurrentFolder(DBusMessageIter& sub_iter, const char* path) {
void AppendOpenFileQueryDictEntryCurrentFolder(DBusMessageIter& sub_iter, const char* path) {
if (!path) return;
DBusMessageIter sub_sub_iter;
DBusMessageIter variant_iter;
@ -529,7 +551,8 @@ template <bool Multiple, bool Directory>
void AppendOpenFileQueryParams(DBusMessage* query,
const char* handle_token,
const nfdnfilteritem_t* filterList,
nfdfiltersize_t filterCount) {
nfdfiltersize_t filterCount,
const nfdnchar_t* defaultPath) {
DBusMessageIter iter;
dbus_message_iter_init_append(query, &iter);
@ -543,6 +566,7 @@ void AppendOpenFileQueryParams(DBusMessage* query,
AppendOpenFileQueryDictEntryMultiple<Multiple>(sub_iter);
AppendOpenFileQueryDictEntryDirectory<Directory>(sub_iter);
AppendOpenFileQueryDictEntryFilters<!Directory>(sub_iter, filterList, filterCount);
AppendOpenFileQueryDictEntryCurrentFolder(sub_iter, defaultPath);
dbus_message_iter_close_container(&iter, &sub_iter);
}
@ -565,7 +589,7 @@ void AppendSaveFileQueryParams(DBusMessage* query,
AppendOpenFileQueryDictEntryHandleToken(sub_iter, handle_token);
AppendSaveFileQueryDictEntryFilters(sub_iter, filterList, filterCount, defaultName);
AppendSaveFileQueryDictEntryCurrentName(sub_iter, defaultName);
AppendSaveFileQueryDictEntryCurrentFolder(sub_iter, defaultPath);
AppendOpenFileQueryDictEntryCurrentFolder(sub_iter, defaultPath);
AppendSaveFileQueryDictEntryCurrentFile(sub_iter, defaultPath, defaultName);
dbus_message_iter_close_container(&iter, &sub_iter);
}
@ -649,7 +673,9 @@ nfdresult_t ReadResponseResults(DBusMessage* msg, DBusMessageIter& resultsIter)
return NFD_CANCEL;
} else {
// Some error occurred
NFDi_SetError("D-Bus file dialog interaction was ended abruptly.");
NFDi_SetFormattedError(
"D-Bus file dialog interaction was ended abruptly with response code %u.",
resp_code);
return NFD_ERROR;
}
}
@ -720,14 +746,14 @@ nfdresult_t ReadResponseUrisSingle(DBusMessage* msg, const char*& file) {
const nfdresult_t res = ReadResponseUris(msg, uri_iter);
if (res != NFD_OKAY) return res; // can be NFD_CANCEL or NFD_ERROR
if (dbus_message_iter_get_arg_type(&uri_iter) != DBUS_TYPE_STRING) {
NFDi_SetError("D-Bus response signal URI sub iter is not an string.");
NFDi_SetError("D-Bus response signal URI sub iter is not a string.");
return NFD_ERROR;
}
dbus_message_iter_get_basic(&uri_iter, &file);
return NFD_OKAY;
}
#if NFD_PORTAL_AUTO_APPEND_FILE_EXTENSION == 1
#ifdef NFD_APPEND_EXTENSION
// Read the response URI and selected extension (in the form "*.abc" or "*") (if any). If response
// was okay, then returns NFD_OKAY and set file and extn to them (the pointer is set to some string
// owned by msg, so you should not manually free it). `file` is the user-entered file name, and
@ -763,47 +789,37 @@ nfdresult_t ReadResponseUrisSingleAndCurrentExtension(DBusMessage* msg,
[&tmp_extn](DBusMessageIter& current_filter_iter) {
// current_filter is best_effort, so if we fail, we still return NFD_OKAY.
if (dbus_message_iter_get_arg_type(&current_filter_iter) != DBUS_TYPE_STRUCT) {
// NFDi_SetError("D-Bus response signal current_filter iter is not a struct.");
return NFD_OKAY;
}
DBusMessageIter current_filter_struct_iter;
dbus_message_iter_recurse(&current_filter_iter, &current_filter_struct_iter);
if (!dbus_message_iter_next(&current_filter_struct_iter)) {
// NFDi_SetError("D-Bus response signal current_filter struct iter ended
// prematurely.");
return NFD_OKAY;
}
if (dbus_message_iter_get_arg_type(&current_filter_struct_iter) !=
DBUS_TYPE_ARRAY) {
// NFDi_SetError("D-Bus response signal URI sub iter is not an string.");
return NFD_OKAY;
}
DBusMessageIter current_filter_array_iter;
dbus_message_iter_recurse(&current_filter_struct_iter, &current_filter_array_iter);
if (dbus_message_iter_get_arg_type(&current_filter_array_iter) !=
DBUS_TYPE_STRUCT) {
// NFDi_SetError("D-Bus response signal current_filter iter is not a struct.");
return NFD_OKAY;
}
DBusMessageIter current_filter_extn_iter;
dbus_message_iter_recurse(&current_filter_array_iter, &current_filter_extn_iter);
if (dbus_message_iter_get_arg_type(&current_filter_extn_iter) != DBUS_TYPE_UINT32) {
// NFDi_SetError("D-Bus response signal URI sub iter is not an string.");
return NFD_OKAY;
}
dbus_uint32_t type;
dbus_message_iter_get_basic(&current_filter_extn_iter, &type);
if (type != 0) {
// NFDi_SetError("Wrong filter type.");
return NFD_OKAY;
}
if (!dbus_message_iter_next(&current_filter_extn_iter)) {
// NFDi_SetError("D-Bus response signal current_filter struct iter ended
// prematurely.");
return NFD_OKAY;
}
if (dbus_message_iter_get_arg_type(&current_filter_extn_iter) != DBUS_TYPE_STRING) {
// NFDi_SetError("D-Bus response signal URI sub iter is not an string.");
return NFD_OKAY;
}
dbus_message_iter_get_basic(&current_filter_extn_iter, &tmp_extn);
@ -942,29 +958,95 @@ class DBusSignalSubscriptionHandler {
}
};
// Returns true if ch is in [0-9A-Za-z], false otherwise.
bool IsHex(char ch) {
return ('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'F') || ('a' <= ch && ch <= 'f');
}
// Returns the hexadecimal value contained in the char. Precondition: IsHex(ch)
char ParseHexUnchecked(char ch) {
if ('0' <= ch && ch <= '9') return ch - '0';
if ('A' <= ch && ch <= 'F') return ch - ('A' - 10);
if ('a' <= ch && ch <= 'f') return ch - ('a' - 10);
#if defined(__GNUC__)
__builtin_unreachable();
#endif
}
// Returns true if the given file URI is decodable (i.e. not malformed), and false otherwise.
// If this function returns true, then `out` will be populated with the length of the decoded URI
// and `fileUriEnd` will point to the trailing null byte of `fileUri`. Otherwise, `out` and
// `fileUriEnd` will be unmodified.
bool TryUriDecodeLen(const char* fileUri, size_t& out, const char*& fileUriEnd) {
size_t len = 0;
while (*fileUri) {
if (*fileUri != '%') {
++fileUri;
} else {
if (*(fileUri + 1) == '\0' || *(fileUri + 2) == '\0') {
return false;
}
if (!IsHex(*(fileUri + 1)) || !IsHex(*(fileUri + 2))) {
return false;
}
fileUri += 3;
}
++len;
}
out = len;
fileUriEnd = fileUri;
return true;
}
// Decodes the given URI and writes it to `outPath`. The caller must ensure that the given URI is
// not malformed (typically with a prior call to `TryUriDecodeLen`). This function does not write
// any trailing null character.
char* UriDecodeUnchecked(const char* fileUri, const char* fileUriEnd, char* outPath) {
while (fileUri != fileUriEnd) {
if (*fileUri != '%') {
*outPath++ = *fileUri++;
} else {
++fileUri;
const char high_nibble = ParseHexUnchecked(*fileUri++);
const char low_nibble = ParseHexUnchecked(*fileUri++);
*outPath++ = (high_nibble << 4) | low_nibble;
}
}
return outPath;
}
constexpr const char FILE_URI_PREFIX[] = "file://";
constexpr size_t FILE_URI_PREFIX_LEN = sizeof(FILE_URI_PREFIX) - 1;
// If fileUri starts with "file://", strips that prefix and copies it to a new buffer, and make
// outPath point to it, and returns NFD_OKAY. Otherwise, does not modify outPath and returns
// NFD_ERROR (with the correct error set)
// If fileUri starts with "file://", strips that prefix and URI-decodes the remaining part to a new
// buffer, and make outPath point to it, and returns NFD_OKAY. Otherwise, does not modify outPath
// and returns NFD_ERROR (with the correct error set)
nfdresult_t AllocAndCopyFilePath(const char* fileUri, char*& outPath) {
const char* file_uri_iter = fileUri;
const char* prefix_begin = FILE_URI_PREFIX;
const char* const prefix_end = FILE_URI_PREFIX + FILE_URI_PREFIX_LEN;
for (; prefix_begin != prefix_end; ++prefix_begin, ++fileUri) {
if (*prefix_begin != *fileUri) {
NFDi_SetError("D-Bus freedesktop portal returned a URI that is not a file URI.");
for (; prefix_begin != prefix_end; ++prefix_begin, ++file_uri_iter) {
if (*prefix_begin != *file_uri_iter) {
NFDi_SetFormattedError(
"D-Bus freedesktop portal returned \"%s\", which is not a file URI.", fileUri);
return NFD_ERROR;
}
}
size_t len = strlen(fileUri);
char* path_without_prefix = NFDi_Malloc<char>(len + 1);
copy(fileUri, fileUri + (len + 1), path_without_prefix);
size_t decoded_len;
const char* file_uri_end;
if (!TryUriDecodeLen(file_uri_iter, decoded_len, file_uri_end)) {
NFDi_SetFormattedError("D-Bus freedesktop portal returned a malformed URI \"%s\".",
fileUri);
return NFD_ERROR;
}
char* const path_without_prefix = NFDi_Malloc<char>(decoded_len + 1);
char* const out_end = UriDecodeUnchecked(file_uri_iter, file_uri_end, path_without_prefix);
*out_end = '\0';
outPath = path_without_prefix;
return NFD_OKAY;
}
#if NFD_PORTAL_AUTO_APPEND_FILE_EXTENSION == 1
#ifdef NFD_APPEND_EXTENSION
bool TryGetValidExtension(const char* extn,
const char*& trimmed_extn,
const char*& trimmed_extn_end) {
@ -985,19 +1067,30 @@ bool TryGetValidExtension(const char* extn,
// expected to be either in the form "*.abc" or "*", but this function will check for it, and ignore
// the extension if it is not in the correct form.
nfdresult_t AllocAndCopyFilePathWithExtn(const char* fileUri, const char* extn, char*& outPath) {
const char* file_uri_iter = fileUri;
const char* prefix_begin = FILE_URI_PREFIX;
const char* const prefix_end = FILE_URI_PREFIX + FILE_URI_PREFIX_LEN;
for (; prefix_begin != prefix_end; ++prefix_begin, ++fileUri) {
if (*prefix_begin != *fileUri) {
NFDi_SetError("D-Bus freedesktop portal returned a URI that is not a file URI.");
for (; prefix_begin != prefix_end; ++prefix_begin, ++file_uri_iter) {
if (*prefix_begin != *file_uri_iter) {
NFDi_SetFormattedError(
"D-Bus freedesktop portal returned \"%s\", which is not a file URI.", fileUri);
return NFD_ERROR;
}
}
const char* file_end = fileUri;
for (; *file_end != '\0'; ++file_end)
;
const char* file_it = file_end;
size_t decoded_len;
const char* file_uri_end;
if (!TryUriDecodeLen(file_uri_iter, decoded_len, file_uri_end)) {
NFDi_SetFormattedError("D-Bus freedesktop portal returned a malformed URI \"%s\".",
fileUri);
return NFD_ERROR;
}
const char* file_it = file_uri_end;
// The following loop condition is safe because `FILE_URI_PREFIX` ends with '/',
// so we won't iterate past the beginning of the URI.
// Also in UTF-8 all non-ASCII code points are encoded using bytes 128-255 so every '.' or '/'
// is also '.' or '/' in UTF-8.
do {
--file_it;
} while (*file_it != '/' && *file_it != '.');
@ -1005,16 +1098,17 @@ nfdresult_t AllocAndCopyFilePathWithExtn(const char* fileUri, const char* extn,
const char* trimmed_extn_end; // includes the '\0'
if (*file_it == '.' || !TryGetValidExtension(extn, trimmed_extn, trimmed_extn_end)) {
// has file extension already or no valid extension in `extn`
++file_end; // includes the '\0'
char* path_without_prefix = NFDi_Malloc<char>(file_end - fileUri);
copy(fileUri, file_end, path_without_prefix);
char* const path_without_prefix = NFDi_Malloc<char>(decoded_len + 1);
char* const out_end = UriDecodeUnchecked(file_uri_iter, file_uri_end, path_without_prefix);
*out_end = '\0';
outPath = path_without_prefix;
} else {
// no file extension and we have a valid extension
char* path_without_prefix =
NFDi_Malloc<char>((file_end - fileUri) + (trimmed_extn_end - trimmed_extn));
char* out = copy(fileUri, file_end, path_without_prefix);
copy(trimmed_extn, trimmed_extn_end, out);
char* const path_without_prefix =
NFDi_Malloc<char>(decoded_len + (trimmed_extn_end - trimmed_extn));
char* const out_mid = UriDecodeUnchecked(file_uri_iter, file_uri_end, path_without_prefix);
char* const out_end = copy(trimmed_extn, trimmed_extn_end, out_mid);
*out_end = '\0';
outPath = path_without_prefix;
}
return NFD_OKAY;
@ -1028,7 +1122,8 @@ nfdresult_t AllocAndCopyFilePathWithExtn(const char* fileUri, const char* extn,
template <bool Multiple, bool Directory>
nfdresult_t NFD_DBus_OpenFile(DBusMessage*& outMsg,
const nfdnfilteritem_t* filterList,
nfdfiltersize_t filterCount) {
nfdfiltersize_t filterCount,
const nfdnchar_t* defaultPath) {
const char* handle_token_ptr;
char* handle_obj_path = MakeUniqueObjectPath(&handle_token_ptr);
Free_Guard<char> handle_obj_path_guard(handle_obj_path);
@ -1045,13 +1140,11 @@ nfdresult_t NFD_DBus_OpenFile(DBusMessage*& outMsg,
// TODO: use XOpenDisplay()/XGetInputFocus() to find xid of window... but what should one do on
// Wayland?
DBusMessage* query = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.FileChooser",
"OpenFile");
DBusMessage* query = dbus_message_new_method_call(
DBUS_DESTINATION, DBUS_PATH, DBUS_FILECHOOSER_IFACE, "OpenFile");
DBusMessage_Guard query_guard(query);
AppendOpenFileQueryParams<Multiple, Directory>(
query, handle_token_ptr, filterList, filterCount);
query, handle_token_ptr, filterList, filterCount, defaultPath);
DBusMessage* reply =
dbus_connection_send_with_reply_and_block(dbus_conn, query, DBUS_TIMEOUT_INFINITE, &err);
@ -1090,7 +1183,7 @@ nfdresult_t NFD_DBus_OpenFile(DBusMessage*& outMsg,
DBusMessage* msg = dbus_connection_pop_message(dbus_conn);
if (!msg) break;
if (dbus_message_is_signal(msg, "org.freedesktop.portal.Request", "Response")) {
if (dbus_message_is_signal(msg, DBUS_REQUEST_IFACE, "Response")) {
// this is the response we're looking for
outMsg = msg;
return NFD_OKAY;
@ -1129,10 +1222,8 @@ nfdresult_t NFD_DBus_SaveFile(DBusMessage*& outMsg,
// TODO: use XOpenDisplay()/XGetInputFocus() to find xid of window... but what should one do on
// Wayland?
DBusMessage* query = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.FileChooser",
"SaveFile");
DBusMessage* query = dbus_message_new_method_call(
DBUS_DESTINATION, DBUS_PATH, DBUS_FILECHOOSER_IFACE, "SaveFile");
DBusMessage_Guard query_guard(query);
AppendSaveFileQueryParams(
query, handle_token_ptr, filterList, filterCount, defaultPath, defaultName);
@ -1174,7 +1265,7 @@ nfdresult_t NFD_DBus_SaveFile(DBusMessage*& outMsg,
DBusMessage* msg = dbus_connection_pop_message(dbus_conn);
if (!msg) break;
if (dbus_message_is_signal(msg, "org.freedesktop.portal.Request", "Response")) {
if (dbus_message_is_signal(msg, DBUS_REQUEST_IFACE, "Response")) {
// this is the response we're looking for
outMsg = msg;
return NFD_OKAY;
@ -1188,6 +1279,57 @@ nfdresult_t NFD_DBus_SaveFile(DBusMessage*& outMsg,
return NFD_ERROR;
}
nfdresult_t NFD_DBus_GetVersion(dbus_uint32_t& outVersion) {
DBusError err; // need a separate error object because we don't want to mess with the old one
// if it's stil set
dbus_error_init(&err);
DBusMessage* query = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.DBus.Properties",
"Get");
DBusMessage_Guard query_guard(query);
{
DBusMessageIter iter;
dbus_message_iter_init_append(query, &iter);
constexpr const char* STR_INTERFACE = "org.freedesktop.portal.FileChooser";
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &STR_INTERFACE);
constexpr const char* STR_VERSION = "version";
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &STR_VERSION);
}
DBusMessage* reply =
dbus_connection_send_with_reply_and_block(dbus_conn, query, DBUS_TIMEOUT_INFINITE, &err);
if (!reply) {
dbus_error_free(&dbus_err);
dbus_move_error(&err, &dbus_err);
NFDi_SetError(dbus_err.message);
return NFD_ERROR;
}
DBusMessage_Guard reply_guard(reply);
{
DBusMessageIter iter;
if (!dbus_message_iter_init(reply, &iter)) {
NFDi_SetError("D-Bus reply for version query is missing an argument.");
return NFD_ERROR;
}
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
NFDi_SetError("D-Bus reply for version query is not a variant.");
return NFD_ERROR;
}
DBusMessageIter variant_iter;
dbus_message_iter_recurse(&iter, &variant_iter);
if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_UINT32) {
NFDi_SetError("D-Bus reply for version query is not a uint32.");
return NFD_ERROR;
}
dbus_message_iter_get_basic(&variant_iter, &outVersion);
}
return NFD_OKAY;
}
} // namespace
/* public */
@ -1202,7 +1344,7 @@ void NFD_ClearError(void) {
}
nfdresult_t NFD_Init(void) {
// Initialize dbus_error
// Initialize dbus_err
dbus_error_init(&dbus_err);
// Get DBus connection
dbus_conn = dbus_bus_get(DBUS_BUS_SESSION, &dbus_err);
@ -1233,37 +1375,35 @@ nfdresult_t NFD_OpenDialogN(nfdnchar_t** outPath,
const nfdnfilteritem_t* filterList,
nfdfiltersize_t filterCount,
const nfdnchar_t* defaultPath) {
(void)defaultPath; // Default path not supported for portal backend
DBusMessage* msg;
{
const nfdresult_t res = NFD_DBus_OpenFile<false, false>(msg, filterList, filterCount);
const nfdresult_t res =
NFD_DBus_OpenFile<false, false>(msg, filterList, filterCount, defaultPath);
if (res != NFD_OKAY) {
return res;
}
}
DBusMessage_Guard msg_guard(msg);
const char* file;
const char* uri;
{
const nfdresult_t res = ReadResponseUrisSingle(msg, file);
const nfdresult_t res = ReadResponseUrisSingle(msg, uri);
if (res != NFD_OKAY) {
return res;
}
}
return AllocAndCopyFilePath(file, *outPath);
return AllocAndCopyFilePath(uri, *outPath);
}
nfdresult_t NFD_OpenDialogMultipleN(const nfdpathset_t** outPaths,
const nfdnfilteritem_t* filterList,
nfdfiltersize_t filterCount,
const nfdnchar_t* defaultPath) {
(void)defaultPath; // Default path not supported for portal backend
DBusMessage* msg;
{
const nfdresult_t res = NFD_DBus_OpenFile<true, false>(msg, filterList, filterCount);
const nfdresult_t res =
NFD_DBus_OpenFile<true, false>(msg, filterList, filterCount, defaultPath);
if (res != NFD_OKAY) {
return res;
}
@ -1295,51 +1435,67 @@ nfdresult_t NFD_SaveDialogN(nfdnchar_t** outPath,
}
DBusMessage_Guard msg_guard(msg);
#if NFD_PORTAL_AUTO_APPEND_FILE_EXTENSION == 1
const char* file;
#ifdef NFD_APPEND_EXTENSION
const char* uri;
const char* extn;
{
const nfdresult_t res = ReadResponseUrisSingleAndCurrentExtension(msg, file, extn);
const nfdresult_t res = ReadResponseUrisSingleAndCurrentExtension(msg, uri, extn);
if (res != NFD_OKAY) {
return res;
}
}
return AllocAndCopyFilePathWithExtn(file, extn, *outPath);
return AllocAndCopyFilePathWithExtn(uri, extn, *outPath);
#else
const char* file;
const char* uri;
{
const nfdresult_t res = ReadResponseUrisSingle(msg, file);
const nfdresult_t res = ReadResponseUrisSingle(msg, uri);
if (res != NFD_OKAY) {
return res;
}
}
return AllocAndCopyFilePath(file, *outPath);
return AllocAndCopyFilePath(uri, *outPath);
#endif
}
nfdresult_t NFD_PickFolderN(nfdnchar_t** outPath, const nfdnchar_t* defaultPath) {
(void)defaultPath; // Default path not supported for portal backend
{
dbus_uint32_t version;
const nfdresult_t res = NFD_DBus_GetVersion(version);
if (res != NFD_OKAY) {
return res;
}
if (version < 3) {
NFDi_SetFormattedError(
"The xdg-desktop-portal installed on this system does not support a folder picker; "
"at least version 3 of the org.freedesktop.portal.FileChooser interface is "
"required but the installed interface version is %u.",
version);
return NFD_ERROR;
}
}
DBusMessage* msg;
{
const nfdresult_t res = NFD_DBus_OpenFile<false, true>(msg, nullptr, 0);
const nfdresult_t res = NFD_DBus_OpenFile<false, true>(msg, nullptr, 0, defaultPath);
if (res != NFD_OKAY) {
return res;
}
}
DBusMessage_Guard msg_guard(msg);
const char* file;
const char* uri;
{
const nfdresult_t res = ReadResponseUrisSingle(msg, file);
const nfdresult_t res = ReadResponseUrisSingle(msg, uri);
if (res != NFD_OKAY) {
return res;
}
}
return AllocAndCopyFilePath(file, *outPath);
return AllocAndCopyFilePath(uri, *outPath);
}
nfdresult_t NFD_PathSet_GetCount(const nfdpathset_t* pathSet, nfdpathsetsize_t* count) {
@ -1356,20 +1512,25 @@ nfdresult_t NFD_PathSet_GetPathN(const nfdpathset_t* pathSet,
DBusMessage* msg = const_cast<DBusMessage*>(static_cast<const DBusMessage*>(pathSet));
DBusMessageIter uri_iter;
ReadResponseUrisUnchecked(msg, uri_iter);
while (index > 0) {
--index;
nfdpathsetsize_t rem_index = index;
while (rem_index > 0) {
--rem_index;
if (!dbus_message_iter_next(&uri_iter)) {
NFDi_SetError("Index out of bounds.");
NFDi_SetFormattedError(
"Index out of bounds; you asked for index %u but there are only %u file paths "
"available.",
index,
index - rem_index);
return NFD_ERROR;
}
}
if (dbus_message_iter_get_arg_type(&uri_iter) != DBUS_TYPE_STRING) {
NFDi_SetError("D-Bus response signal URI sub iter is not an string.");
NFDi_SetError("D-Bus response signal URI sub iter is not a string.");
return NFD_ERROR;
}
const char* file;
dbus_message_iter_get_basic(&uri_iter, &file);
return AllocAndCopyFilePath(file, *outPath);
const char* uri;
dbus_message_iter_get_basic(&uri_iter, &uri);
return AllocAndCopyFilePath(uri, *outPath);
}
void NFD_PathSet_FreePathN(const nfdnchar_t* filePath) {
@ -1402,12 +1563,12 @@ nfdresult_t NFD_PathSet_EnumNextN(nfdpathsetenum_t* enumerator, nfdnchar_t** out
return NFD_OKAY;
}
if (arg_type != DBUS_TYPE_STRING) {
NFDi_SetError("D-Bus response signal URI sub iter is not an string.");
NFDi_SetError("D-Bus response signal URI sub iter is not a string.");
return NFD_ERROR;
}
const char* file;
dbus_message_iter_get_basic(&uri_iter, &file);
const nfdresult_t res = AllocAndCopyFilePath(file, *outPath);
const char* uri;
dbus_message_iter_get_basic(&uri_iter, &uri);
const nfdresult_t res = AllocAndCopyFilePath(uri, *outPath);
if (res != NFD_OKAY) return res;
dbus_message_iter_next(&uri_iter);
return NFD_OKAY;