From 7a6e7972064fc63a5c069b71de9e5a8b097e025b Mon Sep 17 00:00:00 2001 From: Justin Shannon Date: Thu, 13 Jul 2023 09:23:01 -0600 Subject: [PATCH] Add option to keep window on top --- CMakeLists.txt | 3 +- include/shared.h | 1 + include/window_manager.h | 7 +++++ src/application.cpp | 2 ++ src/main.cpp | 8 ++++++ src/modals/settings.cpp | 7 +++++ src/window_manager.cpp | 62 ++++++++++++++++++++++++++++++++++++++++ src/window_manager.mm | 16 +++++++++++ 8 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 include/window_manager.h create mode 100644 src/window_manager.cpp create mode 100644 src/window_manager.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 405c308..4a65105 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/include ${NEARGYE_SEMVER_INCLUDE_DIRS}) if (APPLE) - set(APPLE_EXTRA_LIBS src/osx_resources.mm) + set(APPLE_EXTRA_LIBS src/osx_resources.mm src/window_manager.mm) endif() if (WIN32) @@ -74,6 +74,7 @@ add_executable(vector_audio src/main.cpp src/application.cpp src/config.cpp src/updater.cpp + src/window_manager.cpp src/data_file_handler.cpp src/modals/settings.cpp ${CMAKE_SOURCE_DIR}/extern/PlatformFolders/sago/platform_folders.cpp diff --git a/include/shared.h b/include/shared.h index d9cdc75..5273896 100644 --- a/include/shared.h +++ b/include/shared.h @@ -64,6 +64,7 @@ inline float mPeak = 60.0f; inline float mVu = 60.0f; inline int vatsim_cid; inline std::string vatsim_password; +inline bool keepWindowOnTop = false; const int kMinVhf = 118000000; // 118.000 const int kMaxVhf = 136975000; // 136.975 diff --git a/include/window_manager.h b/include/window_manager.h new file mode 100644 index 0000000..365549f --- /dev/null +++ b/include/window_manager.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +namespace vector_audio { + void setAlwaysOnTop(sf::RenderWindow& window, bool alwaysOnTop); +} \ No newline at end of file diff --git a/src/application.cpp b/src/application.cpp index b144818..2b34aa9 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -47,6 +47,8 @@ App::App() vector_audio::shared::vatsim_password = toml::find_or( cfg::config, "user", "vatsim_password", std::string("password")); + vector_audio::shared::keepWindowOnTop = toml::find_or(cfg::config, "user", "keepWindowOnTop", false); + vector_audio::shared::ptt = static_cast( toml::find_or(cfg::config, "user", "ptt", static_cast(sf::Keyboard::Scan::Unknown))); diff --git a/src/main.cpp b/src/main.cpp index 637bfc7..4be8d1f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,7 @@ #include "spdlog/spdlog.h" #include "style.h" #include "updater.h" +#include "window_manager.h" // Main code int main(int, char**) @@ -93,6 +94,9 @@ int main(int, char**) auto current_app = std::make_unique(); + bool alwaysOnTop = vector_audio::shared::keepWindowOnTop; + vector_audio::setAlwaysOnTop(window, alwaysOnTop); + // Main loop sf::Clock delta_clock; while (window.isOpen()) { @@ -137,7 +141,11 @@ int main(int, char**) vector_audio::configuration::write_config_async(); vector_audio::shared::capture_ptt_flag = false; } + } + if (vector_audio::shared::keepWindowOnTop != alwaysOnTop) { + vector_audio::setAlwaysOnTop(window, vector_audio::shared::keepWindowOnTop); + alwaysOnTop = vector_audio::shared::keepWindowOnTop; } } diff --git a/src/modals/settings.cpp b/src/modals/settings.cpp index 62839ef..be33897 100644 --- a/src/modals/settings.cpp +++ b/src/modals/settings.cpp @@ -142,6 +142,12 @@ void vector_audio::modals::Settings::render(afv_native::api::atcClient* mClient) } vector_audio::style::button_reset_colour(); + ImGui::NewLine(); + + ImGui::Checkbox("Keep Window On Top", &vector_audio::shared::keepWindowOnTop); + ImGui::SameLine(); + vector_audio::util::HelpMarker("Enable this option to make the VectorAudio\nwindow stay on top of other windows."); + ImGui::TableNextColumn(); ImGui::Text("Audio configuration"); @@ -309,6 +315,7 @@ void vector_audio::modals::Settings::render(afv_native::api::atcClient* mClient) if (ImGui::Button("Save", ImVec2(ImGui::GetContentRegionAvail().x, 0.0F))) { vector_audio::configuration::config["user"]["vatsim_id"] = vector_audio::shared::vatsim_cid; vector_audio::configuration::config["user"]["vatsim_password"] = vector_audio::shared::vatsim_password; + vector_audio::configuration::config["user"]["keepWindowOnTop"] = vector_audio::shared::keepWindowOnTop; vector_audio::configuration::config["audio"]["input_filters"] = vector_audio::shared::mInputFilter; vector_audio::configuration::config["audio"]["vhf_effects"] = vector_audio::shared::mOutputEffects; vector_audio::configuration::config["audio"]["hardware_type"] = static_cast(vector_audio::shared::hardware); diff --git a/src/window_manager.cpp b/src/window_manager.cpp new file mode 100644 index 0000000..cf91ee3 --- /dev/null +++ b/src/window_manager.cpp @@ -0,0 +1,62 @@ +#include "window_manager.h" + +#include + +#ifdef SFML_SYSTEM_WINDOWS +#include +#elif defined(SFML_SYSTEM_LINUX) +#include +#include +#endif + +namespace vector_audio { + +#if !defined(SFML_SYSTEM_MACOS) + +void setAlwaysOnTop(sf::RenderWindow& window, bool alwaysOnTop) { +#ifdef SFML_SYSTEM_WINDOWS + + HWND hwnd = window.getSystemHandle(); + SetWindowPos(hwnd, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + +#elif defined(SFML_SYSTEM_LINUX) + + XEvent event; + Atom wmStateAbove; + Atom wmNetWmState; + + auto display = XOpenDisplay(NULL); + if(!display) { + std::cerr << "WindowManager: failed to open display" << std::endl; + return; + } + + auto xwin = static_cast(window.getSystemHandle()); + if(!xwin) { + std::cerr << "WindowManager: getSystemHandle is null" << std::endl; + return; + } + + wmStateAbove = XInternAtom(display, "_NET_WM_STATE_ABOVE", False); + wmNetWmState = XInternAtom(display, "_NET_WM_STATE", False); + + event.xclient.type = ClientMessage; + event.xclient.display = display; + event.xclient.window = xwin; + event.xclient.message_type = wmNetWmState; + event.xclient.format = 32; + event.xclient.data.l[0] = alwaysOnTop ? 1 : 0; // _NET_WM_STATE_ADD + event.xclient.data.l[1] = wmStateAbove; + event.xclient.data.l[2] = 0; // No second property + event.xclient.data.l[3] = 1; // Normal application window + + XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &event); + XSync(display, False); + XCloseDisplay(display); + +#endif +} + +#endif + +} \ No newline at end of file diff --git a/src/window_manager.mm b/src/window_manager.mm new file mode 100644 index 0000000..0137b83 --- /dev/null +++ b/src/window_manager.mm @@ -0,0 +1,16 @@ +#include "window_manager.h" + +#import + +namespace vector_audio { + + void setAlwaysOnTop(sf::RenderWindow& window, bool alwaysOnTop) { + NSWindow* nsWindow = static_cast(window.getSystemHandle()); + if (alwaysOnTop) { + [nsWindow setLevel:NSFloatingWindowLevel]; + } else { + [nsWindow setLevel:NSNormalWindowLevel]; + } + } + +} \ No newline at end of file