8194327: [macos] AWT windows have incorrect main/key window behaviors

Reviewed-by: serb, erikj
This commit is contained in:
Alan Snyder 2018-05-16 16:46:51 -07:00 committed by Sergey Bylokhov
parent f9abf6bee6
commit d7e59b52c5
7 changed files with 653 additions and 44 deletions

View File

@ -64,6 +64,14 @@ else
endif
endif
ifeq ($(OPENJDK_TARGET_OS), macosx)
BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libTestMainKeyWindow := -ObjC
BUILD_JDK_JTREG_LIBRARIES_LIBS_libTestMainKeyWindow := -framework JavaVM \
-framework Cocoa -framework JavaNativeFoundation
else
BUILD_JDK_JTREG_EXCLUDE += libTestMainKeyWindow.c
endif
$(eval $(call SetupTestFilesCompilation, BUILD_JDK_JTREG_LIBRARIES, \
TYPE := LIBRARY, \
SOURCE_DIRS := $(BUILD_JDK_JTREG_NATIVE_SRC), \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -262,7 +262,7 @@ AWT_NS_WINDOW_IMPLEMENTATION
} else {
[self.nsWindow setCollectionBehavior:NSWindowCollectionBehaviorDefault];
}
}
}
}
- (id) initWithPlatformWindow:(JNFWeakJObjectWrapper *)platformWindow
@ -465,7 +465,7 @@ AWT_ASSERT_APPKIT_THREAD;
// Tests whether window is blocked by modal dialog/window
- (BOOL) isBlocked {
BOOL isBlocked = NO;
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
if (platformWindow != NULL) {
@ -473,7 +473,7 @@ AWT_ASSERT_APPKIT_THREAD;
isBlocked = JNFCallBooleanMethod(env, platformWindow, jm_isBlocked) == JNI_TRUE ? YES : NO;
(*env)->DeleteLocalRef(env, platformWindow);
}
return isBlocked;
}
@ -679,7 +679,7 @@ AWT_ASSERT_APPKIT_THREAD;
JNFCallVoidMethod(env, platformWindow, jm_windowWillMiniaturize);
(*env)->DeleteLocalRef(env, platformWindow);
}
// Excplicitly make myself a key window to avoid possible
// Explicitly make myself a key window to avoid possible
// negative visual effects during iconify operation
[self.nsWindow makeKeyAndOrderFront:self.nsWindow];
[self iconifyChildWindows:YES];
@ -713,13 +713,47 @@ AWT_ASSERT_APPKIT_THREAD;
}
}
- (void) windowDidBecomeMain: (NSNotification *) notification {
AWT_ASSERT_APPKIT_THREAD;
[AWTToolkit eventCountPlusPlus];
#ifdef DEBUG
NSLog(@"became main: %d %@ %@", [self.nsWindow isKeyWindow], [self.nsWindow title], [self menuBarForWindow]);
#endif
if (![self.nsWindow isKeyWindow]) {
[self activateWindowMenuBar];
}
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
if (platformWindow != NULL) {
static JNF_MEMBER_CACHE(jm_windowDidBecomeMain, jc_CPlatformWindow, "windowDidBecomeMain", "()V");
JNFCallVoidMethod(env, platformWindow, jm_windowDidBecomeMain);
(*env)->DeleteLocalRef(env, platformWindow);
}
}
- (void) windowDidBecomeKey: (NSNotification *) notification {
AWT_ASSERT_APPKIT_THREAD;
[AWTToolkit eventCountPlusPlus];
#ifdef DEBUG
NSLog(@"became key: %d %@ %@", [self.nsWindow isMainWindow], [self.nsWindow title], [self menuBarForWindow]);
#endif
AWTWindow *opposite = [AWTWindow lastKeyWindow];
// Finds appropriate menubar in our hierarchy,
if (![self.nsWindow isMainWindow]) {
[self activateWindowMenuBar];
}
[AWTWindow setLastKeyWindow:nil];
[self _deliverWindowFocusEvent:YES oppositeWindow: opposite];
[self orderChildWindows:YES];
}
- (void) activateWindowMenuBar {
AWT_ASSERT_APPKIT_THREAD;
// Finds appropriate menubar in our hierarchy
AWTWindow *awtWindow = self;
while (awtWindow.ownerWindow != nil) {
awtWindow = awtWindow.ownerWindow;
@ -738,26 +772,48 @@ AWT_ASSERT_APPKIT_THREAD;
}
[CMenuBar activate:menuBar modallyDisabled:isDisabled];
[AWTWindow setLastKeyWindow:nil];
[self _deliverWindowFocusEvent:YES oppositeWindow: opposite];
[self orderChildWindows:YES];
}
#ifdef DEBUG
- (CMenuBar *) menuBarForWindow {
AWT_ASSERT_APPKIT_THREAD;
AWTWindow *awtWindow = self;
while (awtWindow.ownerWindow != nil) {
awtWindow = awtWindow.ownerWindow;
}
return awtWindow.javaMenuBar;
}
#endif
- (void) windowDidResignKey: (NSNotification *) notification {
// TODO: check why sometimes at start is invoked *not* on AppKit main thread.
AWT_ASSERT_APPKIT_THREAD;
[AWTToolkit eventCountPlusPlus];
[self.javaMenuBar deactivate];
// In theory, this might cause flickering if the window gaining focus
// has its own menu. However, I couldn't reproduce it on practice, so
// perhaps this is a non issue.
CMenuBar* defaultMenu = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
if (defaultMenu != nil) {
[CMenuBar activate:defaultMenu modallyDisabled:NO];
#ifdef DEBUG
NSLog(@"resigned key: %d %@ %@", [self.nsWindow isMainWindow], [self.nsWindow title], [self menuBarForWindow]);
#endif
if (![self.nsWindow isMainWindow]) {
[self deactivateWindow];
}
}
- (void) windowDidResignMain: (NSNotification *) notification {
AWT_ASSERT_APPKIT_THREAD;
[AWTToolkit eventCountPlusPlus];
#ifdef DEBUG
NSLog(@"resigned main: %d %@ %@", [self.nsWindow isKeyWindow], [self.nsWindow title], [self menuBarForWindow]);
#endif
if (![self.nsWindow isKeyWindow]) {
[self deactivateWindow];
}
}
- (void) deactivateWindow {
AWT_ASSERT_APPKIT_THREAD;
#ifdef DEBUG
NSLog(@"deactivating window: %@", [self.nsWindow title]);
#endif
[self.javaMenuBar deactivate];
// the new key window
NSWindow *keyWindow = [NSApp keyWindow];
@ -773,19 +829,6 @@ AWT_ASSERT_APPKIT_THREAD;
[self orderChildWindows:NO];
}
- (void) windowDidBecomeMain: (NSNotification *) notification {
AWT_ASSERT_APPKIT_THREAD;
[AWTToolkit eventCountPlusPlus];
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
if (platformWindow != NULL) {
static JNF_MEMBER_CACHE(jm_windowDidBecomeMain, jc_CPlatformWindow, "windowDidBecomeMain", "()V");
JNFCallVoidMethod(env, platformWindow, jm_windowDidBecomeMain);
(*env)->DeleteLocalRef(env, platformWindow);
}
}
- (BOOL)windowShouldClose:(id)sender {
AWT_ASSERT_APPKIT_THREAD;
[AWTToolkit eventCountPlusPlus];
@ -1040,7 +1083,7 @@ JNF_COCOA_ENTER(env);
AWTWindow *window = (AWTWindow*)[nsWindow delegate];
if ([nsWindow isKeyWindow]) {
if ([nsWindow isKeyWindow] || [nsWindow isMainWindow]) {
[window.javaMenuBar deactivate];
}
@ -1051,7 +1094,7 @@ JNF_COCOA_ENTER(env);
actualMenuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
}
if ([nsWindow isKeyWindow]) {
if ([nsWindow isKeyWindow] || [nsWindow isMainWindow]) {
[CMenuBar activate:actualMenuBar modallyDisabled:NO];
}
}];

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,6 +31,7 @@
#import "CMenuBar.h"
#import "CMenu.h"
#import "ThreadUtilities.h"
#import "ApplicationDelegate.h"
#import "sun_lwawt_macosx_CMenuBar.h"
@ -101,6 +102,10 @@ static BOOL sSetupHelpMenu = NO;
return;
}
#ifdef DEBUG
NSLog(@"activating menu bar: %@", menubar);
#endif
@synchronized([CMenuBar class]) {
sActiveMenuBar = menubar;
}
@ -184,12 +189,30 @@ static BOOL sSetupHelpMenu = NO;
-(void) deactivate {
AWT_ASSERT_APPKIT_THREAD;
BOOL isDeactivated = NO;
@synchronized([CMenuBar class]) {
sActiveMenuBar = nil;
if (sActiveMenuBar == self) {
sActiveMenuBar = nil;
isDeactivated = YES;
}
}
@synchronized(self) {
fModallyDisabled = NO;
if (isDeactivated) {
#ifdef DEBUG
NSLog(@"deactivating menu bar: %@", self);
#endif
@synchronized(self) {
fModallyDisabled = NO;
}
// In theory, this might cause flickering if the window gaining focus
// has its own menu. However, I couldn't reproduce it on practice, so
// perhaps this is a non issue.
CMenuBar* defaultMenu = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
if (defaultMenu != nil) {
[CMenuBar activate:defaultMenu modallyDisabled:NO];
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@
#import "CMenuItem.h"
#import "CMenu.h"
#import "AWTEvent.h"
#import "AWTWindow.h"
#import "ThreadUtilities.h"
#import "java_awt_Event.h"
@ -111,12 +112,14 @@
}
eventKey = [NSString stringWithCharacters: &newChar length: 1];
}
// The action event can be ignored only if the key window is an AWT window.
// Otherwise, the action event is the only notification and must be processed.
NSWindow *keyWindow = [NSApp keyWindow];
if (keyWindow != nil) {
if (keyWindow != nil && [AWTWindow isAWTWindow: keyWindow]) {
return;
}
}
}
static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem");
static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event)
@ -126,7 +129,7 @@
JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event)
}
JNF_COCOA_EXIT(env);
}
- (void) setJavaLabel:(NSString *)theLabel shortcut:(NSString *)theKeyEquivalent modifierMask:(jint)modifiers {

View File

@ -30,7 +30,7 @@
#import <Cocoa/Cocoa.h>
#define DEBUG 1
//#define DEBUG 1
// number of mouse buttons supported
extern int gNumberOfButtons;

View File

@ -0,0 +1,409 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @key headful
* @bug 8194327
* @summary [macosx] AWT windows have incorrect main/key window behaviors
* @author Alan Snyder
* @run main/othervm/native TestMainKeyWindow
* @requires (os.family == "mac")
*/
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
import javax.swing.*;
public class TestMainKeyWindow
{
static TestMainKeyWindow theTest;
KeyStroke commandT = KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.META_DOWN_MASK);
int nextX = 130;
private final MyFrame frame1;
private final MyFrame frame2;
private final Object COLOR_PANEL = "Color Panel";
private final Object NATIVE_WINDOW = "Native Window";
// these bounds must agree with the native code that creates the windows
private Rectangle colorPanelBounds = new Rectangle(130, 300, 225, 400); // approximate is OK
private Rectangle nativeWindowBounds = new Rectangle(130, 200, 200, 100);
private Robot robot;
private int actionCounter;
private Object actionTarget;
private int failureCount;
private boolean isApplicationOpened;
public TestMainKeyWindow()
{
System.loadLibrary("testMainKeyWindow");
JMenuBar defaultMenuBar = createMenuBar("Application", true);
Desktop.getDesktop().setDefaultMenuBar(defaultMenuBar);
setup();
frame1 = new MyFrame("Frame 1");
frame2 = new MyFrame("Frame 2");
frame1.setVisible(true);
frame2.setVisible(true);
try {
robot = new Robot();
robot.setAutoDelay(50);
} catch (AWTException ex) {
throw new RuntimeException(ex);
}
}
class MyFrame
extends JFrame
{
public MyFrame(String title)
throws HeadlessException
{
super(title);
JMenuBar mainMenuBar = createMenuBar(title, true);
setJMenuBar(mainMenuBar);
setBounds(nextX, 60, 200, 90);
nextX += 250;
JComponent contentPane = new JPanel();
setContentPane(contentPane);
contentPane.setLayout(new FlowLayout());
contentPane.add(new JCheckBox("foo", true));
InputMap inputMap = contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(commandT, "test");
ActionMap actionMap = contentPane.getActionMap();
actionMap.put("test", new MyAction(title + " Key"));
}
}
private void runTest()
{
failureCount = 0;
robot.waitForIdle();
performTest(frame1, false);
performTest(frame1, true);
performTest(frame2, false);
performTest(frame2, true);
performTest(NATIVE_WINDOW, false);
performTest(NATIVE_WINDOW, true);
performTest(COLOR_PANEL, false);
if (failureCount > 0) {
throw new RuntimeException("Test failed: " + failureCount + " failure(s)");
}
}
private void performTest(Object windowIdentification, boolean selectColorPanel)
{
setupWindows(windowIdentification, selectColorPanel);
performMenuShortcutTest(windowIdentification, selectColorPanel);
performMenuItemTest(windowIdentification, selectColorPanel);
// test deactivating and reactivating the application
// the window state and behavior should be restored
openOtherApplication();
activateApplication();
robot.delay(1000);
performMenuShortcutTest(windowIdentification, selectColorPanel);
performMenuItemTest(windowIdentification, selectColorPanel);
}
private void openOtherApplication() {
try {
String[] cmd = { "/usr/bin/open", "/Applications/System Preferences.app" };
Runtime.getRuntime().exec(cmd);
if (!isApplicationOpened) {
String[] cmd2 = { "/usr/bin/osascript", "-e",
"tell application \"System Preferences\" to set bounds of window 1 to {400, 180, 1068, 821}" };
Runtime.getRuntime().exec(cmd2);
}
isApplicationOpened = true;
} catch (IOException ex) {
throw new RuntimeException("Unable to deactivate test application");
}
robot.delay(1000);
}
private void performMenuShortcutTest(Object windowIdentification, boolean selectColorPanel)
{
int currentActionCount = actionCounter;
// Perform the menu shortcut
robot.keyPress(KeyEvent.VK_META);
robot.keyPress(KeyEvent.VK_T);
robot.keyRelease(KeyEvent.VK_T);
robot.keyRelease(KeyEvent.VK_META);
robot.waitForIdle();
Object target = waitForAction(currentActionCount + 1);
boolean isDirectKey = windowIdentification instanceof Window && !selectColorPanel;
Object expectedTarget = getExpectedTarget(windowIdentification, isDirectKey);
if (!Objects.equals(target, expectedTarget)) {
failureCount++;
String configuration = getConfigurationName(windowIdentification, selectColorPanel);
System.err.println("***** Menu shortcut test failed for " + configuration + ". Expected: " + expectedTarget + ", Actual: " + target);
}
}
private void performMenuItemTest(Object windowIdentification, boolean selectColorPanel)
{
int currentActionCount = actionCounter;
// Find the menu on the screen menu bar
// The location depends upon the application name which is the name of the first menu.
// Unfortunately, the application name can vary based on how the application is run.
// The work around is to make the menu and the menu item names very long.
int menuBarX = 250;
int menuBarY = 11;
int menuItemX = menuBarX;
int menuItemY = 34;
robot.mouseMove(menuBarX, menuBarY);
robot.delay(100);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.delay(100);
robot.mouseMove(menuItemX, menuItemY);
robot.delay(100);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle();
Object target = waitForAction(currentActionCount + 1);
Object expectedTarget = getExpectedTarget(windowIdentification, false);
if (!Objects.equals(target, expectedTarget)) {
failureCount++;
String configuration = getConfigurationName(windowIdentification, selectColorPanel);
System.err.println("***** Menu item test failed for " + configuration + ". Expected: " + expectedTarget + ", Actual: " + target);
}
}
private String getConfigurationName(Object windowIdentification, boolean selectColorPanel)
{
String name = "Unknown";
if (windowIdentification instanceof Window) {
Window w = (Window) windowIdentification;
name = getWindowTitle(w);
} else if (windowIdentification == NATIVE_WINDOW) {
name = "Native Window";
} else if (windowIdentification == COLOR_PANEL) {
name = "Color Panel";
}
if (selectColorPanel) {
return name + " with color panel";
} else {
return name;
}
}
private Object getExpectedTarget(Object windowIdentification, boolean isDirectKey)
{
if (windowIdentification instanceof Window) {
Window w = (Window) windowIdentification;
String title = getWindowTitle(w);
if (isDirectKey) {
title = title + " Key";
}
return title;
}
return "Application";
}
private String getWindowTitle(Window w)
{
if (w instanceof Frame) {
Frame f = (Frame) w;
return f.getTitle();
}
if (w instanceof Dialog) {
Dialog d = (Dialog) w;
return d.getTitle();
}
throw new IllegalStateException();
}
private synchronized void registerAction(Object target)
{
actionCounter++;
actionTarget = target;
}
private synchronized Object waitForAction(int count)
{
try {
for (int i = 0; i < 10; i++) {
if (actionCounter == count) {
return actionTarget;
}
if (actionCounter > count) {
throw new IllegalStateException();
}
wait(100);
}
} catch (InterruptedException ex) {
}
return "No Action";
}
private void setupWindows(Object windowIdentification, boolean selectColorPanel)
{
clickOnWindowTitleBar(windowIdentification);
if (selectColorPanel) {
clickOnWindowTitleBar(COLOR_PANEL);
}
}
private void clickOnWindowTitleBar(Object windowIdentification)
{
Rectangle bounds = getWindowBounds(windowIdentification);
int x = bounds.x + 70; // to the right of the stoplight buttons
int y = bounds.y + 12; // in the title bar
robot.mouseMove(x, y);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle();
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle();
}
private Rectangle getWindowBounds(Object windowIdentification)
{
if (windowIdentification instanceof Window) {
Window w = (Window) windowIdentification;
return w.getBounds();
}
if (windowIdentification == COLOR_PANEL) {
return colorPanelBounds;
}
if (windowIdentification == NATIVE_WINDOW) {
return nativeWindowBounds;
}
throw new IllegalArgumentException();
}
JMenuBar createMenuBar(String text, boolean isEnabled)
{
JMenuBar mb = new JMenuBar();
// A very long name makes it more likely that the robot will hit the menu
JMenu menu = new JMenu("TestTestTestTestTestTestTestTestTestTest");
mb.add(menu);
JMenuItem item = new JMenuItem("TestTestTestTestTestTestTestTestTestTest");
item.setAccelerator(commandT);
item.setEnabled(isEnabled);
item.addActionListener(ev -> {
registerAction(text);
});
menu.add(item);
return mb;
}
void dispose()
{
frame1.setVisible(false);
frame2.setVisible(false);
frame1.dispose();
frame2.dispose();
takedown();
Desktop.getDesktop().setDefaultMenuBar(null);
if (isApplicationOpened) {
try {
String[] cmd = { "/usr/bin/osascript", "-e", "tell application \"System Preferences\" to close window 1" };
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
} catch (IOException | InterruptedException ex) {
}
}
}
class MyAction
extends AbstractAction
{
String text;
public MyAction(String text)
{
super("Test");
this.text = text;
}
@Override
public void actionPerformed(ActionEvent e)
{
registerAction(text);
}
}
private static native void setup();
private static native void takedown();
private static native void activateApplication();
public static void main(String[] args)
{
if (!System.getProperty("os.name").contains("OS X")) {
System.out.println("This test is for MacOS only. Automatically passed on other platforms.");
return;
}
System.setProperty("apple.laf.useScreenMenuBar", "true");
try {
runSwing(() -> {
theTest = new TestMainKeyWindow();
});
theTest.runTest();
} finally {
if (theTest != null) {
runSwing(() -> {
theTest.dispose();
});
}
}
}
private static void runSwing(Runnable r)
{
try {
SwingUtilities.invokeAndWait(r);
} catch (InterruptedException e) {
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import <Cocoa/Cocoa.h>
#import <JavaNativeFoundation/JavaNativeFoundation.h>
static NSWindow *testWindow;
static NSColorPanel *colorPanel;
/*
* Class: TestMainKeyWindow
* Method: setup
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_TestMainKeyWindow_setup(JNIEnv *env, jclass cl)
{
JNF_COCOA_ENTER(env);
void (^block)() = ^(){
NSScreen *mainScreen = [NSScreen mainScreen];
NSRect screenFrame = [mainScreen frame];
NSRect frame = NSMakeRect(130, screenFrame.size.height - 280, 200, 100);
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
NSWindowStyleMask style = NSWindowStyleMaskTitled;
#else
NSInteger style = NSTitledWindowMask;
#endif
NSRect rect = [NSWindow contentRectForFrameRect:frame styleMask:style];
NSBackingStoreType bt = NSBackingStoreBuffered;
testWindow = [[[NSWindow alloc] initWithContentRect:rect styleMask:style backing:bt defer:NO] retain];
testWindow.title = @"NSWindow";
[testWindow setBackgroundColor:[NSColor blueColor]];
[testWindow makeKeyAndOrderFront:nil];
// Java coordinates are 100, 200
colorPanel = [[NSColorPanel sharedColorPanel] retain];
[colorPanel setReleasedWhenClosed: YES];
colorPanel.restorable = NO;
[colorPanel setFrameTopLeftPoint: NSMakePoint(130, screenFrame.size.height - 300)];
// Java coordinates are 100, 400
[colorPanel makeKeyAndOrderFront: nil];
};
if ([NSThread isMainThread]) {
block();
} else {
[JNFRunLoop performOnMainThreadWaiting:YES withBlock:block];
}
JNF_COCOA_EXIT(env);
}
/*
* Class: TestMainKeyWindow
* Method: takedown
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_TestMainKeyWindow_takedown(JNIEnv *env, jclass cl)
{
JNF_COCOA_ENTER(env);
void (^block)() = ^(){
if (testWindow != nil) {
[testWindow close];
testWindow = nil;
}
if (colorPanel != nil) {
[colorPanel orderOut:nil];
colorPanel = nil;
}
};
if ([NSThread isMainThread]) {
block();
} else {
[JNFRunLoop performOnMainThreadWaiting:YES withBlock:block];
}
JNF_COCOA_EXIT(env);
}
/*
* Class: TestMainKeyWindow
* Method: activateApplication
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_TestMainKeyWindow_activateApplication
(JNIEnv *env, jclass cl)
{
JNF_COCOA_ENTER(env);
void (^block)() = ^(){
[NSApp activateIgnoringOtherApps:YES];
};
[JNFRunLoop performOnMainThreadWaiting:YES withBlock:block];
JNF_COCOA_EXIT(env);
}