diff --git a/desktop-ui/desktop-ui.cpp b/desktop-ui/desktop-ui.cpp index 648a4a6c7d..f731d90f92 100644 --- a/desktop-ui/desktop-ui.cpp +++ b/desktop-ui/desktop-ui.cpp @@ -112,6 +112,9 @@ auto nall::main(Arguments arguments) -> void { print(" --terminal Create new terminal window\n"); #endif print(" --fullscreen Start in full screen mode\n"); +#if defined(PLATFORM_WINDOWS) + print(" --no/--Borderless Disable/Enable Borderless Window"); +#endif print(" --system name Specify the system name\n"); print(" --shader name Specify the name of the shader to use\n"); print(" --setting name=value Specify a value for a setting\n"); @@ -126,6 +129,15 @@ auto nall::main(Arguments arguments) -> void { print("\n"); return; } + +#if defined(PLATFORM_WINDOWS) + if(arguments.take("--noBorderless")) { + settings.general.borderless = false; + } + if(arguments.take("--Borderless")) { + settings.general.borderless = true; + } +#endif if(arguments.take("--dump-all-settings")) { function dump; diff --git a/desktop-ui/input/hotkeys.cpp b/desktop-ui/input/hotkeys.cpp index 5ac5407958..1c404a3be1 100644 --- a/desktop-ui/input/hotkeys.cpp +++ b/desktop-ui/input/hotkeys.cpp @@ -139,6 +139,12 @@ auto InputManager::createHotkeys() -> void { if(!emulator) return; if(settings.audio.volume >= (f64)(0.1)) settings.audio.volume -= (f64)(0.1); })); + +#if defined(PLATFORM_WINDOWS) + hotkeys.append(InputHotkey("Toggle Borderless Window").onPress([&] { + program.updateBorderless(); + })); +#endif } auto InputManager::pollHotkeys() -> void { diff --git a/desktop-ui/presentation/presentation.cpp b/desktop-ui/presentation/presentation.cpp index 0b867b9884..d1647fb3da 100644 --- a/desktop-ui/presentation/presentation.cpp +++ b/desktop-ui/presentation/presentation.cpp @@ -100,6 +100,17 @@ Presentation::Presentation() { } if(visible()) resizeWindow(); }).doToggle(); +#if defined(PLATFORM_WINDOWS) + showBorderlessSetting.setText("Borderless Window").setChecked(settings.general.borderless).onToggle([&] { + settings.general.borderless = showBorderlessSetting.checked(); + if(!showBorderlessSetting.checked()) { + Window::setBorderless(false); + }else{ + Window::setBorderless(true); + } + if(visible()) resizeWindow(); + }).doToggle(); +#endif videoSettingsAction.setText("Video" ELLIPSIS).setIcon(Icon::Device::Display).onActivate([&] { settingsWindow.show("Video"); }); diff --git a/desktop-ui/presentation/presentation.hpp b/desktop-ui/presentation/presentation.hpp index 50ff8566c5..47be172e1f 100644 --- a/desktop-ui/presentation/presentation.hpp +++ b/desktop-ui/presentation/presentation.hpp @@ -40,6 +40,9 @@ struct Presentation : Window { MenuSeparator groupSettingsSeparatpr{&settingsMenu}; MenuCheckItem muteAudioSetting{&settingsMenu}; MenuCheckItem showStatusBarSetting{&settingsMenu}; +#if defined(PLATFORM_WINDOWS) + MenuCheckItem showBorderlessSetting{&settingsMenu}; +#endif MenuSeparator audioSettingsSeparator{&settingsMenu}; MenuItem videoSettingsAction{&settingsMenu}; MenuItem audioSettingsAction{&settingsMenu}; diff --git a/desktop-ui/program/program.hpp b/desktop-ui/program/program.hpp index 862c57ba12..2cf0a07c10 100644 --- a/desktop-ui/program/program.hpp +++ b/desktop-ui/program/program.hpp @@ -30,6 +30,9 @@ struct Program : ares::Platform { //status.cpp auto updateMessage() -> void; auto showMessage(const string&) -> void; +#if defined(PLATFORM_WINDOWS) + auto updateBorderless() -> void; +#endif //utility.cpp auto pause(bool) -> void; diff --git a/desktop-ui/program/status.cpp b/desktop-ui/program/status.cpp index bf2614604c..35c9111f89 100644 --- a/desktop-ui/program/status.cpp +++ b/desktop-ui/program/status.cpp @@ -28,3 +28,17 @@ auto Program::showMessage(const string& text) -> void { messages.append({chrono::millisecond(), text}); printf("%s\n", (const char*)text); } +#if defined(PLATFORM_WINDOWS) +auto Program::updateBorderless() -> void { + bool state = settings.general.borderless ? false : true; + if(!state){ + presentation.Window::setBorderless(false); + presentation.showBorderlessSetting.setChecked(false); + } else { + presentation.Window::setBorderless(true); + presentation.showBorderlessSetting.setChecked(true); + } + settings.general.borderless = state; + if(presentation.visible()) presentation.resizeWindow(); +} +#endif \ No newline at end of file diff --git a/desktop-ui/settings/settings.cpp b/desktop-ui/settings/settings.cpp index b913db5803..d5808f044a 100644 --- a/desktop-ui/settings/settings.cpp +++ b/desktop-ui/settings/settings.cpp @@ -100,6 +100,9 @@ auto Settings::process(bool load) -> void { bind(boolean, "General/RunAhead", general.runAhead); bind(boolean, "General/AutoSaveMemory", general.autoSaveMemory); bind(boolean, "General/HomebrewMode", general.homebrewMode); +#if defined(PLATFORM_WINDOWS) + bind(boolean, "General/Borderless", general.borderless); +#endif bind(natural, "Rewind/Length", rewind.length); bind(natural, "Rewind/Frequency", rewind.frequency); diff --git a/desktop-ui/settings/settings.hpp b/desktop-ui/settings/settings.hpp index 7a538389ba..d62be81948 100644 --- a/desktop-ui/settings/settings.hpp +++ b/desktop-ui/settings/settings.hpp @@ -66,6 +66,9 @@ struct Settings : Markup::Node { bool runAhead = false; bool autoSaveMemory = true; bool homebrewMode = false; +#if defined(PLATFORM_WINDOWS) + bool borderless = false; +#endif } general; struct Rewind { diff --git a/hiro/core/shared.hpp b/hiro/core/shared.hpp index ff9f52e25b..695e59d185 100644 --- a/hiro/core/shared.hpp +++ b/hiro/core/shared.hpp @@ -904,6 +904,7 @@ struct Window : sWindow { auto append(sSizable sizable) { return self().append(sizable), *this; } auto append(sStatusBar statusBar) { return self().append(statusBar), *this; } auto backgroundColor() const { return self().backgroundColor(); } + auto borderless() const { return self().borderless(); } auto dismissable() const { return self().dismissable(); } auto doClose() const { return self().doClose(); } auto doDrop(vector names) const { return self().doDrop(names); } @@ -937,6 +938,7 @@ struct Window : sWindow { auto setAlignment(Alignment alignment = Alignment::Center) { return self().setAlignment(alignment), *this; } auto setAlignment(sWindow relativeTo, Alignment alignment = Alignment::Center) { return self().setAlignment(relativeTo, alignment), *this; } auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setBorderless(bool borderless = true) { return self().setBorderless(borderless), *this; } auto setDismissable(bool dismissable = true) { return self().setDismissable(dismissable), *this; } auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; } auto setFrameGeometry(Geometry geometry) { return self().setFrameGeometry(geometry), *this; } diff --git a/hiro/core/window.cpp b/hiro/core/window.cpp index 23ff03ba65..c690a7edbe 100644 --- a/hiro/core/window.cpp +++ b/hiro/core/window.cpp @@ -389,4 +389,14 @@ auto mWindow::title() const -> string { return state.title; } +auto mWindow::borderless() const -> bool { + return state.borderless; +} + +auto mWindow::setBorderless(bool borderless) -> type& { + state.borderless = borderless; + signal(setBorderless, borderless); + return *this; +} + #endif diff --git a/hiro/core/window.hpp b/hiro/core/window.hpp index 52df3916c7..ac658c2706 100644 --- a/hiro/core/window.hpp +++ b/hiro/core/window.hpp @@ -9,6 +9,7 @@ struct mWindow : mObject { auto append(sSizable sizable) -> type&; auto append(sStatusBar statusBar) -> type&; auto backgroundColor() const -> Color; + auto borderless() const -> bool; auto dismissable() const -> bool; auto doClose() const -> void; auto doDrop(vector) const -> void; @@ -42,6 +43,7 @@ struct mWindow : mObject { auto setAlignment(Alignment = Alignment::Center) -> type&; auto setAlignment(sWindow relativeTo, Alignment = Alignment::Center) -> type&; auto setBackgroundColor(Color color = {}) -> type&; + auto setBorderless(bool borderless = true) -> type&; auto setDismissable(bool dismissable = true) -> type&; auto setDroppable(bool droppable = true) -> type&; auto setFrameGeometry(Geometry geometry) -> type&; @@ -69,7 +71,8 @@ struct mWindow : mObject { //private: struct State { Color backgroundColor; - bool dismissable = false; + bool borderless = false; + bool dismissable = false; bool droppable = false; bool fullScreen = false; Geometry geometry = {128, 128, 256, 256}; diff --git a/hiro/windows/window.cpp b/hiro/windows/window.cpp index 118ff0d799..14c1dbbed7 100644 --- a/hiro/windows/window.cpp +++ b/hiro/windows/window.cpp @@ -19,6 +19,7 @@ static auto CALLBACK Window_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARA static constexpr u32 PopupStyle = WS_POPUP | WS_CLIPCHILDREN; static constexpr u32 FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER | WS_CLIPCHILDREN; static constexpr u32 ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN; +static constexpr u32 BorderlessStyle = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS; u32 pWindow::minimumStatusHeight = 0; @@ -423,6 +424,15 @@ auto pWindow::_statusHeight() const -> s32 { return height; } +auto pWindow::setBorderless(bool borderless) -> void { + DWORD newframeStyle = (borderless) ? BorderlessStyle : ResizableStyle; + DWORD oldframeStyle = static_cast(GetWindowLongPtrW(hwnd, GWL_STYLE)); + if (newframeStyle != oldframeStyle) { + SetWindowLongPtrW(hwnd, GWL_STYLE, static_cast(newframeStyle)); + SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE); + ShowWindow(hwnd, SW_SHOW); + } +} } #endif diff --git a/hiro/windows/window.hpp b/hiro/windows/window.hpp index d6334952c5..59a6d51b16 100644 --- a/hiro/windows/window.hpp +++ b/hiro/windows/window.hpp @@ -20,6 +20,7 @@ struct pWindow : pObject { auto remove(sSizable sizable) -> void; auto remove(sStatusBar statusBar) -> void; auto setBackgroundColor(Color color) -> void; + auto setBorderless(bool borderless) -> void; auto setDismissable(bool dismissable) -> void; auto setDroppable(bool droppable) -> void; auto setEnabled(bool enabled) -> void override; @@ -34,7 +35,7 @@ struct pWindow : pObject { auto setModal(bool modal) -> void; auto setResizable(bool resizable) -> void; auto setTitle(string text) -> void; - auto setVisible(bool visible) -> void override; + auto setVisible(bool visible) -> void override; auto modalIncrement() -> void; auto modalDecrement() -> void;