mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-5174 Opening project as tabs in Mac OS (version2)
JBR-5023 Configure TabbingIdentifier during create native window JBR-5256 IDEA window resizes to zero height when exit full-screen mode with new window controls enabled JBR-5197 Window control buttons are not visible in full-screen mode in dark themes when IDE window is focused JBR-5175 jb/java/awt/Window/FullScreenTwoFrames.java: -[AWTWindow resetWindowFullScreeControls]: unrecognized selector sent to instance 0x60000232d5f0 JBR-5499 Window control buttons bugfix JBR-4462 BigSur: project tab does not gain focus when click it after focusing another app
This commit is contained in:
committed by
Nikita Gubarkov
parent
54f70cfc23
commit
540d5a32c4
@@ -991,6 +991,14 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
private boolean isTabbedWindow() {
|
||||
AtomicBoolean ref = new AtomicBoolean();
|
||||
execute(ptr -> {
|
||||
ref.set(CWrapper.NSWindow.isTabbedWindow(ptr));
|
||||
});
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
// We want a window to be always shown at the same space as its owning window.
|
||||
// But macOS doesn't have an API to control the target space for a window -
|
||||
// it's always shown at the active space. So if the target space isn't active now,
|
||||
@@ -1353,7 +1361,9 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
// which is going to become 'main window', are placed above their siblings.
|
||||
CPlatformWindow rootOwner = getRootOwner();
|
||||
if (rootOwner.isVisible() && !rootOwner.isIconified() && !rootOwner.isActive()) {
|
||||
rootOwner.execute(CWrapper.NSWindow::orderFrontIfOnActiveSpace);
|
||||
if (rootOwner != this || !isTabbedWindow()) {
|
||||
rootOwner.execute(CWrapper.NSWindow::orderFrontIfOnActiveSpace);
|
||||
}
|
||||
}
|
||||
|
||||
// Do not order child windows of iconified owner.
|
||||
|
||||
@@ -108,6 +108,8 @@ final class CWrapper {
|
||||
static native void zoom(long window);
|
||||
|
||||
static native void makeFirstResponder(long window, long responder);
|
||||
|
||||
static native boolean isTabbedWindow(long window);
|
||||
}
|
||||
|
||||
static final class NSView {
|
||||
|
||||
@@ -50,6 +50,10 @@
|
||||
NSWindowTabbingMode javaWindowTabbingMode;
|
||||
BOOL isEnterFullScreen;
|
||||
CGFloat _customTitleBarHeight;
|
||||
BOOL hideTabController;
|
||||
NSView *_fullScreenButtons;
|
||||
NSView *_fullScreenOriginalButtons;
|
||||
|
||||
}
|
||||
|
||||
// An instance of either AWTWindow_Normal or AWTWindow_Panel
|
||||
@@ -74,6 +78,7 @@
|
||||
@property (nonatomic, retain) NSMutableArray *customTitleBarConstraints;
|
||||
@property (nonatomic, retain) NSLayoutConstraint *customTitleBarHeightConstraint;
|
||||
@property (nonatomic, retain) NSMutableArray *customTitleBarButtonCenterXConstraints;
|
||||
@property (nonatomic) BOOL hideTabController;
|
||||
|
||||
- (id) initWithPlatformWindow:(jobject)javaPlatformWindow
|
||||
ownerWindow:owner
|
||||
@@ -116,4 +121,13 @@
|
||||
- (id) initWithPlatformWindow:(jobject)javaPlatformWindow;
|
||||
@end
|
||||
|
||||
@interface AWTButtonsView : NSView {
|
||||
@private BOOL _showButtons;
|
||||
NSColor* _color;
|
||||
}
|
||||
|
||||
- (void)configureColors;
|
||||
|
||||
@end
|
||||
|
||||
#endif _AWTWINDOW_H
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#import "ThreadUtilities.h"
|
||||
#import "NSApplicationAWT.h"
|
||||
#import "JNIUtilities.h"
|
||||
#import "PropertiesUtilities.h"
|
||||
|
||||
#define MASK(KEY) \
|
||||
(sun_lwawt_macosx_CPlatformWindow_ ## KEY)
|
||||
@@ -55,6 +56,14 @@ static jclass jc_CPlatformWindow = NULL;
|
||||
#define GET_CPLATFORM_WINDOW_CLASS_RETURN(ret) \
|
||||
GET_CLASS_RETURN(jc_CPlatformWindow, "sun/lwawt/macosx/CPlatformWindow", ret);
|
||||
|
||||
@interface NSTitlebarAccessoryViewController (Private)
|
||||
- (void)_setHidden:(BOOL)h animated:(BOOL)a;
|
||||
@end
|
||||
|
||||
@interface NSWindow (Private)
|
||||
- (void)_setTabBarAccessoryViewController:(id)controller;
|
||||
@end
|
||||
|
||||
// Cocoa windowDidBecomeKey/windowDidResignKey notifications
|
||||
// doesn't provide information about "opposite" window, so we
|
||||
// have to do a bit of tracking. This variable points to a window
|
||||
@@ -348,6 +357,26 @@ AWT_NS_WINDOW_IMPLEMENTATION
|
||||
[super orderOut:sender];
|
||||
}
|
||||
|
||||
- (void)_setTabBarAccessoryViewController:(id)_controller {
|
||||
if (((AWTWindow *)self.delegate).hideTabController) {
|
||||
NSTitlebarAccessoryViewController* controller = [[NSTitlebarAccessoryViewController alloc] init];
|
||||
controller.view = [[NSView alloc] init];
|
||||
[controller.view setFrame:NSMakeRect(0, 0, 0, 0)];
|
||||
[controller _setHidden:YES animated:NO];
|
||||
|
||||
[super _setTabBarAccessoryViewController:controller];
|
||||
} else {
|
||||
[super _setTabBarAccessoryViewController:_controller];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isNativeSelected {
|
||||
if (@available(macOS 10.13, *)) {
|
||||
return [[self tabGroup] selectedWindow] == self;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@implementation AWTWindow_Panel
|
||||
AWT_NS_WINDOW_IMPLEMENTATION
|
||||
@@ -372,6 +401,7 @@ AWT_NS_WINDOW_IMPLEMENTATION
|
||||
@synthesize isJustCreated;
|
||||
@synthesize javaWindowTabbingMode;
|
||||
@synthesize isEnterFullScreen;
|
||||
@synthesize hideTabController;
|
||||
|
||||
- (void) updateMinMaxSize:(BOOL)resizable {
|
||||
if (resizable) {
|
||||
@@ -547,6 +577,8 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
self.nsWindow.collectionBehavior = NSWindowCollectionBehaviorManaged;
|
||||
self.isEnterFullScreen = NO;
|
||||
|
||||
[self configureJavaWindowTabbingIdentifier];
|
||||
|
||||
if (self.isCustomTitleBarEnabled && !self.isFullScreen) {
|
||||
[self setUpCustomTitleBar];
|
||||
}
|
||||
@@ -569,6 +601,64 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
return [self.nsWindow windowNumber] == [AWTWindow getTopmostWindowUnderMouseID];
|
||||
}
|
||||
|
||||
- (void) configureJavaWindowTabbingIdentifier {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
self.hideTabController = NO;
|
||||
|
||||
if (self.javaWindowTabbingMode != NSWindowTabbingModeAutomatic) {
|
||||
return;
|
||||
}
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
|
||||
if (platformWindow == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
GET_CPLATFORM_WINDOW_CLASS();
|
||||
DECLARE_FIELD(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;");
|
||||
jobject awtWindow = (*env)->GetObjectField(env, platformWindow, jf_target);
|
||||
|
||||
if (awtWindow != NULL) {
|
||||
DECLARE_CLASS(jc_RootPaneContainer, "javax/swing/RootPaneContainer");
|
||||
if ((*env)->IsInstanceOf(env, awtWindow, jc_RootPaneContainer)) {
|
||||
DECLARE_METHOD(jm_getRootPane, jc_RootPaneContainer, "getRootPane", "()Ljavax/swing/JRootPane;");
|
||||
jobject rootPane = (*env)->CallObjectMethod(env, awtWindow, jm_getRootPane);
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
if (rootPane != NULL) {
|
||||
DECLARE_CLASS(jc_JComponent, "javax/swing/JComponent");
|
||||
DECLARE_METHOD(jm_getClientProperty, jc_JComponent, "getClientProperty", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
jstring jKey = NSStringToJavaString(env, @"JavaWindowTabbingIdentifier");
|
||||
jobject jValue = (*env)->CallObjectMethod(env, rootPane, jm_getClientProperty, jKey);
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
if (jValue != NULL) {
|
||||
DECLARE_CLASS(jc_String, "java/lang/String");
|
||||
if ((*env)->IsInstanceOf(env, jValue, jc_String)) {
|
||||
NSString *winId = JavaStringToNSString(env, (jstring)jValue);
|
||||
[self.nsWindow setTabbingIdentifier:winId];
|
||||
if ([winId characterAtIndex:0] == '+') {
|
||||
self.hideTabController = YES;
|
||||
[self.nsWindow _setTabBarAccessoryViewController:nil];
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, jValue);
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, jKey);
|
||||
(*env)->DeleteLocalRef(env, rootPane);
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, awtWindow);
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, platformWindow);
|
||||
}
|
||||
|
||||
- (NSWindowTabbingMode) getJavaWindowTabbingMode {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
@@ -1309,6 +1399,15 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
if (self.isCustomTitleBarEnabled) {
|
||||
[self forceHideCustomTitleBarTitle:NO];
|
||||
[self updateCustomTitleBarInsets:NO];
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
NSString *newFullScreenControls1 = [PropertiesUtilities
|
||||
javaSystemPropertyForKey:@"apple.awt.newFullScreeControls" withEnv:env];
|
||||
NSString *newFullScreenControls2 = [PropertiesUtilities
|
||||
javaSystemPropertyForKey:@"apple.awt.newFullScreenControls" withEnv:env];
|
||||
if ([@"true" isCaseInsensitiveLike:newFullScreenControls1] || [@"true" isCaseInsensitiveLike:newFullScreenControls2]) {
|
||||
[self setWindowFullScreenControls];
|
||||
}
|
||||
}
|
||||
[self allowMovingChildrenBetweenSpaces:NO];
|
||||
[self fullScreenTransitionFinished];
|
||||
@@ -1355,6 +1454,8 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
}
|
||||
|
||||
- (void)windowDidExitFullScreen:(NSNotification *)notification {
|
||||
[self resetWindowFullScreenControls];
|
||||
|
||||
self.isEnterFullScreen = NO;
|
||||
|
||||
[self fullScreenTransitionFinished];
|
||||
@@ -1464,7 +1565,9 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
|
||||
}
|
||||
|
||||
- (void) setUpCustomTitleBar {
|
||||
|
||||
if (self.customTitleBarConstraints != nil) {
|
||||
[self resetCustomTitleBar];
|
||||
}
|
||||
/**
|
||||
* The view hierarchy normally looks as follows:
|
||||
* NSThemeFrame
|
||||
@@ -1560,6 +1663,8 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
|
||||
}];
|
||||
[self setWindowControlsHidden:!self.customTitleBarControlsVisible];
|
||||
[self updateCustomTitleBarInsets:self.customTitleBarControlsVisible];
|
||||
|
||||
[self updateFullScreenButtons];
|
||||
}
|
||||
|
||||
- (void) resetCustomTitleBar {
|
||||
@@ -1598,11 +1703,104 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
|
||||
}
|
||||
|
||||
- (void) setWindowControlsHidden: (BOOL) hidden {
|
||||
if (_fullScreenOriginalButtons != nil) {
|
||||
[_fullScreenOriginalButtons.window.contentView setHidden:NO];
|
||||
_fullScreenButtons.hidden = YES;
|
||||
}
|
||||
|
||||
[self.nsWindow standardWindowButton:NSWindowCloseButton].hidden = hidden;
|
||||
[self.nsWindow standardWindowButton:NSWindowZoomButton].hidden = hidden;
|
||||
[self.nsWindow standardWindowButton:NSWindowMiniaturizeButton].hidden = hidden;
|
||||
}
|
||||
|
||||
- (void) setWindowFullScreenControls {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
NSString *dfmMode = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.distraction.free.mode" withEnv:env];
|
||||
if ([@"true" isCaseInsensitiveLike:dfmMode]) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSView* oldCloseButton = [self.nsWindow standardWindowButton:NSWindowCloseButton];
|
||||
_fullScreenOriginalButtons = oldCloseButton.superview;
|
||||
|
||||
NSRect closeButtonRect = [oldCloseButton frame];
|
||||
NSRect miniaturizeButtonRect = [[self.nsWindow standardWindowButton:NSWindowMiniaturizeButton] frame];
|
||||
NSRect zoomButtonRect = [[self.nsWindow standardWindowButton:NSWindowZoomButton] frame];
|
||||
|
||||
for (NSWindow* window in [[NSApplication sharedApplication] windows]) {
|
||||
if ([window isKindOfClass:NSClassFromString(@"NSToolbarFullScreenWindow")]) {
|
||||
[window.contentView setHidden:YES];
|
||||
}
|
||||
}
|
||||
|
||||
_fullScreenButtons = [[AWTButtonsView alloc] init];
|
||||
[self updateFullScreenButtons];
|
||||
[_fullScreenButtons addTrackingArea:[[NSTrackingArea alloc] initWithRect:[_fullScreenButtons visibleRect]
|
||||
options:(NSTrackingActiveAlways | NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved)
|
||||
owner:_fullScreenButtons userInfo:nil]];
|
||||
|
||||
NSUInteger masks = [self.nsWindow styleMask];
|
||||
|
||||
NSButton *closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:masks];
|
||||
[closeButton setFrame:closeButtonRect];
|
||||
[_fullScreenButtons addSubview:closeButton];
|
||||
|
||||
NSButton *miniaturizeButton = [NSWindow standardWindowButton:NSWindowMiniaturizeButton forStyleMask:masks];
|
||||
[miniaturizeButton setFrame:miniaturizeButtonRect];
|
||||
[_fullScreenButtons addSubview:miniaturizeButton];
|
||||
|
||||
NSButton *zoomButton = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:masks];
|
||||
[zoomButton setFrame:zoomButtonRect];
|
||||
[_fullScreenButtons addSubview:zoomButton];
|
||||
|
||||
[self.nsWindow.contentView addSubview:_fullScreenButtons];
|
||||
|
||||
[self updateColors];
|
||||
}
|
||||
|
||||
- (void)updateColors {
|
||||
if (_fullScreenButtons != nil) {
|
||||
[(AWTButtonsView *)_fullScreenButtons configureColors];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateFullScreenButtons {
|
||||
if (_fullScreenButtons == nil || _fullScreenOriginalButtons == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSView *parent = self.nsWindow.contentView;
|
||||
CGFloat w = 80;
|
||||
CGFloat h = _fullScreenOriginalButtons.frame.size.height;
|
||||
CGFloat x = 6;
|
||||
CGFloat y = parent.frame.size.height - h - (self.customTitleBarHeight - h) / 2.0;
|
||||
|
||||
[_fullScreenButtons setFrame:NSMakeRect(x, y, w - x, h)];
|
||||
}
|
||||
|
||||
- (void)updateFullScreenButtons: (BOOL) dfm {
|
||||
if (dfm) {
|
||||
if (_fullScreenButtons == nil || _fullScreenOriginalButtons == nil) {
|
||||
return;
|
||||
}
|
||||
[_fullScreenOriginalButtons.window.contentView setHidden:NO];
|
||||
[self resetWindowFullScreenControls];
|
||||
} else {
|
||||
if (!self.isCustomTitleBarEnabled || _fullScreenButtons != nil) {
|
||||
return;
|
||||
}
|
||||
[self setWindowFullScreenControls];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) resetWindowFullScreenControls {
|
||||
if (_fullScreenButtons != nil) {
|
||||
[_fullScreenButtons removeFromSuperview];
|
||||
_fullScreenButtons = nil;
|
||||
_fullScreenOriginalButtons = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) isFullScreen {
|
||||
NSUInteger masks = [self.nsWindow styleMask];
|
||||
return (masks & NSWindowStyleMaskFullScreen) != 0;
|
||||
@@ -1648,6 +1846,8 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
|
||||
} else {
|
||||
[self resetCustomTitleBar];
|
||||
}
|
||||
} else {
|
||||
[self updateFullScreenButtons];
|
||||
}
|
||||
} else if (enabled) {
|
||||
[self updateCustomTitleBarConstraints];
|
||||
@@ -1766,6 +1966,96 @@ static const CGFloat DefaultHorizontalTitleBarButtonOffset = 20.0;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AWTButtonsView
|
||||
|
||||
- (void)dealloc {
|
||||
[_color release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(NSEvent *)theEvent {
|
||||
[self updateButtons:YES];
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent *)theEvent {
|
||||
[self updateButtons:NO];
|
||||
}
|
||||
|
||||
- (void)configureColors {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
NSString *javaColor = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.newFullScreeControls.background" withEnv:env];
|
||||
|
||||
[_color release];
|
||||
|
||||
if (javaColor == nil) {
|
||||
_color = nil;
|
||||
} else {
|
||||
int rgb = [javaColor intValue];
|
||||
|
||||
CGFloat alpha = (((rgb >> 24) & 0xff) / 255.0);
|
||||
CGFloat red = (((rgb >> 16) & 0xff) / 255.0);
|
||||
CGFloat green = (((rgb >> 8) & 0xff) / 255.0);
|
||||
CGFloat blue = (((rgb >> 0) & 0xff) / 255.0);
|
||||
|
||||
_color = [NSColor colorWithDeviceRed:red green:green blue:blue alpha:alpha];
|
||||
[_color retain];
|
||||
}
|
||||
|
||||
[self updateButtons:NO];
|
||||
}
|
||||
|
||||
- (void)updateButtons:(BOOL) flag {
|
||||
_showButtons = flag;
|
||||
|
||||
if (self.subviews.count == 3) {
|
||||
[self updateButton:0 flag:flag]; // close
|
||||
[self updateButton:1 flag:NO]; // miniaturize
|
||||
[self updateButton:2 flag:flag]; // zoom
|
||||
}
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)updateButton: (int)index flag:(BOOL) flag {
|
||||
NSButton *button = (NSButton*)self.subviews[index];
|
||||
[button setHidden:!flag];
|
||||
[button setHighlighted:flag];
|
||||
}
|
||||
|
||||
- (void)drawRect: (NSRect)dirtyRect {
|
||||
if (self.subviews.count != 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_color == nil) {
|
||||
[[NSColor whiteColor] setFill];
|
||||
} else {
|
||||
[_color setFill];
|
||||
}
|
||||
|
||||
if (_showButtons) {
|
||||
[self drawButton:1]; // miniaturize
|
||||
} else {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
[self drawButton:i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawButton: (int)index {
|
||||
NSButton *button = (NSButton*)self.subviews[index];
|
||||
NSRect rect = button.frame;
|
||||
CGFloat r = 12;
|
||||
CGFloat x = rect.origin.x + (rect.size.width - r) / 2;
|
||||
CGFloat y = rect.origin.y + (rect.size.height - r) / 2;
|
||||
|
||||
NSBezierPath* circlePath = [NSBezierPath bezierPath];
|
||||
[circlePath appendBezierPathWithOvalInRect:CGRectMake(x, y, r, r)];
|
||||
[circlePath fill];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CPlatformWindow
|
||||
* Method: nativeSetAllAllowAutomaticTabbingProperty
|
||||
|
||||
@@ -516,6 +516,31 @@ JNI_COCOA_ENTER(env);
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CWrapper$NSWindow
|
||||
* Method: isTabbedWindow
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_lwawt_macosx_CWrapper_00024NSWindow_isTabbedWindow
|
||||
(JNIEnv *env, jclass cls, jlong windowPtr)
|
||||
{
|
||||
__block jboolean isTabbedWindow = JNI_FALSE;
|
||||
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
if (@available(macOS 10.13, *)) {
|
||||
NSWindow *window = (NSWindow *)jlong_to_ptr(windowPtr);
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
isTabbedWindow = [[[window tabGroup] windows] count] > 1;
|
||||
}];
|
||||
}
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
|
||||
return isTabbedWindow;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CWrapper$NSView
|
||||
* Method: addSubview
|
||||
|
||||
Reference in New Issue
Block a user