diff --git a/lib/libimhex/include/hex/helpers/utils_macos.hpp b/lib/libimhex/include/hex/helpers/utils_macos.hpp index 46f09bc6d..fc1a5045c 100644 --- a/lib/libimhex/include/hex/helpers/utils_macos.hpp +++ b/lib/libimhex/include/hex/helpers/utils_macos.hpp @@ -9,6 +9,7 @@ void errorMessageMacos(const char *message); void openWebpageMacos(const char *url); bool isMacosSystemDarkModeEnabled(); + bool isMacosFullScreenModeEnabled(GLFWwindow *window); float getBackingScaleFactor(); void setupMacosWindowStyle(GLFWwindow *window); diff --git a/lib/libimhex/source/helpers/utils_macos.m b/lib/libimhex/source/helpers/utils_macos.m index 997b0cf2e..d1c97bd70 100644 --- a/lib/libimhex/source/helpers/utils_macos.m +++ b/lib/libimhex/source/helpers/utils_macos.m @@ -46,13 +46,19 @@ void setupMacosWindowStyle(GLFWwindow *window) { NSWindow* cocoaWindow = glfwGetCocoaWindow(window); + cocoaWindow.titleVisibility = NSWindowTitleHidden; + cocoaWindow.titlebarAppearsTransparent = YES; + cocoaWindow.styleMask |= NSWindowStyleMaskFullSizeContentView; - NSVisualEffectView *visualEffectView = [[NSVisualEffectView alloc] init]; - [visualEffectView setMaterial:NSVisualEffectMaterialAppearanceBased]; - [visualEffectView setBlendingMode:NSVisualEffectBlendingModeBehindWindow]; + [cocoaWindow setOpaque:NO]; + [cocoaWindow setHasShadow:YES]; + [cocoaWindow setBackgroundColor:[NSColor colorWithWhite: 0 alpha: 0.001f]]; + } - [cocoaWindow.contentView addSubview:visualEffectView positioned:NSWindowBelow relativeTo:nil]; + bool isMacosFullScreenModeEnabled(GLFWwindow *window) { + NSWindow* cocoaWindow = glfwGetCocoaWindow(window); + return (cocoaWindow.styleMask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen; } @interface HexDocument : NSDocument diff --git a/main/gui/source/window/macos_window.cpp b/main/gui/source/window/macos_window.cpp index 2fe501839..904eda012 100644 --- a/main/gui/source/window/macos_window.cpp +++ b/main/gui/source/window/macos_window.cpp @@ -41,6 +41,8 @@ namespace hex { } void Window::setupNativeWindow() { + ImHexApi::System::impl::setBorderlessWindowMode(true); + bool themeFollowSystem = ImHexApi::System::usesSystemThemeDetection(); EventOSThemeChanged::subscribe(this, [themeFollowSystem] { if (!themeFollowSystem) return; diff --git a/plugins/builtin/source/content/main_menu_items.cpp b/plugins/builtin/source/content/main_menu_items.cpp index 89364dda1..e12ab4f94 100644 --- a/plugins/builtin/source/content/main_menu_items.cpp +++ b/plugins/builtin/source/content/main_menu_items.cpp @@ -517,34 +517,38 @@ namespace hex::plugin::builtin { static void createViewMenu() { ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.view", 3000); - ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.view", "hex.builtin.menu.view.always_on_top" }, ICON_VS_PINNED, 1000, Keys::F10, [] { - static bool state = false; + #if !defined(OS_WEB) + ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.view", "hex.builtin.menu.view.always_on_top" }, ICON_VS_PINNED, 1000, Keys::F10, [] { + static bool state = false; - state = !state; - glfwSetWindowAttrib(ImHexApi::System::getMainWindowHandle(), GLFW_FLOATING, state); - }, []{ return true; }, []{ return glfwGetWindowAttrib(ImHexApi::System::getMainWindowHandle(), GLFW_FLOATING); }); + state = !state; + glfwSetWindowAttrib(ImHexApi::System::getMainWindowHandle(), GLFW_FLOATING, state); + }, []{ return true; }, []{ return glfwGetWindowAttrib(ImHexApi::System::getMainWindowHandle(), GLFW_FLOATING); }); + #endif - ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.view", "hex.builtin.menu.view.fullscreen" }, ICON_VS_SCREEN_FULL, 2000, Keys::F11, [] { - static bool state = false; - static ImVec2 position, size; + #if !defined(OS_MACOS) && !defined(OS_WEB) + ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.view", "hex.builtin.menu.view.fullscreen" }, ICON_VS_SCREEN_FULL, 2000, Keys::F11, [] { + static bool state = false; + static ImVec2 position, size; - state = !state; + state = !state; - const auto window = ImHexApi::System::getMainWindowHandle(); - if (state) { - position = ImHexApi::System::getMainWindowPosition(); - size = ImHexApi::System::getMainWindowSize(); + const auto window = ImHexApi::System::getMainWindowHandle(); + if (state) { + position = ImHexApi::System::getMainWindowPosition(); + size = ImHexApi::System::getMainWindowSize(); - const auto monitor = glfwGetPrimaryMonitor(); - const auto videoMode = glfwGetVideoMode(monitor); + const auto monitor = glfwGetPrimaryMonitor(); + const auto videoMode = glfwGetVideoMode(monitor); - glfwSetWindowMonitor(window, monitor, 0, 0, videoMode->width, videoMode->height, videoMode->refreshRate); - } else { - glfwSetWindowMonitor(window, nullptr, position.x, position.y, size.x, size.y, 0); - } + glfwSetWindowMonitor(window, monitor, 0, 0, videoMode->width, videoMode->height, videoMode->refreshRate); + } else { + glfwSetWindowMonitor(window, nullptr, position.x, position.y, size.x, size.y, 0); + } - }, []{ return true; }, []{ return glfwGetWindowMonitor(ImHexApi::System::getMainWindowHandle()) != nullptr; }); + }, []{ return true; }, []{ return glfwGetWindowMonitor(ImHexApi::System::getMainWindowHandle()) != nullptr; }); + #endif ContentRegistry::Interface::addMenuItemSeparator({ "hex.builtin.menu.view" }, 3000); diff --git a/plugins/builtin/source/content/window_decoration.cpp b/plugins/builtin/source/content/window_decoration.cpp index f05c014e0..d6708659b 100644 --- a/plugins/builtin/source/content/window_decoration.cpp +++ b/plugins/builtin/source/content/window_decoration.cpp @@ -132,21 +132,55 @@ namespace hex::plugin::builtin { ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabActive)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabHovered)); + auto framePadding = ImGui::GetStyle().FramePadding * 2; + const auto windowSize = ImHexApi::System::getMainWindowSize(); - const auto searchBoxSize = ImVec2(windowSize.x / 2.5, titleBarHeight - 3_scaled); - const auto searchBoxPos = ImVec2((windowSize / 2 - searchBoxSize / 2).x, 3_scaled); + const auto searchBoxSize = ImVec2(windowSize.x / 2.5, titleBarHeight); + const auto searchBoxPos = ImVec2((windowSize / 2 - searchBoxSize / 2).x, framePadding.y); s_searchBarPosition = searchBoxPos.x; // Custom titlebar buttons implementation for borderless window mode + auto window = ImHexApi::System::getMainWindowHandle(); + bool titleBarButtonsVisible = false; + if (ImHexApi::System::isBorderlessWindowModeEnabled() && glfwGetWindowMonitor(window) == nullptr) { + #if defined(OS_WINDOWS) + titleBarButtonsVisible = true; + + // Draw minimize, restore and maximize buttons + ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 3); + if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_MINIMIZE, buttonSize)) + glfwIconifyWindow(window); + if (glfwGetWindowAttrib(window, GLFW_MAXIMIZED)) { + if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_RESTORE, buttonSize)) + glfwRestoreWindow(window); + } else { + if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_MAXIMIZE, buttonSize)) + glfwMaximizeWindow(window); + } + + ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xFF7A70F1); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF2311E8); + + // Draw close button + if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_CLOSE, buttonSize)) { + ImHexApi::System::closeImHex(); + } + + ImGui::PopStyleColor(2); + + #endif + } + auto &titleBarButtons = ContentRegistry::Interface::impl::getTitleBarButtons(); // Draw custom title bar buttons if (!titleBarButtons.empty()) { - ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * float(4 + titleBarButtons.size())); + ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * float((titleBarButtonsVisible ? 4 : 0) + titleBarButtons.size())); if (ImGui::GetCursorPosX() > (searchBoxPos.x + searchBoxSize.x)) { - for (const auto &[icon, tooltip, callback]: titleBarButtons) { + for (const auto &[icon, tooltip, callback] : titleBarButtons) { + ImGui::SetCursorPosY(framePadding.y); if (ImGuiExt::TitleBarButton(icon.c_str(), buttonSize)) { callback(); } @@ -155,31 +189,6 @@ namespace hex::plugin::builtin { } } - auto window = ImHexApi::System::getMainWindowHandle(); - if (ImHexApi::System::isBorderlessWindowModeEnabled() && glfwGetWindowMonitor(window) == nullptr) { - // Draw minimize, restore and maximize buttons - ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 3); - if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_MINIMIZE, buttonSize)) - glfwIconifyWindow(window); - if (glfwGetWindowAttrib(window, GLFW_MAXIMIZED)) { - if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_RESTORE, buttonSize)) - glfwRestoreWindow(window); - } else { - if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_MAXIMIZE, buttonSize)) - glfwMaximizeWindow(window); - } - - ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xFF7A70F1); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF2311E8); - - // Draw close button - if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_CLOSE, buttonSize)) { - ImHexApi::System::closeImHex(); - } - - ImGui::PopStyleColor(2); - } - ImGui::PopStyleColor(3); ImGui::PopStyleVar(); @@ -213,22 +222,33 @@ namespace hex::plugin::builtin { } } - void drawMainMenu(float menuBarHeight) { + void drawMainMenu([[maybe_unused]] float menuBarHeight) { ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F); ImGui::SetNextWindowScroll(ImVec2(0, 0)); + + #if defined(OS_MACOS) + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(ImGui::GetStyle().FramePadding.x, 8_scaled)); + #endif + if (ImGui::BeginMainMenuBar()) { + auto window = ImHexApi::System::getMainWindowHandle(); + + ImGui::PopStyleVar(); if (ImHexApi::System::isBorderlessWindowModeEnabled()) { - ImGui::SetCursorPosX(5); - - ImGui::Image(s_logoTexture, ImVec2(menuBarHeight, menuBarHeight)); - ImGui::SetCursorPosX(5); - ImGui::InvisibleButton("##logo", ImVec2(menuBarHeight, menuBarHeight)); - ImGui::OpenPopupOnItemClick("WindowingMenu", ImGuiPopupFlags_MouseButtonLeft); + #if defined(OS_WINDOWS) + ImGui::SetCursorPosX(5_scaled); + ImGui::Image(s_logoTexture, ImVec2(menuBarHeight, menuBarHeight)); + ImGui::SetCursorPosX(5_scaled); + ImGui::InvisibleButton("##logo", ImVec2(menuBarHeight, menuBarHeight)); + ImGui::OpenPopupOnItemClick("WindowingMenu", ImGuiPopupFlags_MouseButtonLeft); + #elif defined(OS_MACOS) + if (!isMacosFullScreenModeEnabled(window)) + ImGui::SetCursorPosX(68_scaled); + #endif } if (ImGui::BeginPopup("WindowingMenu")) { - auto window = ImHexApi::System::getMainWindowHandle(); bool maximized = glfwGetWindowAttrib(window, GLFW_MAXIMIZED); ImGui::BeginDisabled(!maximized); @@ -289,7 +309,10 @@ namespace hex::plugin::builtin { drawTitleBar(); ImGui::EndMainMenuBar(); + } else { + ImGui::PopStyleVar(); } + ImGui::PopStyleVar(); }