Skip to content

Commit ae6718b

Browse files
authored
Portal: Make PickFolder() check that portal interface version is >=3 (#94)
This makes `NFD_PickFolder()` check that the xdg-desktop-portal interface version is at least 3 before requesting for a folder picker. On earlier interface versions, it will return with an error. This is because the `directory` flag on the `OpenFile` method of the portal was added in version 3. On earlier versions, this flag will be ignored, which will cause a file picker (instead of folder picker) to be opened instead, and this is unlikely to be an appropriate fallback.
1 parent 0821601 commit ae6718b

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ To use the portal implementation, add `-DNFD_PORTAL=ON` to the build command.
256256

257257
*Note: Setting a default path is not supported by the portal implementation, and any default path passed to NFDe will be ignored. This is a limitation of the portal API, so there is no way NFDe can work around it. If this feature is something you desire, please show your interest on https://github.com/flatpak/xdg-desktop-portal/pull/874.*
258258

259+
*Note 2: The folder picker is only supported on org.freedesktop.portal.FileChooser interface version >= 3, which corresponds to xdg-desktop-portal version >= 1.7.1. `NFD_PickFolder()` will query the interface version at runtime, and return `NFD_ERROR` if the version is too low.
260+
259261
### What is a portal?
260262

261263
Unlike Windows and MacOS, Linux does not have a file chooser baked into the operating system. Linux applications that want a file chooser usually link with a library that provides one (such as GTK, as in the Linux screenshot above). This is a mostly acceptable solution that many applications use, but may make the file chooser look foreign on non-GTK distros.

src/nfd_portal.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,57 @@ nfdresult_t NFD_DBus_SaveFile(DBusMessage*& outMsg,
12761276
return NFD_ERROR;
12771277
}
12781278

1279+
nfdresult_t NFD_DBus_GetVersion(dbus_uint32_t& outVersion) {
1280+
DBusError err; // need a separate error object because we don't want to mess with the old one
1281+
// if it's stil set
1282+
dbus_error_init(&err);
1283+
1284+
DBusMessage* query = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
1285+
"/org/freedesktop/portal/desktop",
1286+
"org.freedesktop.DBus.Properties",
1287+
"Get");
1288+
DBusMessage_Guard query_guard(query);
1289+
{
1290+
DBusMessageIter iter;
1291+
dbus_message_iter_init_append(query, &iter);
1292+
1293+
constexpr const char* STR_INTERFACE = "org.freedesktop.portal.FileChooser";
1294+
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &STR_INTERFACE);
1295+
constexpr const char* STR_VERSION = "version";
1296+
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &STR_VERSION);
1297+
}
1298+
1299+
DBusMessage* reply =
1300+
dbus_connection_send_with_reply_and_block(dbus_conn, query, DBUS_TIMEOUT_INFINITE, &err);
1301+
if (!reply) {
1302+
dbus_error_free(&dbus_err);
1303+
dbus_move_error(&err, &dbus_err);
1304+
NFDi_SetError(dbus_err.message);
1305+
return NFD_ERROR;
1306+
}
1307+
DBusMessage_Guard reply_guard(reply);
1308+
{
1309+
DBusMessageIter iter;
1310+
if (!dbus_message_iter_init(reply, &iter)) {
1311+
NFDi_SetError("D-Bus reply for version query is missing an argument.");
1312+
return NFD_ERROR;
1313+
}
1314+
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1315+
NFDi_SetError("D-Bus reply for version query is not a variant.");
1316+
return NFD_ERROR;
1317+
}
1318+
DBusMessageIter variant_iter;
1319+
dbus_message_iter_recurse(&iter, &variant_iter);
1320+
if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_UINT32) {
1321+
NFDi_SetError("D-Bus reply for version query is not a uint32.");
1322+
return NFD_ERROR;
1323+
}
1324+
dbus_message_iter_get_basic(&variant_iter, &outVersion);
1325+
}
1326+
1327+
return NFD_OKAY;
1328+
}
1329+
12791330
} // namespace
12801331

12811332
/* public */
@@ -1410,6 +1461,22 @@ nfdresult_t NFD_SaveDialogN(nfdnchar_t** outPath,
14101461
nfdresult_t NFD_PickFolderN(nfdnchar_t** outPath, const nfdnchar_t* defaultPath) {
14111462
(void)defaultPath; // Default path not supported for portal backend
14121463

1464+
{
1465+
dbus_uint32_t version;
1466+
const nfdresult_t res = NFD_DBus_GetVersion(version);
1467+
if (res != NFD_OKAY) {
1468+
return res;
1469+
}
1470+
if (version < 3) {
1471+
NFDi_SetFormattedError(
1472+
"The xdg-desktop-portal installed on this system does not support a folder picker; "
1473+
"at least version 3 of the org.freedesktop.portal.FileChooser interface is "
1474+
"required but the installed interface version is %u.",
1475+
version);
1476+
return NFD_ERROR;
1477+
}
1478+
}
1479+
14131480
DBusMessage* msg;
14141481
{
14151482
const nfdresult_t res = NFD_DBus_OpenFile<false, true>(msg, nullptr, 0);

0 commit comments

Comments
 (0)