improve Linux runtime behavior
This commit is contained in:
parent
32a6743554
commit
2c21bd516b
11 changed files with 349 additions and 54 deletions
|
|
@ -112,6 +112,8 @@ bool IsFinalized();
|
||||||
void SaveConfig(const std::filesystem::path& config_path);
|
void SaveConfig(const std::filesystem::path& config_path);
|
||||||
void SaveConfigValues(const std::filesystem::path& config_path,
|
void SaveConfigValues(const std::filesystem::path& config_path,
|
||||||
std::initializer_list<std::string_view> names);
|
std::initializer_list<std::string_view> names);
|
||||||
|
void SaveConfigValues(const std::filesystem::path& config_path,
|
||||||
|
const std::vector<std::string_view>& names);
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Flag Registry
|
// Flag Registry
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ class MnkInputDriver final : public InputDriver,
|
||||||
void UpdateMouseCapture();
|
void UpdateMouseCapture();
|
||||||
void SetKeyState(uint16_t vk, bool down);
|
void SetKeyState(uint16_t vk, bool down);
|
||||||
void EnqueueKeystroke(uint16_t vk_pad, bool down);
|
void EnqueueKeystroke(uint16_t vk_pad, bool down);
|
||||||
|
void ClearStateLocked();
|
||||||
|
|
||||||
rex::ui::Window* attached_window_ = nullptr;
|
rex::ui::Window* attached_window_ = nullptr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@ class ImGuiDialog {
|
||||||
|
|
||||||
ImGuiDrawer* imgui_drawer() const { return imgui_drawer_; }
|
ImGuiDrawer* imgui_drawer() const { return imgui_drawer_; }
|
||||||
ImGuiIO& GetIO();
|
ImGuiIO& GetIO();
|
||||||
|
void SetDrawActive(bool active);
|
||||||
|
bool IsDrawActive() const { return is_draw_active_; }
|
||||||
|
|
||||||
// Closes the dialog and returns to any waiters.
|
// Closes the dialog and returns to any waiters.
|
||||||
void Close();
|
void Close();
|
||||||
|
|
@ -54,6 +56,7 @@ class ImGuiDialog {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ImGuiDrawer* imgui_drawer_ = nullptr;
|
ImGuiDrawer* imgui_drawer_ = nullptr;
|
||||||
|
bool is_draw_active_ = true;
|
||||||
bool has_close_pending_ = false;
|
bool has_close_pending_ = false;
|
||||||
std::vector<rex::thread::Fence*> waiting_fences_;
|
std::vector<rex::thread::Fence*> waiting_fences_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,14 @@ class GTKWindow : public Window {
|
||||||
GtkWidget* window() const { return window_; }
|
GtkWidget* window() const { return window_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
uint32_t GetLatestDpiImpl() const override;
|
||||||
bool OpenImpl() override;
|
bool OpenImpl() override;
|
||||||
void RequestCloseImpl() override;
|
void RequestCloseImpl() override;
|
||||||
|
|
||||||
void ApplyNewFullscreen() override;
|
void ApplyNewFullscreen() override;
|
||||||
void ApplyNewTitle() override;
|
void ApplyNewTitle() override;
|
||||||
void ApplyNewMainMenu(MenuItem* old_main_menu) override;
|
void ApplyNewMainMenu(MenuItem* old_main_menu) override;
|
||||||
|
void ApplyNewCursorVisibility(CursorVisibility old_cursor_visibility) override;
|
||||||
// Mouse capture seems to happen implicitly compared to Windows.
|
// Mouse capture seems to happen implicitly compared to Windows.
|
||||||
void FocusImpl() override;
|
void FocusImpl() override;
|
||||||
|
|
||||||
|
|
@ -51,6 +53,7 @@ class GTKWindow : public Window {
|
||||||
void RequestPaintImpl() override;
|
void RequestPaintImpl() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void UpdateDpi(WindowDestructionReceiver* destruction_receiver = nullptr);
|
||||||
void HandleSizeUpdate(WindowDestructionReceiver& destruction_receiver);
|
void HandleSizeUpdate(WindowDestructionReceiver& destruction_receiver);
|
||||||
// For updating multiple factors that may influence the window size at once,
|
// For updating multiple factors that may influence the window size at once,
|
||||||
// without handling the configure event multiple times (that may not only
|
// without handling the configure event multiple times (that may not only
|
||||||
|
|
@ -64,6 +67,9 @@ class GTKWindow : public Window {
|
||||||
bool HandleKeyboard(GdkEventKey* event, WindowDestructionReceiver& destruction_receiver);
|
bool HandleKeyboard(GdkEventKey* event, WindowDestructionReceiver& destruction_receiver);
|
||||||
gboolean WindowEventHandler(GdkEvent* event);
|
gboolean WindowEventHandler(GdkEvent* event);
|
||||||
static gboolean WindowEventHandlerThunk(GtkWidget* widget, GdkEvent* event, gpointer user_data);
|
static gboolean WindowEventHandlerThunk(GtkWidget* widget, GdkEvent* event, gpointer user_data);
|
||||||
|
void ApplyCursor();
|
||||||
|
void SetCursorAutoHideTimer();
|
||||||
|
static gboolean AutoHideCursorTimerCallback(gpointer user_data);
|
||||||
|
|
||||||
// Handling events related specifically to the drawing (client) area.
|
// Handling events related specifically to the drawing (client) area.
|
||||||
gboolean DrawingAreaEventHandler(GdkEvent* event);
|
gboolean DrawingAreaEventHandler(GdkEvent* event);
|
||||||
|
|
@ -75,6 +81,10 @@ class GTKWindow : public Window {
|
||||||
GtkWidget* window_ = nullptr;
|
GtkWidget* window_ = nullptr;
|
||||||
GtkWidget* box_ = nullptr;
|
GtkWidget* box_ = nullptr;
|
||||||
GtkWidget* drawing_area_ = nullptr;
|
GtkWidget* drawing_area_ = nullptr;
|
||||||
|
GdkCursor* blank_cursor_ = nullptr;
|
||||||
|
guint cursor_auto_hide_timer_ = 0;
|
||||||
|
bool cursor_currently_auto_hidden_ = false;
|
||||||
|
uint32_t dpi_ = 96;
|
||||||
|
|
||||||
uint32_t batched_size_update_depth_ = 0;
|
uint32_t batched_size_update_depth_ = 0;
|
||||||
bool batched_size_update_contained_configure_ = false;
|
bool batched_size_update_contained_configure_ = false;
|
||||||
|
|
|
||||||
|
|
@ -606,25 +606,16 @@ bool IsFinalized() {
|
||||||
void SaveConfig(const std::filesystem::path& config_path) {
|
void SaveConfig(const std::filesystem::path& config_path) {
|
||||||
try {
|
try {
|
||||||
toml::table config;
|
toml::table config;
|
||||||
if (std::filesystem::exists(config_path)) {
|
|
||||||
config = toml::parse_file(config_path.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard lock(GetRegistryMutex());
|
std::lock_guard lock(GetRegistryMutex());
|
||||||
bool modified = false;
|
|
||||||
for (const auto& entry : GetRegistryStorage()) {
|
for (const auto& entry : GetRegistryStorage()) {
|
||||||
if (entry.getter() == entry.default_value) {
|
if (entry.getter() == entry.default_value) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string value = entry.getter();
|
const std::string value = entry.getter();
|
||||||
modified |= WriteConfigValue(config, entry, value);
|
WriteConfigValue(config, entry, value);
|
||||||
}
|
|
||||||
|
|
||||||
if (!modified) {
|
|
||||||
REXLOG_DEBUG("SaveConfig: no modified flags to save");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -638,6 +629,11 @@ void SaveConfig(const std::filesystem::path& config_path) {
|
||||||
|
|
||||||
void SaveConfigValues(const std::filesystem::path& config_path,
|
void SaveConfigValues(const std::filesystem::path& config_path,
|
||||||
std::initializer_list<std::string_view> names) {
|
std::initializer_list<std::string_view> names) {
|
||||||
|
SaveConfigValues(config_path, std::vector<std::string_view>(names));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveConfigValues(const std::filesystem::path& config_path,
|
||||||
|
const std::vector<std::string_view>& names) {
|
||||||
try {
|
try {
|
||||||
toml::table config;
|
toml::table config;
|
||||||
if (std::filesystem::exists(config_path)) {
|
if (std::filesystem::exists(config_path)) {
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,20 @@
|
||||||
#include <rex/input/sdl/sdl_input_driver.h>
|
#include <rex/input/sdl/sdl_input_driver.h>
|
||||||
#include <rex/input/xinput/xinput_input_driver.h>
|
#include <rex/input/xinput/xinput_input_driver.h>
|
||||||
#include <rex/logging.h>
|
#include <rex/logging.h>
|
||||||
|
#include <rex/platform.h>
|
||||||
|
|
||||||
REXCVAR_DEFINE_STRING(input_backend, "xinput", "Input", "Input backend: sdl, xinput")
|
namespace {
|
||||||
|
|
||||||
|
constexpr const char* kDefaultInputBackend =
|
||||||
|
#if REX_PLATFORM_WIN32
|
||||||
|
"xinput";
|
||||||
|
#else
|
||||||
|
"sdl";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
REXCVAR_DEFINE_STRING(input_backend, kDefaultInputBackend, "Input", "Input backend: sdl, xinput")
|
||||||
.allowed({"sdl", "xinput"});
|
.allowed({"sdl", "xinput"});
|
||||||
|
|
||||||
REXCVAR_DEFINE_BOOL(guide_button, false, "Input", "Enable guide button pass-through");
|
REXCVAR_DEFINE_BOOL(guide_button, false, "Input", "Enable guide button pass-through");
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,12 @@ bool MnkInputDriver::IsEnabled() const {
|
||||||
return REXCVAR_GET(mnk_mode);
|
return REXCVAR_GET(mnk_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MnkInputDriver::ClearStateLocked() {
|
||||||
|
std::memset(key_down_, 0, sizeof(key_down_));
|
||||||
|
mouse_dx_ = 0;
|
||||||
|
mouse_dy_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool IsBindPressed(const bool (&key_down)[256], const std::string& cvar_val) {
|
static bool IsBindPressed(const bool (&key_down)[256], const std::string& cvar_val) {
|
||||||
VirtualKey vk = rex::ui::ParseVirtualKey(cvar_val);
|
VirtualKey vk = rex::ui::ParseVirtualKey(cvar_val);
|
||||||
if (vk == VirtualKey::kNone)
|
if (vk == VirtualKey::kNone)
|
||||||
|
|
@ -138,13 +144,20 @@ X_RESULT MnkInputDriver::GetCapabilities(uint32_t user_index, uint32_t flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
X_RESULT MnkInputDriver::GetState(uint32_t user_index, X_INPUT_STATE* out_state) {
|
X_RESULT MnkInputDriver::GetState(uint32_t user_index, X_INPUT_STATE* out_state) {
|
||||||
if (!IsEnabled() || user_index != UserIndex()) {
|
if (!IsEnabled()) {
|
||||||
|
std::lock_guard lock(state_mutex_);
|
||||||
|
ClearStateLocked();
|
||||||
|
return X_ERROR_DEVICE_NOT_CONNECTED;
|
||||||
|
}
|
||||||
|
if (user_index != UserIndex()) {
|
||||||
return X_ERROR_DEVICE_NOT_CONNECTED;
|
return X_ERROR_DEVICE_NOT_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateMouseCapture();
|
UpdateMouseCapture();
|
||||||
|
|
||||||
if (!is_active() || !has_focus_) {
|
if (!is_active() || !has_focus_) {
|
||||||
|
std::lock_guard lock(state_mutex_);
|
||||||
|
ClearStateLocked();
|
||||||
if (out_state) {
|
if (out_state) {
|
||||||
std::memset(out_state, 0, sizeof(*out_state));
|
std::memset(out_state, 0, sizeof(*out_state));
|
||||||
out_state->packet_number = packet_number_;
|
out_state->packet_number = packet_number_;
|
||||||
|
|
@ -235,10 +248,25 @@ X_RESULT MnkInputDriver::SetState(uint32_t user_index, X_INPUT_VIBRATION* vibrat
|
||||||
|
|
||||||
X_RESULT MnkInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags,
|
X_RESULT MnkInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags,
|
||||||
X_INPUT_KEYSTROKE* out_keystroke) {
|
X_INPUT_KEYSTROKE* out_keystroke) {
|
||||||
if (!IsEnabled() || user_index != UserIndex()) {
|
if (!IsEnabled()) {
|
||||||
|
std::lock_guard lock(state_mutex_);
|
||||||
|
ClearStateLocked();
|
||||||
|
while (!keystroke_queue_.empty()) {
|
||||||
|
keystroke_queue_.pop();
|
||||||
|
}
|
||||||
|
return X_ERROR_DEVICE_NOT_CONNECTED;
|
||||||
|
}
|
||||||
|
if (user_index != UserIndex()) {
|
||||||
return X_ERROR_DEVICE_NOT_CONNECTED;
|
return X_ERROR_DEVICE_NOT_CONNECTED;
|
||||||
}
|
}
|
||||||
std::lock_guard lock(state_mutex_);
|
std::lock_guard lock(state_mutex_);
|
||||||
|
if (!is_active() || !has_focus_) {
|
||||||
|
ClearStateLocked();
|
||||||
|
while (!keystroke_queue_.empty()) {
|
||||||
|
keystroke_queue_.pop();
|
||||||
|
}
|
||||||
|
return X_ERROR_EMPTY;
|
||||||
|
}
|
||||||
if (keystroke_queue_.empty()) {
|
if (keystroke_queue_.empty()) {
|
||||||
return X_ERROR_EMPTY;
|
return X_ERROR_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
@ -308,8 +336,9 @@ void MnkInputDriver::SetKeyState(uint16_t vk, bool down) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MnkInputDriver::OnKeyDown(rex::ui::KeyEvent& e) {
|
void MnkInputDriver::OnKeyDown(rex::ui::KeyEvent& e) {
|
||||||
if (!IsEnabled() || !has_focus_)
|
if (!IsEnabled() || !has_focus_ || !is_active()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
std::lock_guard lock(state_mutex_);
|
std::lock_guard lock(state_mutex_);
|
||||||
uint16_t vk = static_cast<uint16_t>(e.virtual_key());
|
uint16_t vk = static_cast<uint16_t>(e.virtual_key());
|
||||||
SetKeyState(vk, true);
|
SetKeyState(vk, true);
|
||||||
|
|
@ -324,7 +353,7 @@ void MnkInputDriver::OnKeyUp(rex::ui::KeyEvent& e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MnkInputDriver::OnMouseDown(rex::ui::MouseEvent& e) {
|
void MnkInputDriver::OnMouseDown(rex::ui::MouseEvent& e) {
|
||||||
if (!IsEnabled() || !has_focus_)
|
if (!IsEnabled() || !has_focus_ || !is_active())
|
||||||
return;
|
return;
|
||||||
std::lock_guard lock(state_mutex_);
|
std::lock_guard lock(state_mutex_);
|
||||||
switch (e.button()) {
|
switch (e.button()) {
|
||||||
|
|
@ -362,7 +391,7 @@ void MnkInputDriver::OnMouseUp(rex::ui::MouseEvent& e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MnkInputDriver::OnMouseMove(rex::ui::MouseEvent& e) {
|
void MnkInputDriver::OnMouseMove(rex::ui::MouseEvent& e) {
|
||||||
if (!IsEnabled() || !has_focus_)
|
if (!IsEnabled() || !has_focus_ || !is_active())
|
||||||
return;
|
return;
|
||||||
std::lock_guard lock(state_mutex_);
|
std::lock_guard lock(state_mutex_);
|
||||||
int32_t x = e.x();
|
int32_t x = e.x();
|
||||||
|
|
@ -376,9 +405,7 @@ void MnkInputDriver::OnMouseMove(rex::ui::MouseEvent& e) {
|
||||||
void MnkInputDriver::OnLostFocus(rex::ui::UISetupEvent&) {
|
void MnkInputDriver::OnLostFocus(rex::ui::UISetupEvent&) {
|
||||||
std::lock_guard lock(state_mutex_);
|
std::lock_guard lock(state_mutex_);
|
||||||
has_focus_ = false;
|
has_focus_ = false;
|
||||||
std::memset(key_down_, 0, sizeof(key_down_));
|
ClearStateLocked();
|
||||||
mouse_dx_ = 0;
|
|
||||||
mouse_dy_ = 0;
|
|
||||||
if (mouse_captured_ && attached_window_) {
|
if (mouse_captured_ && attached_window_) {
|
||||||
mouse_captured_ = false;
|
mouse_captured_ = false;
|
||||||
attached_window_->SetCursorVisibility(rex::ui::Window::CursorVisibility::kVisible);
|
attached_window_->SetCursorVisibility(rex::ui::Window::CursorVisibility::kVisible);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ ImGuiDialog::ImGuiDialog(ImGuiDrawer* imgui_drawer) : imgui_drawer_(imgui_drawer
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiDialog::~ImGuiDialog() {
|
ImGuiDialog::~ImGuiDialog() {
|
||||||
imgui_drawer_->RemoveDialog(this);
|
SetDrawActive(false);
|
||||||
for (auto fence : waiting_fences_) {
|
for (auto fence : waiting_fences_) {
|
||||||
fence->Signal();
|
fence->Signal();
|
||||||
}
|
}
|
||||||
|
|
@ -41,6 +41,18 @@ ImGuiIO& ImGuiDialog::GetIO() {
|
||||||
return imgui_drawer()->GetIO();
|
return imgui_drawer()->GetIO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImGuiDialog::SetDrawActive(bool active) {
|
||||||
|
if (is_draw_active_ == active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
is_draw_active_ = active;
|
||||||
|
if (active) {
|
||||||
|
imgui_drawer_->AddDialog(this);
|
||||||
|
} else {
|
||||||
|
imgui_drawer_->RemoveDialog(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ImGuiDialog::Draw() {
|
void ImGuiDialog::Draw() {
|
||||||
// Draw UI.
|
// Draw UI.
|
||||||
OnDraw(GetIO());
|
OnDraw(GetIO());
|
||||||
|
|
|
||||||
|
|
@ -23,18 +23,44 @@ constexpr std::array<double, 6> kFrameCapRates = {60.0, 90.0, 120.0, 144.0, 165.
|
||||||
constexpr std::array<const char*, 7> kFrameCapLabels = {"Unlimited", "60 FPS", "90 FPS",
|
constexpr std::array<const char*, 7> kFrameCapLabels = {"Unlimited", "60 FPS", "90 FPS",
|
||||||
"120 FPS", "144 FPS", "165 FPS",
|
"120 FPS", "144 FPS", "165 FPS",
|
||||||
"240 FPS"};
|
"240 FPS"};
|
||||||
constexpr std::array<std::string_view, 10> kSimpleSettingsCvars = {
|
constexpr std::array<std::string_view, 7> kCoreSimpleSettingsCvars = {
|
||||||
"resolution_scale",
|
"resolution_scale",
|
||||||
"draw_resolution_scale_x",
|
"draw_resolution_scale_x",
|
||||||
"draw_resolution_scale_y",
|
"draw_resolution_scale_y",
|
||||||
"d3d12_present_frame_limiter",
|
|
||||||
"d3d12_present_frame_limiter_fps",
|
|
||||||
"fullscreen",
|
"fullscreen",
|
||||||
"vsync",
|
"vsync",
|
||||||
"d3d12_allow_variable_refresh_rate_and_tearing",
|
|
||||||
"mnk_mode",
|
"mnk_mode",
|
||||||
"mnk_capture_mouse"};
|
"mnk_capture_mouse"};
|
||||||
|
|
||||||
|
bool HasCvar(std::string_view name) {
|
||||||
|
return rex::cvar::GetFlagInfo(name) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string_view> GetSimpleSettingsCvars() {
|
||||||
|
std::vector<std::string_view> cvars;
|
||||||
|
cvars.reserve(14);
|
||||||
|
cvars.insert(cvars.end(), kCoreSimpleSettingsCvars.begin(), kCoreSimpleSettingsCvars.end());
|
||||||
|
if (HasCvar("d3d12_present_frame_limiter")) {
|
||||||
|
cvars.push_back("d3d12_present_frame_limiter");
|
||||||
|
}
|
||||||
|
if (HasCvar("d3d12_present_frame_limiter_fps")) {
|
||||||
|
cvars.push_back("d3d12_present_frame_limiter_fps");
|
||||||
|
}
|
||||||
|
if (HasCvar("d3d12_allow_variable_refresh_rate_and_tearing")) {
|
||||||
|
cvars.push_back("d3d12_allow_variable_refresh_rate_and_tearing");
|
||||||
|
}
|
||||||
|
if (HasCvar("vulkan_allow_present_mode_immediate")) {
|
||||||
|
cvars.push_back("vulkan_allow_present_mode_immediate");
|
||||||
|
}
|
||||||
|
if (HasCvar("vulkan_allow_present_mode_mailbox")) {
|
||||||
|
cvars.push_back("vulkan_allow_present_mode_mailbox");
|
||||||
|
}
|
||||||
|
if (HasCvar("vulkan_allow_present_mode_fifo_relaxed")) {
|
||||||
|
cvars.push_back("vulkan_allow_present_mode_fifo_relaxed");
|
||||||
|
}
|
||||||
|
return cvars;
|
||||||
|
}
|
||||||
|
|
||||||
int ResolutionIndexFromCvar() {
|
int ResolutionIndexFromCvar() {
|
||||||
int32_t current = rex::cvar::Query<int32_t>("resolution_scale");
|
int32_t current = rex::cvar::Query<int32_t>("resolution_scale");
|
||||||
int best = 0;
|
int best = 0;
|
||||||
|
|
@ -50,7 +76,14 @@ int ResolutionIndexFromCvar() {
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasFrameCapCvars() {
|
||||||
|
return HasCvar("d3d12_present_frame_limiter") && HasCvar("d3d12_present_frame_limiter_fps");
|
||||||
|
}
|
||||||
|
|
||||||
int FrameCapIndexFromCvar() {
|
int FrameCapIndexFromCvar() {
|
||||||
|
if (!HasFrameCapCvars()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (!rex::cvar::Query<bool>("d3d12_present_frame_limiter")) {
|
if (!rex::cvar::Query<bool>("d3d12_present_frame_limiter")) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -77,6 +110,31 @@ void SetBoolCvar(std::string_view name, bool value) {
|
||||||
rex::cvar::SetFlagByName(name, value ? "true" : "false");
|
rex::cvar::SetFlagByName(name, value ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TearingFromCvar() {
|
||||||
|
if (HasCvar("d3d12_allow_variable_refresh_rate_and_tearing")) {
|
||||||
|
return rex::cvar::Query<bool>("d3d12_allow_variable_refresh_rate_and_tearing");
|
||||||
|
}
|
||||||
|
if (HasCvar("vulkan_allow_present_mode_immediate")) {
|
||||||
|
return rex::cvar::Query<bool>("vulkan_allow_present_mode_immediate");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTearingCvars(bool value) {
|
||||||
|
if (HasCvar("d3d12_allow_variable_refresh_rate_and_tearing")) {
|
||||||
|
SetBoolCvar("d3d12_allow_variable_refresh_rate_and_tearing", value);
|
||||||
|
}
|
||||||
|
if (HasCvar("vulkan_allow_present_mode_immediate")) {
|
||||||
|
SetBoolCvar("vulkan_allow_present_mode_immediate", value);
|
||||||
|
}
|
||||||
|
if (HasCvar("vulkan_allow_present_mode_mailbox")) {
|
||||||
|
SetBoolCvar("vulkan_allow_present_mode_mailbox", value);
|
||||||
|
}
|
||||||
|
if (HasCvar("vulkan_allow_present_mode_fifo_relaxed")) {
|
||||||
|
SetBoolCvar("vulkan_allow_present_mode_fifo_relaxed", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SectionTitle(const char* label) {
|
void SectionTitle(const char* label) {
|
||||||
ImGui::PushFont(nullptr, 20.0f);
|
ImGui::PushFont(nullptr, 20.0f);
|
||||||
ImGui::TextUnformatted(label);
|
ImGui::TextUnformatted(label);
|
||||||
|
|
@ -103,17 +161,7 @@ bool PrimaryButton(const char* label) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void SaveSimpleSettingsConfig(const std::filesystem::path& config_path) {
|
void SaveSimpleSettingsConfig(const std::filesystem::path& config_path) {
|
||||||
rex::cvar::SaveConfigValues(config_path,
|
rex::cvar::SaveConfigValues(config_path, GetSimpleSettingsCvars());
|
||||||
{"resolution_scale",
|
|
||||||
"draw_resolution_scale_x",
|
|
||||||
"draw_resolution_scale_y",
|
|
||||||
"d3d12_present_frame_limiter",
|
|
||||||
"d3d12_present_frame_limiter_fps",
|
|
||||||
"fullscreen",
|
|
||||||
"vsync",
|
|
||||||
"d3d12_allow_variable_refresh_rate_and_tearing",
|
|
||||||
"mnk_mode",
|
|
||||||
"mnk_capture_mouse"});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnsureSimpleSettingsConfig(const std::filesystem::path& config_path) {
|
void EnsureSimpleSettingsConfig(const std::filesystem::path& config_path) {
|
||||||
|
|
@ -121,7 +169,7 @@ void EnsureSimpleSettingsConfig(const std::filesystem::path& config_path) {
|
||||||
if (!should_save) {
|
if (!should_save) {
|
||||||
try {
|
try {
|
||||||
auto config = toml::parse_file(config_path.string());
|
auto config = toml::parse_file(config_path.string());
|
||||||
for (std::string_view name : kSimpleSettingsCvars) {
|
for (std::string_view name : GetSimpleSettingsCvars()) {
|
||||||
if (!config.contains(name)) {
|
if (!config.contains(name)) {
|
||||||
should_save = true;
|
should_save = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -152,12 +200,14 @@ SimpleSettingsDialog::SimpleSettingsDialog(ImGuiDrawer* drawer, std::filesystem:
|
||||||
restart_game_(std::move(restart_game)) {
|
restart_game_(std::move(restart_game)) {
|
||||||
ReloadProfiles();
|
ReloadProfiles();
|
||||||
LoadSettingsFromCvars();
|
LoadSettingsFromCvars();
|
||||||
|
SetDrawActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleSettingsDialog::~SimpleSettingsDialog() = default;
|
SimpleSettingsDialog::~SimpleSettingsDialog() = default;
|
||||||
|
|
||||||
void SimpleSettingsDialog::Show() {
|
void SimpleSettingsDialog::Show() {
|
||||||
visible_ = true;
|
visible_ = true;
|
||||||
|
SetDrawActive(true);
|
||||||
ReloadProfiles();
|
ReloadProfiles();
|
||||||
LoadSettingsFromCvars();
|
LoadSettingsFromCvars();
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +217,7 @@ void SimpleSettingsDialog::LoadSettingsFromCvars() {
|
||||||
frame_cap_index_ = FrameCapIndexFromCvar();
|
frame_cap_index_ = FrameCapIndexFromCvar();
|
||||||
fullscreen_ = rex::cvar::Query<bool>("fullscreen");
|
fullscreen_ = rex::cvar::Query<bool>("fullscreen");
|
||||||
vsync_ = rex::cvar::Query<bool>("vsync");
|
vsync_ = rex::cvar::Query<bool>("vsync");
|
||||||
tearing_ = rex::cvar::Query<bool>("d3d12_allow_variable_refresh_rate_and_tearing");
|
tearing_ = TearingFromCvar();
|
||||||
mnk_mode_ = rex::cvar::Query<bool>("mnk_mode");
|
mnk_mode_ = rex::cvar::Query<bool>("mnk_mode");
|
||||||
mnk_capture_mouse_ = rex::cvar::Query<bool>("mnk_capture_mouse");
|
mnk_capture_mouse_ = rex::cvar::Query<bool>("mnk_capture_mouse");
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +227,7 @@ bool SimpleSettingsDialog::HasSettingsChanges() const {
|
||||||
frame_cap_index_ != FrameCapIndexFromCvar() ||
|
frame_cap_index_ != FrameCapIndexFromCvar() ||
|
||||||
fullscreen_ != rex::cvar::Query<bool>("fullscreen") ||
|
fullscreen_ != rex::cvar::Query<bool>("fullscreen") ||
|
||||||
vsync_ != rex::cvar::Query<bool>("vsync") ||
|
vsync_ != rex::cvar::Query<bool>("vsync") ||
|
||||||
tearing_ != rex::cvar::Query<bool>("d3d12_allow_variable_refresh_rate_and_tearing") ||
|
tearing_ != TearingFromCvar() ||
|
||||||
mnk_mode_ != rex::cvar::Query<bool>("mnk_mode") ||
|
mnk_mode_ != rex::cvar::Query<bool>("mnk_mode") ||
|
||||||
mnk_capture_mouse_ != rex::cvar::Query<bool>("mnk_capture_mouse");
|
mnk_capture_mouse_ != rex::cvar::Query<bool>("mnk_capture_mouse");
|
||||||
}
|
}
|
||||||
|
|
@ -195,6 +245,7 @@ void SimpleSettingsDialog::Hide() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
visible_ = false;
|
visible_ = false;
|
||||||
|
SetDrawActive(false);
|
||||||
if (close_settings_) {
|
if (close_settings_) {
|
||||||
close_settings_();
|
close_settings_();
|
||||||
}
|
}
|
||||||
|
|
@ -222,14 +273,16 @@ void SimpleSettingsDialog::SaveVideo() {
|
||||||
rex::cvar::SetFlagByName("resolution_scale", scale);
|
rex::cvar::SetFlagByName("resolution_scale", scale);
|
||||||
rex::cvar::SetFlagByName("draw_resolution_scale_x", scale);
|
rex::cvar::SetFlagByName("draw_resolution_scale_x", scale);
|
||||||
rex::cvar::SetFlagByName("draw_resolution_scale_y", scale);
|
rex::cvar::SetFlagByName("draw_resolution_scale_y", scale);
|
||||||
SetBoolCvar("d3d12_present_frame_limiter", frame_cap_index_ != 0);
|
if (HasFrameCapCvars()) {
|
||||||
if (frame_cap_index_ != 0) {
|
SetBoolCvar("d3d12_present_frame_limiter", frame_cap_index_ != 0);
|
||||||
|
}
|
||||||
|
if (HasFrameCapCvars() && frame_cap_index_ != 0) {
|
||||||
rex::cvar::SetFlagByName("d3d12_present_frame_limiter_fps",
|
rex::cvar::SetFlagByName("d3d12_present_frame_limiter_fps",
|
||||||
std::to_string(kFrameCapRates[frame_cap_index_ - 1]));
|
std::to_string(kFrameCapRates[frame_cap_index_ - 1]));
|
||||||
}
|
}
|
||||||
SetBoolCvar("fullscreen", fullscreen_);
|
SetBoolCvar("fullscreen", fullscreen_);
|
||||||
SetBoolCvar("vsync", vsync_);
|
SetBoolCvar("vsync", vsync_);
|
||||||
SetBoolCvar("d3d12_allow_variable_refresh_rate_and_tearing", tearing_);
|
SetTearingCvars(tearing_);
|
||||||
SetBoolCvar("mnk_mode", mnk_mode_);
|
SetBoolCvar("mnk_mode", mnk_mode_);
|
||||||
SetBoolCvar("mnk_capture_mouse", mnk_capture_mouse_);
|
SetBoolCvar("mnk_capture_mouse", mnk_capture_mouse_);
|
||||||
SaveSimpleSettingsConfig(config_path_);
|
SaveSimpleSettingsConfig(config_path_);
|
||||||
|
|
@ -341,10 +394,12 @@ void SimpleSettingsDialog::OnDraw(ImGuiIO& io) {
|
||||||
static_cast<int>(kResolutionLabels.size()));
|
static_cast<int>(kResolutionLabels.size()));
|
||||||
EndFieldRow();
|
EndFieldRow();
|
||||||
|
|
||||||
BeginFieldRow("Framerate Cap");
|
if (HasFrameCapCvars()) {
|
||||||
ImGui::Combo("##frame_cap", &frame_cap_index_, kFrameCapLabels.data(),
|
BeginFieldRow("Framerate Cap");
|
||||||
static_cast<int>(kFrameCapLabels.size()));
|
ImGui::Combo("##frame_cap", &frame_cap_index_, kFrameCapLabels.data(),
|
||||||
EndFieldRow();
|
static_cast<int>(kFrameCapLabels.size()));
|
||||||
|
EndFieldRow();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include <rex/filesystem.h>
|
#include <rex/filesystem.h>
|
||||||
#include <rex/logging/sink.h>
|
#include <rex/logging/sink.h>
|
||||||
#include <rex/logging.h>
|
#include <rex/logging.h>
|
||||||
|
#include <rex/platform.h>
|
||||||
#include <rex/ui/overlay/console_overlay.h>
|
#include <rex/ui/overlay/console_overlay.h>
|
||||||
#include <rex/ui/overlay/debug_overlay.h>
|
#include <rex/ui/overlay/debug_overlay.h>
|
||||||
#include <rex/ui/overlay/settings_overlay.h>
|
#include <rex/ui/overlay/settings_overlay.h>
|
||||||
|
|
@ -50,7 +51,18 @@
|
||||||
|
|
||||||
namespace rex {
|
namespace rex {
|
||||||
|
|
||||||
REXCVAR_DEFINE_BOOL(advanced_settings_overlay_enabled, false, "UI/Advanced",
|
namespace {
|
||||||
|
|
||||||
|
constexpr bool kBlockShaderStorageStartup =
|
||||||
|
#if REX_PLATFORM_WIN32
|
||||||
|
true;
|
||||||
|
#else
|
||||||
|
false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
REXCVAR_DEFINE_BOOL(advanced_settings_overlay_enabled, true, "UI/Advanced",
|
||||||
"Enable the developer cvar browser on F4");
|
"Enable the developer cvar browser on F4");
|
||||||
|
|
||||||
// --- ReXApp ---
|
// --- ReXApp ---
|
||||||
|
|
@ -262,7 +274,8 @@ bool ReXApp::ConstructRuntime(const PathConfig& paths) {
|
||||||
input_sys->SetActiveCallback([this]() {
|
input_sys->SetActiveCallback([this]() {
|
||||||
if (!debug_overlay_ && !console_overlay_ && !settings_overlay_)
|
if (!debug_overlay_ && !console_overlay_ && !settings_overlay_)
|
||||||
return true;
|
return true;
|
||||||
return !imgui_drawer_->GetIO().WantCaptureMouse;
|
const auto& io = imgui_drawer_->GetIO();
|
||||||
|
return !io.WantCaptureMouse && !io.WantCaptureKeyboard;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -416,7 +429,8 @@ void ReXApp::LaunchModule() {
|
||||||
uint32_t title_id = runtime_->kernel_state()->title_id();
|
uint32_t title_id = runtime_->kernel_state()->title_id();
|
||||||
if (title_id != 0) {
|
if (title_id != 0) {
|
||||||
REXLOG_INFO("Initializing shader storage for title {:08X}...", title_id);
|
REXLOG_INFO("Initializing shader storage for title {:08X}...", title_id);
|
||||||
graphics_system->InitializeShaderStorage(runtime_->cache_root(), title_id, true);
|
graphics_system->InitializeShaderStorage(runtime_->cache_root(), title_id,
|
||||||
|
kBlockShaderStorageStartup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,50 @@
|
||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
REXCVAR_DEFINE_DOUBLE(gtk_ui_scale, 1.25, "UI/GTK",
|
||||||
|
"GTK effective UI scale multiplier")
|
||||||
|
.range(0.75, 2.0)
|
||||||
|
.lifecycle(rex::cvar::Lifecycle::kRequiresRestart);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr uint32_t kDefaultDpi = 96;
|
||||||
|
|
||||||
|
uint32_t CalculateMonitorDpi(GdkMonitor* monitor) {
|
||||||
|
if (!monitor) {
|
||||||
|
return kDefaultDpi;
|
||||||
|
}
|
||||||
|
// GDK monitor geometry plus physical millimeter size gives EDID physical
|
||||||
|
// density, not the desktop UI scale. Match Windows DPI behavior by exposing
|
||||||
|
// effective UI DPI instead.
|
||||||
|
const int scale_factor = std::max(1, gdk_monitor_get_scale_factor(monitor));
|
||||||
|
const auto dpi =
|
||||||
|
uint32_t(double(kDefaultDpi * uint32_t(scale_factor)) * REXCVAR_GET(gtk_ui_scale) + 0.5);
|
||||||
|
return std::clamp(dpi, uint32_t(48), uint32_t(384));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t QueryWidgetDpi(GtkWidget* widget) {
|
||||||
|
GdkDisplay* display = widget ? gtk_widget_get_display(widget) : gdk_display_get_default();
|
||||||
|
if (!display) {
|
||||||
|
return kDefaultDpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
GdkMonitor* monitor = nullptr;
|
||||||
|
if (widget) {
|
||||||
|
GdkWindow* gdk_window = gtk_widget_get_window(widget);
|
||||||
|
if (gdk_window) {
|
||||||
|
monitor = gdk_display_get_monitor_at_window(display, gdk_window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!monitor) {
|
||||||
|
monitor = gdk_display_get_primary_monitor(display);
|
||||||
|
}
|
||||||
|
if (!monitor && gdk_display_get_n_monitors(display) > 0) {
|
||||||
|
monitor = gdk_display_get_monitor(display, 0);
|
||||||
|
}
|
||||||
|
return CalculateMonitorDpi(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t ResolveWindowWidth(uint32_t requested_width) {
|
uint32_t ResolveWindowWidth(uint32_t requested_width) {
|
||||||
if (REXCVAR_GET(window_width) > 0) {
|
if (REXCVAR_GET(window_width) > 0) {
|
||||||
return uint32_t(REXCVAR_GET(window_width));
|
return uint32_t(REXCVAR_GET(window_width));
|
||||||
|
|
@ -313,10 +355,20 @@ std::unique_ptr<Window> Window::Create(WindowedAppContext& app_context,
|
||||||
|
|
||||||
GTKWindow::GTKWindow(WindowedAppContext& app_context, const std::string_view title,
|
GTKWindow::GTKWindow(WindowedAppContext& app_context, const std::string_view title,
|
||||||
uint32_t desired_logical_width, uint32_t desired_logical_height)
|
uint32_t desired_logical_width, uint32_t desired_logical_height)
|
||||||
: Window(app_context, title, desired_logical_width, desired_logical_height) {}
|
: Window(app_context, title, desired_logical_width, desired_logical_height) {
|
||||||
|
dpi_ = QueryWidgetDpi(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
GTKWindow::~GTKWindow() {
|
GTKWindow::~GTKWindow() {
|
||||||
EnterDestructor();
|
EnterDestructor();
|
||||||
|
if (cursor_auto_hide_timer_) {
|
||||||
|
g_source_remove(cursor_auto_hide_timer_);
|
||||||
|
cursor_auto_hide_timer_ = 0;
|
||||||
|
}
|
||||||
|
if (blank_cursor_) {
|
||||||
|
g_object_unref(blank_cursor_);
|
||||||
|
blank_cursor_ = nullptr;
|
||||||
|
}
|
||||||
if (window_) {
|
if (window_) {
|
||||||
// Set window_ to null to ignore events from now on since this ui::GTKWindow
|
// Set window_ to null to ignore events from now on since this ui::GTKWindow
|
||||||
// is entering an indeterminate state.
|
// is entering an indeterminate state.
|
||||||
|
|
@ -329,8 +381,26 @@ GTKWindow::~GTKWindow() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t GTKWindow::GetLatestDpiImpl() const {
|
||||||
|
return dpi_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GTKWindow::UpdateDpi(WindowDestructionReceiver* destruction_receiver) {
|
||||||
|
const uint32_t new_dpi = QueryWidgetDpi(drawing_area_ ? drawing_area_ : window_);
|
||||||
|
if (!new_dpi || new_dpi == dpi_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dpi_ = new_dpi;
|
||||||
|
if (destruction_receiver) {
|
||||||
|
UISetupEvent e(this);
|
||||||
|
OnDpiChanged(e, *destruction_receiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool GTKWindow::OpenImpl() {
|
bool GTKWindow::OpenImpl() {
|
||||||
window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||||
|
blank_cursor_ = gdk_cursor_new_for_display(gtk_widget_get_display(window_), GDK_BLANK_CURSOR);
|
||||||
|
|
||||||
gtk_window_set_title(GTK_WINDOW(window_), GetTitle().c_str());
|
gtk_window_set_title(GTK_WINDOW(window_), GetTitle().c_str());
|
||||||
|
|
||||||
|
|
@ -345,6 +415,10 @@ bool GTKWindow::OpenImpl() {
|
||||||
if (main_menu_widget) {
|
if (main_menu_widget) {
|
||||||
gtk_box_pack_start(GTK_BOX(box_), main_menu_widget, FALSE, FALSE, 0);
|
gtk_box_pack_start(GTK_BOX(box_), main_menu_widget, FALSE, FALSE, 0);
|
||||||
}
|
}
|
||||||
|
const bool initial_fullscreen = IsFullscreen();
|
||||||
|
if (initial_fullscreen && main_menu_widget) {
|
||||||
|
gtk_container_remove(GTK_CONTAINER(box_), main_menu_widget);
|
||||||
|
}
|
||||||
|
|
||||||
// Create the drawing area for creating the surface for, which will be the
|
// Create the drawing area for creating the surface for, which will be the
|
||||||
// client area of the window occupying all the window space not taken by the
|
// client area of the window occupying all the window space not taken by the
|
||||||
|
|
@ -371,8 +445,22 @@ bool GTKWindow::OpenImpl() {
|
||||||
g_signal_connect(G_OBJECT(drawing_area_), "draw", G_CALLBACK(DrawHandler),
|
g_signal_connect(G_OBJECT(drawing_area_), "draw", G_CALLBACK(DrawHandler),
|
||||||
reinterpret_cast<gpointer>(this));
|
reinterpret_cast<gpointer>(this));
|
||||||
|
|
||||||
|
if (initial_fullscreen) {
|
||||||
|
gtk_window_fullscreen(GTK_WINDOW(window_));
|
||||||
|
g_idle_add(
|
||||||
|
[](gpointer user_data) -> gboolean {
|
||||||
|
auto* gtk_window = reinterpret_cast<GTKWindow*>(user_data);
|
||||||
|
if (gtk_window->window_ && gtk_window->IsFullscreen()) {
|
||||||
|
gtk_window_fullscreen(GTK_WINDOW(gtk_window->window_));
|
||||||
|
}
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
},
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
// Finally show all the widgets in the window, including the main menu.
|
// Finally show all the widgets in the window, including the main menu.
|
||||||
gtk_widget_show_all(window_);
|
gtk_widget_show_all(window_);
|
||||||
|
UpdateDpi();
|
||||||
|
|
||||||
// Remove the size request after finishing the initial layout because it makes
|
// Remove the size request after finishing the initial layout because it makes
|
||||||
// it impossible to make the window smaller.
|
// it impossible to make the window smaller.
|
||||||
|
|
@ -393,12 +481,10 @@ bool GTKWindow::OpenImpl() {
|
||||||
|
|
||||||
// After setting up the initial layout for non-fullscreen, enter fullscreen if
|
// After setting up the initial layout for non-fullscreen, enter fullscreen if
|
||||||
// requested.
|
// requested.
|
||||||
if (IsFullscreen()) {
|
if (initial_fullscreen) {
|
||||||
if (main_menu_widget) {
|
|
||||||
gtk_container_remove(GTK_CONTAINER(box_), main_menu_widget);
|
|
||||||
}
|
|
||||||
gtk_window_fullscreen(GTK_WINDOW(window_));
|
gtk_window_fullscreen(GTK_WINDOW(window_));
|
||||||
}
|
}
|
||||||
|
ApplyNewCursorVisibility(CursorVisibility::kVisible);
|
||||||
|
|
||||||
// Make sure the initial state after opening is reported to the common Window
|
// Make sure the initial state after opening is reported to the common Window
|
||||||
// class no matter how GTK sends the events.
|
// class no matter how GTK sends the events.
|
||||||
|
|
@ -556,6 +642,20 @@ void GTKWindow::ApplyNewMainMenu(MenuItem* old_main_menu) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GTKWindow::ApplyNewCursorVisibility(CursorVisibility old_cursor_visibility) {
|
||||||
|
CursorVisibility new_cursor_visibility = GetCursorVisibility();
|
||||||
|
if (cursor_auto_hide_timer_) {
|
||||||
|
g_source_remove(cursor_auto_hide_timer_);
|
||||||
|
cursor_auto_hide_timer_ = 0;
|
||||||
|
}
|
||||||
|
cursor_currently_auto_hidden_ = new_cursor_visibility != CursorVisibility::kVisible;
|
||||||
|
ApplyCursor();
|
||||||
|
if (new_cursor_visibility == CursorVisibility::kAutoHidden &&
|
||||||
|
old_cursor_visibility == CursorVisibility::kAutoHidden) {
|
||||||
|
SetCursorAutoHideTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GTKWindow::FocusImpl() {
|
void GTKWindow::FocusImpl() {
|
||||||
gtk_window_activate_focus(GTK_WINDOW(window_));
|
gtk_window_activate_focus(GTK_WINDOW(window_));
|
||||||
}
|
}
|
||||||
|
|
@ -594,10 +694,17 @@ void GTKWindow::HandleSizeUpdate(WindowDestructionReceiver& destruction_receiver
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(Triang3l): Report the desired client area size.
|
UpdateDpi(&destruction_receiver);
|
||||||
|
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GtkAllocation drawing_area_allocation;
|
GtkAllocation drawing_area_allocation;
|
||||||
gtk_widget_get_allocation(drawing_area_, &drawing_area_allocation);
|
gtk_widget_get_allocation(drawing_area_, &drawing_area_allocation);
|
||||||
|
if (!IsFullscreen()) {
|
||||||
|
OnDesiredLogicalSizeUpdate(SizeToLogical(uint32_t(drawing_area_allocation.width)),
|
||||||
|
SizeToLogical(uint32_t(drawing_area_allocation.height)));
|
||||||
|
}
|
||||||
OnActualSizeUpdate(uint32_t(drawing_area_allocation.width),
|
OnActualSizeUpdate(uint32_t(drawing_area_allocation.width),
|
||||||
uint32_t(drawing_area_allocation.height), destruction_receiver);
|
uint32_t(drawing_area_allocation.height), destruction_receiver);
|
||||||
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
||||||
|
|
@ -757,6 +864,14 @@ gboolean GTKWindow::WindowEventHandler(GdkEvent* event) {
|
||||||
// at some point in closing anyway.
|
// at some point in closing anyway.
|
||||||
GtkWidget* window = window_;
|
GtkWidget* window = window_;
|
||||||
window_ = nullptr;
|
window_ = nullptr;
|
||||||
|
if (cursor_auto_hide_timer_) {
|
||||||
|
g_source_remove(cursor_auto_hide_timer_);
|
||||||
|
cursor_auto_hide_timer_ = 0;
|
||||||
|
}
|
||||||
|
if (blank_cursor_) {
|
||||||
|
g_object_unref(blank_cursor_);
|
||||||
|
blank_cursor_ = nullptr;
|
||||||
|
}
|
||||||
// Destroying the top-level window also destroys its children.
|
// Destroying the top-level window also destroys its children.
|
||||||
drawing_area_ = nullptr;
|
drawing_area_ = nullptr;
|
||||||
box_ = nullptr;
|
box_ = nullptr;
|
||||||
|
|
@ -773,6 +888,7 @@ gboolean GTKWindow::WindowEventHandler(GdkEvent* event) {
|
||||||
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
ApplyCursor();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case GDK_KEY_PRESS:
|
case GDK_KEY_PRESS:
|
||||||
|
|
@ -805,12 +921,59 @@ gboolean GTKWindow::WindowEventHandlerThunk(GtkWidget* widget, GdkEvent* event,
|
||||||
return window->WindowEventHandler(event);
|
return window->WindowEventHandler(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GTKWindow::ApplyCursor() {
|
||||||
|
if (!drawing_area_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GdkWindow* drawing_area_window = gtk_widget_get_window(drawing_area_);
|
||||||
|
if (!drawing_area_window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GdkCursor* cursor = nullptr;
|
||||||
|
switch (GetCursorVisibility()) {
|
||||||
|
case CursorVisibility::kVisible:
|
||||||
|
cursor = nullptr;
|
||||||
|
break;
|
||||||
|
case CursorVisibility::kAutoHidden:
|
||||||
|
cursor = cursor_currently_auto_hidden_ ? blank_cursor_ : nullptr;
|
||||||
|
break;
|
||||||
|
case CursorVisibility::kHidden:
|
||||||
|
cursor = blank_cursor_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gdk_window_set_cursor(drawing_area_window, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GTKWindow::SetCursorAutoHideTimer() {
|
||||||
|
if (cursor_auto_hide_timer_) {
|
||||||
|
g_source_remove(cursor_auto_hide_timer_);
|
||||||
|
cursor_auto_hide_timer_ = 0;
|
||||||
|
}
|
||||||
|
cursor_auto_hide_timer_ =
|
||||||
|
g_timeout_add(kDefaultCursorAutoHideMilliseconds, AutoHideCursorTimerCallback, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean GTKWindow::AutoHideCursorTimerCallback(gpointer user_data) {
|
||||||
|
auto* gtk_window = reinterpret_cast<GTKWindow*>(user_data);
|
||||||
|
gtk_window->cursor_auto_hide_timer_ = 0;
|
||||||
|
if (gtk_window->GetCursorVisibility() == CursorVisibility::kAutoHidden) {
|
||||||
|
gtk_window->cursor_currently_auto_hidden_ = true;
|
||||||
|
gtk_window->ApplyCursor();
|
||||||
|
}
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean GTKWindow::DrawingAreaEventHandler(GdkEvent* event) {
|
gboolean GTKWindow::DrawingAreaEventHandler(GdkEvent* event) {
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case GDK_MOTION_NOTIFY:
|
case GDK_MOTION_NOTIFY:
|
||||||
case GDK_BUTTON_PRESS:
|
case GDK_BUTTON_PRESS:
|
||||||
case GDK_BUTTON_RELEASE:
|
case GDK_BUTTON_RELEASE:
|
||||||
case GDK_SCROLL: {
|
case GDK_SCROLL: {
|
||||||
|
if (GetCursorVisibility() == CursorVisibility::kAutoHidden) {
|
||||||
|
cursor_currently_auto_hidden_ = false;
|
||||||
|
ApplyCursor();
|
||||||
|
SetCursorAutoHideTimer();
|
||||||
|
}
|
||||||
WindowDestructionReceiver destruction_receiver(this);
|
WindowDestructionReceiver destruction_receiver(this);
|
||||||
HandleMouse(event, destruction_receiver);
|
HandleMouse(event, destruction_receiver);
|
||||||
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
if (destruction_receiver.IsWindowDestroyedOrClosed()) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue