cef/tests/cefclient/browser/client_prefs.cc

209 lines
6.6 KiB
C++

// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "tests/cefclient/browser/client_prefs.h"
#include <memory>
#include "include/base/cef_logging.h"
#include "include/cef_command_line.h"
#include "include/cef_preference.h"
#include "include/cef_values.h"
#include "include/views/cef_display.h"
#include "include/wrapper/cef_helpers.h"
#include "tests/shared/common/client_switches.h"
#include "tests/shared/common/string_util.h"
namespace client::prefs {
namespace {
constexpr char kPrefWindowRestore[] = "cefclient.window_restore";
constexpr char kWindowRestoreStateKey[] = "state";
constexpr char kWindowRestoreBoundsKey[] = "bounds";
constexpr char kWindowRestoreBoundsKey_X[] = "x";
constexpr char kWindowRestoreBoundsKey_Y[] = "y";
constexpr char kWindowRestoreBoundsKey_W[] = "w";
constexpr char kWindowRestoreBoundsKey_H[] = "h";
static struct {
const char* str;
cef_show_state_t state;
} const kWindowRestoreStateValueMap[] = {
{"normal", CEF_SHOW_STATE_NORMAL},
{"minimized", CEF_SHOW_STATE_MINIMIZED},
{"maximized", CEF_SHOW_STATE_MAXIMIZED},
{"fullscreen", CEF_SHOW_STATE_FULLSCREEN},
#if defined(OS_MAC)
// Hidden show state is only supported on MacOS.
{"hidden", CEF_SHOW_STATE_HIDDEN},
#endif
};
std::optional<cef_show_state_t> ShowStateFromString(const std::string& str) {
const auto strLower = AsciiStrToLower(str);
for (auto i : kWindowRestoreStateValueMap) {
if (strLower == i.str) {
return i.state;
}
}
return std::nullopt;
}
const char* ShowStateToString(cef_show_state_t show_state) {
for (auto i : kWindowRestoreStateValueMap) {
if (show_state == i.state) {
return i.str;
}
}
NOTREACHED();
return nullptr;
}
// Create the CefValue representation that will be stored in preferences.
CefRefPtr<CefValue> CreateWindowRestoreValue(
cef_show_state_t show_state,
std::optional<CefRect> dip_bounds) {
auto dict = CefDictionaryValue::Create();
// Show state is required.
dict->SetString(kWindowRestoreStateKey, ShowStateToString(show_state));
// Bounds is optional.
if (dip_bounds) {
auto bounds_dict = CefDictionaryValue::Create();
bounds_dict->SetInt(kWindowRestoreBoundsKey_X, dip_bounds->x);
bounds_dict->SetInt(kWindowRestoreBoundsKey_Y, dip_bounds->y);
bounds_dict->SetInt(kWindowRestoreBoundsKey_W, dip_bounds->width);
bounds_dict->SetInt(kWindowRestoreBoundsKey_H, dip_bounds->height);
dict->SetDictionary(kWindowRestoreBoundsKey, bounds_dict);
}
auto value = CefValue::Create();
value->SetDictionary(dict);
return value;
}
CefRefPtr<CefValue> CreateDefaultWindowRestoreValue() {
return CreateWindowRestoreValue(CEF_SHOW_STATE_NORMAL, std::nullopt);
}
// Parse the CefValue representation that was stored in preferences.
bool ParseWindowRestoreValue(CefRefPtr<CefValue> value,
cef_show_state_t& show_state,
std::optional<CefRect>& dip_bounds) {
if (!value || value->GetType() != VTYPE_DICTIONARY) {
return false;
}
auto dict = value->GetDictionary();
bool has_state = false;
// Show state is required.
if (dict->GetType(kWindowRestoreStateKey) == VTYPE_STRING) {
auto result = ShowStateFromString(dict->GetString(kWindowRestoreStateKey));
if (result) {
show_state = *result;
has_state = true;
}
}
// Bounds is optional.
if (has_state && dict->GetType(kWindowRestoreBoundsKey) == VTYPE_DICTIONARY) {
auto bounds_dict = dict->GetDictionary(kWindowRestoreBoundsKey);
if (bounds_dict->GetType(kWindowRestoreBoundsKey_X) == VTYPE_INT &&
bounds_dict->GetType(kWindowRestoreBoundsKey_Y) == VTYPE_INT &&
bounds_dict->GetType(kWindowRestoreBoundsKey_W) == VTYPE_INT &&
bounds_dict->GetType(kWindowRestoreBoundsKey_H) == VTYPE_INT) {
dip_bounds = CefRect(bounds_dict->GetInt(kWindowRestoreBoundsKey_X),
bounds_dict->GetInt(kWindowRestoreBoundsKey_Y),
bounds_dict->GetInt(kWindowRestoreBoundsKey_W),
bounds_dict->GetInt(kWindowRestoreBoundsKey_H));
}
}
return has_state;
}
// Keep the bounds inside the closest display work area.
CefRect ClampBoundsToDisplay(const CefRect& dip_bounds) {
auto display = CefDisplay::GetDisplayMatchingBounds(
dip_bounds, /*input_pixel_coords=*/false);
const auto work_area = display->GetWorkArea();
CefRect bounds = dip_bounds;
if (bounds.width > work_area.width) {
bounds.width = work_area.width;
}
if (bounds.height > work_area.height) {
bounds.height = work_area.height;
}
if (bounds.x < work_area.x) {
bounds.x = work_area.x;
} else if (bounds.x + bounds.width >= work_area.x + work_area.width) {
bounds.x = work_area.x + work_area.width - bounds.width;
}
if (bounds.y < work_area.y) {
bounds.y = work_area.y;
} else if (bounds.y + bounds.height >= work_area.y + work_area.height) {
bounds.y = work_area.y + work_area.height - bounds.height;
}
return bounds;
}
} // namespace
void RegisterGlobalPreferences(CefRawPtr<CefPreferenceRegistrar> registrar) {
registrar->AddPreference(kPrefWindowRestore,
CreateDefaultWindowRestoreValue());
}
bool LoadWindowRestorePreferences(cef_show_state_t& show_state,
std::optional<CefRect>& dip_bounds) {
CEF_REQUIRE_UI_THREAD();
// Check if show state was specified on the command-line.
auto command_line = CefCommandLine::GetGlobalCommandLine();
if (command_line->HasSwitch(switches::kInitialShowState)) {
auto result = ShowStateFromString(
command_line->GetSwitchValue(switches::kInitialShowState));
if (result) {
show_state = *result;
return true;
}
}
// Check if show state was saved in global preferences.
auto manager = CefPreferenceManager::GetGlobalPreferenceManager();
if (ParseWindowRestoreValue(manager->GetPreference(kPrefWindowRestore),
show_state, dip_bounds)) {
if (dip_bounds) {
// Keep the bounds inside the closest display.
dip_bounds = ClampBoundsToDisplay(*dip_bounds);
}
return true;
}
return false;
}
bool SaveWindowRestorePreferences(cef_show_state_t show_state,
std::optional<CefRect> dip_bounds) {
CEF_REQUIRE_UI_THREAD();
auto manager = CefPreferenceManager::GetGlobalPreferenceManager();
CefString error;
return manager->SetPreference(
kPrefWindowRestore, CreateWindowRestoreValue(show_state, dip_bounds),
error);
}
} // namespace client::prefs