Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: draggable regions on MAS #37474

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
91 changes: 91 additions & 0 deletions shell/browser/ui/cocoa/electron_ns_window.mm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#include "shell/browser/ui/cocoa/root_view_mac.h"
#include "ui/base/cocoa/window_size_constants.h"

#import <objc/message.h>
#import <objc/runtime.h>

namespace electron {

int ScopedDisableResize::disable_resize_ = 0;
Expand All @@ -19,8 +22,65 @@

@interface NSWindow (PrivateAPI)
- (NSImage*)_cornerMask;
- (int64_t)_resizeDirectionForMouseLocation:(CGPoint)location;
@end

#if IS_MAS_BUILD()
// See components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
@interface NSView (CRFrameViewAdditions)
- (void)cr_mouseDownOnFrameView:(NSEvent*)event;
@end

typedef void (*MouseDownImpl)(id, SEL, NSEvent*);

namespace {
MouseDownImpl g_nsthemeframe_mousedown;
MouseDownImpl g_nsnextstepframe_mousedown;
} // namespace

// This class is never instantiated, it's just a container for our swizzled
// mouseDown method.
@interface SwizzledMouseDownHolderClass : NSView
@end

@implementation SwizzledMouseDownHolderClass
- (void)swiz_nsthemeframe_mouseDown:(NSEvent*)event {
if ([self.window respondsToSelector:@selector(shell)]) {
electron::NativeWindowMac* shell =
(electron::NativeWindowMac*)[(id)self.window shell];
if (shell && !shell->has_frame())
[self cr_mouseDownOnFrameView:event];
g_nsthemeframe_mousedown(self, @selector(mouseDown:), event);
}
}

- (void)swiz_nsnextstepframe_mouseDown:(NSEvent*)event {
if ([self.window respondsToSelector:@selector(shell)]) {
electron::NativeWindowMac* shell =
(electron::NativeWindowMac*)[(id)self.window shell];
if (shell && !shell->has_frame()) {
[self cr_mouseDownOnFrameView:event];
}
g_nsnextstepframe_mousedown(self, @selector(mouseDown:), event);
}
}
@end

namespace {
void SwizzleMouseDown(NSView* frame_view,
SEL swiz_selector,
MouseDownImpl* orig_impl) {
Method original_mousedown =
class_getInstanceMethod([frame_view class], @selector(mouseDown:));
*orig_impl = (MouseDownImpl)method_getImplementation(original_mousedown);
Method new_mousedown = class_getInstanceMethod(
[SwizzledMouseDownHolderClass class], swiz_selector);
method_setImplementation(original_mousedown,
method_getImplementation(new_mousedown));
}
} // namespace
#endif // IS_MAS_BUILD

@implementation ElectronNSWindow

@synthesize acceptsFirstMouse;
Expand All @@ -36,6 +96,37 @@ - (id)initWithShell:(electron::NativeWindowMac*)shell
styleMask:styleMask
backing:NSBackingStoreBuffered
defer:NO])) {
#if IS_MAS_BUILD()
// The first time we create a frameless window, we swizzle the
// implementation of -[NSNextStepFrame mouseDown:], replacing it with our
// own.
// This is only necessary on MAS where we can't directly refer to
// NSNextStepFrame or NSThemeFrame, as they are private APIs.
// See components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm for
// the non-MAS-compatible way of doing this.
if (styleMask & NSWindowStyleMaskTitled) {
if (!g_nsthemeframe_mousedown) {
NSView* theme_frame = [[self contentView] superview];
DCHECK(strcmp(class_getName([theme_frame class]), "NSThemeFrame") == 0)
<< "Expected NSThemeFrame but was "
<< class_getName([theme_frame class]);
SwizzleMouseDown(theme_frame, @selector(swiz_nsthemeframe_mouseDown:),
&g_nsthemeframe_mousedown);
}
} else {
if (!g_nsnextstepframe_mousedown) {
NSView* nextstep_frame = [[self contentView] superview];
DCHECK(strcmp(class_getName([nextstep_frame class]),
"NSNextStepFrame") == 0)
<< "Expected NSNextStepFrame but was "
<< class_getName([nextstep_frame class]);
SwizzleMouseDown(nextstep_frame,
@selector(swiz_nsnextstepframe_mouseDown:),
&g_nsnextstepframe_mousedown);
}
}
#endif // IS_MAS_BUILD

shell_ = shell;
}
return self;
Expand Down