mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-03 07:01:19 +00:00
Bug 1837079 - [3/10] Refactor Windows nsFilePicker dialog creation r=gstoll,handyman,win-reviewers,mhowell
Extract the creation of Windows file dialogs into a separate function, as preparation for (sometimes) performing that remotely (that is, out- of-process). No functional changes. Differential Revision: https://phabricator.services.mozilla.com/D180340
This commit is contained in:
parent
f72bfe06f7
commit
c5c346391a
@ -97,6 +97,19 @@ static HRESULT GetShellItemPath(IShellItem* aItem, nsString& aResultString) {
|
||||
if (FAILED(_tmp_hr_)) return Err(_tmp_hr_); \
|
||||
} while (0)
|
||||
|
||||
mozilla::Result<RefPtr<IFileDialog>, HRESULT> MakeFileDialog(
|
||||
FileDialogType type) {
|
||||
RefPtr<IFileDialog> dialog;
|
||||
|
||||
CLSID const clsid = type == FileDialogType::Open ? CLSID_FileOpenDialog
|
||||
: CLSID_FileSaveDialog;
|
||||
HRESULT const hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_IFileDialog, getter_AddRefs(dialog));
|
||||
MOZ_ENSURE_HRESULT_OK(hr);
|
||||
|
||||
return std::move(dialog);
|
||||
}
|
||||
|
||||
HRESULT ApplyCommands(::IFileDialog* dialog,
|
||||
nsTArray<Command> const& commands) {
|
||||
Applicator applicator{.dialog = dialog};
|
||||
|
@ -9,10 +9,17 @@
|
||||
|
||||
#include "mozilla/widget/filedialog/WinFileDialogCommandsDefn.h"
|
||||
|
||||
// Windows interface type, defined in <shobjidl_core.h>
|
||||
// Windows interface types, defined in <shobjidl.h>
|
||||
struct IFileDialog;
|
||||
struct IFileOpenDialog;
|
||||
|
||||
namespace mozilla::widget::filedialog {
|
||||
|
||||
enum class FileDialogType : uint8_t { Open, Save };
|
||||
|
||||
// Create a file-dialog of the relevant type. Requires MSCOM to be initialized.
|
||||
mozilla::Result<RefPtr<IFileDialog>, HRESULT> MakeFileDialog(FileDialogType);
|
||||
|
||||
// Apply the selected commands to the IFileDialog, in preparation for showing
|
||||
// it. (The actual showing step is left to the caller.)
|
||||
[[nodiscard]] HRESULT ApplyCommands(::IFileDialog*,
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
#include "mozilla/widget/filedialog/WinFileDialogCommands.h"
|
||||
|
||||
using mozilla::Maybe;
|
||||
using mozilla::Result;
|
||||
using mozilla::UniquePtr;
|
||||
|
||||
using namespace mozilla::widget;
|
||||
@ -78,6 +80,62 @@ NS_IMETHODIMP nsFilePicker::Init(mozIDOMWindowProxy* aParent,
|
||||
return nsBaseFilePicker::Init(aParent, aTitle, aMode);
|
||||
}
|
||||
|
||||
/* static */
|
||||
Result<Maybe<filedialog::Results>, HRESULT> nsFilePicker::ShowFilePickerLocal(
|
||||
HWND parent, filedialog::FileDialogType type,
|
||||
nsTArray<filedialog::Command> const& commands) {
|
||||
using mozilla::Err;
|
||||
using mozilla::Nothing;
|
||||
using mozilla::Some;
|
||||
|
||||
namespace fd = filedialog;
|
||||
|
||||
RefPtr<IFileDialog> dialog;
|
||||
MOZ_TRY_VAR(dialog, fd::MakeFileDialog(type));
|
||||
|
||||
if (auto const res = fd::ApplyCommands(dialog.get(), commands); FAILED(res)) {
|
||||
return Err(res);
|
||||
}
|
||||
|
||||
// synchronously show the dialog
|
||||
auto const ret = dialog->Show(parent);
|
||||
if (ret == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
|
||||
return Maybe<fd::Results>(Nothing());
|
||||
}
|
||||
if (FAILED(ret)) {
|
||||
return Err(ret);
|
||||
}
|
||||
|
||||
return fd::GetFileResults(dialog.get()).map(mozilla::Some<fd::Results>);
|
||||
}
|
||||
|
||||
/* static */
|
||||
Result<Maybe<nsString>, HRESULT> nsFilePicker::ShowFolderPickerLocal(
|
||||
HWND parent, nsTArray<filedialog::Command> const& commands) {
|
||||
using mozilla::Err;
|
||||
using mozilla::Nothing;
|
||||
using mozilla::Some;
|
||||
namespace fd = filedialog;
|
||||
|
||||
RefPtr<IFileDialog> dialog;
|
||||
MOZ_TRY_VAR(dialog, fd::MakeFileDialog(fd::FileDialogType::Open));
|
||||
|
||||
if (auto const res = fd::ApplyCommands(dialog.get(), commands); FAILED(res)) {
|
||||
return Err(res);
|
||||
}
|
||||
|
||||
// synchronously show the dialog
|
||||
auto const ret = dialog->Show(parent);
|
||||
if (ret == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
|
||||
return Maybe<nsString>(Nothing());
|
||||
}
|
||||
if (FAILED(ret)) {
|
||||
return Err(ret);
|
||||
}
|
||||
|
||||
return fd::GetFolderResults(dialog.get()).map(mozilla::Some<nsString>);
|
||||
}
|
||||
|
||||
/*
|
||||
* Folder picker invocation
|
||||
*/
|
||||
@ -90,13 +148,6 @@ NS_IMETHODIMP nsFilePicker::Init(mozIDOMWindowProxy* aParent,
|
||||
* @return true if a file was selected successfully.
|
||||
*/
|
||||
bool nsFilePicker::ShowFolderPicker(const nsString& aInitialDir) {
|
||||
RefPtr<IFileOpenDialog> dialog;
|
||||
if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr,
|
||||
CLSCTX_INPROC_SERVER, IID_IFileOpenDialog,
|
||||
getter_AddRefs(dialog)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace fd = ::mozilla::widget::filedialog;
|
||||
nsTArray<fd::Command> commands = {
|
||||
fd::SetOptions(FOS_PICKFOLDERS),
|
||||
@ -111,25 +162,28 @@ bool nsFilePicker::ShowFolderPicker(const nsString& aInitialDir) {
|
||||
commands.AppendElement(fd::SetFolder(aInitialDir));
|
||||
}
|
||||
|
||||
nsString result;
|
||||
{
|
||||
if (FAILED(fd::ApplyCommands(dialog, commands))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedRtlShimWindow shim(mParentWidget.get());
|
||||
mozilla::BackgroundHangMonitor().NotifyWait();
|
||||
AutoWidgetPickerState awps(mParentWidget);
|
||||
|
||||
if (FAILED(dialog->Show(shim.get()))) {
|
||||
mozilla::BackgroundHangMonitor().NotifyWait();
|
||||
auto res = ShowFolderPickerLocal(shim.get(), commands);
|
||||
if (res.isErr()) {
|
||||
NS_WARNING("ShowFolderPickerImpl failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto optResults = res.unwrap();
|
||||
if (!optResults) {
|
||||
// cancellation, not error
|
||||
return false;
|
||||
}
|
||||
|
||||
result = optResults.extract();
|
||||
}
|
||||
|
||||
auto result = fd::GetFolderResults(dialog.get());
|
||||
if (result.isErr()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mUnicodeFile = result.unwrap();
|
||||
mUnicodeFile = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -147,21 +201,6 @@ bool nsFilePicker::ShowFolderPicker(const nsString& aInitialDir) {
|
||||
bool nsFilePicker::ShowFilePicker(const nsString& aInitialDir) {
|
||||
AUTO_PROFILER_LABEL("nsFilePicker::ShowFilePicker", OTHER);
|
||||
|
||||
RefPtr<IFileDialog> dialog;
|
||||
if (mMode != modeSave) {
|
||||
if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr,
|
||||
CLSCTX_INPROC_SERVER, IID_IFileOpenDialog,
|
||||
getter_AddRefs(dialog)))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (FAILED(CoCreateInstance(CLSID_FileSaveDialog, nullptr,
|
||||
CLSCTX_INPROC_SERVER, IID_IFileSaveDialog,
|
||||
getter_AddRefs(dialog)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace fd = ::mozilla::widget::filedialog;
|
||||
nsTArray<fd::Command> commands;
|
||||
// options
|
||||
@ -241,29 +280,33 @@ bool nsFilePicker::ShowFilePicker(const nsString& aInitialDir) {
|
||||
}
|
||||
|
||||
// display
|
||||
fd::Results result;
|
||||
{
|
||||
if (FAILED(fd::ApplyCommands(dialog, commands))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedRtlShimWindow shim(mParentWidget.get());
|
||||
AutoWidgetPickerState awps(mParentWidget);
|
||||
|
||||
mozilla::BackgroundHangMonitor().NotifyWait();
|
||||
if (FAILED(dialog->Show(shim.get()))) {
|
||||
auto res = ShowFilePickerLocal(
|
||||
shim.get(),
|
||||
mMode == modeSave ? FileDialogType::Save : FileDialogType::Open,
|
||||
commands);
|
||||
|
||||
if (res.isErr()) {
|
||||
NS_WARNING("ShowFilePickerImpl failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// results
|
||||
auto result_ = fd::GetFileResults(dialog.get());
|
||||
if (result_.isErr()) {
|
||||
return false;
|
||||
auto optResults = res.unwrap();
|
||||
if (!optResults) {
|
||||
// cancellation, not error
|
||||
return false;
|
||||
}
|
||||
|
||||
result = optResults.extract();
|
||||
}
|
||||
auto result = result_.unwrap();
|
||||
|
||||
// Remember what filter type the user selected
|
||||
mSelectedType = result.selectedFileTypeIndex();
|
||||
mSelectedType = int32_t(result.selectedFileTypeIndex());
|
||||
|
||||
auto const& paths = result.paths();
|
||||
|
||||
|
@ -21,6 +21,12 @@
|
||||
|
||||
class nsILoadContext;
|
||||
|
||||
namespace mozilla::widget::filedialog {
|
||||
class Command;
|
||||
class Results;
|
||||
enum class FileDialogType : uint8_t;
|
||||
} // namespace mozilla::widget::filedialog
|
||||
|
||||
class nsBaseWinFilePicker : public nsBaseFilePicker {
|
||||
public:
|
||||
NS_IMETHOD GetDefaultString(nsAString& aDefaultString) override;
|
||||
@ -41,6 +47,15 @@ class nsBaseWinFilePicker : public nsBaseFilePicker {
|
||||
class nsFilePicker : public nsBaseWinFilePicker {
|
||||
virtual ~nsFilePicker() = default;
|
||||
|
||||
template <typename T>
|
||||
using Maybe = mozilla::Maybe<T>;
|
||||
template <typename T>
|
||||
using Result = mozilla::Result<T, HRESULT>;
|
||||
|
||||
using Command = mozilla::widget::filedialog::Command;
|
||||
using Results = mozilla::widget::filedialog::Results;
|
||||
using FileDialogType = mozilla::widget::filedialog::FileDialogType;
|
||||
|
||||
public:
|
||||
nsFilePicker();
|
||||
|
||||
@ -66,6 +81,14 @@ class nsFilePicker : public nsBaseWinFilePicker {
|
||||
void GetFilterListArray(nsString& aFilterList);
|
||||
bool ShowFolderPicker(const nsString& aInitialDir);
|
||||
bool ShowFilePicker(const nsString& aInitialDir);
|
||||
|
||||
private:
|
||||
static Result<Maybe<Results>> ShowFilePickerLocal(
|
||||
HWND aParent, FileDialogType type, nsTArray<Command> const& commands);
|
||||
static Result<Maybe<nsString>> ShowFolderPickerLocal(
|
||||
HWND aParent, nsTArray<Command> const& commands);
|
||||
|
||||
protected:
|
||||
void RememberLastUsedDirectory();
|
||||
bool IsPrivacyModeEnabled();
|
||||
bool IsDefaultPathLink();
|
||||
|
Loading…
x
Reference in New Issue
Block a user