Index: autoupdate/src/org/netbeans/modules/autoupdate/Autoupdater.java *** /doma/jarda/netbeans-src/autoupdate/src/org/netbeans/modules/autoupdate/Autoupdater.java --- /doma/jarda/netbeans-src/autoupdate/src/org/netbeans/modules/autoupdate/Autoupdater.java *************** *** 70,103 **** // XXX probably not ideal but should work for now... if (! Boolean.getBoolean("netbeans.full.hack") && ! Boolean.getBoolean("netbeans.close")) { // NOI18N // Just wait for GUI to pop up, whatever... ! l = new WindowListener () { ! public void windowOpened(WindowEvent e) { ! doInstallUpdateChecker (updateChecker); } - public void windowClosing(WindowEvent e) {} - public void windowClosed(WindowEvent e) {} - public void windowIconified(WindowEvent e) {} - public void windowDeiconified(WindowEvent e) {} - public void windowActivated(WindowEvent e) {} - public void windowDeactivated(WindowEvent e) {} }; ! // WindowsAPI is required to be called from AWT thread only ! SwingUtilities.invokeLater (new Runnable () { ! public void run () { ! WindowManager.getDefault ().getMainWindow ().addWindowListener (l); ! } ! }); } } - private static WindowListener l; - - private static void doInstallUpdateChecker (final Runnable updateChecker) { - // bugfix #43655, postpone the connect to AU till the main window is opened - RequestProcessor.getDefault().post(updateChecker, 5000); - WindowManager.getDefault ().getMainWindow ().removeWindowListener (l); - } - // Try to avoid referring directly to IDESettings. // If we can in fact find IDESettings and all appropriate methods, then we // use them. This means proxy config etc. will be properly persisted in --- 70,85 ---- // XXX probably not ideal but should work for now... if (! Boolean.getBoolean("netbeans.full.hack") && ! Boolean.getBoolean("netbeans.close")) { // NOI18N // Just wait for GUI to pop up, whatever... ! ! Runnable l = new Runnable () { ! public void run() { ! // bugfix #43655, postpone the connect to AU till the main window is opened ! RequestProcessor.getDefault().post(updateChecker, 5000); } }; ! WindowManager.getDefault().invokeExclusively(l); } } // Try to avoid referring directly to IDESettings. // If we can in fact find IDESettings and all appropriate methods, then we Index: core/windows/nbproject/project.properties *** /doma/jarda/netbeans-src/core/windows/nbproject/project.properties --- /doma/jarda/netbeans-src/core/windows/nbproject/project.properties *************** *** 11,14 **** spec.version.base=2.6.0 ! test.unit.cp.extra=${core.dir}/lib/boot.jar:${openide/masterfs.dir}/modules/org-netbeans-modules-masterfs.jar --- 11,16 ---- spec.version.base=2.6.0 ! test.unit.cp.extra=${core.dir}/lib/boot.jar:\ ! ${openide/masterfs.dir}/modules/org-netbeans-modules-masterfs.jar:\ ! ${nb_all}/openide/windows/build/test/unit/classes/ Index: core/windows/test/unit/src/org/netbeans/core/windows/WMCompatTest.java *** /doma/jarda/netbeans-src/core/windows/test/unit/src/org/netbeans/core/windows/WMCompatTest.java --- /doma/jarda/netbeans-src/core/windows/test/unit/src/org/netbeans/core/windows/WMCompatTest.java *************** *** 1,0 **** --- 1,75 ---- + /* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 2002 Sun + * Microsystems, Inc. All Rights Reserved. + */ + + package org.netbeans.core.windows; + + import java.lang.reflect.InvocationTargetException; + import javax.swing.SwingUtilities; + import junit.framework.*; + import org.netbeans.junit.*; + import org.openide.windows.WindowManager; + import org.openide.windows.WindowSystemCompatibilityTest; + + /** Checks the consistence of Menu folder. + * + * @author Jaroslav Tulach + */ + public class WMCompatTest extends NbTestCase { + public WMCompatTest(String s) { + super(s); + } + + public static Test suite() throws InterruptedException, InvocationTargetException { + WindowSystemCompatibilityTest.init(); + + TestSuite suite = new NbTestSuite(WMCompatTest.class); + suite.addTest(WindowSystemCompatibilityTest.suite(new WindowManagerImpl())); + + WindowManagerImpl.getInstance().setVisible(true); + // wait + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + } + }); + + return suite; + } + + public void testIfNotShownThenItIsNotExecuted() throws Exception { + class Run implements Runnable { + public volatile boolean executed; + + public void run() { + executed = true; + } + } + + WindowManagerImpl.getInstance().setVisible(false); + // wait + SwingUtilities.invokeAndWait(new Run()); + + Run run = new Run(); + WindowManager.getDefault().invokeExclusively(run); + + Thread.sleep(100); + assertFalse("Not run at all", run.executed); + + WindowManagerImpl.getInstance().setVisible(true); + + // wait + SwingUtilities.invokeAndWait(new Run()); + + assertTrue("Finished", run.executed); + } + } + Index: core/windows/src/org/netbeans/core/windows/WindowManagerImpl.java *** /doma/jarda/netbeans-src/core/windows/src/org/netbeans/core/windows/WindowManagerImpl.java --- /doma/jarda/netbeans-src/core/windows/src/org/netbeans/core/windows/WindowManagerImpl.java *************** *** 19,20 **** --- 19,25 ---- import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.net.URL; + import java.util.ArrayList; import java.util.Iterator; import java.util.Set; import javax.swing.Action; *************** *** 77,78 **** --- 78,85 ---- /** Only for hack 40237, to not call componentShowing twice */ private TopComponent persistenceShowingTC; + /** exclusive invocation of runnables */ + private Exclusive exclusive = new Exclusive(); /** Default constructor. Don't use directly, use getDefault() *************** *** 708,709 **** --- 711,717 ---- /** Sets visible or invisible window system GUI. */ public void setVisible(boolean visible) { central.setVisible(visible); + SwingUtilities.invokeLater(exclusive); } /** Indicates whether windows system shows GUI. */ *************** *** 1122,1127 **** new IllegalStateException("Assertion failed. " + ASSERTION_ERROR_MESSAGE)); // NOI18N } } ! } --- 1126,1171 ---- new IllegalStateException("Assertion failed. " + ASSERTION_ERROR_MESSAGE)); // NOI18N } } ! ! public void invokeExclusively(Runnable run) { ! exclusive.register(run); ! } ! ! /** Handles exclusive invocation of Runnables. ! */ ! private static final class Exclusive implements Runnable { ! /** lists of runnables to run */ ! private ArrayList arr = new ArrayList(); ! ! public synchronized void register(Runnable r) { ! arr.add(r); ! SwingUtilities.invokeLater(this); ! } ! ! public void run() { ! if (!WindowManagerImpl.getInstance().isVisible()) { ! return; ! } ! ! Iterator it; ! synchronized (this) { ! if (arr.isEmpty()) { ! return; ! } ! ! it = arr.iterator(); ! arr = new ArrayList(); ! } ! ! while (it.hasNext()) { ! Runnable r = (Runnable)it.next(); ! try { ! r.run(); ! } catch (RuntimeException ex) { ! ErrorManager.getDefault().notify(ex); ! } ! } ! } ! } } Index: java/javacore/src/org/netbeans/modules/javacore/JavaCoreModule.java *** /doma/jarda/netbeans-src/java/javacore/src/org/netbeans/modules/javacore/JavaCoreModule.java --- /doma/jarda/netbeans-src/java/javacore/src/org/netbeans/modules/javacore/JavaCoreModule.java *************** *** 47,57 **** ((MDRManagerImpl) manager).setProgressListener(new ShutDownProgressListener()); } final CompL l = new CompL(); ! if (SwingUtilities.isEventDispatchThread()) { ! l.run(); ! } else { ! SwingUtilities.invokeLater(l); ! } org.netbeans.modules.javacore.internalapi.JavaMetamodel.getManager(); } --- 47,53 ---- ((MDRManagerImpl) manager).setProgressListener(new ShutDownProgressListener()); } final CompL l = new CompL(); ! WindowManager.getDefault().invokeExclusively(l); org.netbeans.modules.javacore.internalapi.JavaMetamodel.getManager(); } *************** *** 60,84 **** return true; } ! private static class CompL extends WindowAdapter implements Runnable { ! public void windowOpened(WindowEvent e) { if (startupInProgress) { startupInProgress = false; ((JMManager) JMManager.getManager()).startupFinished(); - removeListener(e.getWindow()); } } - - private void addListener(Window window) { - window.addWindowListener(this); - } - - private void removeListener(Window window) { - window.removeWindowListener(this); - } - - public void run() { - addListener(WindowManager.getDefault().getMainWindow()); - } } } --- 56,67 ---- return true; } ! private static class CompL implements Runnable { ! public void run() { if (startupInProgress) { startupInProgress = false; ((JMManager) JMManager.getManager()).startupFinished(); } } } } Index: openide/windows/apichanges.xml *** /doma/jarda/netbeans-src/openide/windows/apichanges.xml --- /doma/jarda/netbeans-src/openide/windows/apichanges.xml *************** *** 17,23 **** Window System API ! Added the TopComponent ability to bring their parent Window to front of other windows. --- 17,39 ---- Window System API ! + New method to invoke code after main window is shown + + + + + + New method WindowManager.invokeExclusively + has been added that can be used to execute a code + that is supposed to run after main window is shown. + + + + + + Added the TopComponent ability to bring their parent Window to front of other windows. Index: openide/windows/test/unit/src/org/openide/windows/WindowSystemCompatibilityTest.java *** /doma/jarda/netbeans-src/openide/windows/test/unit/src/org/openide/windows/WindowSystemCompatibilityTest.java --- /doma/jarda/netbeans-src/openide/windows/test/unit/src/org/openide/windows/WindowSystemCompatibilityTest.java *************** *** 1,0 **** --- 1,96 ---- + /* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun + * Microsystems, Inc. All Rights Reserved. + */ + package org.openide.windows; + + import junit.framework.*; + import org.openide.util.Lookup; + import org.openide.util.lookup.AbstractLookup; + import org.openide.util.lookup.InstanceContent; + import org.openide.util.lookup.Lookups; + import org.openide.util.lookup.ProxyLookup; + + /** Tests that a window system implementation conforms to the expected + * behaviour. + * + * @author Jaroslav Tulach + */ + public final class WindowSystemCompatibilityTest extends Object { + /** initialize the lookup for the test */ + public static void init() { + System.setProperty("org.openide.util.Lookup", WindowSystemCompatibilityTest.class.getName() + "$Lkp"); + + Object o = Lookup.getDefault(); + if (!(o instanceof Lkp)) { + Assert.fail("Wrong lookup object: " + o); + } + } + + private WindowSystemCompatibilityTest(String testName) { + } + + /** Checks the default implementation. + */ + public static Test suite() { + return suite(null); + } + + /** Executes the test for provided window manager. + */ + public static Test suite(WindowManager wm) { + init(); + + Object o = Lookup.getDefault(); + Lkp l = (Lkp)o; + l.assignWM(wm); + + if (wm != null) { + Assert.assertEquals("Same engine found", wm, WindowManager.getDefault()); + } else { + o = WindowManager.getDefault(); + Assert.assertNotNull("Engine found", o); + Assert.assertEquals(DummyWindowManager.class, o.getClass()); + } + + TestSuite ts = new TestSuite(); + ts.addTestSuite(WindowManagerHid.class); + + return ts; + } + + /** Default lookup used in the suite. + */ + public static final class Lkp extends ProxyLookup { + private InstanceContent ic; + + public Lkp() { + super(new Lookup[0]); + + ic = new InstanceContent(); + AbstractLookup al = new AbstractLookup(ic); + + setLookups(new Lookup[] { + al, Lookups.metaInfServices(Lkp.class.getClassLoader()) + }); + } + + final void assignWM(WindowManager executionEngine) { + // ic.setPairs(java.util.Collections.EMPTY_LIST); + if (executionEngine != null) { + ic.add(executionEngine); + } + } + + + } + + } Index: openide/windows/test/build-unit.xml *** /doma/jarda/netbeans-src/openide/windows/test/build-unit.xml --- /doma/jarda/netbeans-src/openide/windows/test/build-unit.xml *************** *** 1,0 **** --- 1,24 ---- + + + + + + + + + + + + Index: openide/windows/test/build.xml *** /doma/jarda/netbeans-src/openide/windows/test/build.xml --- /doma/jarda/netbeans-src/openide/windows/test/build.xml *************** *** 1,0 **** --- 1,26 ---- + + + + + + + + + + + + + + + Index: openide/windows/test/cfg-unit.xml *** /doma/jarda/netbeans-src/openide/windows/test/cfg-unit.xml --- /doma/jarda/netbeans-src/openide/windows/test/cfg-unit.xml *************** *** 1,0 **** --- 1,34 ---- + + + + + + + + + + + + + + + + + + + + + + Index: openide/windows/manifest.mf *** /doma/jarda/netbeans-src/openide/windows/manifest.mf --- /doma/jarda/netbeans-src/openide/windows/manifest.mf *************** *** 1,5 **** Manifest-Version: 1.0 OpenIDE-Module: org.openide.windows ! OpenIDE-Module-Specification-Version: 6.3 OpenIDE-Module-Localizing-Bundle: org/openide/windows/Bundle.properties --- 1,5 ---- Manifest-Version: 1.0 OpenIDE-Module: org.openide.windows ! OpenIDE-Module-Specification-Version: 6.4 OpenIDE-Module-Localizing-Bundle: org/openide/windows/Bundle.properties Index: openide/windows/src/org/openide/windows/WindowManager.java *** /doma/jarda/netbeans-src/openide/windows/src/org/openide/windows/WindowManager.java --- /doma/jarda/netbeans-src/openide/windows/src/org/openide/windows/WindowManager.java *************** *** 452,453 **** --- 452,474 ---- * @since 4.15 */ public abstract TopComponent findTopComponent(String tcID); + /** Provides support for executing a piece of code in 'exclusive' manner, + * at the 'right' time. The behaviour is similar to {@link SwingUtilities#invokeLater} + * moreover it is guaranteed that only one Runnable runs at given time. + * This method can be invoked from any thread. + * + *

+ * The typical usecase is to call this method during startup of NetBeans + * based application. The default manager then waits till the main window + * is opened and then executes all the registered methods one by one. + *

+ * @param run the runnable that executes the exclusive code + * @since 6.4 + */ + public void invokeExclusively(Runnable run) { + SwingUtilities.invokeLater(run); + } + /** A manager that handles operations on top components. * It is always attached to a {@link TopComponent}. * @deprecated Do not use anymore. This interface is replaced by bunch of protedcted methods Index: openide/windows/test/unit/src/org/openide/windows/WindowManagerHid.java *** /doma/jarda/netbeans-src/openide/windows/test/unit/src/org/openide/windows/WindowManagerHid.java --- /doma/jarda/netbeans-src/openide/windows/test/unit/src/org/openide/windows/WindowManagerHid.java *************** *** 1,0 **** --- 1,89 ---- + /* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun + * Microsystems, Inc. All Rights Reserved. + */ + + package org.openide.windows; + + import java.security.AllPermission; + import java.security.CodeSource; + import java.security.PermissionCollection; + import java.security.Permissions; + import javax.swing.SwingUtilities; + import junit.framework.TestCase; + import org.netbeans.junit.NbTestCase; + import org.openide.util.Lookup; + + /** A piece of the test compatibility suite for the execution APIs. + * + * @author Jaroslav Tulach + */ + public class WindowManagerHid extends NbTestCase { + + public WindowManagerHid(String testName) { + super(testName); + } + + public void testGetDefault() { + WindowManager result = WindowManager.getDefault(); + assertNotNull(result); + } + + public void testInvokeExclusively() throws Exception { + class R implements Runnable { + public boolean started; + public boolean finished; + public boolean block; + + public synchronized void run() { + assertTrue("Runs only in AWT thread", SwingUtilities.isEventDispatchThread()); + try { + started = true; + notifyAll(); + if (block) { + wait(); + } + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + finished = true; + notifyAll(); + } + } + + R run = new R(); + R snd = new R(); + + WindowManager wm = WindowManager.getDefault(); + synchronized (run) { + wm.invokeExclusively(run); + run.block = true; + run.wait(); + } + assertTrue("started", run.started); + assertFalse("but not finished", run.finished); + + wm.invokeExclusively(snd); + + Thread.sleep(100); + + assertFalse("Not started", snd.started); + synchronized (snd) { + synchronized (run) { + run.notifyAll(); + run.wait(); + } + assertTrue("run is finished", run.finished); + snd.wait(); + assertTrue("snd also finished", snd.finished); + } + } + }