fix: multiple directory selection on Linux (#45394)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
This commit is contained in:
trop[bot] 2025-01-31 09:38:44 +01:00 committed by GitHub
parent 895bc51272
commit e9b3e4cc91
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -14,10 +14,25 @@ It also:
This may be partially upstreamed to Chromium in the future.
diff --git a/ui/gtk/select_file_dialog_linux_gtk.cc b/ui/gtk/select_file_dialog_linux_gtk.cc
index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a846f0d923 100644
index b83f0177a2adb0a19be49684f865941e6708f626..a8c7032cfc122b97665c41da9e1191e747b95a33 100644
--- a/ui/gtk/select_file_dialog_linux_gtk.cc
+++ b/ui/gtk/select_file_dialog_linux_gtk.cc
@@ -407,9 +407,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
@@ -259,8 +259,12 @@ void SelectFileDialogLinuxGtk::SelectFileImpl(
case SELECT_EXISTING_FOLDER:
dialog = CreateSelectFolderDialog(type, title_string, default_path,
owning_window);
- connect("response",
- &SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse);
+ if (allow_multiple_selection())
+ connect("response",
+ &SelectFileDialogLinuxGtk::OnSelectMultiFolderDialogResponse);
+ else
+ connect("response",
+ &SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse);
break;
case SELECT_OPEN_FILE:
dialog = CreateFileOpenDialog(title_string, default_path, owning_window);
@@ -407,9 +411,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
const std::string& title,
const base::FilePath& default_path,
gfx::NativeWindow parent) {
@ -30,7 +45,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
SetGtkTransientForAura(dialog, parent);
AddFilters(GTK_FILE_CHOOSER(dialog));
@@ -425,6 +427,7 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
@@ -425,6 +431,7 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog),
*last_opened_path());
}
@ -38,7 +53,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
return dialog;
}
@@ -440,11 +443,15 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
@@ -440,11 +447,15 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
? l10n_util::GetStringUTF8(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE)
: l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE);
}
@ -59,7 +74,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
GtkWidget* dialog = GtkFileChooserDialogNew(
title_string.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
@@ -466,7 +473,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
@@ -466,7 +477,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
gtk_file_filter_add_mime_type(only_folders, "inode/directory");
gtk_file_filter_add_mime_type(only_folders, "text/directory");
gtk_file_chooser_add_filter(chooser, only_folders);
@ -69,7 +84,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
return dialog;
}
@@ -503,10 +511,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
@@ -503,10 +515,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
std::string title_string =
!title.empty() ? title
: l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE);
@ -83,7 +98,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
GTK_RESPONSE_ACCEPT);
SetGtkTransientForAura(dialog, parent);
@@ -532,9 +541,10 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
@@ -532,9 +545,10 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
// Overwrite confirmation is always enabled in GTK4.
if (!GtkCheckVersion(4)) {
@ -96,6 +111,65 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
return dialog;
}
@@ -589,15 +603,29 @@ void SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse(
void SelectFileDialogLinuxGtk::OnSelectMultiFileDialogResponse(
GtkWidget* dialog,
int response_id) {
+ SelectMultiFileHelper(dialog, response_id, false);
+}
+
+void SelectFileDialogLinuxGtk::OnSelectMultiFolderDialogResponse(
+ GtkWidget* dialog,
+ int response_id) {
+ SelectMultiFileHelper(dialog, response_id, true);
+}
+
+void SelectFileDialogLinuxGtk::SelectMultiFileHelper(GtkWidget* dialog,
+ int response_id,
+ bool allow_folder) {
if (IsCancelResponse(response_id)) {
FileNotSelected(dialog);
return;
}
auto filenames = GtkFileChooserGetFilenames(dialog);
- std::erase_if(filenames, [this](const base::FilePath& path) {
- return CallDirectoryExistsOnUIThread(path);
+ std::erase_if(filenames, [this, &allow_folder](const base::FilePath& path) {
+ bool directory_exists = CallDirectoryExistsOnUIThread(path);
+ return !allow_folder && directory_exists;
});
+
if (filenames.empty()) {
FileNotSelected(dialog);
return;
diff --git a/ui/gtk/select_file_dialog_linux_gtk.h b/ui/gtk/select_file_dialog_linux_gtk.h
index 213eaa5ec6d657a659726cb38103e8bd671fe907..f497447c598198bf690758b1d1c5c6fe4112627f 100644
--- a/ui/gtk/select_file_dialog_linux_gtk.h
+++ b/ui/gtk/select_file_dialog_linux_gtk.h
@@ -108,6 +108,12 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
gint response_id,
bool allow_folder);
+ // Common function for OnSelectMultiFileDialogResponse and
+ // OnSelectMultiFolderDialogResponse.
+ void SelectMultiFileHelper(GtkWidget* dialog,
+ gint response_id,
+ bool allow_folder);
+
// Common function for CreateFileOpenDialog and CreateMultiFileOpenDialog.
GtkWidget* CreateFileOpenHelper(const std::string& title,
const base::FilePath& default_path,
@@ -122,6 +128,9 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
// Callback for when the user responds to a Open Multiple Files dialog.
void OnSelectMultiFileDialogResponse(GtkWidget* dialog, int response_id);
+ // Callback for when the user responds to a Select Multiple Folders dialog.
+ void OnSelectMultiFolderDialogResponse(GtkWidget* dialog, int response_id);
+
// Callback for when the file chooser gets destroyed.
void OnFileChooserDestroy(GtkWidget* dialog);
diff --git a/ui/shell_dialogs/select_file_dialog.h b/ui/shell_dialogs/select_file_dialog.h
index eb3d997598631b220c3566748f23a5cdac3e4692..b4b2f7294ce6e9349a4a8a05f614e93359eca25a 100644
--- a/ui/shell_dialogs/select_file_dialog.h
@ -186,18 +260,90 @@ index 61683d0eddb04c494ca5e650e7d556b44968ec49..5492456a9138b250e97a5479838bb443
} // namespace ui
diff --git a/ui/shell_dialogs/select_file_dialog_linux_kde.cc b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
index 64a79ebe2e2d21d5a6b4a98042d1cdb7b6edad52..16f2ae01a8d33e6341ed52638e963c340455ebf8 100644
index 64a79ebe2e2d21d5a6b4a98042d1cdb7b6edad52..748c2506781a237641b25b426876be14c8b7ba82 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_kde.cc
+++ b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
@@ -468,7 +468,7 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
@@ -154,9 +154,20 @@ class SelectFileDialogLinuxKde : public SelectFileDialogLinux {
void OnSelectMultiFileDialogResponse(
gfx::AcceleratedWidget parent,
std::unique_ptr<KDialogOutputParams> results);
+
+ // Common function for OnSelectSingleFolderDialogResponse and
+ // OnSelectMultiFileDialogResponse.
+ void SelectMultiFileDialogHelper(
+ bool allow_folder,
+ gfx::AcceleratedWidget parent,
+ std::unique_ptr<KDialogOutputParams> results);
+
void OnSelectSingleFolderDialogResponse(
gfx::AcceleratedWidget parent,
std::unique_ptr<KDialogOutputParams> results);
+ void OnSelectMultiFolderDialogResponse(
+ gfx::AcceleratedWidget parent,
+ std::unique_ptr<KDialogOutputParams> results);
// Should be either DESKTOP_ENVIRONMENT_KDE3, KDE4, KDE5, or KDE6.
base::nix::DesktopEnvironment desktop_;
@@ -461,6 +472,7 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
int title_message_id = (type == SELECT_UPLOAD_FOLDER)
? IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE
: IDS_SELECT_FOLDER_DIALOG_TITLE;
+ bool multiple_selection = allow_multiple_selection();
pipe_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
@@ -468,10 +480,12 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
KDialogParams(
"--getexistingdirectory", GetTitle(title, title_message_id),
default_path.empty() ? *last_opened_path() : default_path, parent,
- false, false)),
+ false, allow_multiple_selection())),
+ false, multiple_selection)),
base::BindOnce(
&SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse, this,
parent));
- &SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse, this,
- parent));
+ multiple_selection
+ ? &SelectFileDialogLinuxKde::OnSelectMultiFolderDialogResponse
+ : &SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse,
+ this, parent));
}
void SelectFileDialogLinuxKde::CreateFileOpenDialog(
@@ -561,7 +575,8 @@ void SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse(
SelectSingleFileHelper(true, std::move(results));
}
-void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
+void SelectFileDialogLinuxKde::SelectMultiFileDialogHelper(
+ bool allow_folder,
gfx::AcceleratedWidget parent,
std::unique_ptr<KDialogOutputParams> results) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -579,7 +594,7 @@ void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
base::SplitStringPiece(results->output, "\n", base::KEEP_WHITESPACE,
base::SPLIT_WANT_NONEMPTY)) {
base::FilePath path(line);
- if (CallDirectoryExistsOnUIThread(path))
+ if (!allow_folder && CallDirectoryExistsOnUIThread(path))
continue;
filenames_fp.push_back(path);
}
@@ -591,4 +606,16 @@ void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
MultiFilesSelected(filenames_fp);
}
+void SelectFileDialogLinuxKde::OnSelectMultiFolderDialogResponse(
+ gfx::AcceleratedWidget parent,
+ std::unique_ptr<KDialogOutputParams> results) {
+ SelectMultiFileDialogHelper(true, parent, std::move(results));
+}
+
+void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
+ gfx::AcceleratedWidget parent,
+ std::unique_ptr<KDialogOutputParams> results) {
+ SelectMultiFileDialogHelper(false, parent, std::move(results));
+}
+
} // namespace ui
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.cc b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
index 9780c80ffff7bdb715a9adcb656e5d33be974db6..cf6edf5c68a8e2f8ffda119b58c6283bc43199c0 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.cc