2022-10-28 20:17:18 +02:00
|
|
|
// 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"
|
|
|
|
|
2024-01-20 03:22:56 +01:00
|
|
|
namespace client::prefs {
|
2022-10-28 20:17:18 +02:00
|
|
|
|
|
|
|
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},
|
2024-01-29 19:38:25 +01:00
|
|
|
#if defined(OS_MAC)
|
|
|
|
// Hidden show state is only supported on MacOS.
|
|
|
|
{"hidden", CEF_SHOW_STATE_HIDDEN},
|
|
|
|
#endif
|
2022-10-28 20:17:18 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
std::optional<cef_show_state_t> ShowStateFromString(const std::string& str) {
|
|
|
|
const auto strLower = AsciiStrToLower(str);
|
2024-01-20 03:22:56 +01:00
|
|
|
for (auto i : kWindowRestoreStateValueMap) {
|
|
|
|
if (strLower == i.str) {
|
|
|
|
return i.state;
|
2022-10-28 20:17:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* ShowStateToString(cef_show_state_t show_state) {
|
2024-01-20 03:22:56 +01:00
|
|
|
for (auto i : kWindowRestoreStateValueMap) {
|
|
|
|
if (show_state == i.state) {
|
|
|
|
return i.str;
|
2022-10-28 20:17:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
2023-01-02 23:59:03 +01:00
|
|
|
if (bounds.width > work_area.width) {
|
2022-10-28 20:17:18 +02:00
|
|
|
bounds.width = work_area.width;
|
2023-01-02 23:59:03 +01:00
|
|
|
}
|
|
|
|
if (bounds.height > work_area.height) {
|
2022-10-28 20:17:18 +02:00
|
|
|
bounds.height = work_area.height;
|
2023-01-02 23:59:03 +01:00
|
|
|
}
|
2022-10-28 20:17:18 +02:00
|
|
|
|
2023-01-02 23:59:03 +01:00
|
|
|
if (bounds.x < work_area.x) {
|
2022-10-28 20:17:18 +02:00
|
|
|
bounds.x = work_area.x;
|
2023-01-02 23:59:03 +01:00
|
|
|
} else if (bounds.x + bounds.width >= work_area.x + work_area.width) {
|
2022-10-28 20:17:18 +02:00
|
|
|
bounds.x = work_area.x + work_area.width - bounds.width;
|
2023-01-02 23:59:03 +01:00
|
|
|
}
|
2022-10-28 20:17:18 +02:00
|
|
|
|
2023-01-02 23:59:03 +01:00
|
|
|
if (bounds.y < work_area.y) {
|
2022-10-28 20:17:18 +02:00
|
|
|
bounds.y = work_area.y;
|
2023-01-02 23:59:03 +01:00
|
|
|
} else if (bounds.y + bounds.height >= work_area.y + work_area.height) {
|
2022-10-28 20:17:18 +02:00
|
|
|
bounds.y = work_area.y + work_area.height - bounds.height;
|
2023-01-02 23:59:03 +01:00
|
|
|
}
|
2022-10-28 20:17:18 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-01-20 03:22:56 +01:00
|
|
|
} // namespace client::prefs
|