--- old/make/test/JtregNativeJdk.gmk 2018-04-02 14:03:37.000000000 -0700 +++ new/make/test/JtregNativeJdk.gmk 2018-04-02 14:03:37.000000000 -0700 @@ -62,6 +62,9 @@ else ifeq ($(OPENJDK_TARGET_OS), solaris) BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava endif + BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libtest8194327 := -ObjC + BUILD_JDK_JTREG_LIBRARIES_LIBS_libtest8194327 := -framework JavaVM \ + -framework Cocoa -framework JavaNativeFoundation endif $(eval $(call SetupTestFilesCompilation, BUILD_JDK_JTREG_LIBRARIES, \ --- old/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m 2018-04-02 14:03:38.000000000 -0700 +++ new/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m 2018-04-02 14:03:38.000000000 -0700 @@ -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 @@ -680,7 +680,7 @@ 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]; @@ -714,13 +714,47 @@ } } +- (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; @@ -739,26 +773,48 @@ } [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]; +#ifdef DEBUG + NSLog(@"resigned key: %d %@ %@", [self.nsWindow isMainWindow], [self.nsWindow title], [self menuBarForWindow]); +#endif + if (![self.nsWindow isMainWindow]) { + [self deactivateWindow]; + } +} - // 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]; +- (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]; @@ -774,19 +830,6 @@ [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]; @@ -1041,7 +1084,7 @@ AWTWindow *window = (AWTWindow*)[nsWindow delegate]; - if ([nsWindow isKeyWindow]) { + if ([nsWindow isKeyWindow] || [nsWindow isMainWindow]) { [window.javaMenuBar deactivate]; } @@ -1052,7 +1095,7 @@ actualMenuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar]; } - if ([nsWindow isKeyWindow]) { + if ([nsWindow isKeyWindow] || [nsWindow isMainWindow]) { [CMenuBar activate:actualMenuBar modallyDisabled:NO]; } }]; --- old/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuBar.m 2018-04-02 14:03:39.000000000 -0700 +++ new/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuBar.m 2018-04-02 14:03:39.000000000 -0700 @@ -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 @@ return; } +#ifdef DEBUG + NSLog(@"activating menu bar: %@", menubar); +#endif + @synchronized([CMenuBar class]) { sActiveMenuBar = menubar; } @@ -184,12 +189,30 @@ -(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]; + } } } --- old/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m 2018-04-02 14:03:41.000000000 -0700 +++ new/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m 2018-04-02 14:03:40.000000000 -0700 @@ -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 { --- /dev/null 2018-04-02 14:03:42.000000000 -0700 +++ new/test/jdk/java/awt/Window/MainKeyWindowTest/Test.java 2018-04-02 14:03:41.000000000 -0700 @@ -0,0 +1,389 @@ +/* + * 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 Test + * @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 Test +{ + static Test theTest; + + KeyStroke commandT = KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.META_DOWN_MASK); + + int nextX = 100; + + 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(100, 400, 225, 400); // approximate is OK + private Rectangle nativeWindowBounds = new Rectangle(100, 200, 150, 150); + + private Robot robot; + + private int actionCounter; + private Object actionTarget; + + private int failureCount; + + public Test() + { + System.loadLibrary("test8194327"); + + 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, 50, 200, 130); + 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 + + try { + Runtime.getRuntime().exec("/usr/bin/open /"); + } catch (IOException ex) { + throw new RuntimeException("Unable to deactivate test application"); + } + robot.delay(1000); + activateApplication(); + robot.delay(1000); + + performMenuShortcutTest(windowIdentification, selectColorPanel); + performMenuItemTest(windowIdentification, selectColorPanel); + } + + 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); + } + + 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 Test(); + }); + 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); + } + } +} --- /dev/null 2018-04-02 14:03:43.000000000 -0700 +++ new/test/jdk/java/awt/Window/MainKeyWindowTest/libtest8194327.c 2018-04-02 14:03:42.000000000 -0700 @@ -0,0 +1,116 @@ +/* + * 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 +#import + +static NSWindow *testWindow; +static NSColorPanel *colorPanel; + +/* + * Class: Test + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_Test_setup(JNIEnv *env, jclass cl) +{ + JNF_COCOA_ENTER(env); + + void (^block)() = ^(){ + NSScreen *mainScreen = [NSScreen mainScreen]; + NSRect screenFrame = [mainScreen frame]; + NSRect frame = NSMakeRect(100, screenFrame.size.height - 350, 150, 150); + NSWindowStyleMask style = NSWindowStyleMaskTitled; + 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: NO]; + [colorPanel makeKeyAndOrderFront: nil]; + [colorPanel setFrameTopLeftPoint: NSMakePoint(100, screenFrame.size.height - 400)]; + // Java coordinates are 100, 400 + }; + + if ([NSThread isMainThread]) { + block(); + } else { + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:block]; + } + + JNF_COCOA_EXIT(env); +} + +/* + * Class: Test + * Method: takedown + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_Test_takedown(JNIEnv *env, jclass cl) +{ + JNF_COCOA_ENTER(env); + + void (^block)() = ^(){ + if (testWindow != nil) { + [testWindow close]; + testWindow = nil; + } + if (colorPanel != nil) { + [colorPanel close]; + colorPanel = nil; + } + }; + + if ([NSThread isMainThread]) { + block(); + } else { + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:block]; + } + + JNF_COCOA_EXIT(env); +} + +/* + * Class: Test + * Method: activateApplication + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_Test_activateApplication + (JNIEnv *env, jclass cl) +{ + JNF_COCOA_ENTER(env); + + void (^block)() = ^(){ + [NSApp activateIgnoringOtherApps:YES]; + }; + + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:block]; + + JNF_COCOA_EXIT(env); +}