#include "remoting/host/win/simple_task_dialog.h"
#include <algorithm>
#include <iterator>
#include <string>
#include "base/logging.h"
#include "remoting/host/win/core_resource.h"
namespace remoting {
namespace {
const HRESULT kTimeoutErrorCode = E_ABORT;
bool LoadStringResource(HMODULE resource_module,
int resource_id,
std::wstring& string) {
DCHECK(resource_module);
string.clear();
const wchar_t* string_resource = nullptr;
int string_length = LoadStringW(resource_module, resource_id,
reinterpret_cast<wchar_t*>(&string_resource),
0);
if (string_length <= 0) {
PLOG(ERROR) << "LoadStringW() failed for resource ID: " << resource_id;
return false;
}
string.append(string_resource, string_length);
return true;
}
}
SimpleTaskDialog::SimpleTaskDialog(HMODULE resource_module)
: resource_module_(resource_module) {}
SimpleTaskDialog::~SimpleTaskDialog() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
bool SimpleTaskDialog::SetTitleTextWithStringId(int title_text_id) {
return LoadStringResource(resource_module_, title_text_id, title_text_);
}
bool SimpleTaskDialog::SetMessageTextWithStringId(int message_text_id) {
return LoadStringResource(resource_module_, message_text_id, message_text_);
}
void SimpleTaskDialog::AppendButton(int button_id,
const std::wstring& button_text) {
dialog_buttons_.emplace_back(button_id, button_text);
}
bool SimpleTaskDialog::AppendButtonWithStringId(int button_id,
int button_text_id) {
std::wstring button_text;
if (!LoadStringResource(resource_module_, button_text_id, button_text)) {
return false;
}
dialog_buttons_.emplace_back(button_id, button_text);
return true;
}
std::optional<int> SimpleTaskDialog::Show() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<TASKDIALOG_BUTTON> taskdialog_buttons;
std::ranges::transform(
dialog_buttons_, std::back_inserter(taskdialog_buttons),
[](const std::pair<int, std::wstring>& button) {
return TASKDIALOG_BUTTON{button.first, button.second.c_str()};
});
TASKDIALOGCONFIG dialog_config = {0};
dialog_config.cbSize = sizeof(dialog_config);
dialog_config.hInstance = resource_module_;
dialog_config.pszWindowTitle = title_text_.c_str();
dialog_config.pszMainInstruction = message_text_.c_str();
dialog_config.pszMainIcon = MAKEINTRESOURCE(IDI_CHROME_REMOTE_DESKTOP);
dialog_config.dwFlags = TDF_CALLBACK_TIMER;
dialog_config.pfCallback = &TaskDialogCallbackProc;
dialog_config.lpCallbackData = reinterpret_cast<LONG_PTR>(this);
dialog_config.cButtons = taskdialog_buttons.size();
dialog_config.pButtons = taskdialog_buttons.data();
dialog_config.nDefaultButton = default_button_;
int button_result = 0;
HRESULT hr = TaskDialogIndirect(&dialog_config, &button_result,
nullptr,
nullptr);
if (FAILED(hr)) {
if (hr == kTimeoutErrorCode) {
LOG(INFO) << "TaskDialog timed out.";
} else {
LOG(ERROR) << "TaskDialogIndirect() Failed: 0x" << std::hex << hr;
}
return std::nullopt;
}
return button_result;
}
HRESULT CALLBACK SimpleTaskDialog::TaskDialogCallbackProc(HWND hwnd,
UINT notification,
WPARAM w_param,
LPARAM l_param,
LONG_PTR ref_data) {
if (notification == TDN_TIMER) {
SimpleTaskDialog* dialog = reinterpret_cast<SimpleTaskDialog*>(ref_data);
DCHECK_CALLED_ON_VALID_SEQUENCE(dialog->sequence_checker_);
if (!dialog->dialog_timeout_.is_zero() &&
static_cast<int64_t>(w_param) >=
dialog->dialog_timeout_.InMilliseconds()) {
return kTimeoutErrorCode;
}
if (!IsWindowVisible(hwnd)) {
ShowWindow(hwnd, SW_SHOWNORMAL);
}
if (hwnd == GetForegroundWindow()) {
dialog->is_foreground_window_ = true;
} else if (dialog->is_foreground_window_) {
SetForegroundWindow(hwnd);
dialog->is_foreground_window_ = false;
}
if (!dialog->is_foreground_window_) {
BringWindowToTop(hwnd);
}
} else if (notification == TDN_CREATED) {
if (!SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE)) {
PLOG(ERROR) << "SetWindowPos() failed";
}
}
return S_OK;
}
}