1
0
mirror of synced 2024-11-12 02:00:52 +01:00

impr: Restore native macOS title bar double click gesture in borderless mode (#1689)

### Problem description

#### Problem 1
In borderless mode ImHex disables the standard macOS titlebar rendering
and input processing. As a result double clicking the titlebar does not
trigger the native macOS behavior set in `System Settings -> Desktop &
Dock -> Double-click a window's title bar to [Zoom/Minimize/Do
nothing]`.

#### Problem 2
The ImHex window shows up as blank/transparent when de-minimizing it
from the dock.

#### Problem 3
Widgets experience ghost hover inputs from the past position of the
cursor during live resizing.

### Implementation description
ImGui elements consume input events in the order they are drawn. As a
result by "drawing" an `InvisibleButton` over the content area of the
titlebar we can catch unprocessed clicks in the titlebar area.
Connecting this button's double clicks to the native window is then a
trivial endeavour.

The blank windows was caused by the rendering stack clearing the GL
buffer, but proceeding to draw nothing in it. I have short circuited
this path.

Ghost hover inputs were squelched by consistently moving the ImGui
cursor to `0, 0` during a live resize. The OS will dispatch a cursor
positioning event once the resizing ends, restoring normal behavior.

### Screenshots
N/A

### Additional things
N/A

---------

Co-authored-by: Nik <werwolv98@gmail.com>
This commit is contained in:
David Mentler 2024-05-20 11:27:57 +02:00 committed by GitHub
parent 666dc7dccb
commit 751eff0edf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 67 additions and 9 deletions

View File

@ -15,6 +15,9 @@
void setupMacosWindowStyle(GLFWwindow *window, bool borderlessWindowMode);
void enumerateFontsMacos();
void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window);
bool macosIsWindowBeingResizedByUser(GLFWwindow *window);
}
#endif
#endif

View File

@ -88,6 +88,36 @@
CFRelease(fontDescriptors);
}
void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window) {
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
// Consult user preferences: "System Settings -> Desktop & Dock -> Double-click a window's title bar to"
NSString* action = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleActionOnDoubleClick"];
if (action == nil || [action isEqualToString:@"None"]) {
// Nothing to do
} else if ([action isEqualToString:@"Minimize"]) {
if ([cocoaWindow isMiniaturizable]) {
[cocoaWindow miniaturize:nil];
}
} else if ([action isEqualToString:@"Maximize"]) {
// `[NSWindow zoom:_ sender]` takes over pumping the main runloop for the duration of the resize,
// and would interfere with our renderer's frame logic. Schedule it for the next frame
CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{
if ([cocoaWindow isZoomable]) {
[cocoaWindow zoom:nil];
}
});
}
}
bool macosIsWindowBeingResizedByUser(GLFWwindow *window) {
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
return cocoaWindow.inLiveResize;
}
@interface HexDocument : NSDocument
@end

View File

@ -683,14 +683,20 @@ namespace hex {
glfwMakeContextCurrent(backupContext);
if (shouldRender) {
int displayWidth, displayHeight;
glfwGetFramebufferSize(m_window, &displayWidth, &displayHeight);
glViewport(0, 0, displayWidth, displayHeight);
glClearColor(0.00F, 0.00F, 0.00F, 0.00F);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
auto* drawData = ImGui::GetDrawData();
// Avoid accidentally clearing the viewport when the application is minimized,
// otherwise the OS will display an empty frame during deminimization on macOS
if (drawData->DisplaySize.x != 0 && drawData->DisplaySize.y != 0) {
int displayWidth, displayHeight;
glfwGetFramebufferSize(m_window, &displayWidth, &displayHeight);
glViewport(0, 0, displayWidth, displayHeight);
glClearColor(0.00F, 0.00F, 0.00F, 0.00F);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(m_window);
glfwSwapBuffers(m_window);
}
m_unlockFrameRate = true;
}
@ -820,7 +826,12 @@ namespace hex {
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
win->m_unlockFrameRate = true;
#if !defined(OS_MACOS)
#if defined(OS_MACOS)
// Stop widgets registering hover effects while the window is being resized
if (macosIsWindowBeingResizedByUser(window)) {
ImGui::GetIO().MousePos = ImVec2();
}
#else
win->fullFrame();
#endif
});

View File

@ -392,6 +392,20 @@ namespace hex::plugin::builtin {
drawMenu();
drawTitleBar();
#if defined(OS_MACOS)
if (ImHexApi::System::isBorderlessWindowModeEnabled()) {
const auto windowSize = ImHexApi::System::getMainWindowSize();
const auto menuUnderlaySize = ImVec2(windowSize.x, ImGui::GetCurrentWindowRead()->MenuBarHeight() * 1.5F);
ImGui::SetCursorPos(ImVec2());
// Drawing this button late allows widgets rendered before it to grab click events, forming an "input underlay"
if (ImGui::InvisibleButton("##mainMenuUnderlay", menuUnderlaySize, ImGuiButtonFlags_PressedOnDoubleClick)) {
macosHandleTitlebarDoubleClickGesture(window);
}
}
#endif
ImGui::EndMainMenuBar();
} else {
ImGui::PopStyleVar(2);