# HG changeset patch # User yan # Date 1206365596 25200 # Node ID a67fedfd0b217d6a074554ff806a3ac2f495e7c8 # Parent 94a4cf0115100d5b695ba0311b362d4cffab4fd9# Parent 3d873ae9aa8805e9fb066a0d833c3a563359820c Merge diff -r 94a4cf011510 -r a67fedfd0b21 jdk/make/sun/splashscreen/Makefile --- a/jdk/make/sun/splashscreen/Makefile Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/make/sun/splashscreen/Makefile Mon Mar 24 06:33:16 2008 -0700 @@ -85,3 +85,13 @@ CPPFLAGS += -I$(PLATFORM_SRC)/native/$(PKGDIR)/splashscreen -I$(SHARE_SRC)/native/$(PKGDIR)/splashscreen CPPFLAGS += -I$(SHARE_SRC)/native/$(PKGDIR)/image/jpeg -I$(SHARE_SRC)/native/java/util/zip/zlib-1.1.3 +ifeq ($(PLATFORM), linux) + ifeq ($(ARCH_DATA_MODEL), 64) + # 64-bit gcc has problems compiling MMX instructions. + # Google it for more details. Possibly the newer versions of + # the PNG-library and/or the new compiler will not need this + # option in the future. + CPPFLAGS += -DPNG_NO_MMX_CODE + endif +endif + diff -r 94a4cf011510 -r a67fedfd0b21 jdk/make/sun/xawt/Makefile --- a/jdk/make/sun/xawt/Makefile Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/make/sun/xawt/Makefile Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ # -# Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2002-2008 Sun Microsystems, Inc. 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 @@ -246,7 +246,7 @@ @if [ "$(DOCOMPARE)$(suffix $@)" = "true.64" ]; then \ $(ECHO) COMPARING $@ and $(STORED_SIZES_TMPL_$(PLATFORM)_$(LIBARCH)); \ $(DIFF) $@ $(STORED_SIZES_TMPL_$(PLATFORM)_$(LIBARCH)); \ - fi + fi $(TEMPDIR)/.gen.wrappers: $(SIZES) $(WRAPPER_GENERATOR_CLASS) $(XLIBTYPES) $(BOOT_JAVA_CMD) -cp $(WRAPPER_GENERATOR_TEMPDIR) WrapperGenerator \ @@ -256,10 +256,11 @@ $(MKDIR) -p $(TEMPDIR) $(TOUCH) $(TEMPDIR)/.gen.wrappers -generated.clean: +generated.clean: $(RM) -r $(WRAPPER_GENERATOR_TEMPDIR) $(RM) -r $(WRAPPER_GENERATOR_DIR) $(RM) -r $(GEN_DIR)/*.java + $(RM) -r $(TEMPDIR)/.gen_icons ifdef OPENJDK ICONS_PATH_PREFIX=$(PLATFORM_SRC) diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/share/classes/java/awt/Component.java --- a/jdk/src/share/classes/java/awt/Component.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Component.java Mon Mar 24 06:33:16 2008 -0700 @@ -634,6 +634,11 @@ */ private PropertyChangeSupport changeSupport; + private transient final Object changeSupportLock = new Object(); + private Object getChangeSupportLock() { + return changeSupportLock; + } + boolean isPacked = false; /** @@ -935,24 +940,26 @@ */ public GraphicsConfiguration getGraphicsConfiguration() { synchronized(getTreeLock()) { - GraphicsConfiguration gc = graphicsConfig; - Component parent = getParent(); - while ((gc == null) && (parent != null)) { - gc = parent.getGraphicsConfiguration(); - parent = parent.getParent(); - } - return gc; + if (graphicsConfig != null) { + return graphicsConfig; + } else if (getParent() != null) { + return getParent().getGraphicsConfiguration(); + } else { + return null; + } } } final GraphicsConfiguration getGraphicsConfiguration_NoClientCode() { - GraphicsConfiguration gc = this.graphicsConfig; - Component par = this.parent; - while ((gc == null) && (par != null)) { - gc = par.getGraphicsConfiguration_NoClientCode(); - par = par.parent; - } - return gc; + GraphicsConfiguration graphicsConfig = this.graphicsConfig; + Container parent = this.parent; + if (graphicsConfig != null) { + return graphicsConfig; + } else if (parent != null) { + return parent.getGraphicsConfiguration_NoClientCode(); + } else { + return null; + } } /** @@ -4602,7 +4609,8 @@ e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), - e.getWheelRotation()); + e.getWheelRotation(), + e.getPreciseWheelRotation()); ((AWTEvent)e).copyPrivateDataInto(newMWE); // When dispatching a wheel event to // ancestor, there is no need trying to find descendant @@ -6484,7 +6492,7 @@ // will need some help. Container parent = this.parent; if (parent != null && parent.peer instanceof LightweightPeer) { - nativeInLightFixer = new NativeInLightFixer(); + relocateComponent(); } } invalidate(); @@ -6595,10 +6603,6 @@ } } - if (nativeInLightFixer != null) { - nativeInLightFixer.uninstall(); - } - ComponentPeer p = peer; if (p != null) { boolean isLightweight = isLightweight(); @@ -7836,15 +7840,17 @@ * @see #getPropertyChangeListeners * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener) */ - public synchronized void addPropertyChangeListener( + public void addPropertyChangeListener( PropertyChangeListener listener) { - if (listener == null) { - return; - } - if (changeSupport == null) { - changeSupport = new PropertyChangeSupport(this); - } - changeSupport.addPropertyChangeListener(listener); + synchronized (getChangeSupportLock()) { + if (listener == null) { + return; + } + if (changeSupport == null) { + changeSupport = new PropertyChangeSupport(this); + } + changeSupport.addPropertyChangeListener(listener); + } } /** @@ -7860,12 +7866,14 @@ * @see #getPropertyChangeListeners * @see #removePropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener) */ - public synchronized void removePropertyChangeListener( + public void removePropertyChangeListener( PropertyChangeListener listener) { - if (listener == null || changeSupport == null) { - return; - } - changeSupport.removePropertyChangeListener(listener); + synchronized (getChangeSupportLock()) { + if (listener == null || changeSupport == null) { + return; + } + changeSupport.removePropertyChangeListener(listener); + } } /** @@ -7882,11 +7890,13 @@ * @see java.beans.PropertyChangeSupport#getPropertyChangeListeners * @since 1.4 */ - public synchronized PropertyChangeListener[] getPropertyChangeListeners() { - if (changeSupport == null) { - return new PropertyChangeListener[0]; - } - return changeSupport.getPropertyChangeListeners(); + public PropertyChangeListener[] getPropertyChangeListeners() { + synchronized (getChangeSupportLock()) { + if (changeSupport == null) { + return new PropertyChangeListener[0]; + } + return changeSupport.getPropertyChangeListeners(); + } } /** @@ -7920,16 +7930,18 @@ * @see #getPropertyChangeListeners(java.lang.String) * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener) */ - public synchronized void addPropertyChangeListener( + public void addPropertyChangeListener( String propertyName, PropertyChangeListener listener) { - if (listener == null) { - return; - } - if (changeSupport == null) { - changeSupport = new PropertyChangeSupport(this); - } - changeSupport.addPropertyChangeListener(propertyName, listener); + synchronized (getChangeSupportLock()) { + if (listener == null) { + return; + } + if (changeSupport == null) { + changeSupport = new PropertyChangeSupport(this); + } + changeSupport.addPropertyChangeListener(propertyName, listener); + } } /** @@ -7948,13 +7960,15 @@ * @see #getPropertyChangeListeners(java.lang.String) * @see #removePropertyChangeListener(java.beans.PropertyChangeListener) */ - public synchronized void removePropertyChangeListener( + public void removePropertyChangeListener( String propertyName, PropertyChangeListener listener) { - if (listener == null || changeSupport == null) { - return; - } - changeSupport.removePropertyChangeListener(propertyName, listener); + synchronized (getChangeSupportLock()) { + if (listener == null || changeSupport == null) { + return; + } + changeSupport.removePropertyChangeListener(propertyName, listener); + } } /** @@ -7971,12 +7985,14 @@ * @see #getPropertyChangeListeners * @since 1.4 */ - public synchronized PropertyChangeListener[] getPropertyChangeListeners( + public PropertyChangeListener[] getPropertyChangeListeners( String propertyName) { - if (changeSupport == null) { - return new PropertyChangeListener[0]; - } - return changeSupport.getPropertyChangeListeners(propertyName); + synchronized (getChangeSupportLock()) { + if (changeSupport == null) { + return new PropertyChangeListener[0]; + } + return changeSupport.getPropertyChangeListeners(propertyName); + } } /** @@ -7991,7 +8007,10 @@ */ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { - PropertyChangeSupport changeSupport = this.changeSupport; + PropertyChangeSupport changeSupport; + synchronized (getChangeSupportLock()) { + changeSupport = this.changeSupport; + } if (changeSupport == null || (oldValue != null && newValue != null && oldValue.equals(newValue))) { return; @@ -8491,8 +8510,6 @@ setComponentOrientation(orientation); } - transient NativeInLightFixer nativeInLightFixer; - /** * Checks that this component meets the prerequesites to be focus owner: * - it is enabled, visible, focusable @@ -8518,188 +8535,25 @@ } /** - * This odd class is to help out a native component that has been - * embedded in a lightweight component. Moving lightweight - * components around and changing their visibility is not seen - * by the native window system. This is a feature for lightweights, - * but a problem for native components that depend upon the - * lightweights. An instance of this class listens to the lightweight - * parents of an associated native component (the outer class). - * - * @author Timothy Prinzing - */ - final class NativeInLightFixer implements ComponentListener, ContainerListener { - - NativeInLightFixer() { - lightParents = new Vector(); - install(parent); - } - - void install(Container parent) { - lightParents.clear(); - Container p = parent; - boolean isLwParentsVisible = true; - // stash a reference to the components that are being observed so that - // we can reliably remove ourself as a listener later. - for (; p.peer instanceof LightweightPeer; p = p.parent) { - - // register listeners and stash a reference - p.addComponentListener(this); - p.addContainerListener(this); - lightParents.addElement(p); - isLwParentsVisible &= p.isVisible(); - } - // register with the native host (native parent of associated native) - // to get notified if the top-level lightweight is removed. - nativeHost = p; - p.addContainerListener(this); - - // kick start the fixup. Since the event isn't looked at - // we can simulate movement notification. - componentMoved(null); - if (!isLwParentsVisible) { - synchronized (getTreeLock()) { - if (peer != null) { - peer.hide(); - } - } - } - } - - void uninstall() { - if (nativeHost != null) { - removeReferences(); - } - } - - // --- ComponentListener ------------------------------------------- - - /** - * Invoked when one of the lightweight parents has been resized. - * This doesn't change the position of the native child so it - * is ignored. - */ - public void componentResized(ComponentEvent e) { - } - - /** - * Invoked when one of the lightweight parents has been moved. - * The native peer must be told of the new position which is - * relative to the native container that is hosting the - * lightweight components. - */ - public void componentMoved(ComponentEvent e) { - synchronized (getTreeLock()) { - int nativeX = x; - int nativeY = y; - for(Component c = parent; (c != null) && - (c.peer instanceof LightweightPeer); - c = c.parent) { - - nativeX += c.x; - nativeY += c.y; - } - if (peer != null) { - peer.setBounds(nativeX, nativeY, width, height, - ComponentPeer.SET_LOCATION); - } - } - } - - /** - * Invoked when a lightweight parent component has been - * shown. The associated native component must also be - * shown if it hasn't had an overriding hide done on it. - */ - public void componentShown(ComponentEvent e) { - if (shouldShow()) { - synchronized (getTreeLock()) { - if (peer != null) { - peer.show(); - } - } - } - } - - /** - * Invoked when one of the lightweight parents become visible. - * Returns true if component and all its lightweight - * parents are visible. - */ - private boolean shouldShow() { - boolean isLwParentsVisible = visible; - for (int i = lightParents.size() - 1; - i >= 0 && isLwParentsVisible; - i--) + * Fix the location of the HW component in a LW container hierarchy. + */ + final void relocateComponent() { + synchronized (getTreeLock()) { + if (peer == null) { + return; + } + int nativeX = x; + int nativeY = y; + for (Component cont = getContainer(); + cont != null && cont.isLightweight(); + cont = cont.getContainer()) { - isLwParentsVisible &= - ((Container) lightParents.elementAt(i)).isVisible(); - } - return isLwParentsVisible; - } - - /** - * Invoked when component has been hidden. - */ - public void componentHidden(ComponentEvent e) { - if (visible) { - synchronized (getTreeLock()) { - if (peer != null) { - peer.hide(); - } - } - } - } - - // --- ContainerListener ------------------------------------ - - /** - * Invoked when a component has been added to a lightweight - * parent. This doesn't effect the native component. - */ - public void componentAdded(ContainerEvent e) { - } - - /** - * Invoked when a lightweight parent has been removed. - * This means the services of this listener are no longer - * required and it should remove all references (ie - * registered listeners). - */ - public void componentRemoved(ContainerEvent e) { - Component c = e.getChild(); - if (c == Component.this) { - removeReferences(); - } else { - int n = lightParents.size(); - for (int i = 0; i < n; i++) { - Container p = (Container) lightParents.elementAt(i); - if (p == c) { - removeReferences(); - break; - } - } - } - } - - /** - * Removes references to this object so it can be - * garbage collected. - */ - void removeReferences() { - int n = lightParents.size(); - for (int i = 0; i < n; i++) { - Container c = (Container) lightParents.elementAt(i); - c.removeComponentListener(this); - c.removeContainerListener(this); - } - nativeHost.removeContainerListener(this); - lightParents.clear(); - nativeHost = null; - } - - Vector lightParents; - Container nativeHost; + nativeX += cont.x; + nativeY += cont.y; + } + peer.setBounds(nativeX, nativeY, width, height, + ComponentPeer.SET_LOCATION); + } } /** @@ -9453,6 +9307,19 @@ // ************************** MIXING CODE ******************************* /** + * Check whether we can trust the current bounds of the component. + * The return value of false indicates that the container of the + * component is invalid, and therefore needs to be layed out, which would + * probably mean changing the bounds of its children. + * Null-layout of the container or absence of the container mean + * the bounds of the component are final and can be trusted. + */ + private boolean areBoundsValid() { + Container cont = getContainer(); + return cont == null || cont.isValid() || cont.getLayout() == null; + } + + /** * Applies the shape to the component * @param shape Shape to be applied to the component */ @@ -9475,7 +9342,7 @@ // to modify the object outside of the mixing code. this.compoundShape = shape; - if (isValid()) { + if (areBoundsValid()) { Point compAbsolute = getLocationOnWindow(); if (mixingLog.isLoggable(Level.FINER)) { @@ -9602,7 +9469,7 @@ void applyCurrentShape() { checkTreeLock(); - if (!isValid()) { + if (!areBoundsValid()) { return; // Because applyCompoundShape() ignores such components anyway } if (mixingLog.isLoggable(Level.FINE)) { diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/share/classes/java/awt/Container.java --- a/jdk/src/share/classes/java/awt/Container.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Container.java Mon Mar 24 06:33:16 2008 -0700 @@ -832,16 +832,8 @@ } if (!comp.isLightweight() && isLightweight()) { // If component is heavyweight and one of the containers is lightweight - // some NativeInLightFixer activity should be performed - if (!curParent.isLightweight()) { - // Moving from heavyweight container to lightweight container - should create NativeInLightFixer - // since addNotify does this - comp.nativeInLightFixer = new NativeInLightFixer(); - } else { - // Component already has NativeInLightFixer - just reinstall it - // because hierarchy changed and he needs to rebuild list of parents to listen. - comp.nativeInLightFixer.install(this); - } + // the location of the component should be fixed. + comp.relocateComponent(); } } } @@ -2267,53 +2259,56 @@ EventTargetFilter filter, boolean searchHeavyweightChildren, boolean searchHeavyweightDescendants) { - int ncomponents = this.ncomponents; - Component component[] = this.component; - - for (int i = 0 ; i < ncomponents ; i++) { - Component comp = component[i]; - if (comp != null && comp.visible && - ((!searchHeavyweightChildren && - comp.peer instanceof LightweightPeer) || - (searchHeavyweightChildren && - !(comp.peer instanceof LightweightPeer))) && - comp.contains(x - comp.x, y - comp.y)) { - - // found a component that intersects the point, see if there is - // a deeper possibility. - if (comp instanceof Container) { - Container child = (Container) comp; - Component deeper = child.getMouseEventTarget(x - child.x, - y - child.y, - includeSelf, - filter, - searchHeavyweightDescendants); - if (deeper != null) { - return deeper; - } - } else { - if (filter.accept(comp)) { - // there isn't a deeper target, but this component is a - // target - return comp; + synchronized (getTreeLock()) { + int ncomponents = this.ncomponents; + Component component[] = this.component; + + for (int i = 0 ; i < ncomponents ; i++) { + Component comp = component[i]; + if (comp != null && comp.visible && + ((!searchHeavyweightChildren && + comp.peer instanceof LightweightPeer) || + (searchHeavyweightChildren && + !(comp.peer instanceof LightweightPeer))) && + comp.contains(x - comp.x, y - comp.y)) { + + // found a component that intersects the point, see if there + // is a deeper possibility. + if (comp instanceof Container) { + Container child = (Container) comp; + Component deeper = child.getMouseEventTarget( + x - child.x, + y - child.y, + includeSelf, + filter, + searchHeavyweightDescendants); + if (deeper != null) { + return deeper; + } + } else { + if (filter.accept(comp)) { + // there isn't a deeper target, but this component + // is a target + return comp; + } } } } + + boolean isPeerOK; + boolean isMouseOverMe; + + isPeerOK = (peer instanceof LightweightPeer) || includeSelf; + isMouseOverMe = contains(x,y); + + // didn't find a child target, return this component if it's + // a possible target + if (isMouseOverMe && isPeerOK && filter.accept(this)) { + return this; + } + // no possible target + return null; } - - boolean isPeerOK; - boolean isMouseOverMe; - - isPeerOK = (peer instanceof LightweightPeer) || includeSelf; - isMouseOverMe = contains(x,y); - - // didn't find a child target, return this component if it's a possible - // target - if (isMouseOverMe && isPeerOK && filter.accept(this)) { - return this; - } - // no possible target - return null; } static interface EventTargetFilter { @@ -3950,6 +3945,83 @@ } } + private void recursiveShowHeavyweightChildren() { + if (!hasHeavyweightDescendants() || !isVisible()) { + return; + } + for (int index = 0; index < getComponentCount(); index++) { + Component comp = getComponent(index); + if (comp.isLightweight()) { + if (comp instanceof Container) { + ((Container)comp).recursiveShowHeavyweightChildren(); + } + } else { + if (comp.isVisible()) { + ComponentPeer peer = comp.getPeer(); + if (peer != null) { + peer.show(); + } + } + } + } + } + + private void recursiveHideHeavyweightChildren() { + if (!hasHeavyweightDescendants()) { + return; + } + for (int index = 0; index < getComponentCount(); index++) { + Component comp = getComponent(index); + if (comp.isLightweight()) { + if (comp instanceof Container) { + ((Container)comp).recursiveHideHeavyweightChildren(); + } + } else { + if (comp.isVisible()) { + ComponentPeer peer = comp.getPeer(); + if (peer != null) { + peer.hide(); + } + } + } + } + } + + private void recursiveRelocateHeavyweightChildren(Point origin) { + for (int index = 0; index < getComponentCount(); index++) { + Component comp = getComponent(index); + if (comp.isLightweight()) { + if (comp instanceof Container && + ((Container)comp).hasHeavyweightDescendants()) + { + final Point newOrigin = new Point(origin); + newOrigin.translate(comp.getX(), comp.getY()); + ((Container)comp).recursiveRelocateHeavyweightChildren(newOrigin); + } + } else { + ComponentPeer peer = comp.getPeer(); + if (peer != null) { + peer.setBounds(origin.x + comp.getX(), origin.y + comp.getY(), + comp.getWidth(), comp.getHeight(), + ComponentPeer.SET_LOCATION); + } + } + } + } + + /* + * Consider the heavyweight container hides or shows the HW descendants + * automatically. Therefore we care of LW containers' visibility only. + */ + private boolean isRecursivelyVisibleUpToHeavyweightContainer() { + if (!isLightweight()) { + return true; + } + return isVisible() && (getContainer() == null || + getContainer().isRecursivelyVisibleUpToHeavyweightContainer()); + } + + @Override void mixOnShowing() { synchronized (getTreeLock()) { if (mixingLog.isLoggable(Level.FINE)) { @@ -3958,6 +4030,10 @@ boolean isLightweight = isLightweight(); + if (isLightweight && isRecursivelyVisibleUpToHeavyweightContainer()) { + recursiveShowHeavyweightChildren(); + } + if (!isLightweight || (isLightweight && hasHeavyweightDescendants())) { recursiveApplyCurrentShape(); } @@ -3966,6 +4042,42 @@ } } + @Override + void mixOnHiding(boolean isLightweight) { + synchronized (getTreeLock()) { + if (mixingLog.isLoggable(Level.FINE)) { + mixingLog.fine("this = " + this + + "; isLightweight=" + isLightweight); + } + if (isLightweight) { + recursiveHideHeavyweightChildren(); + } + super.mixOnHiding(isLightweight); + } + } + + @Override + void mixOnReshaping() { + synchronized (getTreeLock()) { + if (mixingLog.isLoggable(Level.FINE)) { + mixingLog.fine("this = " + this); + } + if (isLightweight() && hasHeavyweightDescendants()) { + final Point origin = new Point(getX(), getY()); + for (Container cont = getContainer(); + cont != null && cont.isLightweight(); + cont = cont.getContainer()) + { + origin.translate(cont.getX(), cont.getY()); + } + + recursiveRelocateHeavyweightChildren(origin); + } + super.mixOnReshaping(); + } + } + + @Override void mixOnZOrderChanging(int oldZorder, int newZorder) { synchronized (getTreeLock()) { if (mixingLog.isLoggable(Level.FINE)) { @@ -4431,7 +4543,8 @@ e.isPopupTrigger(), ((MouseWheelEvent)e).getScrollType(), ((MouseWheelEvent)e).getScrollAmount(), - ((MouseWheelEvent)e).getWheelRotation()); + ((MouseWheelEvent)e).getWheelRotation(), + ((MouseWheelEvent)e).getPreciseWheelRotation()); } else { retargeted = new MouseEvent(target, diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java --- a/jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/share/classes/java/awt/DefaultKeyboardFocusManager.java Mon Mar 24 06:33:16 2008 -0700 @@ -154,7 +154,7 @@ private boolean doRestoreFocus(Component toFocus, Component vetoedComponent, boolean clearOnFailure) { - if (toFocus.isShowing() && toFocus.isFocusable() && + if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.isFocusable() && toFocus.requestFocus(false, CausedFocusEvent.Cause.ROLLBACK)) { return true; } else { diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/share/classes/java/awt/Window.java --- a/jdk/src/share/classes/java/awt/Window.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/share/classes/java/awt/Window.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1995-2008 Sun Microsystems, Inc. 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 @@ -24,7 +24,6 @@ */ package java.awt; -import java.applet.Applet; import java.awt.event.*; import java.awt.im.InputContext; import java.awt.image.BufferStrategy; @@ -355,18 +354,21 @@ static class WindowDisposerRecord implements sun.java2d.DisposerRecord { final WeakReference owner; final WeakReference weakThis; - final AppContext context; + final WeakReference context; WindowDisposerRecord(AppContext context, Window victim) { owner = new WeakReference(victim.getOwner()); weakThis = victim.weakThis; - this.context = context; + this.context = new WeakReference(context); } public void dispose() { Window parent = owner.get(); if (parent != null) { parent.removeOwnedWindow(weakThis); } - Window.removeFromWindowList(context, weakThis); + AppContext ac = context.get(); + if (null != ac) { + Window.removeFromWindowList(ac, weakThis); + } } } @@ -824,7 +826,10 @@ static private final AtomicBoolean beforeFirstWindowShown = new AtomicBoolean(true); - static final void closeSplashScreen() { + final void closeSplashScreen() { + if (isTrayIconWindow) { + return; + } if (beforeFirstWindowShown.getAndSet(false)) { SunToolkit.closeSplashScreen(); } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java --- a/jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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 @@ -49,7 +49,6 @@ import sun.awt.datatransfer.DataTransferer; - /** * The SystemFlavorMap is a configurable map between "natives" (Strings), which * correspond to platform-specific data formats, and "flavors" (DataFlavors), @@ -117,16 +116,51 @@ /** * Maps native Strings to Lists of DataFlavors (or base type Strings for * text DataFlavors). + * Do not use the field directly, use getNativeToFlavor() instead. */ private Map nativeToFlavor = new HashMap(); /** + * Accessor to nativeToFlavor map. Since we use lazy initialization we must + * use this accessor instead of direct access to the field which may not be + * initialized yet. This method will initialize the field if needed. + * + * @return nativeToFlavor + */ + private Map getNativeToFlavor() { + if (!isMapInitialized) { + initSystemFlavorMap(); + } + return nativeToFlavor; + } + + /** * Maps DataFlavors (or base type Strings for text DataFlavors) to Lists of * native Strings. + * Do not use the field directly, use getFlavorToNative() instead. */ private Map flavorToNative = new HashMap(); /** + * Accessor to flavorToNative map. Since we use lazy initialization we must + * use this accessor instead of direct access to the field which may not be + * initialized yet. This method will initialize the field if needed. + * + * @return flavorToNative + */ + private synchronized Map getFlavorToNative() { + if (!isMapInitialized) { + initSystemFlavorMap(); + } + return flavorToNative; + } + + /** + * Shows if the object has been initialized. + */ + private boolean isMapInitialized = false; + + /** * Caches the result of getNativesForFlavor(). Maps DataFlavors to * SoftReferences which reference Lists of String natives. */ @@ -169,15 +203,24 @@ return fm; } + private SystemFlavorMap() { + } + /** - * Constructs a SystemFlavorMap by reading flavormap.properties and + * Initializes a SystemFlavorMap by reading flavormap.properties and * AWT.DnD.flavorMapFileURL. + * For thread-safety must be called under lock on this. */ - private SystemFlavorMap() { - BufferedReader flavormapDotProperties = (BufferedReader) + private void initSystemFlavorMap() { + if (isMapInitialized) { + return; + } + + isMapInitialized = true; + BufferedReader flavormapDotProperties = java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { + new java.security.PrivilegedAction() { + public BufferedReader run() { String fileName = System.getProperty("java.home") + File.separator + @@ -197,12 +240,11 @@ } }); - BufferedReader flavormapURL = (BufferedReader) + BufferedReader flavormapURL = java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - String url = Toolkit.getDefaultToolkit().getProperty - ("AWT.DnD.flavorMapFileURL", null); + new java.security.PrivilegedAction() { + public BufferedReader run() { + String url = Toolkit.getProperty("AWT.DnD.flavorMapFileURL", null); if (url == null) { return null; @@ -237,7 +279,6 @@ } } } - /** * Copied code from java.util.Properties. Parsing the data ourselves is the * only way to handle duplicate keys and values. @@ -388,11 +429,11 @@ // For text/* flavors, store mappings in separate maps to // enable dynamic mapping generation at a run-time. if ("text".equals(flavor.getPrimaryType())) { - store(value, key, flavorToNative); - store(key, value, nativeToFlavor); + store(value, key, getFlavorToNative()); + store(key, value, getNativeToFlavor()); } else { - store(flavor, key, flavorToNative); - store(key, flavor, nativeToFlavor); + store(flavor, key, getFlavorToNative()); + store(key, flavor, getNativeToFlavor()); } } } @@ -494,7 +535,7 @@ * only if the specified native is encoded as a Java MIME type. */ private List nativeToFlavorLookup(String nat) { - List flavors = (List)nativeToFlavor.get(nat); + List flavors = (List)getNativeToFlavor().get(nat); if (nat != null && !disabledMappingGenerationKeys.contains(nat)) { DataTransferer transferer = DataTransferer.getInstance(); @@ -530,15 +571,15 @@ if (flavor != null) { flavors = new ArrayList(1); - nativeToFlavor.put(nat, flavors); + getNativeToFlavor().put(nat, flavors); flavors.add(flavor); getFlavorsForNativeCache.remove(nat); getFlavorsForNativeCache.remove(null); - List natives = (List)flavorToNative.get(flavor); + List natives = (List)getFlavorToNative().get(flavor); if (natives == null) { natives = new ArrayList(1); - flavorToNative.put(flavor, natives); + getFlavorToNative().put(flavor, natives); } natives.add(nat); getNativesForFlavorCache.remove(flavor); @@ -559,7 +600,7 @@ */ private List flavorToNativeLookup(final DataFlavor flav, final boolean synthesize) { - List natives = (List)flavorToNative.get(flav); + List natives = (List)getFlavorToNative().get(flav); if (flav != null && !disabledMappingGenerationKeys.contains(flav)) { DataTransferer transferer = DataTransferer.getInstance(); @@ -584,15 +625,15 @@ if (synthesize) { String encoded = encodeDataFlavor(flav); natives = new ArrayList(1); - flavorToNative.put(flav, natives); + getFlavorToNative().put(flav, natives); natives.add(encoded); getNativesForFlavorCache.remove(flav); getNativesForFlavorCache.remove(null); - List flavors = (List)nativeToFlavor.get(encoded); + List flavors = (List)getNativeToFlavor().get(encoded); if (flavors == null) { flavors = new ArrayList(1); - nativeToFlavor.put(encoded, flavors); + getNativeToFlavor().put(encoded, flavors); } flavors.add(flav); getFlavorsForNativeCache.remove(encoded); @@ -645,7 +686,7 @@ } if (flav == null) { - retval = new ArrayList(nativeToFlavor.keySet()); + retval = new ArrayList(getNativeToFlavor().keySet()); } else if (disabledMappingGenerationKeys.contains(flav)) { // In this case we shouldn't synthesize a native for this flavor, // since its mappings were explicitly specified. @@ -655,7 +696,7 @@ // For text/* flavors, flavor-to-native mappings specified in // flavormap.properties are stored per flavor's base type. if ("text".equals(flav.getPrimaryType())) { - retval = (List)flavorToNative.get(flav.mimeType.getBaseType()); + retval = (List)getFlavorToNative().get(flav.mimeType.getBaseType()); if (retval != null) { // To prevent the List stored in the map from modification. retval = new ArrayList(retval); @@ -663,7 +704,7 @@ } // Also include text/plain natives, but don't duplicate Strings - List textPlainList = (List)flavorToNative.get(TEXT_PLAIN_BASE_TYPE); + List textPlainList = (List)getFlavorToNative().get(TEXT_PLAIN_BASE_TYPE); if (textPlainList != null && !textPlainList.isEmpty()) { // To prevent the List stored in the map from modification. @@ -699,7 +740,7 @@ } } } else if (DataTransferer.isFlavorNoncharsetTextType(flav)) { - retval = (List)flavorToNative.get(flav.mimeType.getBaseType()); + retval = (List)getFlavorToNative().get(flav.mimeType.getBaseType()); if (retval == null || retval.isEmpty()) { retval = flavorToNativeLookup(flav, SYNTHESIZE_IF_NOT_FOUND); @@ -1025,10 +1066,10 @@ throw new NullPointerException("null arguments not permitted"); } - List natives = (List)flavorToNative.get(flav); + List natives = (List)getFlavorToNative().get(flav); if (natives == null) { natives = new ArrayList(1); - flavorToNative.put(flav, natives); + getFlavorToNative().put(flav, natives); } else if (natives.contains(nat)) { return; } @@ -1071,7 +1112,7 @@ throw new NullPointerException("null arguments not permitted"); } - flavorToNative.remove(flav); + getFlavorToNative().remove(flav); for (int i = 0; i < natives.length; i++) { addUnencodedNativeForFlavor(flav, natives[i]); } @@ -1105,10 +1146,10 @@ throw new NullPointerException("null arguments not permitted"); } - List flavors = (List)nativeToFlavor.get(nat); + List flavors = (List)getNativeToFlavor().get(nat); if (flavors == null) { flavors = new ArrayList(1); - nativeToFlavor.put(nat, flavors); + getNativeToFlavor().put(nat, flavors); } else if (flavors.contains(flav)) { return; } @@ -1150,7 +1191,7 @@ throw new NullPointerException("null arguments not permitted"); } - nativeToFlavor.remove(nat); + getNativeToFlavor().remove(nat); for (int i = 0; i < flavors.length; i++) { addFlavorForUnencodedNative(nat, flavors[i]); } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/share/classes/java/awt/dnd/DropTarget.java --- a/jdk/src/share/classes/java/awt/dnd/DropTarget.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/share/classes/java/awt/dnd/DropTarget.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. 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 @@ -110,7 +110,11 @@ setActive(act); } - if (fm != null) flavorMap = fm; + if (fm != null) { + flavorMap = fm; + } else { + flavorMap = SystemFlavorMap.getDefaultFlavorMap(); + } } /** @@ -850,5 +854,5 @@ * The FlavorMap */ - private transient FlavorMap flavorMap = SystemFlavorMap.getDefaultFlavorMap(); + private transient FlavorMap flavorMap; } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/share/classes/java/awt/event/MouseWheelEvent.java --- a/jdk/src/share/classes/java/awt/event/MouseWheelEvent.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/share/classes/java/awt/event/MouseWheelEvent.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2007 Sun Microsystems, Inc. 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 @@ -74,6 +74,19 @@ * methods for conforming to the underlying platform settings. These * platform settings can be changed at any time by the user. MouseWheelEvents * reflect the most recent settings. + *

+ * The MouseWheelEvent class includes methods for + * getting the number of "clicks" by which the mouse wheel is rotated. + * The {@link #getWheelRotation} method returns the integer number + * of "clicks" corresponding to the number of notches by which the wheel was + * rotated. In addition to this method, the MouseWheelEvent + * class provides the {@link #getPreciseWheelRotation} method which returns + * a double number of "clicks" in case a partial rotation occurred. + * The {@link #getPreciseWheelRotation} method is useful if a mouse supports + * a high-resolution wheel, such as a freely rotating wheel with no + * notches. Applications can benefit by using this method to process + * mouse wheel events more precisely, and thus, making visual perception + * smoother. * * @author Brent Christian * @see MouseWheelListener @@ -131,6 +144,13 @@ */ int wheelRotation; + /** + * Indicates how far the mouse wheel was rotated. + * + * @see #getPreciseWheelRotation + */ + double preciseWheelRotation; + /* * serialVersionUID */ @@ -165,8 +185,8 @@ * WHEEL_BLOCK_SCROLL * @param scrollAmount for scrollType WHEEL_UNIT_SCROLL, * the number of units to be scrolled - * @param wheelRotation the amount that the mouse wheel was rotated (the - * number of "clicks") + * @param wheelRotation the integer number of "clicks" by which the mouse + * wheel was rotated * * @throws IllegalArgumentException if source is null * @see MouseEvent#MouseEvent(java.awt.Component, int, long, int, int, int, int, boolean) @@ -211,8 +231,8 @@ * WHEEL_BLOCK_SCROLL * @param scrollAmount for scrollType WHEEL_UNIT_SCROLL, * the number of units to be scrolled - * @param wheelRotation the amount that the mouse wheel was rotated (the - * number of "clicks") + * @param wheelRotation the integer number of "clicks" by which the mouse + * wheel was rotated * * @throws IllegalArgumentException if source is null * @see MouseEvent#MouseEvent(java.awt.Component, int, long, int, int, int, int, boolean) @@ -223,12 +243,68 @@ int x, int y, int xAbs, int yAbs, int clickCount, boolean popupTrigger, int scrollType, int scrollAmount, int wheelRotation) { + this(source, id, when, modifiers, x, y, xAbs, yAbs, clickCount, popupTrigger, + scrollType, scrollAmount, wheelRotation, wheelRotation); + + } + + + /** + * Constructs a MouseWheelEvent object with the specified + * source component, type, modifiers, coordinates, absolute coordinates, + * scroll type, scroll amount, and wheel rotation. + *

Note that passing in an invalid id parameter results + * in unspecified behavior. This method throws an + * IllegalArgumentException if source equals + * null. + *

Even if inconsistent values for relative and absolute coordinates + * are passed to the constructor, a MouseWheelEvent instance + * is still created and no exception is thrown. + * + * @param source the Component that originated the event + * @param id the integer value that identifies the event + * @param when a long value that gives the time when the event occurred + * @param modifiers the modifier keys down during event + * (shift, ctrl, alt, meta) + * @param x the horizontal x coordinate for the + * mouse location + * @param y the vertical y coordinate for the + * mouse location + * @param xAbs the absolute horizontal x coordinate for + * the mouse location + * @param yAbs the absolute vertical y coordinate for + * the mouse location + * @param clickCount the number of mouse clicks associated with the event + * @param popupTrigger a boolean value, true if this event is a trigger + * for a popup-menu + * @param scrollType the type of scrolling which should take place in + * response to this event; valid values are + * WHEEL_UNIT_SCROLL and + * WHEEL_BLOCK_SCROLL + * @param scrollAmount for scrollType WHEEL_UNIT_SCROLL, + * the number of units to be scrolled + * @param wheelRotation the integer number of "clicks" by which the mouse wheel + * was rotated + * @param preciseWheelRotation the double number of "clicks" by which the mouse wheel + * was rotated + * + * @throws IllegalArgumentException if source is null + * @see MouseEvent#MouseEvent(java.awt.Component, int, long, int, int, int, int, boolean) + * @see MouseEvent#MouseEvent(java.awt.Component, int, long, int, int, int, int, int, int, boolean, int) + * @since 1.7 + */ + public MouseWheelEvent (Component source, int id, long when, int modifiers, + int x, int y, int xAbs, int yAbs, int clickCount, boolean popupTrigger, + int scrollType, int scrollAmount, int wheelRotation, double preciseWheelRotation) { + super(source, id, when, modifiers, x, y, xAbs, yAbs, clickCount, popupTrigger, MouseEvent.NOBUTTON); this.scrollType = scrollType; this.scrollAmount = scrollAmount; this.wheelRotation = wheelRotation; + this.preciseWheelRotation = preciseWheelRotation; + } /** @@ -267,17 +343,35 @@ } /** - * Returns the number of "clicks" the mouse wheel was rotated. + * Returns the number of "clicks" the mouse wheel was rotated, as an integer. + * A partial rotation may occur if the mouse supports a high-resolution wheel. + * In this case, the method returns zero until a full "click" has been accumulated. * * @return negative values if the mouse wheel was rotated up/away from * the user, and positive values if the mouse wheel was rotated down/ * towards the user + * @see #getPreciseWheelRotation */ public int getWheelRotation() { return wheelRotation; } /** + * Returns the number of "clicks" the mouse wheel was rotated, as a double. + * A partial rotation may occur if the mouse supports a high-resolution wheel. + * In this case, the return value will include a fractional "click". + * + * @return negative values if the mouse wheel was rotated up or away from + * the user, and positive values if the mouse wheel was rotated down or + * towards the user + * @see #getWheelRotation + * @since 1.7 + */ + public double getPreciseWheelRotation() { + return preciseWheelRotation; + } + + /** * This is a convenience method to aid in the implementation of * the common-case MouseWheelListener - to scroll a ScrollPane or * JScrollPane by an amount which conforms to the platform settings. @@ -348,6 +442,6 @@ } return super.paramString()+",scrollType="+scrollTypeStr+ ",scrollAmount="+getScrollAmount()+",wheelRotation="+ - getWheelRotation(); + getWheelRotation()+",preciseWheelRotation="+getPreciseWheelRotation(); } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/share/classes/sun/awt/AppContext.java --- a/jdk/src/share/classes/sun/awt/AppContext.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/share/classes/sun/awt/AppContext.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2008 Sun Microsystems, Inc. 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 @@ -40,6 +40,8 @@ import java.util.Map; import java.util.Set; import java.util.HashSet; +import java.util.logging.Level; +import java.util.logging.Logger; import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeListener; @@ -126,6 +128,7 @@ * @author Fred Ecks */ public final class AppContext { + private static final Logger log = Logger.getLogger("sun.awt.AppContext"); /* Since the contents of an AppContext are unique to each Java * session, this class should never be serialized. */ @@ -143,13 +146,15 @@ * Returns a set containing all AppContexts. */ public static Set getAppContexts() { - return new HashSet(threadGroup2appContext.values()); + synchronized (threadGroup2appContext) { + return new HashSet(threadGroup2appContext.values()); + } } /* The main "system" AppContext, used by everything not otherwise contained in another AppContext. */ - private static AppContext mainAppContext = null; + private static volatile AppContext mainAppContext = null; /* * The hash map associated with this AppContext. A private delegate @@ -174,31 +179,30 @@ public static final String DISPOSED_PROPERTY_NAME = "disposed"; public static final String GUI_DISPOSED = "guidisposed"; - private boolean isDisposed = false; // true if AppContext is disposed + private volatile boolean isDisposed = false; // true if AppContext is disposed public boolean isDisposed() { return isDisposed; } - static { // On the main Thread, we get the ThreadGroup, make a corresponding // AppContext, and instantiate the Java EventQueue. This way, legacy // code is unaffected by the move to multiple AppContext ability. AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - ThreadGroup currentThreadGroup = - Thread.currentThread().getThreadGroup(); - ThreadGroup parentThreadGroup = currentThreadGroup.getParent(); - while (parentThreadGroup != null) { - // Find the root ThreadGroup to construct our main AppContext - currentThreadGroup = parentThreadGroup; - parentThreadGroup = currentThreadGroup.getParent(); + public Object run() { + ThreadGroup currentThreadGroup = + Thread.currentThread().getThreadGroup(); + ThreadGroup parentThreadGroup = currentThreadGroup.getParent(); + while (parentThreadGroup != null) { + // Find the root ThreadGroup to construct our main AppContext + currentThreadGroup = parentThreadGroup; + parentThreadGroup = currentThreadGroup.getParent(); + } + mainAppContext = new AppContext(currentThreadGroup); + numAppContexts = 1; + return mainAppContext; } - mainAppContext = new AppContext(currentThreadGroup); - numAppContexts = 1; - return mainAppContext; - } }); } @@ -209,7 +213,7 @@ * number is 1. If so, it returns the sole AppContext without * checking Thread.currentThread(). */ - private static int numAppContexts; + private static volatile int numAppContexts; /* * The context ClassLoader that was used to create this AppContext. @@ -236,14 +240,15 @@ threadGroup2appContext.put(threadGroup, this); this.contextClassLoader = - (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { + AccessController.doPrivileged(new PrivilegedAction() { + public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } }); } - private static MostRecentThreadAppContext mostRecentThreadAppContext = null; + private static final ThreadLocal threadAppContext = + new ThreadLocal(); /** * Returns the appropriate AppContext for the caller, @@ -260,59 +265,46 @@ if (numAppContexts == 1) // If there's only one system-wide, return mainAppContext; // return the main system AppContext. - final Thread currentThread = Thread.currentThread(); - - AppContext appContext = null; - - // Note: this most recent Thread/AppContext caching is thread-hot. - // A simple test using SwingSet found that 96.8% of lookups - // were matched using the most recent Thread/AppContext. By - // instantiating a simple MostRecentThreadAppContext object on - // cache misses, the cache hits can be processed without - // synchronization. + AppContext appContext = threadAppContext.get(); - MostRecentThreadAppContext recent = mostRecentThreadAppContext; - if ((recent != null) && (recent.thread == currentThread)) { - appContext = recent.appContext; // Cache hit - } else { - appContext = (AppContext)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - // Get the current ThreadGroup, and look for it and its - // parents in the hash from ThreadGroup to AppContext -- - // it should be found, because we use createNewContext() - // when new AppContext objects are created. - ThreadGroup currentThreadGroup = currentThread.getThreadGroup(); - ThreadGroup threadGroup = currentThreadGroup; - AppContext context = threadGroup2appContext.get(threadGroup); - while (context == null) { - threadGroup = threadGroup.getParent(); - if (threadGroup == null) { - // If we get here, we're running under a ThreadGroup that - // has no AppContext associated with it. This should never - // happen, because createNewContext() should be used by the - // toolkit to create the ThreadGroup that everything runs - // under. - throw new RuntimeException("Invalid ThreadGroup"); + if (null == appContext) { + appContext = AccessController.doPrivileged(new PrivilegedAction() + { + public AppContext run() { + // Get the current ThreadGroup, and look for it and its + // parents in the hash from ThreadGroup to AppContext -- + // it should be found, because we use createNewContext() + // when new AppContext objects are created. + ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup(); + ThreadGroup threadGroup = currentThreadGroup; + AppContext context = threadGroup2appContext.get(threadGroup); + while (context == null) { + threadGroup = threadGroup.getParent(); + if (threadGroup == null) { + // If we get here, we're running under a ThreadGroup that + // has no AppContext associated with it. This should never + // happen, because createNewContext() should be used by the + // toolkit to create the ThreadGroup that everything runs + // under. + throw new RuntimeException("Invalid ThreadGroup"); + } + context = threadGroup2appContext.get(threadGroup); + } + // In case we did anything in the above while loop, we add + // all the intermediate ThreadGroups to threadGroup2appContext + // so we won't spin again. + for (ThreadGroup tg = currentThreadGroup; tg != threadGroup; tg = tg.getParent()) { + threadGroup2appContext.put(tg, context); + } + // Now we're done, so we cache the latest key/value pair. + // (we do this before checking with any AWTSecurityManager, so if + // this Thread equates with the main AppContext in the cache, it + // still will) + threadAppContext.set(context); + + return context; } - context = threadGroup2appContext.get(threadGroup); - } - // In case we did anything in the above while loop, we add - // all the intermediate ThreadGroups to threadGroup2appContext - // so we won't spin again. - for (ThreadGroup tg = currentThreadGroup; tg != threadGroup; tg = tg.getParent()) { - threadGroup2appContext.put(tg, context); - } - // Now we're done, so we cache the latest key/value pair. - // (we do this before checking with any AWTSecurityManager, so if - // this Thread equates with the main AppContext in the cache, it - // still will) - mostRecentThreadAppContext = - new MostRecentThreadAppContext(currentThread, context); - - return context; - } - }); + }); } if (appContext == mainAppContext) { @@ -321,9 +313,9 @@ // allow it to choose the AppContext to return. SecurityManager securityManager = System.getSecurityManager(); if ((securityManager != null) && - (securityManager instanceof AWTSecurityManager)) { - AWTSecurityManager awtSecMgr = - (AWTSecurityManager)securityManager; + (securityManager instanceof AWTSecurityManager)) + { + AWTSecurityManager awtSecMgr = (AWTSecurityManager)securityManager; AppContext secAppContext = awtSecMgr.getAppContext(); if (secAppContext != null) { appContext = secAppContext; // Return what we're told @@ -385,7 +377,13 @@ public void run() { Window[] windowsToDispose = Window.getOwnerlessWindows(); for (Window w : windowsToDispose) { - w.dispose(); + try { + w.dispose(); + } catch (Throwable t) { + if (log.isLoggable(Level.FINER)) { + log.log(Level.FINER, "exception occured while disposing app context", t); + } + } } AccessController.doPrivileged(new PrivilegedAction() { public Object run() { @@ -444,7 +442,7 @@ // Threads in the ThreadGroup to exit. long startTime = System.currentTimeMillis(); - long endTime = startTime + (long)THREAD_INTERRUPT_TIMEOUT; + long endTime = startTime + THREAD_INTERRUPT_TIMEOUT; while ((this.threadGroup.activeCount() > 0) && (System.currentTimeMillis() < endTime)) { try { @@ -459,7 +457,7 @@ // Threads in the ThreadGroup to die. startTime = System.currentTimeMillis(); - endTime = startTime + (long)THREAD_INTERRUPT_TIMEOUT; + endTime = startTime + THREAD_INTERRUPT_TIMEOUT; while ((this.threadGroup.activeCount() > 0) && (System.currentTimeMillis() < endTime)) { try { @@ -478,10 +476,7 @@ } threadGroup2appContext.remove(this.threadGroup); - MostRecentThreadAppContext recent = mostRecentThreadAppContext; - if ((recent != null) && (recent.appContext == this)) - mostRecentThreadAppContext = null; - // If the "most recent" points to this, clear it for GC + threadAppContext.set(null); // Finally, we destroy the ThreadGroup entirely. try { @@ -664,6 +659,7 @@ * Returns a string representation of this AppContext. * @since 1.2 */ + @Override public String toString() { return getClass().getName() + "[threadGroup=" + threadGroup.getName() + "]"; } @@ -769,15 +765,6 @@ } } -final class MostRecentThreadAppContext { - final Thread thread; - final AppContext appContext; - MostRecentThreadAppContext(Thread key, AppContext value) { - thread = key; - appContext = value; - } -} - final class MostRecentKeyValue { Object key; Object value; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java --- a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2008 Sun Microsystems, Inc. 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 @@ -270,62 +270,58 @@ * instead, null will be returned. */ public static DataTransferer getInstance() { - if (transferer == null) { - synchronized (DataTransferer.class) { - if (transferer == null) { - final String name = SunToolkit. - getDataTransfererClassName(); - if (name != null) { - PrivilegedAction action = new PrivilegedAction() { - public Object run() { - Class cls = null; - Method method = null; - Object ret = null; + synchronized (DataTransferer.class) { + if (transferer == null) { + final String name = SunToolkit.getDataTransfererClassName(); + if (name != null) { + PrivilegedAction action = new PrivilegedAction() + { + public DataTransferer run() { + Class cls = null; + Method method = null; + DataTransferer ret = null; - try { - cls = Class.forName(name); - } catch (ClassNotFoundException e) { - ClassLoader cl = ClassLoader. - getSystemClassLoader(); - if (cl != null) { - try { - cls = cl.loadClass(name); - } catch (ClassNotFoundException ee) { - ee.printStackTrace(); - throw new AWTError("DataTransferer not found: " + name); - } + try { + cls = Class.forName(name); + } catch (ClassNotFoundException e) { + ClassLoader cl = ClassLoader. + getSystemClassLoader(); + if (cl != null) { + try { + cls = cl.loadClass(name); + } catch (ClassNotFoundException ee) { + ee.printStackTrace(); + throw new AWTError("DataTransferer not found: " + name); } } - if (cls != null) { - try { - method = cls.getDeclaredMethod - ("getInstanceImpl"); - method.setAccessible(true); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - throw new AWTError("Cannot instantiate DataTransferer: " + name); - } catch (SecurityException e) { - e.printStackTrace(); - throw new AWTError("Access is denied for DataTransferer: " + name); - } + } + if (cls != null) { + try { + method = cls.getDeclaredMethod("getInstanceImpl"); + method.setAccessible(true); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + throw new AWTError("Cannot instantiate DataTransferer: " + name); + } catch (SecurityException e) { + e.printStackTrace(); + throw new AWTError("Access is denied for DataTransferer: " + name); } - if (method != null) { - try { - ret = method.invoke(null); - } catch (InvocationTargetException e) { - e.printStackTrace(); - throw new AWTError("Cannot instantiate DataTransferer: " + name); - } catch (IllegalAccessException e) { - e.printStackTrace(); - throw new AWTError("Cannot access DataTransferer: " + name); - } + } + if (method != null) { + try { + ret = (DataTransferer) method.invoke(null); + } catch (InvocationTargetException e) { + e.printStackTrace(); + throw new AWTError("Cannot instantiate DataTransferer: " + name); + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new AWTError("Cannot access DataTransferer: " + name); } - return ret; } - }; - transferer = (DataTransferer) - AccessController.doPrivileged(action); - } + return ret; + } + }; + transferer = AccessController.doPrivileged(action); } } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/MotifDnDConstants.java --- a/jdk/src/solaris/classes/sun/awt/X11/MotifDnDConstants.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/MotifDnDConstants.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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 @@ -39,6 +39,8 @@ * @since 1.5 */ class MotifDnDConstants { + // utility class can not be instantiated + private MotifDnDConstants() {} // Note that offsets in all native structures below do not depend on the // architecture. private static final Unsafe unsafe = XlibWrapper.unsafe; @@ -55,8 +57,7 @@ XAtom.get("XmTRANSFER_SUCCESS"); static final XAtom XA_XmTRANSFER_FAILURE = XAtom.get("XmTRANSFER_FAILURE"); - static final XSelection MotifDnDSelection = - new XSelection(XA_MOTIF_ATOM_0, null); + static final XSelection MotifDnDSelection = new XSelection(XA_MOTIF_ATOM_0); public static final byte MOTIF_DND_PROTOCOL_VERSION = 0; @@ -231,6 +232,9 @@ } public static final class Swapper { + // utility class can not be instantiated + private Swapper() {} + public static short swap(short s) { return (short)(((s & 0xFF00) >>> 8) | ((s & 0xFF) << 8)); } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/MotifDnDDropTargetProtocol.java --- a/jdk/src/solaris/classes/sun/awt/X11/MotifDnDDropTargetProtocol.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/MotifDnDDropTargetProtocol.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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 @@ -933,7 +933,7 @@ XSelection selection = XSelection.getSelection(selectionAtom); if (selection == null) { - selection = new XSelection(selectionAtom, null); + selection = new XSelection(selectionAtom); } return selection.getData(format, time_stamp); @@ -1056,7 +1056,7 @@ // the original structure can be freed before this // SunDropTargetEvent is dispatched. if (xclient != null) { - int size = new XClientMessageEvent(nativeCtxt).getSize(); + int size = XClientMessageEvent.getSize(); nativeCtxt = unsafe.allocateMemory(size + 4 * Native.getLongSize()); diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/OwnershipListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/awt/X11/OwnershipListener.java Mon Mar 24 06:33:16 2008 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.awt.X11; + +interface OwnershipListener { + public void ownershipChanged(final boolean isOwner); +} diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XAtom.java --- a/jdk/src/solaris/classes/sun/awt/X11/XAtom.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XAtom.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2008 Sun Microsystems, Inc. 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 @@ -58,7 +58,7 @@ import sun.misc.Unsafe; import java.util.HashMap; -public class XAtom { +public final class XAtom { // Order of lock: XAWTLock -> XAtom.class @@ -175,7 +175,7 @@ public static XAtom get(String name) { XAtom xatom = lookup(name); if (xatom == null) { - xatom = new XAtom(name); + xatom = new XAtom(XToolkit.getDisplay(), name); } return xatom; } @@ -232,10 +232,6 @@ this(display, name, true); } - private XAtom(String name) { - this(XToolkit.getDisplay(), name, true); - } - public XAtom(String name, boolean autoIntern) { this(XToolkit.getDisplay(), name, autoIntern); } @@ -262,7 +258,7 @@ * @since 1.5 */ - public XAtom(long display, String name, boolean autoIntern) { + private XAtom(long display, String name, boolean autoIntern) { this.name = name; this.display = display; if (autoIntern) { @@ -651,28 +647,6 @@ } } - /** - * Initializes atom with name and display values - */ - public void setValues(long display, String name, boolean autoIntern) { - this.display = display; - this.name = name; - if (autoIntern) { - XToolkit.awtLock(); - try { - atom = XlibWrapper.InternAtom(display,name,0); - } finally { - XToolkit.awtUnlock(); - } - } - register(); - } - - public void setValues(long display, long atom) { - this.display = display; - this.atom = atom; - register(); - } public void setValues(long display, String name, long atom) { this.display = display; this.atom = atom; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XClipboard.java --- a/jdk/src/solaris/classes/sun/awt/X11/XClipboard.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XClipboard.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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 @@ -26,30 +26,32 @@ package sun.awt.X11; import java.awt.datatransfer.Transferable; - import java.util.SortedMap; -import java.util.Set; -import java.util.Iterator; -import java.util.HashSet; - import java.io.IOException; - import java.security.AccessController; - +import java.util.HashMap; +import java.util.Map; +import sun.awt.UNIXToolkit; import sun.awt.datatransfer.DataTransferer; import sun.awt.datatransfer.SunClipboard; import sun.awt.datatransfer.ClipboardTransferable; - import sun.security.action.GetIntegerAction; - - /** * A class which interfaces with the X11 selection service in order to support * data transfer via Clipboard operations. */ -public class XClipboard extends SunClipboard implements Runnable { +public final class XClipboard extends SunClipboard implements OwnershipListener +{ private final XSelection selection; + // Time of calling XConvertSelection(). + private long convertSelectionTime; + // The flag used not to call XConvertSelection() if the previous SelectionNotify + // has not been processed by checkChange(). + private volatile boolean isSelectionNotifyProcessed; + // The property in which the owner should place requested targets + // when tracking changes of available data flavors (practically targets). + private volatile XAtom targetsPropertyAtom; private static final Object classLock = new Object(); @@ -57,31 +59,33 @@ private static int pollInterval; - private static Set listenedClipboards; - + private static Map targetsAtom2Clipboard; /** * Creates a system clipboard object. */ public XClipboard(String name, String selectionName) { super(name); - selection = new XSelection(XAtom.get(selectionName), this); + selection = new XSelection(XAtom.get(selectionName)); + selection.registerOwershipListener(this); } - /** - * The action to be run when we lose ownership + /* * NOTE: This method may be called by privileged threads. * DO NOT INVOKE CLIENT CODE ON THIS THREAD! */ - public void run() { - lostOwnershipImpl(); + public void ownershipChanged(final boolean isOwner) { + if (isOwner) { + checkChangeHere(contents); + } else { + lostOwnershipImpl(); + } } protected synchronized void setContentsNative(Transferable contents) { SortedMap formatMap = DataTransferer.getInstance().getFormatsForTransferable (contents, DataTransferer.adaptFlavorMap(flavorMap)); - long[] formats = - DataTransferer.getInstance().keysToLongArray(formatMap); + long[] formats = DataTransferer.keysToLongArray(formatMap); if (!selection.setOwner(contents, formatMap, formats, XToolkit.getCurrentServerTime())) { @@ -94,6 +98,7 @@ return selection.getSelectionAtom().getAtom(); } + @Override public synchronized Transferable getContents(Object requestor) { if (contents != null) { return contents; @@ -115,62 +120,163 @@ return selection.getData(format, XToolkit.getCurrentServerTime()); } - // Called on the toolkit thread under awtLock. - public void checkChange(long[] formats) { - if (!selection.isOwner()) { - super.checkChange(formats); - } - } - - void checkChangeHere(Transferable contents) { + private void checkChangeHere(Transferable contents) { if (areFlavorListenersRegistered()) { - super.checkChange(DataTransferer.getInstance(). + checkChange(DataTransferer.getInstance(). getFormatsForTransferableAsArray(contents, flavorMap)); } } + private static int getPollInterval() { + synchronized (XClipboard.classLock) { + if (pollInterval <= 0) { + pollInterval = AccessController.doPrivileged( + new GetIntegerAction("awt.datatransfer.clipboard.poll.interval", + defaultPollInterval)); + if (pollInterval <= 0) { + pollInterval = defaultPollInterval; + } + } + return pollInterval; + } + } + + private XAtom getTargetsPropertyAtom() { + if (null == targetsPropertyAtom) { + targetsPropertyAtom = + XAtom.get("XAWT_TARGETS_OF_SELECTION:" + selection.getSelectionAtom().getName()); + } + return targetsPropertyAtom; + } + protected void registerClipboardViewerChecked() { - if (pollInterval <= 0) { - pollInterval = ((Integer)AccessController.doPrivileged( - new GetIntegerAction("awt.datatransfer.clipboard.poll.interval", - defaultPollInterval))).intValue(); - if (pollInterval <= 0) { - pollInterval = defaultPollInterval; + // for XConvertSelection() to be called for the first time in getTargetsDelayed() + isSelectionNotifyProcessed = true; + + boolean mustSchedule = false; + synchronized (XClipboard.classLock) { + if (targetsAtom2Clipboard == null) { + targetsAtom2Clipboard = new HashMap(2); + } + mustSchedule = targetsAtom2Clipboard.isEmpty(); + targetsAtom2Clipboard.put(getTargetsPropertyAtom().getAtom(), this); + if (mustSchedule) { + XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), + new SelectionNotifyHandler()); } } - selection.initializeSelectionForTrackingChanges(); - boolean mustSchedule = false; - synchronized (XClipboard.classLock) { - if (listenedClipboards == null) { - listenedClipboards = new HashSet(2); - } - mustSchedule = listenedClipboards.isEmpty(); - listenedClipboards.add(this); - } if (mustSchedule) { - XToolkit.schedule(new CheckChangeTimerTask(), pollInterval); + XToolkit.schedule(new CheckChangeTimerTask(), XClipboard.getPollInterval()); } } private static class CheckChangeTimerTask implements Runnable { public void run() { - for (Iterator iter = listenedClipboards.iterator(); iter.hasNext();) { - XClipboard clpbrd = (XClipboard)iter.next(); - clpbrd.selection.getTargetsDelayed(); + for (XClipboard clpbrd : targetsAtom2Clipboard.values()) { + clpbrd.getTargetsDelayed(); } synchronized (XClipboard.classLock) { - if (listenedClipboards != null && !listenedClipboards.isEmpty()) { - XToolkit.schedule(this, pollInterval); + if (targetsAtom2Clipboard != null && !targetsAtom2Clipboard.isEmpty()) { + XToolkit.schedule(this, XClipboard.getPollInterval()); + } + } + } + } + + private static class SelectionNotifyHandler implements XEventDispatcher { + public void dispatchEvent(XEvent ev) { + if (ev.get_type() == XlibWrapper.SelectionNotify) { + final XSelectionEvent xse = ev.get_xselection(); + XClipboard clipboard = null; + synchronized (XClipboard.classLock) { + if (targetsAtom2Clipboard != null && !targetsAtom2Clipboard.isEmpty()) { + XToolkit.removeEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), this); + return; + } + final long propertyAtom = xse.get_property(); + clipboard = targetsAtom2Clipboard.get(propertyAtom); + } + if (null != clipboard) { + clipboard.checkChange(xse); } } } } protected void unregisterClipboardViewerChecked() { - selection.deinitializeSelectionForTrackingChanges(); + isSelectionNotifyProcessed = false; synchronized (XClipboard.classLock) { - listenedClipboards.remove(this); + targetsAtom2Clipboard.remove(getTargetsPropertyAtom().getAtom()); + } + } + + // checkChange() will be called on SelectionNotify + private void getTargetsDelayed() { + XToolkit.awtLock(); + try { + long curTime = System.currentTimeMillis(); + if (isSelectionNotifyProcessed || curTime >= (convertSelectionTime + UNIXToolkit.getDatatransferTimeout())) + { + convertSelectionTime = curTime; + XlibWrapper.XConvertSelection(XToolkit.getDisplay(), + selection.getSelectionAtom().getAtom(), + XDataTransferer.TARGETS_ATOM.getAtom(), + getTargetsPropertyAtom().getAtom(), + XWindow.getXAWTRootWindow().getWindow(), + XlibWrapper.CurrentTime); + isSelectionNotifyProcessed = false; + } + } finally { + XToolkit.awtUnlock(); } } + /* + * Tracks changes of available formats. + * NOTE: This method may be called by privileged threads. + * DO NOT INVOKE CLIENT CODE ON THIS THREAD! + */ + private void checkChange(XSelectionEvent xse) { + final long propertyAtom = xse.get_property(); + if (propertyAtom != getTargetsPropertyAtom().getAtom()) { + // wrong atom + return; + } + + final XAtom selectionAtom = XAtom.get(xse.get_selection()); + final XSelection changedSelection = XSelection.getSelection(selectionAtom); + + if (null == changedSelection || changedSelection != selection) { + // unknown selection - do nothing + return; + } + + isSelectionNotifyProcessed = true; + + if (selection.isOwner()) { + // selection is owner - do not need formats + return; + } + + long[] formats = null; + + if (propertyAtom == XlibWrapper.None) { + // We treat None property atom as "empty selection". + formats = new long[0]; + } else { + WindowPropertyGetter targetsGetter = + new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(), + XAtom.get(propertyAtom), 0, + XSelection.MAX_LENGTH, true, + XlibWrapper.AnyPropertyType); + try { + targetsGetter.execute(); + formats = XSelection.getFormats(targetsGetter); + } finally { + targetsGetter.dispose(); + } + } + + checkChange(formats); + } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2008 Sun Microsystems, Inc. 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,17 +31,13 @@ import java.awt.Component; import java.awt.Container; import java.awt.Cursor; -import java.awt.DefaultKeyboardFocusManager; import java.awt.Dimension; -import java.awt.Event; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Image; import java.awt.Insets; import java.awt.KeyboardFocusManager; -import java.awt.MenuBar; -import java.awt.Point; import java.awt.Rectangle; import java.awt.SystemColor; import java.awt.Toolkit; @@ -60,12 +56,9 @@ import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; import java.awt.image.VolatileImage; -import java.awt.peer.CanvasPeer; import java.awt.peer.ComponentPeer; import java.awt.peer.ContainerPeer; import java.awt.peer.LightweightPeer; -import java.awt.peer.PanelPeer; -import java.awt.peer.WindowPeer; import java.lang.reflect.*; import java.security.*; import java.util.Collection; @@ -821,7 +814,7 @@ public void setFont(Font f) { synchronized (getStateLock()) { if (f == null) { - f = defaultFont; + f = XWindow.getDefaultFont(); } font = f; } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XContentWindow.java --- a/jdk/src/solaris/classes/sun/awt/X11/XContentWindow.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XContentWindow.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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 @@ -39,16 +39,37 @@ * This class implements window which serves as content window for decorated frames. * Its purpose to provide correct events dispatching for the complex * constructs such as decorated frames. + * + * It should always be located at (- left inset, - top inset) in the associated + * decorated window. So coordinates in it would be the same as java coordinates. */ -public class XContentWindow extends XWindow implements XConstants { +public final class XContentWindow extends XWindow implements XConstants { private static Logger insLog = Logger.getLogger("sun.awt.X11.insets.XContentWindow"); - XDecoratedPeer parentFrame; + static XContentWindow createContent(XDecoratedPeer parentFrame) { + final WindowDimensions dims = parentFrame.getDimensions(); + Rectangle rec = dims.getBounds(); + // Fix for - set the location of the content window to the (-left inset, -top inset) + Insets ins = dims.getInsets(); + if (ins != null) { + rec.x = -ins.left; + rec.y = -ins.top; + } else { + rec.x = 0; + rec.y = 0; + } + final XContentWindow cw = new XContentWindow(parentFrame, rec); + cw.xSetVisible(true); + return cw; + } + + private final XDecoratedPeer parentFrame; // A list of expose events that come when the parentFrame is iconified - private java.util.List iconifiedExposeEvents = new java.util.ArrayList(); + private final java.util.List iconifiedExposeEvents = + new java.util.ArrayList(); - XContentWindow(XDecoratedPeer parentFrame, Rectangle bounds) { + private XContentWindow(XDecoratedPeer parentFrame, Rectangle bounds) { super((Component)parentFrame.getTarget(), parentFrame.getShell(), bounds); this.parentFrame = parentFrame; } @@ -63,9 +84,6 @@ } } - void initialize() { - xSetVisible(true); - } protected String getWMName() { return "Content window"; } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -36,7 +36,7 @@ import sun.awt.ComponentAccessor; import sun.awt.SunToolkit; -class XDecoratedPeer extends XWindowPeer { +abstract class XDecoratedPeer extends XWindowPeer { private static final Logger log = Logger.getLogger("sun.awt.X11.XDecoratedPeer"); private static final Logger insLog = Logger.getLogger("sun.awt.X11.insets.XDecoratedPeer"); private static final Logger focusLog = Logger.getLogger("sun.awt.X11.focus.XDecoratedPeer"); @@ -98,8 +98,7 @@ // happen after the X window is created. initResizability(); updateSizeHints(dimensions); - content = createContent(dimensions); - content.initialize(); + content = XContentWindow.createContent(this); if (warningWindow != null) { warningWindow.toFront(); } @@ -160,20 +159,6 @@ } } - XContentWindow createContent(WindowDimensions dims) { - Rectangle rec = dims.getBounds(); - // Fix for - set the location of the content window to the (-left inset, -top inset) - Insets ins = dims.getInsets(); - if (ins != null) { - rec.x = -ins.left; - rec.y = -ins.top; - } else { - rec.x = 0; - rec.y = 0; - } - return new XContentWindow(this, rec); - } - XFocusProxyWindow createFocusProxy() { return new XFocusProxyWindow(this); } @@ -286,7 +271,7 @@ return; } Component t = (Component)target; - if (getDecorations() == winAttr.AWT_DECOR_NONE) { + if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) { setReparented(true); insets_corrected = true; reshape(dimensions, SET_SIZE, false); @@ -471,6 +456,15 @@ if (insLog.isLoggable(Level.FINE)) { insLog.fine("Reshaping " + this + " to " + newDimensions + " op " + op + " user reshape " + userReshape); } + if (userReshape) { + // We handle only userReshape == true cases. It means that + // if the window manager or any other part of the windowing + // system sets inappropriate size for this window, we can + // do nothing but accept it. + Rectangle reqBounds = newDimensions.getBounds(); + Rectangle newBounds = constrainBounds(reqBounds.x, reqBounds.y, reqBounds.width, reqBounds.height); + newDimensions = new WindowDimensions(newBounds, newDimensions.getInsets(), newDimensions.isClientSizeSet()); + } XToolkit.awtLock(); try { if (!isReparented() || !isVisible()) { @@ -586,6 +580,49 @@ reshape(dims, operation, userReshape); } + // This method gets overriden in XFramePeer & XDialogPeer. + abstract boolean isTargetUndecorated(); + + @Override + Rectangle constrainBounds(int x, int y, int width, int height) { + // We don't restrict the setBounds() operation if the code is trusted. + if (!hasWarningWindow()) { + return new Rectangle(x, y, width, height); + } + + // If it's undecorated or is not currently visible, + // apply the same constraints as for the Window. + if (!isVisible() || isTargetUndecorated()) { + return super.constrainBounds(x, y, width, height); + } + + // If it's visible & decorated, constraint the size only + int newX = x; + int newY = y; + int newW = width; + int newH = height; + + GraphicsConfiguration gc = ((Window)target).getGraphicsConfiguration(); + Rectangle sB = gc.getBounds(); + Insets sIn = ((Window)target).getToolkit().getScreenInsets(gc); + + Rectangle curBounds = getBounds(); + + int maxW = Math.max(sB.width - sIn.left - sIn.right, curBounds.width); + int maxH = Math.max(sB.height - sIn.top - sIn.bottom, curBounds.height); + + // First make sure the size is withing the visible part of the screen + if (newW > maxW) { + newW = maxW; + } + + if (newH > maxH) { + newH = maxH; + } + + return new Rectangle(newX, newY, newW, newH); + } + /** * @see java.awt.peer.ComponentPeer#setBounds */ @@ -651,12 +688,12 @@ } if (!isReparented() && isVisible() && runningWM != XWM.NO_WM && !XWM.isNonReparentingWM() - && getDecorations() != winAttr.AWT_DECOR_NONE) { + && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { insLog.fine("- visible but not reparented, skipping"); return; } //Last chance to correct insets - if (!insets_corrected && getDecorations() != winAttr.AWT_DECOR_NONE) { + if (!insets_corrected && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { long parent = XlibUtil.getParentWindow(window); Insets correctWM = (parent != -1) ? XWM.getWM().getInsets(this, window, parent) : null; if (insLog.isLoggable(Level.FINER)) { @@ -824,7 +861,7 @@ fs &= ~(MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE); } winAttr.functions = fs; - XWM.setShellNotResizable(this, dimensions, dimensions.getScreenBounds(), false); + XWM.setShellNotResizable(this, dimensions, dimensions.getBounds(), false); } } @@ -870,7 +907,7 @@ return getSize().height; } - public WindowDimensions getDimensions() { + final public WindowDimensions getDimensions() { return dimensions; } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XDialogPeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XDialogPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XDialogPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -88,7 +88,8 @@ } } - private boolean isTargetUndecorated() { + @Override + boolean isTargetUndecorated() { if (undecorated != null) { return undecorated.booleanValue(); } else { diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XDnDConstants.java --- a/jdk/src/solaris/classes/sun/awt/X11/XDnDConstants.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XDnDConstants.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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 @@ -48,8 +48,7 @@ static final XAtom XA_XdndStatus = XAtom.get("XdndStatus"); static final XAtom XA_XdndFinished = XAtom.get("XdndFinished"); - static final XSelection XDnDSelection = - new XSelection(XA_XdndSelection, null); + static final XSelection XDnDSelection = new XSelection(XA_XdndSelection); public static final int XDND_MIN_PROTOCOL_VERSION = 3; public static final int XDND_PROTOCOL_VERSION = 5; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XEmbedCanvasPeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XEmbedCanvasPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbedCanvasPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -647,12 +647,6 @@ } if (isXEmbedActive()) { switch ((int)msg.get_data(1)) { - case _SUN_XEMBED_START: - // Child has finished initialization and waits for notify - xembed.processXEmbedInfo(); - - notifyChildEmbedded(); - break; case XEMBED_REQUEST_FOCUS: requestXEmbedFocus(); break; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XEmbedClientHelper.java --- a/jdk/src/solaris/classes/sun/awt/X11/XEmbedClientHelper.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbedClientHelper.java Mon Mar 24 06:33:16 2008 -0700 @@ -74,7 +74,6 @@ XToolkit.awtUnlock(); } } - notifyReady(); } void handleClientMessage(XEvent xev) { @@ -84,7 +83,6 @@ if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Embedded message: " + msgidToString((int)msg.get_data(1))); switch ((int)msg.get_data(1)) { case XEMBED_EMBEDDED_NOTIFY: // Notification about embedding protocol start - // NOTE: May be called two times because we send _SUN_XEMBED_START active = true; server = getEmbedder(embedded, msg); // Check if window is reparented. If not - it was created with @@ -223,13 +221,4 @@ long getX11Mods(AWTKeyStroke stroke) { return XWindow.getXModifiers(stroke); } - - void notifyReady() { - long wnd = server; - if (wnd == 0) { - // Server is still 0, get the parent - wnd = embedded.getParentWindowHandle(); - } - sendMessage(wnd, _SUN_XEMBED_START); - } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XEmbedHelper.java --- a/jdk/src/solaris/classes/sun/awt/X11/XEmbedHelper.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbedHelper.java Mon Mar 24 06:33:16 2008 -0700 @@ -58,7 +58,6 @@ final static int XEMBED_REGISTER_ACCELERATOR = 12; final static int XEMBED_UNREGISTER_ACCELERATOR= 13; final static int XEMBED_ACTIVATE_ACCELERATOR = 14; - final static int _SUN_XEMBED_START = 1119; final static int NON_STANDARD_XEMBED_GTK_GRAB_KEY = 108; final static int NON_STANDARD_XEMBED_GTK_UNGRAB_KEY = 109; @@ -151,8 +150,6 @@ return "NON_STANDARD_XEMBED_GTK_UNGRAB_KEY"; case NON_STANDARD_XEMBED_GTK_GRAB_KEY: return "NON_STANDARD_XEMBED_GTK_GRAB_KEY"; - case _SUN_XEMBED_START: - return "XEMBED_START"; case XConstants.KeyPress | XEmbedServerTester.SYSTEM_EVENT_MASK: return "KeyPress"; case XConstants.MapNotify | XEmbedServerTester.SYSTEM_EVENT_MASK: diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XEmbedServerTester.java --- a/jdk/src/solaris/classes/sun/awt/X11/XEmbedServerTester.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbedServerTester.java Mon Mar 24 06:33:16 2008 -0700 @@ -177,13 +177,6 @@ embedCompletely(); } - public void test3_2() { - embedCompletely(); - int res = getEventPos(); - sendMessage(XEmbedHelper._SUN_XEMBED_START); - waitEmbeddedNotify(res); - } - public void test3_3() { reparent = true; embedCompletely(); diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFramePeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFramePeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFramePeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -184,6 +184,12 @@ } } + @Override + Rectangle constrainBounds(int x, int y, int width, int height) { + // We don't constrain the bounds of the EmbeddedFrames + return new Rectangle(x, y, width, height); + } + // don't use getBounds() inherited from XDecoratedPeer public Rectangle getBounds() { return new Rectangle(x, y, width, height); diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XFramePeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XFramePeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XFramePeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2008 Sun Microsystems, Inc. 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 @@ -24,15 +24,18 @@ */ package sun.awt.X11; -import java.util.Vector; -import java.awt.*; -import java.awt.peer.*; -import java.awt.event.*; -import sun.awt.im.*; -import sun.awt.*; -import java.util.logging.*; -import java.lang.reflect.Field; -import java.util.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.MenuBar; +import java.awt.Rectangle; +import java.awt.peer.FramePeer; +import java.util.logging.Level; +import java.util.logging.Logger; class XFramePeer extends XDecoratedPeer implements FramePeer, XConstants { private static Logger log = Logger.getLogger("sun.awt.X11.XFramePeer"); @@ -92,7 +95,8 @@ } } - private boolean isTargetUndecorated() { + @Override + boolean isTargetUndecorated() { if (undecorated != null) { return undecorated.booleanValue(); } else { @@ -285,19 +289,20 @@ * Let's see if this is a window state protocol message, and * if it is - decode a new state in terms of java constants. */ - Integer newState = XWM.getWM().isStateChange(this, ev); - if (newState == null) { + if (!XWM.getWM().isStateChange(this, ev)) { + stateLog.finer("either not a state atom or state has not been changed"); return; } - int changed = state ^ newState.intValue(); + final int newState = XWM.getWM().getState(this); + int changed = state ^ newState; if (changed == 0) { stateLog.finer("State is the same: " + state); return; } int old_state = state; - state = newState.intValue(); + state = newState; if ((changed & Frame.ICONIFIED) != 0) { if ((state & Frame.ICONIFIED) != 0) { diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XMenuItemPeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XMenuItemPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XMenuItemPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2008 Sun Microsystems, Inc. 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 @@ -218,7 +218,7 @@ Font getTargetFont() { if (target == null) { - return XWindow.defaultFont; + return XWindow.getDefaultFont(); } try { return (Font)m_getFont.invoke(target, new Object[0]); @@ -227,7 +227,7 @@ } catch (InvocationTargetException e) { e.printStackTrace(); } - return XWindow.defaultFont; + return XWindow.getDefaultFont(); } String getTargetLabel() { diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XNETProtocol.java --- a/jdk/src/solaris/classes/sun/awt/X11/XNETProtocol.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XNETProtocol.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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 @@ -26,17 +26,15 @@ package sun.awt.X11; -import java.awt.*; +import java.awt.Frame; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.logging.LogManager; -import java.awt.*; -import java.awt.image.*; -import java.util.*; -class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProtocol { - final static Logger log = Logger.getLogger("sun.awt.X11.XNETProtocol"); +final class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProtocol +{ + private final static Logger log = Logger.getLogger("sun.awt.X11.XNETProtocol"); private final static Logger iconLog = Logger.getLogger("sun.awt.X11.icon.XNETProtocol"); + private static Logger stateLog = Logger.getLogger("sun.awt.X11.states.XNETProtocol"); /** * XStateProtocol @@ -276,6 +274,7 @@ boolean doStateProtocol() { boolean res = active() && checkProtocol(XA_NET_SUPPORTED, XA_NET_WM_STATE); + stateLog.finer("doStateProtocol() returns " + res); return res; } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XPopupMenuPeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XPopupMenuPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XPopupMenuPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2008 Sun Microsystems, Inc. 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 @@ -187,7 +187,7 @@ //Fix for 6267144: PIT: Popup menu label is not shown, XToolkit Font getTargetFont() { if (popupMenuTarget == null) { - return XWindow.defaultFont; + return XWindow.getDefaultFont(); } try { return (Font)m_getFont.invoke(popupMenuTarget, new Object[0]); @@ -196,7 +196,7 @@ } catch (InvocationTargetException e) { e.printStackTrace(); } - return XWindow.defaultFont; + return XWindow.getDefaultFont(); } String getTargetLabel() { diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XSelection.java --- a/jdk/src/solaris/classes/sun/awt/X11/XSelection.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XSelection.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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 @@ -32,9 +32,6 @@ import java.util.Hashtable; import java.util.Map; -import java.util.Set; -import java.util.HashSet; -import java.util.Collections; import sun.awt.AppContext; import sun.awt.SunToolkit; @@ -45,7 +42,7 @@ /** * A class which interfaces with the X11 selection service. */ -public class XSelection { +public final class XSelection { /* Maps atoms to XSelection instances. */ private static final Hashtable table = new Hashtable(); @@ -69,8 +66,6 @@ XToolkit.awtUnlock(); } } - /* The selection timeout. */ - private static long SELECTION_TIMEOUT = UNIXToolkit.getDatatransferTimeout(); /* The PropertyNotify event handler for incremental data transfer. */ private static final XEventDispatcher incrementalTransferHandler = @@ -84,11 +79,6 @@ /* The X atom for the underlying selection. */ private final XAtom selectionAtom; - /* - * XClipboard.run() is to be called when we lose ownership. - * XClipbioard.checkChange() is to be called when tracking changes of flavors. - */ - private final XClipboard clipboard; /* * Owner-related variables - protected with synchronized (this). @@ -109,17 +99,8 @@ private long ownershipTime = 0; // True if we are the owner of this selection. private boolean isOwner; - // The property in which the owner should place requested targets - // when tracking changes of available data flavors (practically targets). - private volatile XAtom targetsPropertyAtom; - // A set of these property atoms. - private static volatile Set targetsPropertyAtoms; - // The flag used not to call XConvertSelection() if the previous SelectionNotify - // has not been processed by checkChange(). - private volatile boolean isSelectionNotifyProcessed; - // Time of calling XConvertSelection(). - private long convertSelectionTime; - + private OwnershipListener ownershipListener = null; + private final Object stateLock = new Object(); static { XToolkit.addEventDispatcher(XWindow.getXAWTRootWindow().getWindow(), @@ -141,12 +122,11 @@ * @param clpbrd the corresponding clipoboard * @exception NullPointerException if atom is null. */ - public XSelection(XAtom atom, XClipboard clpbrd) { + public XSelection(XAtom atom) { if (atom == null) { throw new NullPointerException("Null atom"); } selectionAtom = atom; - clipboard = clpbrd; table.put(selectionAtom, this); } @@ -154,25 +134,9 @@ return selectionAtom; } - void initializeSelectionForTrackingChanges() { - targetsPropertyAtom = XAtom.get("XAWT_TARGETS_OF_SELECTION:" + selectionAtom.getName()); - if (targetsPropertyAtoms == null) { - targetsPropertyAtoms = Collections.synchronizedSet(new HashSet(2)); - } - targetsPropertyAtoms.add(Long.valueOf(targetsPropertyAtom.getAtom())); - // for XConvertSelection() to be called for the first time in getTargetsDelayed() - isSelectionNotifyProcessed = true; - } - - void deinitializeSelectionForTrackingChanges() { - if (targetsPropertyAtoms != null && targetsPropertyAtom != null) { - targetsPropertyAtoms.remove(Long.valueOf(targetsPropertyAtom.getAtom())); - } - isSelectionNotifyProcessed = false; - } - public synchronized boolean setOwner(Transferable contents, Map formatMap, - long[] formats, long time) { + long[] formats, long time) + { long owner = XWindow.getXAWTRootWindow().getWindow(); long selection = selectionAtom.getAtom(); @@ -192,15 +156,12 @@ XlibWrapper.XSetSelectionOwner(XToolkit.getDisplay(), selection, owner, time); if (XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(), - selection) != owner) { - + selection) != owner) + { reset(); return false; } - isOwner = true; - if (clipboard != null) { - clipboard.checkChangeHere(contents); - } + setOwnerProp(true); return true; } finally { XToolkit.awtUnlock(); @@ -217,7 +178,7 @@ do { DataTransferer.getInstance().processDataConversionRequests(); XToolkit.awtLockWait(250); - } while (propertyGetter == dataGetter && System.currentTimeMillis() < startTime + SELECTION_TIMEOUT); + } while (propertyGetter == dataGetter && System.currentTimeMillis() < startTime + UNIXToolkit.getDatatransferTimeout()); } finally { XToolkit.awtUnlock(); } @@ -232,11 +193,9 @@ throw new Error("UNIMPLEMENTED"); } - long[] formats = null; + long[] targets = null; synchronized (lock) { - SELECTION_TIMEOUT = UNIXToolkit.getDatatransferTimeout(); - WindowPropertyGetter targetsGetter = new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(), selectionPropertyAtom, 0, MAX_LENGTH, @@ -267,23 +226,25 @@ } finally { XToolkit.awtUnlock(); } - formats = getFormats(targetsGetter); + targets = getFormats(targetsGetter); } finally { targetsGetter.dispose(); } } - return formats; + return targets; } - private static long[] getFormats(WindowPropertyGetter targetsGetter) { + static long[] getFormats(WindowPropertyGetter targetsGetter) { long[] formats = null; if (targetsGetter.isExecuted() && !targetsGetter.isDisposed() && (targetsGetter.getActualType() == XAtom.XA_ATOM || targetsGetter.getActualType() == XDataTransferer.TARGETS_ATOM.getAtom()) && - targetsGetter.getActualFormat() == 32) { - - int count = (int)targetsGetter.getNumberOfItems(); + targetsGetter.getActualFormat() == 32) + { + // we accept property with TARGETS type to be compatible with old jdks + // see 6607163 + int count = targetsGetter.getNumberOfItems(); if (count > 0) { long atoms = targetsGetter.getData(); formats = new long[count]; @@ -297,26 +258,6 @@ return formats != null ? formats : new long[0]; } - // checkChange() will be called on SelectionNotify - void getTargetsDelayed() { - XToolkit.awtLock(); - try { - long curTime = System.currentTimeMillis(); - if (isSelectionNotifyProcessed || curTime >= convertSelectionTime + SELECTION_TIMEOUT) { - convertSelectionTime = curTime; - XlibWrapper.XConvertSelection(XToolkit.getDisplay(), - getSelectionAtom().getAtom(), - XDataTransferer.TARGETS_ATOM.getAtom(), - targetsPropertyAtom.getAtom(), - XWindow.getXAWTRootWindow().getWindow(), - XlibWrapper.CurrentTime); - isSelectionNotifyProcessed = false; - } - } finally { - XToolkit.awtUnlock(); - } - } - /* * Requests the selection data in the specified format and returns * the data provided by the owner. @@ -329,8 +270,6 @@ byte[] data = null; synchronized (lock) { - SELECTION_TIMEOUT = UNIXToolkit.getDatatransferTimeout(); - WindowPropertyGetter dataGetter = new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(), selectionPropertyAtom, 0, MAX_LENGTH, @@ -379,7 +318,7 @@ dataGetter.getActualFormat()); } - int count = (int)dataGetter.getNumberOfItems(); + int count = dataGetter.getNumberOfItems(); if (count <= 0) { throw new IOException("INCR data is missed."); @@ -455,7 +394,7 @@ incrDataGetter.getActualFormat()); } - count = (int)incrDataGetter.getNumberOfItems(); + count = incrDataGetter.getNumberOfItems(); if (count == 0) { break; @@ -489,7 +428,7 @@ dataGetter.getActualFormat()); } - int count = (int)dataGetter.getNumberOfItems(); + int count = dataGetter.getNumberOfItems(); if (count > 0) { data = new byte[count]; long ptr = dataGetter.getData(); @@ -511,11 +450,14 @@ return isOwner; } - public void lostOwnership() { - isOwner = false; - if (clipboard != null) { - clipboard.run(); - } + // To be MT-safe this method should be called under awtLock. + private void setOwnerProp(boolean f) { + isOwner = f; + fireOwnershipChanges(isOwner); + } + + private void lostOwnership() { + setOwnerProp(false); } public synchronized void reset() { @@ -595,125 +537,39 @@ private void handleSelectionRequest(XSelectionRequestEvent xsre) { long property = xsre.get_property(); - long requestor = xsre.get_requestor(); - long requestTime = xsre.get_time(); - long format = xsre.get_target(); - int dataFormat = 0; + final long requestor = xsre.get_requestor(); + final long requestTime = xsre.get_time(); + final long format = xsre.get_target(); boolean conversionSucceeded = false; if (ownershipTime != 0 && - (requestTime == XlibWrapper.CurrentTime || - requestTime >= ownershipTime)) { - - property = xsre.get_property(); - + (requestTime == XlibWrapper.CurrentTime || requestTime >= ownershipTime)) + { // Handle MULTIPLE requests as per ICCCM. if (format == XDataTransferer.MULTIPLE_ATOM.getAtom()) { - // The property cannot be 0 for a MULTIPLE request. - if (property != 0) { - // First retrieve the list of requested targets. - WindowPropertyGetter wpg = - new WindowPropertyGetter(requestor, XAtom.get(property), 0, - MAX_LENGTH, false, - XlibWrapper.AnyPropertyType); - try { - wpg.execute(); - - if (wpg.getActualFormat() == 32 && - (wpg.getNumberOfItems() % 2) == 0) { - long count = wpg.getNumberOfItems() / 2; - long pairsPtr = wpg.getData(); - boolean writeBack = false; - for (int i = 0; i < count; i++) { - long target = Native.getLong(pairsPtr, 2*i); - long prop = Native.getLong(pairsPtr, 2*i + 1); - - if (!convertAndStore(requestor, target, prop)) { - // To report failure, we should replace the - // target atom with 0 in the MULTIPLE property. - Native.putLong(pairsPtr, 2*i, 0); - writeBack = true; - } - } - if (writeBack) { - XToolkit.awtLock(); - try { - XlibWrapper.XChangeProperty(XToolkit.getDisplay(), requestor, - property, - wpg.getActualType(), - wpg.getActualFormat(), - XlibWrapper.PropModeReplace, - wpg.getData(), - wpg.getNumberOfItems()); - } finally { - XToolkit.awtUnlock(); - } - } - conversionSucceeded = true; - } - } finally { - wpg.dispose(); - } - } + conversionSucceeded = handleMultipleRequest(requestor, property); } else { - // Support for obsolete clients as per ICCCM. - if (property == 0) { + if (property == XlibWrapper.None) { property = format; } if (format == XDataTransferer.TARGETS_ATOM.getAtom()) { - long nativeDataPtr = 0; - int count = 0; - dataFormat = 32; - - // Use a local copy to avoid synchronization. - long[] formatsLocal = formats; - - if (formatsLocal == null) { - throw new IllegalStateException("Not an owner."); - } - - count = formatsLocal.length; - - try { - if (count > 0) { - nativeDataPtr = Native.allocateLongArray(count); - Native.put(nativeDataPtr, formatsLocal); - } - - conversionSucceeded = true; - - XToolkit.awtLock(); - try { - XlibWrapper.XChangeProperty(XToolkit.getDisplay(), requestor, - property, format, dataFormat, - XlibWrapper.PropModeReplace, - nativeDataPtr, count); - } finally { - XToolkit.awtUnlock(); - } - } finally { - if (nativeDataPtr != 0) { - XlibWrapper.unsafe.freeMemory(nativeDataPtr); - nativeDataPtr = 0; - } - } + conversionSucceeded = handleTargetsRequest(property, requestor); } else { - conversionSucceeded = convertAndStore(requestor, format, - property); + conversionSucceeded = convertAndStore(requestor, format, property); } } } if (!conversionSucceeded) { - // Zero property indicates conversion failure. - property = 0; + // None property indicates conversion failure. + property = XlibWrapper.None; } XSelectionEvent xse = new XSelectionEvent(); try { - xse.set_type((int)XlibWrapper.SelectionNotify); + xse.set_type(XlibWrapper.SelectionNotify); xse.set_send_event(true); xse.set_requestor(requestor); xse.set_selection(selectionAtom.getAtom()); @@ -733,40 +589,123 @@ } } - private static void checkChange(XSelectionEvent xse) { - if (targetsPropertyAtoms == null || targetsPropertyAtoms.isEmpty()) { - // We are not tracking changes. - return; + private boolean handleMultipleRequest(final long requestor, long property) { + if (XlibWrapper.None == property) { + // The property cannot be None for a MULTIPLE request. + return false; + } + + boolean conversionSucceeded = false; + + // First retrieve the list of requested targets. + WindowPropertyGetter wpg = + new WindowPropertyGetter(requestor, XAtom.get(property), + 0, MAX_LENGTH, false, + XlibWrapper.AnyPropertyType); + try { + wpg.execute(); + + if (wpg.getActualFormat() == 32 && (wpg.getNumberOfItems() % 2) == 0) { + final long count = wpg.getNumberOfItems() / 2; + final long pairsPtr = wpg.getData(); + boolean writeBack = false; + + for (int i = 0; i < count; i++) { + long target = Native.getLong(pairsPtr, 2 * i); + long prop = Native.getLong(pairsPtr, 2 * i + 1); + + if (!convertAndStore(requestor, target, prop)) { + // To report failure, we should replace the + // target atom with 0 in the MULTIPLE property. + Native.putLong(pairsPtr, 2 * i, 0); + writeBack = true; + } + } + if (writeBack) { + XToolkit.awtLock(); + try { + XlibWrapper.XChangeProperty(XToolkit.getDisplay(), + requestor, + property, + wpg.getActualType(), + wpg.getActualFormat(), + XlibWrapper.PropModeReplace, + wpg.getData(), + wpg.getNumberOfItems()); + } finally { + XToolkit.awtUnlock(); + } + } + conversionSucceeded = true; + } + } finally { + wpg.dispose(); } - long propertyAtom = xse.get_property(); - long[] formats = null; + return conversionSucceeded; + } + + private boolean handleTargetsRequest(long property, long requestor) + throws IllegalStateException + { + boolean conversionSucceeded = false; + // Use a local copy to avoid synchronization. + long[] formatsLocal = formats; + + if (formatsLocal == null) { + throw new IllegalStateException("Not an owner."); + } + + long nativeDataPtr = 0; + + try { + final int count = formatsLocal.length; + final int dataFormat = 32; - if (propertyAtom == XlibWrapper.None) { - // We threat None property atom as "empty selection". - formats = new long[0]; - } else if (!targetsPropertyAtoms.contains(Long.valueOf(propertyAtom))) { - return; - } else { - WindowPropertyGetter targetsGetter = - new WindowPropertyGetter(XWindow.getXAWTRootWindow().getWindow(), - XAtom.get(propertyAtom), 0, MAX_LENGTH, - true, XlibWrapper.AnyPropertyType); + if (count > 0) { + nativeDataPtr = Native.allocateLongArray(count); + Native.put(nativeDataPtr, formatsLocal); + } + + conversionSucceeded = true; + + XToolkit.awtLock(); try { - targetsGetter.execute(); - formats = getFormats(targetsGetter); + XlibWrapper.XChangeProperty(XToolkit.getDisplay(), requestor, + property, XAtom.XA_ATOM, dataFormat, + XlibWrapper.PropModeReplace, + nativeDataPtr, count); } finally { - targetsGetter.dispose(); + XToolkit.awtUnlock(); + } + } finally { + if (nativeDataPtr != 0) { + XlibWrapper.unsafe.freeMemory(nativeDataPtr); + nativeDataPtr = 0; } } + return conversionSucceeded; + } - XAtom selectionAtom = XAtom.get(xse.get_selection()); - XSelection selection = getSelection(selectionAtom); - if (selection != null) { - selection.isSelectionNotifyProcessed = true; - if (selection.clipboard != null) { - selection.clipboard.checkChange(formats); - } + private void fireOwnershipChanges(final boolean isOwner) { + OwnershipListener l = null; + synchronized (stateLock) { + l = ownershipListener; + } + if (null != l) { + l.ownershipChanged(isOwner); + } + } + + void registerOwershipListener(OwnershipListener l) { + synchronized (stateLock) { + ownershipListener = l; + } + } + + void unregisterOwnershipListener() { + synchronized (stateLock) { + ownershipListener = null; } } @@ -774,10 +713,9 @@ public void dispatchEvent(XEvent ev) { switch (ev.get_type()) { case XlibWrapper.SelectionNotify: { - XSelectionEvent xse = ev.get_xselection(); - checkChange(xse); XToolkit.awtLock(); try { + XSelectionEvent xse = ev.get_xselection(); // Ignore the SelectionNotify event if it is not the response to our last request. if (propertyGetter != null && xse.get_time() == lastRequestServerTime) { // The property will be None in case of convertion failure. diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XToolkit.java --- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2008 Sun Microsystems, Inc. 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 @@ -25,11 +25,9 @@ package sun.awt.X11; import java.awt.*; -import java.awt.event.*; -import java.awt.peer.*; -import java.beans.PropertyChangeListener; -import sun.awt.*; -import java.util.*; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.datatransfer.Clipboard; import java.awt.dnd.DragSource; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragGestureEvent; @@ -37,20 +35,27 @@ import java.awt.dnd.MouseDragGestureRecognizer; import java.awt.dnd.InvalidDnDOperationException; import java.awt.dnd.peer.DragSourceContextPeer; -import java.awt.image.*; -import java.security.*; import java.awt.im.InputMethodHighlight; import java.awt.im.spi.InputMethodDescriptor; -import java.awt.datatransfer.Clipboard; +import java.awt.image.ColorModel; +import java.awt.peer.*; +import java.beans.PropertyChangeListener; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.LookAndFeel; import javax.swing.UIDefaults; -import java.util.logging.*; +import sun.awt.*; import sun.font.FontManager; import sun.misc.PerformanceLogger; import sun.print.PrintJob2D; -import java.lang.reflect.*; -public class XToolkit extends UNIXToolkit implements Runnable, XConstants { +public final class XToolkit extends UNIXToolkit implements Runnable, XConstants +{ private static Logger log = Logger.getLogger("sun.awt.X11.XToolkit"); private static Logger eventLog = Logger.getLogger("sun.awt.X11.event.XToolkit"); private static final Logger timeoutTaskLog = Logger.getLogger("sun.awt.X11.timeoutTask.XToolkit"); @@ -1871,9 +1876,7 @@ } public boolean isAlwaysOnTopSupported() { - Iterator iter = XWM.getWM().getProtocols(XLayerProtocol.class).iterator(); - while (iter.hasNext()) { - XLayerProtocol proto = (XLayerProtocol)iter.next(); + for (XLayerProtocol proto : XWM.getWM().getProtocols(XLayerProtocol.class)) { if (proto.supportsLayer(XLayerProtocol.LAYER_ALWAYS_ON_TOP)) { return true; } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XTrayIconPeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XTrayIconPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XTrayIconPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2008 Sun Microsystems, Inc. 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,11 +31,8 @@ import sun.awt.*; import java.awt.image.*; import java.text.BreakIterator; -import java.util.Vector; -import java.lang.reflect.Field; import java.util.logging.Logger; import java.util.logging.Level; -import java.util.AbstractQueue; import java.util.concurrent.ArrayBlockingQueue; import java.security.AccessController; import java.security.PrivilegedAction; @@ -629,7 +626,7 @@ final static int TOOLTIP_MAX_LENGTH = 64; final static int TOOLTIP_MOUSE_CURSOR_INDENT = 5; final static Color TOOLTIP_BACKGROUND_COLOR = new Color(255, 255, 220); - final static Font TOOLTIP_TEXT_FONT = XWindow.defaultFont; + final static Font TOOLTIP_TEXT_FONT = XWindow.getDefaultFont(); Tooltip(XTrayIconPeer xtiPeer, Frame parent) { super(parent, Color.black); diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XWM.java --- a/jdk/src/solaris/classes/sun/awt/X11/XWM.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XWM.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2008 Sun Microsystems, Inc. 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,20 +31,23 @@ package sun.awt.X11; import sun.misc.Unsafe; -import java.util.regex.*; +import java.awt.Insets; import java.awt.Frame; import java.awt.Rectangle; -import java.util.*; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; import java.util.logging.Level; -import java.util.logging.LogManager; import java.util.logging.Logger; -import java.awt.Insets; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Class incapsulating knowledge about window managers in general * Descendants should provide some information about specific window manager. */ -class XWM implements MWMConstants, XUtilConstants { +final class XWM implements MWMConstants, XUtilConstants +{ private final static Logger log = Logger.getLogger("sun.awt.X11.XWM"); private final static Logger insLog = Logger.getLogger("sun.awt.X11.insets.XWM"); @@ -1026,21 +1029,21 @@ /*****************************************************************************\ * Protocols support */ - HashMap, Collection> protocolsMap = new HashMap, Collection>(); + private HashMap, Collection> protocolsMap = new HashMap, Collection>(); /** * Returns all protocols supporting given protocol interface */ - Collection getProtocols(Class protocolInterface) { - Collection res = protocolsMap.get(protocolInterface); + Collection getProtocols(Class protocolInterface) { + Collection res = (Collection) protocolsMap.get(protocolInterface); if (res != null) { - return (Collection)res; + return res; } else { - return new LinkedList(); + return new LinkedList(); } } - void addProtocol(Class protocolInterface, XProtocol protocol) { - Collection protocols = getProtocols(protocolInterface); + private void addProtocol(Class protocolInterface, T protocol) { + Collection protocols = getProtocols(protocolInterface); protocols.add(protocol); protocolsMap.put(protocolInterface, protocols); } @@ -1085,9 +1088,7 @@ } /* FALLTROUGH */ case Frame.MAXIMIZED_BOTH: - Iterator iter = getProtocols(XStateProtocol.class).iterator(); - while (iter.hasNext()) { - XStateProtocol proto = (XStateProtocol)iter.next(); + for (XStateProtocol proto : getProtocols(XStateProtocol.class)) { if (proto.supportsState(state)) { return true; } @@ -1105,10 +1106,8 @@ int getExtendedState(XWindowPeer window) { - Iterator iter = getProtocols(XStateProtocol.class).iterator(); int state = 0; - while (iter.hasNext()) { - XStateProtocol proto = (XStateProtocol)iter.next(); + for (XStateProtocol proto : getProtocols(XStateProtocol.class)) { state |= proto.getState(window); } if (state != 0) { @@ -1127,18 +1126,17 @@ /* * Check if property change is a window state protocol message. - * If it is - return the new state as Integer, otherwise return null */ - Integer isStateChange(XDecoratedPeer window, XPropertyEvent e) { + boolean isStateChange(XDecoratedPeer window, XPropertyEvent e) { if (!window.isShowing()) { stateLog.finer("Window is not showing"); - return null; + return false; } int wm_state = window.getWMState(); if (wm_state == XlibWrapper.WithdrawnState) { stateLog.finer("WithdrawnState"); - return null; + return false; } else { stateLog.finer("Window WM_STATE is " + wm_state); } @@ -1147,26 +1145,26 @@ is_state_change = true; } - Iterator iter = getProtocols(XStateProtocol.class).iterator(); - while (iter.hasNext()) { - XStateProtocol proto = (XStateProtocol)iter.next(); + for (XStateProtocol proto : getProtocols(XStateProtocol.class)) { is_state_change |= proto.isStateChange(e); + stateLog.finest(proto + ": is state changed = " + is_state_change); } - int res = 0; + return is_state_change; + } - if (is_state_change) { - if (wm_state == XlibWrapper.IconicState) { - res = Frame.ICONIFIED; - } else { - res = Frame.NORMAL; - } - res |= getExtendedState(window); + /* + * Returns current state (including extended) of a given window. + */ + int getState(XDecoratedPeer window) { + int res = 0; + final int wm_state = window.getWMState(); + if (wm_state == XlibWrapper.IconicState) { + res = Frame.ICONIFIED; + } else { + res = Frame.NORMAL; } - if (is_state_change) { - return Integer.valueOf(res); - } else { - return null; - } + res |= getExtendedState(window); + return res; } /*****************************************************************************\ @@ -1180,9 +1178,7 @@ * in XLayerProtocol */ void setLayer(XWindowPeer window, int layer) { - Iterator iter = getProtocols(XLayerProtocol.class).iterator(); - while (iter.hasNext()) { - XLayerProtocol proto = (XLayerProtocol)iter.next(); + for (XLayerProtocol proto : getProtocols(XLayerProtocol.class)) { if (proto.supportsLayer(layer)) { proto.setLayer(window, layer); } @@ -1191,9 +1187,7 @@ } void setExtendedState(XWindowPeer window, int state) { - Iterator iter = getProtocols(XStateProtocol.class).iterator(); - while (iter.hasNext()) { - XStateProtocol proto = (XStateProtocol)iter.next(); + for (XStateProtocol proto : getProtocols(XStateProtocol.class)) { if (proto.supportsState(state)) { proto.setState(window, state); break; @@ -1239,9 +1233,7 @@ void unshadeKludge(XDecoratedPeer window) { assert(window.isShowing()); - Iterator iter = getProtocols(XStateProtocol.class).iterator(); - while (iter.hasNext()) { - XStateProtocol proto = (XStateProtocol)iter.next(); + for (XStateProtocol proto : getProtocols(XStateProtocol.class)) { proto.unshadeKludge(window); } XToolkit.XSync(); diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XWindow.java --- a/jdk/src/solaris/classes/sun/awt/X11/XWindow.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindow.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2008 Sun Microsystems, Inc. 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 @@ -92,8 +92,16 @@ SurfaceData surfaceData; XRepaintArea paintArea; + // fallback default font object - final static Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); + private static Font defaultFont; + + static synchronized Font getDefaultFont() { + if (null == defaultFont) { + defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); + } + return defaultFont; + } /* * Keeps all buttons which were pressed at the time of the last mouse @@ -333,7 +341,7 @@ } Font font = afont; if (font == null) { - font = defaultFont; + font = XWindow.getDefaultFont(); } return new SunGraphics2D(surfData, fgColor, bgColor, font); } @@ -902,13 +910,11 @@ super.handleConfigureNotifyEvent(xev); insLog.log(Level.FINER, "Configure, {0}, event disabled: {1}", - new Object[] {xev, isEventDisabled(xev)}); + new Object[] {xev.get_xconfigure(), isEventDisabled(xev)}); if (isEventDisabled(xev)) { return; } - long eventWindow = xev.get_xany().get_window(); - // if ( Check if it's a resize, a move, or a stacking order change ) // { Rectangle bounds = getBounds(); @@ -982,7 +988,6 @@ // called directly from this package, unlike handleKeyRelease. // un-final it if you need to override it in a subclass. final void handleKeyPress(XKeyEvent ev) { - int keycode = java.awt.event.KeyEvent.VK_UNDEFINED; long keysym[] = new long[2]; char unicodeKey = 0; keysym[0] = NoSymbol; @@ -1066,7 +1071,6 @@ } // un-private it if you need to call it from elsewhere private void handleKeyRelease(XKeyEvent ev) { - int keycode = java.awt.event.KeyEvent.VK_UNDEFINED; long keysym[] = new long[2]; char unicodeKey = 0; keysym[0] = NoSymbol; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2002-2008 Sun Microsystems, Inc. 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 @@ -112,9 +112,6 @@ PARENT_WINDOW, Long.valueOf(0)})); } - // fallback default font object - static Font defaultFont; - /* * This constant defines icon size recommended for using. * Apparently, we should use XGetIconSizes which should @@ -162,10 +159,7 @@ Font f = target.getFont(); if (f == null) { - if (defaultFont == null) { - defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); - } - f = defaultFont; + f = XWindow.getDefaultFont(); target.setFont(f); // we should not call setFont because it will call a repaint // which the peer may not be ready to do yet. @@ -188,6 +182,9 @@ GraphicsConfiguration gc = getGraphicsConfiguration(); ((X11GraphicsDevice)gc.getDevice()).addDisplayChangedListener(this); + + Rectangle bounds = (Rectangle)(params.get(BOUNDS)); + params.put(BOUNDS, constrainBounds(bounds.x, bounds.y, bounds.width, bounds.height)); } private void initWMProtocols() { @@ -437,6 +434,56 @@ return ownerPeer; } + // This method is overriden at the XDecoratedPeer to handle + // decorated windows a bit differently. + Rectangle constrainBounds(int x, int y, int width, int height) { + // We don't restrict the setBounds() operation if the code is trusted. + if (!hasWarningWindow()) { + return new Rectangle(x, y, width, height); + } + + // The window bounds should be within the visible part of the screen + int newX = x; + int newY = y; + int newW = width; + int newH = height; + + // Now check each point is within the visible part of the screen + GraphicsConfiguration gc = ((Window)target).getGraphicsConfiguration(); + Rectangle sB = gc.getBounds(); + Insets sIn = ((Window)target).getToolkit().getScreenInsets(gc); + + int screenX = sB.x + sIn.left; + int screenY = sB.y + sIn.top; + int screenW = sB.width - sIn.left - sIn.right; + int screenH = sB.height - sIn.top - sIn.bottom; + + + // First make sure the size is withing the visible part of the screen + if (newW > screenW) { + newW = screenW; + } + + if (newH > screenH) { + newH = screenH; + } + + // Tweak the location if needed + if (newX < screenX) { + newX = screenX; + } else if (newX + newW > screenX + screenW) { + newX = screenX + screenW - newW; + } + + if (newY < screenY) { + newY = screenY; + } else if (newY + newH > screenY + screenH) { + newY = screenY + screenH - newH; + } + + return new Rectangle(newX, newY, newW, newH); + } + //Fix for 6318144: PIT:Setting Min Size bigger than current size enlarges //the window but fails to revalidate, Sol-CDE //This bug is regression for @@ -445,10 +492,14 @@ //Note that this function is overriden in XDecoratedPeer so event //posting is not changing for decorated peers public void setBounds(int x, int y, int width, int height, int op) { + Rectangle newBounds = constrainBounds(x, y, width, height); + XToolkit.awtLock(); try { Rectangle oldBounds = getBounds(); - super.setBounds(x, y, width, height, op); + + super.setBounds(newBounds.x, newBounds.y, newBounds.width, newBounds.height, op); + Rectangle bounds = getBounds(); XSizeHints hints = getHints(); @@ -1035,7 +1086,7 @@ return !(target instanceof Frame || target instanceof Dialog); } boolean hasWarningWindow() { - return warningWindow != null; + return ((Window)target).getWarningString() != null; } // The height of menu bar window diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/motif/MDialogPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MDialogPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/motif/MDialogPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -102,4 +102,9 @@ public void blockWindows(java.util.List toBlock) { // do nothing } + + @Override + final boolean isTargetUndecorated() { + return ((Dialog)target).isUndecorated(); + } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/motif/MEmbeddedFramePeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MEmbeddedFramePeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/motif/MEmbeddedFramePeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -204,4 +204,10 @@ } public native Rectangle getBoundsPrivate(); + + @Override + Rectangle constrainBounds(int x, int y, int width, int height) { + // We don't constrain the bounds of the EmbeddedFrames + return new Rectangle(x, y, width, height); + } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/motif/MFramePeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MFramePeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/motif/MFramePeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -503,4 +503,9 @@ public Rectangle getBoundsPrivate() { return getBounds(); } + + @Override + final boolean isTargetUndecorated() { + return ((Frame)target).isUndecorated(); + } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/solaris/classes/sun/awt/motif/MWindowPeer.java --- a/jdk/src/solaris/classes/sun/awt/motif/MWindowPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/solaris/classes/sun/awt/motif/MWindowPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -113,6 +113,12 @@ insets.right = getInset("awt.frame.rightInset", -1); } + Rectangle bounds = target.getBounds(); + sysX = bounds.x; + sysY = bounds.y; + sysW = bounds.width; + sysH = bounds.height; + super.init(target); InputMethodManager imm = InputMethodManager.getInstance(); String menuString = imm.getTriggerMenuString(); @@ -150,6 +156,7 @@ GraphicsConfiguration gc = getGraphicsConfiguration(); ((X11GraphicsDevice)gc.getDevice()).addDisplayChangedListener(this); + } /* Support for multiple icons is not implemented in MAWT */ @@ -246,6 +253,8 @@ // NOTE: This method may be called by privileged threads. // DO NOT INVOKE CLIENT CODE ON THIS THREAD! public void handleResize(int width, int height) { + sysW = width; + sysH = height; // REMIND: Is this secure? Can client code subclass input method? if (!tcList.isEmpty() && @@ -268,6 +277,8 @@ } public void handleMoved(int x, int y) { + sysX = x; + sysY = y; postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); } @@ -505,4 +516,87 @@ } return false; } + + private final boolean hasWarningWindow() { + return ((Window)target).getWarningString() != null; + } + + // This method is overriden at Dialog and Frame peers. + boolean isTargetUndecorated() { + return true; + } + + private volatile int sysX = 0; + private volatile int sysY = 0; + private volatile int sysW = 0; + private volatile int sysH = 0; + + Rectangle constrainBounds(int x, int y, int width, int height) { + // We don't restrict the setBounds() operation if the code is trusted. + if (!hasWarningWindow()) { + return new Rectangle(x, y, width, height); + } + + int newX = x; + int newY = y; + int newW = width; + int newH = height; + + GraphicsConfiguration gc = ((Window)target).getGraphicsConfiguration(); + Rectangle sB = gc.getBounds(); + Insets sIn = ((Window)target).getToolkit().getScreenInsets(gc); + + int screenW = sB.width - sIn.left - sIn.right; + int screenH = sB.height - sIn.top - sIn.bottom; + + // If it's undecorated or is not currently visible, + // then check each point is within the visible part of the screen + if (!target.isVisible() || isTargetUndecorated()) { + int screenX = sB.x + sIn.left; + int screenY = sB.y + sIn.top; + + // First make sure the size is withing the visible part of the screen + if (newW > screenW) { + newW = screenW; + } + + if (newH > screenH) { + newH = screenH; + } + + // Tweak the location if needed + if (newX < screenX) { + newX = screenX; + } else if (newX + newW > screenX + screenW) { + newX = screenX + screenW - newW; + } + + if (newY < screenY) { + newY = screenY; + } else if (newY + newH > screenY + screenH) { + newY = screenY + screenH - newH; + } + } else { + int maxW = Math.max(screenW, sysW); + int maxH = Math.max(screenH, sysH); + + // Make sure the size is withing the visible part of the screen + // OR is less that the current size of the window. + if (newW > maxW) { + newW = maxW; + } + + if (newH > maxH) { + newH = maxH; + } + } + + return new Rectangle(newX, newY, newW, newH); + } + + public void setBounds(int x, int y, int width, int height, int op) { + Rectangle newBounds = constrainBounds(x, y, width, height); + super.setBounds(newBounds.x, newBounds.y, newBounds.width, newBounds.height, op); + } + } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/classes/sun/awt/windows/WDialogPeer.java --- a/jdk/src/windows/classes/sun/awt/windows/WDialogPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/classes/sun/awt/windows/WDialogPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -108,11 +108,18 @@ } } + @Override + boolean isTargetUndecorated() { + return ((Dialog)target).isUndecorated(); + } + public void reshape(int x, int y, int width, int height) { + Rectangle newBounds = constrainBounds(x, y, width, height); + if (((Dialog)target).isUndecorated()) { - super.reshape(x,y,width,height); + super.reshape(newBounds.x, newBounds.y, newBounds.width, newBounds.height); } else { - reshapeFrame(x,y,width,height); + reshapeFrame(newBounds.x, newBounds.y, newBounds.width, newBounds.height); } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java --- a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -65,4 +65,10 @@ public native Rectangle getBoundsPrivate(); public native void synthesizeWmActivate(boolean doActivate); + + @Override + Rectangle constrainBounds(int x, int y, int width, int height) { + // We don't constrain the bounds of the EmbeddedFrames + return new Rectangle(x, y, width, height); + } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/classes/sun/awt/windows/WFramePeer.java --- a/jdk/src/windows/classes/sun/awt/windows/WFramePeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/classes/sun/awt/windows/WFramePeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -64,11 +64,18 @@ } } + @Override + boolean isTargetUndecorated() { + return ((Frame)target).isUndecorated(); + } + public void reshape(int x, int y, int width, int height) { + Rectangle newBounds = constrainBounds(x, y, width, height); + if (((Frame)target).isUndecorated()) { - super.reshape(x,y,width,height); + super.reshape(newBounds.x, newBounds.y, newBounds.width, newBounds.height); } else { - reshapeFrame(x,y,width,height); + reshapeFrame(newBounds.x, newBounds.y, newBounds.width, newBounds.height); } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/classes/sun/awt/windows/WObjectPeer.java --- a/jdk/src/windows/classes/sun/awt/windows/WObjectPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/classes/sun/awt/windows/WObjectPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2008 Sun Microsystems, Inc. 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 @@ -30,8 +30,12 @@ initIDs(); } - long pData; // The Windows handle for the native widget. - Object target; // The associated AWT object. + // The Windows handle for the native widget. + long pData; + // if the native peer has been destroyed + boolean destroyed = false; + // The associated AWT object. + Object target; private volatile boolean disposed; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java --- a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java Mon Mar 24 06:33:16 2008 -0700 @@ -434,6 +434,97 @@ private native void nativeGrab(); private native void nativeUngrab(); + private final boolean hasWarningWindow() { + return ((Window)target).getWarningString() != null; + } + + boolean isTargetUndecorated() { + return true; + } + + // These are the peer bounds. They get updated at: + // 1. the WWindowPeer.setBounds() method. + // 2. the native code (on WM_SIZE/WM_MOVE) + private volatile int sysX = 0; + private volatile int sysY = 0; + private volatile int sysW = 0; + private volatile int sysH = 0; + + Rectangle constrainBounds(int x, int y, int width, int height) { + // We don't restrict the setBounds() operation if the code is trusted. + if (!hasWarningWindow()) { + return new Rectangle(x, y, width, height); + } + + int newX = x; + int newY = y; + int newW = width; + int newH = height; + + GraphicsConfiguration gc = ((Window)target).getGraphicsConfiguration(); + Rectangle sB = gc.getBounds(); + Insets sIn = ((Window)target).getToolkit().getScreenInsets(gc); + + int screenW = sB.width - sIn.left - sIn.right; + int screenH = sB.height - sIn.top - sIn.bottom; + + // If it's undecorated or is not currently visible + if (!((Window)target).isVisible() || isTargetUndecorated()) { + // Now check each point is within the visible part of the screen + int screenX = sB.x + sIn.left; + int screenY = sB.y + sIn.top; + + // First make sure the size is withing the visible part of the screen + if (newW > screenW) { + newW = screenW; + } + + if (newH > screenH) { + newH = screenH; + } + + // Tweak the location if needed + if (newX < screenX) { + newX = screenX; + } else if (newX + newW > screenX + screenW) { + newX = screenX + screenW - newW; + } + + if (newY < screenY) { + newY = screenY; + } else if (newY + newH > screenY + screenH) { + newY = screenY + screenH - newH; + } + } else { + int maxW = Math.max(screenW, sysW); + int maxH = Math.max(screenH, sysH); + + // Make sure the size is withing the visible part of the screen + // OR less that the current size of the window. + if (newW > maxW) { + newW = maxW; + } + + if (newH > maxH) { + newH = maxH; + } + } + + return new Rectangle(newX, newY, newW, newH); + } + + @Override + public void setBounds(int x, int y, int width, int height, int op) { + Rectangle newBounds = constrainBounds(x, y, width, height); + + sysX = newBounds.x; + sysY = newBounds.y; + sysW = newBounds.width; + sysH = newBounds.height; + + super.setBounds(newBounds.x, newBounds.y, newBounds.width, newBounds.height, op); + } + /* * The method maps the list of the active windows to the window's AppContext, * then the method registers ActiveWindowListener, GuiDisposedListener listeners; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt.h --- a/jdk/src/windows/native/sun/windows/awt.h Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt.h Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2008 Sun Microsystems, Inc. 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 @@ -47,7 +47,7 @@ JNI_CHECK_NULL_GOTO(peer, "peer", where); \ pData = JNI_GET_PDATA(peer); \ if (pData == NULL) { \ - JNU_ThrowNullPointerException(env, "null pData"); \ + THROW_NULL_PDATA_IF_NOT_DESTROYED(peer); \ goto where; \ } \ } @@ -63,7 +63,7 @@ JNI_CHECK_NULL_RETURN(peer, "peer"); \ pData = JNI_GET_PDATA(peer); \ if (pData == NULL) { \ - JNU_ThrowNullPointerException(env, "null pData"); \ + THROW_NULL_PDATA_IF_NOT_DESTROYED(peer); \ return; \ } \ } @@ -96,7 +96,7 @@ JNI_CHECK_NULL_RETURN_NULL(peer, "peer"); \ pData = JNI_GET_PDATA(peer); \ if (pData == NULL) { \ - JNU_ThrowNullPointerException(env, "null pData"); \ + THROW_NULL_PDATA_IF_NOT_DESTROYED(peer); \ return 0; \ } \ } @@ -105,16 +105,27 @@ JNI_CHECK_NULL_RETURN_VAL(peer, "peer", val); \ pData = JNI_GET_PDATA(peer); \ if (pData == NULL) { \ - JNU_ThrowNullPointerException(env, "null pData"); \ + THROW_NULL_PDATA_IF_NOT_DESTROYED(peer); \ return val; \ } \ } +#define THROW_NULL_PDATA_IF_NOT_DESTROYED(peer) { \ + jboolean destroyed = JNI_GET_DESTROYED(peer); \ + if (destroyed != JNI_TRUE) { \ + JNU_ThrowNullPointerException(env, "null pData"); \ + } \ +} + #define JNI_GET_PDATA(peer) (PDATA) env->GetLongField(peer, AwtObject::pDataID) +#define JNI_GET_DESTROYED(peer) env->GetBooleanField(peer, AwtObject::destroyedID) #define JNI_SET_PDATA(peer, data) env->SetLongField(peer, \ - AwtObject::pDataID, \ - (jlong)data) + AwtObject::pDataID, \ + (jlong)data) +#define JNI_SET_DESTROYED(peer) env->SetBooleanField(peer, \ + AwtObject::destroyedID, \ + JNI_TRUE) /* /NEW JNI */ /* diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt_Component.cpp --- a/jdk/src/windows/native/sun/windows/awt_Component.cpp Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Component.cpp Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2008 Sun Microsystems, Inc. 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 @@ -226,6 +226,8 @@ CriticalSection windowMoveLock; BOOL windowMoveLockHeld = FALSE; +int AwtComponent::sm_wheelRotationAmount = 0; + /************************************************************************ * AwtComponent methods */ @@ -2074,6 +2076,8 @@ sm_realFocusOpposite = NULL; } + sm_wheelRotationAmount = 0; + SendFocusEvent(java_awt_event_FocusEvent_FOCUS_GAINED, hWndLostFocus); return mrDoDefault; @@ -2105,6 +2109,7 @@ } sm_focusOwner = NULL; + sm_wheelRotationAmount = 0; SendFocusEvent(java_awt_event_FocusEvent_FOCUS_LOST, hWndGotFocus); return mrDoDefault; @@ -2190,8 +2195,11 @@ DWORD fgProcessID; ::GetWindowThreadProcessId(fgWindow, &fgProcessID); - if (fgProcessID != ::GetCurrentProcessId()) { - // fix for 6458497. we shouldn't request focus if it is out of our application. + if (fgProcessID != ::GetCurrentProcessId() + && !AwtToolkit::GetInstance().IsEmbedderProcessId(fgProcessID)) + { + // fix for 6458497. we shouldn't request focus if it is out of both + // our and embedder process. return FALSE; } } @@ -2619,9 +2627,13 @@ BOOL result; UINT platformLines; + sm_wheelRotationAmount += wheelRotation; + // AWT interprets wheel rotation differently than win32, so we need to // decode wheel amount. - jint newWheelRotation = wheelRotation / (-1 * WHEEL_DELTA); + jint roundedWheelRotation = sm_wheelRotationAmount / (-1 * WHEEL_DELTA); + jdouble preciseWheelRotation = (jdouble) wheelRotation / (-1 * WHEEL_DELTA); + MSG msg; if (IS_WIN95 && !IS_WIN98) { @@ -2654,7 +2666,9 @@ SendMouseWheelEvent(java_awt_event_MouseEvent_MOUSE_WHEEL, TimeHelper::getMessageTimeUTC(), eventPt.x, eventPt.y, GetJavaModifiers(), 0, 0, scrollType, - scrollLines, newWheelRotation, &msg); + scrollLines, roundedWheelRotation, preciseWheelRotation, &msg); + + sm_wheelRotationAmount %= WHEEL_DELTA; return mrConsume; } @@ -4986,8 +5000,8 @@ AwtComponent::SendMouseWheelEvent(jint id, jlong when, jint x, jint y, jint modifiers, jint clickCount, jboolean popupTrigger, jint scrollType, - jint scrollAmount, jint wheelRotation, - MSG *pMsg) + jint scrollAmount, jint roundedWheelRotation, + jdouble preciseWheelRotation, MSG *pMsg) { /* Code based not so loosely on AwtComponent::SendMouseEvent */ JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); @@ -5015,7 +5029,7 @@ if (mouseWheelEventConst == NULL) { mouseWheelEventConst = env->GetMethodID(mouseWheelEventCls, "", - "(Ljava/awt/Component;IJIIIIZIII)V"); + "(Ljava/awt/Component;IJIIIIIIZIIID)V"); DASSERT(mouseWheelEventConst); } if (env->EnsureLocalCapacity(2) < 0) { @@ -5023,14 +5037,16 @@ } jobject target = GetTarget(env); DTRACE_PRINTLN("creating MWE in JNI"); + jobject mouseWheelEvent = env->NewObject(mouseWheelEventCls, mouseWheelEventConst, target, id, when, modifiers, x+insets.left, y+insets.top, + 0, 0, clickCount, popupTrigger, scrollType, scrollAmount, - wheelRotation); + roundedWheelRotation, preciseWheelRotation); if (safe_ExceptionOccurred(env)) { env->ExceptionDescribe(); env->ExceptionClear(); @@ -5400,6 +5416,7 @@ if (m_peerObject) { env->SetLongField(m_peerObject, AwtComponent::hwndID, 0); JNI_SET_PDATA(m_peerObject, static_cast(NULL)); + JNI_SET_DESTROYED(m_peerObject); env->DeleteGlobalRef(m_peerObject); m_peerObject = NULL; } @@ -5408,7 +5425,13 @@ void AwtComponent::Enable(BOOL bEnable) { sm_suppressFocusAndActivation = TRUE; + + if (bEnable && IsTopLevel()) { + // we should not enable blocked toplevels + bEnable = !::IsWindow(AwtWindow::GetModalBlocker(GetHWnd())); + } ::EnableWindow(GetHWnd(), bEnable); + sm_suppressFocusAndActivation = FALSE; CriticalSection::Lock l(GetLock()); VerifyState(); diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt_Component.h --- a/jdk/src/windows/native/sun/windows/awt_Component.h Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Component.h Mon Mar 24 06:33:16 2008 -0700 @@ -392,7 +392,7 @@ jint modifiers, jint clickCount, jboolean popupTrigger, jint scrollType, jint scrollAmount, jint wheelRotation, - MSG *msg = NULL); + jdouble preciseWheelRotation, MSG *msg = NULL); /* * Allocate and initialize a new java.awt.event.FocusEvent, and @@ -785,7 +785,9 @@ int windowMoveLockPosCX; int windowMoveLockPosCY; -private: + // 6524352: support finer-resolution + static int sm_wheelRotationAmount; + /* * The association list of children's IDs and corresponding components. * Some components like Choice or List are required their sizes while diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt_Dialog.cpp --- a/jdk/src/windows/native/sun/windows/awt_Dialog.cpp Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Dialog.cpp Mon Mar 24 06:33:16 2008 -0700 @@ -273,6 +273,10 @@ { HWND blocker = AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(hWnd)); HWND topMostBlocker = blocker; + HWND prevForegroundWindow = ::GetForegroundWindow(); + if (::IsWindow(blocker)) { + ::BringWindowToTop(hWnd); + } while (::IsWindow(blocker)) { topMostBlocker = blocker; ::BringWindowToTop(blocker); @@ -282,7 +286,7 @@ // no beep/flash if the mouse was clicked in the taskbar menu // or the dialog is currently inactive if ((::WindowFromPoint(mhs->pt) == hWnd) && - (::GetForegroundWindow() == topMostBlocker)) + (prevForegroundWindow == topMostBlocker)) { ::MessageBeep(MB_OK); // some heuristics: 3 times x 64 milliseconds @@ -292,6 +296,7 @@ ::BringWindowToTop(topMostBlocker); ::SetForegroundWindow(topMostBlocker); } + return 1; } } } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt_Frame.cpp --- a/jdk/src/windows/native/sun/windows/awt_Frame.cpp Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Frame.cpp Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2008 Sun Microsystems, Inc. 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 @@ -221,8 +221,7 @@ // Update target's dimensions to reflect this embedded window. ::GetClientRect(frame->m_hwnd, &rect); - ::MapWindowPoints(frame->m_hwnd, hwndParent, (LPPOINT)&rect, - 2); + ::MapWindowPoints(frame->m_hwnd, hwndParent, (LPPOINT)&rect, 2); env->SetIntField(target, AwtComponent::xID, rect.left); env->SetIntField(target, AwtComponent::yID, rect.top); @@ -231,6 +230,7 @@ env->SetIntField(target, AwtComponent::heightID, rect.bottom-rect.top); frame->InitPeerGraphicsConfig(env, self); + AwtToolkit::GetInstance().RegisterEmbedderProcessId(hwndParent); } else { jint state = env->GetIntField(target, AwtFrame::stateID); DWORD exStyle; @@ -408,8 +408,9 @@ * message. This breaks Java focus. To workaround the problem we * set the toplevel being shown foreground programmatically. * The fix is localized to non-foreground process case only. + * (See also: 6599270) */ - if (show == TRUE && status == 0) { + if (!IsEmbeddedFrame() && show == TRUE && status == 0) { HWND fgHWnd = ::GetForegroundWindow(); if (fgHWnd != NULL) { DWORD fgProcessID; @@ -495,7 +496,7 @@ ::SetWindowPos(GetHWnd(), NULL, r.left, r.top, r.right-r.left, r.bottom-r.top, - SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOZORDER | + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOCOPYBITS | SWP_DEFERERASE); } return mrConsume; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt_Object.cpp --- a/jdk/src/windows/native/sun/windows/awt_Object.cpp Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Object.cpp Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2008 Sun Microsystems, Inc. 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 @@ -39,6 +39,7 @@ */ jfieldID AwtObject::pDataID; +jfieldID AwtObject::destroyedID; jfieldID AwtObject::targetID; jclass AwtObject::wObjectPeerClass; jmethodID AwtObject::getPeerForTargetMID; @@ -223,6 +224,7 @@ AwtObject::wObjectPeerClass = (jclass)env->NewGlobalRef(cls); AwtObject::pDataID = env->GetFieldID(cls, "pData", "J"); + AwtObject::destroyedID = env->GetFieldID(cls, "destroyed", "Z"); AwtObject::targetID = env->GetFieldID(cls, "target", "Ljava/lang/Object;"); @@ -233,6 +235,7 @@ AwtObject::createErrorID = env->GetFieldID(cls, "createError", "Ljava/lang/Error;"); DASSERT(AwtObject::pDataID != NULL); + DASSERT(AwtObject::destroyedID != NULL); DASSERT(AwtObject::targetID != NULL); DASSERT(AwtObject::getPeerForTargetMID != NULL); DASSERT(AwtObject::createErrorID != NULL); diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt_Object.h --- a/jdk/src/windows/native/sun/windows/awt_Object.h Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Object.h Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2008 Sun Microsystems, Inc. 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 @@ -51,6 +51,7 @@ /* sun.awt.windows.WObjectPeer field and method ids */ static jfieldID pDataID; + static jfieldID destroyedID; static jfieldID targetID; static jmethodID getPeerForTargetMID; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt_Toolkit.cpp --- a/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2008 Sun Microsystems, Inc. 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 @@ -354,6 +354,7 @@ m_dllHandle = NULL; m_displayChanged = FALSE; + m_embedderProcessID = 0; // XXX: keyboard mapping should really be moved out of AwtComponent AwtComponent::InitDynamicKeyMapTable(); @@ -1442,49 +1443,17 @@ } } -/* - * Returns a reference to the class java.awt.Component. - */ -jclass -getComponentClass(JNIEnv *env) +// for now we support only one embedder, but should be ready for future +void AwtToolkit::RegisterEmbedderProcessId(HWND embedder) { - static jclass componentCls = NULL; - - // get global reference of java/awt/Component class (run only once) - if (componentCls == NULL) { - jclass componentClsLocal = env->FindClass("java/awt/Component"); - DASSERT(componentClsLocal != NULL); - if (componentClsLocal == NULL) { - /* exception already thrown */ - return NULL; - } - componentCls = (jclass)env->NewGlobalRef(componentClsLocal); - env->DeleteLocalRef(componentClsLocal); + if (m_embedderProcessID) { + // we already set embedder process and do not expect + // two different processes to embed the same AwtToolkit + return; } - return componentCls; -} - -/* - * Returns a reference to the class java.awt.MenuComponent. - */ -jclass -getMenuComponentClass(JNIEnv *env) -{ - static jclass menuComponentCls = NULL; - - // get global reference of java/awt/MenuComponent class (run only once) - if (menuComponentCls == NULL) { - jclass menuComponentClsLocal = env->FindClass("java/awt/MenuComponent"); - DASSERT(menuComponentClsLocal != NULL); - if (menuComponentClsLocal == NULL) { - /* exception already thrown */ - return NULL; - } - menuComponentCls = (jclass)env->NewGlobalRef(menuComponentClsLocal); - env->DeleteLocalRef(menuComponentClsLocal); - } - return menuComponentCls; + embedder = ::GetAncestor(embedder, GA_ROOT); + ::GetWindowThreadProcessId(embedder, &m_embedderProcessID); } JNIEnv* AwtToolkit::m_env; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt_Toolkit.h --- a/jdk/src/windows/native/sun/windows/awt_Toolkit.h Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.h Mon Mar 24 06:33:16 2008 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2008 Sun Microsystems, Inc. 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 @@ -426,10 +426,17 @@ */ private: BOOL m_displayChanged; /* Tracks displayChanged events */ + // 0 means we are not embedded. + DWORD m_embedderProcessID; public: BOOL HasDisplayChanged() { return m_displayChanged; } void ResetDisplayChanged() { m_displayChanged = FALSE; } + void RegisterEmbedderProcessId(HWND); + BOOL IsEmbedderProcessId(const DWORD processID) const + { + return m_embedderProcessID && (processID == m_embedderProcessID); + } private: static JNIEnv *m_env; diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt_Window.cpp --- a/jdk/src/windows/native/sun/windows/awt_Window.cpp Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Window.cpp Mon Mar 24 06:33:16 2008 -0700 @@ -125,6 +125,11 @@ jclass AwtWindow::wwindowPeerCls; jmethodID AwtWindow::getActiveWindowsMID; +jfieldID AwtWindow::sysXID; +jfieldID AwtWindow::sysYID; +jfieldID AwtWindow::sysWID; +jfieldID AwtWindow::sysHID; + int AwtWindow::ms_instanceCounter = 0; HHOOK AwtWindow::ms_hCBTFilter; AwtWindow * AwtWindow::m_grabbedWindow = NULL; @@ -180,7 +185,6 @@ } ::RemoveProp(GetHWnd(), ModalBlockerProp); - ::RemoveProp(GetHWnd(), ModalSaveWSEXProp); if (m_grabbedWindow == this) { Ungrab(); @@ -330,8 +334,11 @@ if (nCode == HCBT_ACTIVATE || nCode == HCBT_SETFOCUS) { AwtComponent *comp = AwtComponent::GetComponent((HWND)wParam); - if (comp != NULL && comp->IsTopLevel() && !((AwtWindow*)comp)->IsFocusableWindow()) { - return 1; // Don't change focus/activation. + if (comp != NULL && comp->IsTopLevel()) { + AwtWindow* win = (AwtWindow*)comp; + if (!win->IsFocusableWindow() || win->m_filterFocusAndActivation) { + return 1; // Don't change focus/activation. + } } } return ::CallNextHookEx(AwtWindow::ms_hCBTFilter, nCode, wParam, lParam); @@ -1053,6 +1060,8 @@ (env)->SetIntField(target, AwtComponent::xID, rect.left); (env)->SetIntField(target, AwtComponent::yID, rect.top); + (env)->SetIntField(peer, AwtWindow::sysXID, rect.left); + (env)->SetIntField(peer, AwtWindow::sysYID, rect.top); SendComponentEvent(java_awt_event_ComponentEvent_COMPONENT_MOVED); env->DeleteLocalRef(target); @@ -1116,6 +1125,11 @@ (env)->SetIntField(target, AwtComponent::widthID, newWidth); (env)->SetIntField(target, AwtComponent::heightID, newHeight); + + jobject peer = GetPeer(env); + (env)->SetIntField(peer, AwtWindow::sysWID, newWidth); + (env)->SetIntField(peer, AwtWindow::sysHID, newHeight); + if (!AwtWindow::IsResizing()) { WindowResized(); } @@ -1455,20 +1469,17 @@ if (!::IsWindow(window)) { return; } - DWORD exStyle = ::GetWindowLong(window, GWL_EXSTYLE); + if (::IsWindow(blocker)) { - // save WS_EX_NOACTIVATE and WS_EX_APPWINDOW styles - DWORD saveStyle = exStyle & (AWT_WS_EX_NOACTIVATE | WS_EX_APPWINDOW); - ::SetProp(window, ModalSaveWSEXProp, reinterpret_cast(saveStyle)); - ::SetWindowLong(window, GWL_EXSTYLE, (exStyle | AWT_WS_EX_NOACTIVATE) & ~WS_EX_APPWINDOW); ::SetProp(window, ModalBlockerProp, reinterpret_cast(blocker)); + ::EnableWindow(window, FALSE); } else { - // restore WS_EX_NOACTIVATE and WS_EX_APPWINDOW styles - DWORD saveStyle = reinterpret_cast(::GetProp(window, ModalSaveWSEXProp)); - ::SetWindowLong(window, GWL_EXSTYLE, - (exStyle & ~(AWT_WS_EX_NOACTIVATE | WS_EX_APPWINDOW)) | saveStyle); - ::RemoveProp(window, ModalSaveWSEXProp); ::RemoveProp(window, ModalBlockerProp); + AwtComponent *comp = AwtComponent::GetComponent(window); + // we don't expect to be called with non-java HWNDs + DASSERT(comp && comp->IsTopLevel()); + // we should not unblock disabled toplevels + ::EnableWindow(window, comp->isEnabled()); } } @@ -1754,17 +1765,22 @@ // Fix for 4459064 : do not enforce thresholds for embedded frames if (!p->IsEmbeddedFrame()) { + jobject peer = p->GetPeer(env); int minWidth = ::GetSystemMetrics(SM_CXMIN); int minHeight = ::GetSystemMetrics(SM_CYMIN); if (w < minWidth) { env->SetIntField(target, AwtComponent::widthID, w = minWidth); + env->SetIntField(peer, AwtWindow::sysWID, + w); } if (h < minHeight) { env->SetIntField(target, AwtComponent::heightID, h = minHeight); + env->SetIntField(peer, AwtWindow::sysHID, + h); } } env->DeleteLocalRef(target); @@ -2148,6 +2164,11 @@ env->GetStaticMethodID(cls, "getActiveWindowHandles", "()[J"); DASSERT(AwtWindow::getActiveWindowsMID != NULL); + AwtWindow::sysXID = env->GetFieldID(cls, "sysX", "I"); + AwtWindow::sysYID = env->GetFieldID(cls, "sysY", "I"); + AwtWindow::sysWID = env->GetFieldID(cls, "sysW", "I"); + AwtWindow::sysHID = env->GetFieldID(cls, "sysH", "I"); + CATCH_BAD_ALLOC; } diff -r 94a4cf011510 -r a67fedfd0b21 jdk/src/windows/native/sun/windows/awt_Window.h --- a/jdk/src/windows/native/sun/windows/awt_Window.h Mon Mar 17 23:03:51 2008 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Window.h Mon Mar 24 06:33:16 2008 -0700 @@ -33,7 +33,6 @@ // property name tagging windows disabled by modality static LPCTSTR ModalBlockerProp = TEXT("SunAwtModalBlockerProp"); -static LPCTSTR ModalSaveWSEXProp = TEXT("SunAwtModalSaveWSEXProp"); static LPCTSTR ModalDialogPeerProp = TEXT("SunAwtModalDialogPeerProp"); #ifndef WH_MOUSE_LL @@ -63,6 +62,12 @@ /* long[] getActiveWindowHandles() method in WWindowPeer */ static jmethodID getActiveWindowsMID; + // The coordinates at the peer. + static jfieldID sysXID; + static jfieldID sysYID; + static jfieldID sysWID; + static jfieldID sysHID; + AwtWindow(); virtual ~AwtWindow(); diff -r 94a4cf011510 -r a67fedfd0b21 jdk/test/java/awt/Focus/NonFocusableResizableTooSmall/NonFocusableResizableTooSmall.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Focus/NonFocusableResizableTooSmall/NonFocusableResizableTooSmall.java Mon Mar 24 06:33:16 2008 -0700 @@ -0,0 +1,413 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test + @bug 6581927 + @summary Non-focusable frame should honor the size of the frame buttons/decorations when resizing + @library ../../regtesthelpers + @build Util + @author anthony.petrov@...: area=awt.toplevel + @run main NonFocusableResizableTooSmall +*/ + +/** + * NonFocusableResizableTooSmall.java + * + * summary: Non-focusable frame should honor the size of the frame buttons/decorations when resizing + */ + +import java.awt.*; +import java.awt.event.*; +import test.java.awt.regtesthelpers.Util; + +public class NonFocusableResizableTooSmall +{ + + //*** test-writer defined static variables go here *** + + + private static void init() + { + //*** Create instructions for the user here *** + + String[] instructions = + { + "This is an AUTOMATIC test, simply wait until it is done.", + "The result (passed or failed) will be shown in the", + "message window below." + }; + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + final Frame frame = new Frame(); + frame.setFocusableWindowState(false); + frame.setSize(200, 100); + frame.setVisible(true); + + final Robot robot = Util.createRobot(); + robot.setAutoDelay(20); + + // To be sure the window is shown and packed + Util.waitForIdle(robot); + + final Insets insets = frame.getInsets(); + System.out.println("The insets of the frame: " + insets); + if (insets.right == 0 || insets.bottom == 0) { + System.out.println("The test environment must have non-zero right & bottom insets!"); + pass(); + return; + } + + // Let's move the mouse pointer to the bottom-right coner of the frame (the "size-grip") + final Rectangle bounds1 = frame.getBounds(); + System.out.println("The bounds before resizing: " + bounds1); + + robot.mouseMove(bounds1.x + bounds1.width - 1, bounds1.y + bounds1.height - 1); + + // ... and start resizing to some very small + robot.mousePress( InputEvent.BUTTON1_MASK ); + + // Now resize the frame so that the width is smaller + // than the widths of the left and the right borders. + // The sum of widths of the icon of the frame + the control-buttons + // (close, minimize, etc.) should be definitely larger! + robot.mouseMove(bounds1.x + insets.left + insets.right - 5, bounds1.y + bounds1.height - 1); + Util.waitForIdle(robot); + + robot.mouseRelease( InputEvent.BUTTON1_MASK ); + + Util.waitForIdle(robot); + + // Check the current bounds of the frame + final Rectangle bounds2 = frame.getBounds(); + System.out.println("The bounds after resizing: " + bounds2); + + if (bounds2.width <= (insets.left + insets.right)) { + fail("The frame has been resized to very small."); + } + pass(); + }//End init() + + + + /***************************************************** + * Standard Test Machinery Section + * DO NOT modify anything in this section -- it's a + * standard chunk of code which has all of the + * synchronisation necessary for the test harness. + * By keeping it the same in all tests, it is easier + * to read and understand someone else's test, as + * well as insuring that all tests behave correctly + * with the test harness. + * There is a section following this for test- + * classes + ******************************************************/ + private static boolean theTestPassed = false; + private static boolean testGeneratedInterrupt = false; + private static String failureMessage = ""; + + private static Thread mainThread = null; + + private static int sleepTime = 300000; + + // Not sure about what happens if multiple of this test are + // instantiated in the same VM. Being static (and using + // static vars), it aint gonna work. Not worrying about + // it for now. + public static void main( String args[] ) throws InterruptedException + { + mainThread = Thread.currentThread(); + try + { + init(); + } + catch( TestPassedException e ) + { + //The test passed, so just return from main and harness will + // interepret this return as a pass + return; + } + //At this point, neither test pass nor test fail has been + // called -- either would have thrown an exception and ended the + // test, so we know we have multiple threads. + + //Test involves other threads, so sleep and wait for them to + // called pass() or fail() + try + { + Thread.sleep( sleepTime ); + //Timed out, so fail the test + throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); + } + catch (InterruptedException e) + { + //The test harness may have interrupted the test. If so, rethrow the exception + // so that the harness gets it and deals with it. + if( ! testGeneratedInterrupt ) throw e; + + //reset flag in case hit this code more than once for some reason (just safety) + testGeneratedInterrupt = false; + + if ( theTestPassed == false ) + { + throw new RuntimeException( failureMessage ); + } + } + + }//main + + public static synchronized void setTimeoutTo( int seconds ) + { + sleepTime = seconds * 1000; + } + + public static synchronized void pass() + { + Sysout.println( "The test passed." ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //first check if this is executing in main thread + if ( mainThread == Thread.currentThread() ) + { + //Still in the main thread, so set the flag just for kicks, + // and throw a test passed exception which will be caught + // and end the test. + theTestPassed = true; + throw new TestPassedException(); + } + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + }//pass() + + public static synchronized void fail() + { + //test writer didn't specify why test failed, so give generic + fail( "it just plain failed! :-)" ); + } + + public static synchronized void fail( String whyFailed ) + { + Sysout.println( "The test failed: " + whyFailed ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //check if this called from main thread + if ( mainThread == Thread.currentThread() ) + { + //If main thread, fail now 'cause not sleeping + throw new RuntimeException( whyFailed ); + } + theTestPassed = false; + testGeneratedInterrupt = true; + failureMessage = whyFailed; + mainThread.interrupt(); + }//fail() + +}// class NonFocusableResizableTooSmall + +//This exception is used to exit from any level of call nesting +// when it's determined that the test has passed, and immediately +// end the test. +class TestPassedException extends RuntimeException +{ +} + +//*********** End Standard Test Machinery Section ********** + + +//************ Begin classes defined for the test **************** + +// if want to make listeners, here is the recommended place for them, then instantiate +// them in init() + +/* Example of a class which may be written as part of a test +class NewClass implements anInterface + { + static int newVar = 0; + + public void eventDispatched(AWTEvent e) + { + //Counting events to see if we get enough + eventCount++; + + if( eventCount == 20 ) + { + //got enough events, so pass + + NonFocusableResizableTooSmall.pass(); + } + else if( tries == 20 ) + { + //tried too many times without getting enough events so fail + + NonFocusableResizableTooSmall.fail(); + } + + }// eventDispatched() + + }// NewClass class + +*/ + + +//************** End classes defined for the test ******************* + + + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout +{ + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + System.out.println(messageIn); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + pack(); + + setVisible(true); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + System.out.println(messageIn); + } + +}// TestDialog class diff -r 94a4cf011510 -r a67fedfd0b21 jdk/test/java/awt/Focus/RestoreFocusOnDisabledComponentTest/RestoreFocusOnDisabledComponentTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Focus/RestoreFocusOnDisabledComponentTest/RestoreFocusOnDisabledComponentTest.java Mon Mar 24 06:33:16 2008 -0700 @@ -0,0 +1,108 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test %W% %E% + @bug 6598089 + @summary Tests restoring focus on a single disabled coponent + @author Anton Tarasov: area=awt-focus + @library ../../regtesthelpers + @build Util + @run main RestoreFocusOnDisabledComponentTest +*/ + +import java.awt.*; +import java.awt.event.*; +import java.applet.Applet; +import test.java.awt.regtesthelpers.Util; + +/* + * The bug is not reproducible on Windows. + */ +public class RestoreFocusOnDisabledComponentTest extends Applet { + Frame frame = new Frame("Frame") {public String toString() {return "FRAME";}}; + Button b0 = new Button("button0") {public String toString() {return "B-0";}}; + Button b1 = new Button("button1") {public String toString() {return "B-1";}}; + volatile int nFocused; + Robot robot; + + public static void main(String[] args) { + RestoreFocusOnDisabledComponentTest app = new RestoreFocusOnDisabledComponentTest(); + app.init(); + app.start(); + } + + public void init() { + robot = Util.createRobot(); + } + + public void start() { + frame.add(b0); + frame.add(b1); + frame.setLayout(new FlowLayout()); + frame.pack(); + + frame.setVisible(true); + + Util.waitForIdle(robot); + KeyboardFocusManager.setCurrentKeyboardFocusManager(new DefaultKeyboardFocusManager() { + public boolean dispatchEvent(AWTEvent e) { + if (e.getID() == FocusEvent.FOCUS_GAINED) { + // Trying to emulate timings. b1 should be disabled just by the time it gets + // FOCUS_GAINED event. The latter is a result of disabling b0 that initiates + // focus auto transfer. + if (e.getSource() == b1) { + b1.setEnabled(false); + + } else if (e.getSource() == b0) { + if (++nFocused > 10) { + nFocused = -1; + throw new TestFailedException("Focus went into busy loop!"); + } + } + } + return super.dispatchEvent(e); + } + }); + // Initiating focus auto transfer. + // Focus will be requested to b1. When FOCUS_GAINED is being dispatched to b1, it will + // be disabled. This will trigger focus restoring. Focus will be requested to b0 (the + // last opposite component). When FOCUS_GAINED is being dispatched to b0, it will + // also be disabled. However, the last opposite component (and the most recent focus owner) + // will still be b0. When DKFM initiates focus restoring it should detect restoring + // on the same component and break. + b0.setEnabled(false); + + Util.waitForIdle(robot); + if (nFocused != -1) { + System.out.println("Test passed."); + } + } +} + +class TestFailedException extends RuntimeException { + TestFailedException(String msg) { + super("Test failed: " + msg); + } +} + diff -r 94a4cf011510 -r a67fedfd0b21 jdk/test/java/awt/Mixing/ValidBounds.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Mixing/ValidBounds.java Mon Mar 24 06:33:16 2008 -0700 @@ -0,0 +1,411 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test + @bug 6637796 + @summary Shape should be correctly updated on invalid components + @author anthony.petrov@...: area=awt.mixing + @library ../regtesthelpers + @build Util + @run main ValidBounds +*/ + +/** + * ValidBounds.java + * + * summary: Shape should be correctly updated on invalid components + */ + +import java.awt.*; +import java.awt.event.*; +import test.java.awt.regtesthelpers.Util; + +public class ValidBounds +{ + + static volatile boolean clickPassed = false; + + private static void init() + { + //*** Create instructions for the user here *** + + String[] instructions = + { + "This is an AUTOMATIC test, simply wait until it is done.", + "The result (passed or failed) will be shown in the", + "message window below." + }; + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + + // Create the frame and the button + Frame f = new Frame(); + f.setBounds(100, 100, 400, 300); + + Button b = new Button("OK"); + + f.setLayout(null); + f.add(b); + b.setBounds(50, 50, 200, 50); + + b.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent e) { + clickPassed = true; + } + }); + + f.setVisible(true); + + // Let's make the button much smaller first... + Robot robot = Util.createRobot(); + robot.setAutoDelay(20); + + Util.waitForIdle(robot); + + b.setBounds(50, 50, 5, 5); + Util.waitForIdle(robot); + + // ... and now let's enlarge it. + b.setBounds(50, 50, 200, 50); + Util.waitForIdle(robot); + + // If the button doesn't receive the click, it means that the test + // failed: the shape of the button was not enlarged. + Point heavyLoc = b.getLocationOnScreen(); + robot.mouseMove(heavyLoc.x + 20, heavyLoc.y + 20); + + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + Util.waitForIdle(robot); + + if (clickPassed) { + pass(); + } else { + fail("The button cannot be clicked."); + } + }//End init() + + + + /***************************************************** + * Standard Test Machinery Section + * DO NOT modify anything in this section -- it's a + * standard chunk of code which has all of the + * synchronisation necessary for the test harness. + * By keeping it the same in all tests, it is easier + * to read and understand someone else's test, as + * well as insuring that all tests behave correctly + * with the test harness. + * There is a section following this for test- + * classes + ******************************************************/ + private static boolean theTestPassed = false; + private static boolean testGeneratedInterrupt = false; + private static String failureMessage = ""; + + private static Thread mainThread = null; + + private static int sleepTime = 300000; + + // Not sure about what happens if multiple of this test are + // instantiated in the same VM. Being static (and using + // static vars), it aint gonna work. Not worrying about + // it for now. + public static void main( String args[] ) throws InterruptedException + { + mainThread = Thread.currentThread(); + try + { + init(); + } + catch( TestPassedException e ) + { + //The test passed, so just return from main and harness will + // interepret this return as a pass + return; + } + //At this point, neither test pass nor test fail has been + // called -- either would have thrown an exception and ended the + // test, so we know we have multiple threads. + + //Test involves other threads, so sleep and wait for them to + // called pass() or fail() + try + { + Thread.sleep( sleepTime ); + //Timed out, so fail the test + throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); + } + catch (InterruptedException e) + { + //The test harness may have interrupted the test. If so, rethrow the exception + // so that the harness gets it and deals with it. + if( ! testGeneratedInterrupt ) throw e; + + //reset flag in case hit this code more than once for some reason (just safety) + testGeneratedInterrupt = false; + + if ( theTestPassed == false ) + { + throw new RuntimeException( failureMessage ); + } + } + + }//main + + public static synchronized void setTimeoutTo( int seconds ) + { + sleepTime = seconds * 1000; + } + + public static synchronized void pass() + { + Sysout.println( "The test passed." ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //first check if this is executing in main thread + if ( mainThread == Thread.currentThread() ) + { + //Still in the main thread, so set the flag just for kicks, + // and throw a test passed exception which will be caught + // and end the test. + theTestPassed = true; + throw new TestPassedException(); + } + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + }//pass() + + public static synchronized void fail() + { + //test writer didn't specify why test failed, so give generic + fail( "it just plain failed! :-)" ); + } + + public static synchronized void fail( String whyFailed ) + { + Sysout.println( "The test failed: " + whyFailed ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //check if this called from main thread + if ( mainThread == Thread.currentThread() ) + { + //If main thread, fail now 'cause not sleeping + throw new RuntimeException( whyFailed ); + } + theTestPassed = false; + testGeneratedInterrupt = true; + failureMessage = whyFailed; + mainThread.interrupt(); + }//fail() + +}// class ValidBounds + +//This exception is used to exit from any level of call nesting +// when it's determined that the test has passed, and immediately +// end the test. +class TestPassedException extends RuntimeException +{ +} + +//*********** End Standard Test Machinery Section ********** + + +//************ Begin classes defined for the test **************** + +// if want to make listeners, here is the recommended place for them, then instantiate +// them in init() + +/* Example of a class which may be written as part of a test +class NewClass implements anInterface + { + static int newVar = 0; + + public void eventDispatched(AWTEvent e) + { + //Counting events to see if we get enough + eventCount++; + + if( eventCount == 20 ) + { + //got enough events, so pass + + ValidBounds.pass(); + } + else if( tries == 20 ) + { + //tried too many times without getting enough events so fail + + ValidBounds.fail(); + } + + }// eventDispatched() + + }// NewClass class + +*/ + + +//************** End classes defined for the test ******************* + + + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout +{ + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + System.out.println(messageIn); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + pack(); + + setVisible(true); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + System.out.println(messageIn); + } + +}// TestDialog class diff -r 94a4cf011510 -r a67fedfd0b21 jdk/test/java/awt/Modal/WsDisabledStyle/CloseBlocker/CloseBlocker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Modal/WsDisabledStyle/CloseBlocker/CloseBlocker.java Mon Mar 24 06:33:16 2008 -0700 @@ -0,0 +1,466 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test %I% %E% + @bug 4080029 + @summary Modal Dialog block input to all frame windows not just its parent. + @author dmitry.cherepanov: area=awt.modal + @run main/manual CloseBlocker +*/ + +/** + * ManualMainTest.java + * + * summary: The test opens and closes blocker dialog, the test verifies + * that active window is correct when the dialog is closed. + */ + +import java.awt.*; +import java.awt.event.*; + +public class CloseBlocker +{ + + private static void init() + { + //*** Create instructions for the user here *** + + String[] instructions = + { + " the test will be run 6 times, to start next test just close all ", + " windows of previous; the instructions are the same for all tests: ", + " 1) there are two frames (one the frames has 'show modal' button), ", + " 2) press the button to show a dialog, ", + " 3) close the dialog (an alternative scenario - activate another", + " native window before closing the dialog), ", + " 4) the frame with button should become next active window, ", + " if it's true, then the test passed, otherwise, it failed. ", + " Press 'pass' button only after all of the 6 tests are completed, ", + " the number of the currently executed test is displayed on the ", + " output window. " + }; + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + test(true, true, false); + test(true, true, true); + test(false, true, false); // 3rd parameter has no affect for ownerless + + test(true, false, false); + test(true, false, true); + test(false, false, false); // 3rd parameter has no affect for ownerless + + }//End init() + + private static final Object obj = new Object(); + private static int counter = 0; + + /* + * The ownerless parameter indicates whether the blocker dialog + * has owner. The usual parameter indicates whether the blocker + * dialog is a Java dialog (non-native dialog like file dialog). + */ + private static void test(final boolean ownerless, final boolean usual, final boolean initiallyOwnerIsActive) { + + Sysout.print(" * test #" + (++counter) + " is running ... "); + + final Frame active = new Frame(); + final Frame nonactive = new Frame(); + Button button = new Button("show modal"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + Dialog dialog = null; + Frame parent = ownerless ? null : (initiallyOwnerIsActive? active : nonactive); + if (usual) { + dialog = new Dialog(parent, "Sample", true); + } else { + dialog = new FileDialog(parent, "Sample", FileDialog.LOAD); + } + dialog.addWindowListener(new WindowAdapter(){ + public void windowClosing(WindowEvent e){ + e.getWindow().dispose(); + } + }); + dialog.setBounds(200, 200, 200, 200); + dialog.setVisible(true); + } + }); + + active.add(button); + active.setBounds(200, 400, 200, 200); + WindowAdapter adapter = new WindowAdapter(){ + public void windowClosing(WindowEvent e){ + active.dispose(); + nonactive.dispose(); + synchronized(obj) { + obj.notify(); + } + } + }; + active.addWindowListener(adapter); + active.setVisible(true); + + nonactive.setBounds(400, 400, 200, 200); + nonactive.addWindowListener(adapter); + nonactive.setVisible(true); + + synchronized(obj) { + try{ + obj.wait(); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + Sysout.println(" completed. "); + + } + + /***************************************************** + * Standard Test Machinery Section + * DO NOT modify anything in this section -- it's a + * standard chunk of code which has all of the + * synchronisation necessary for the test harness. + * By keeping it the same in all tests, it is easier + * to read and understand someone else's test, as + * well as insuring that all tests behave correctly + * with the test harness. + * There is a section following this for test-defined + * classes + ******************************************************/ + private static boolean theTestPassed = false; + private static boolean testGeneratedInterrupt = false; + private static String failureMessage = ""; + + private static Thread mainThread = null; + + private static int sleepTime = 300000; + + public static void main( String args[] ) throws InterruptedException + { + mainThread = Thread.currentThread(); + try + { + init(); + } + catch( TestPassedException e ) + { + //The test passed, so just return from main and harness will + // interepret this return as a pass + return; + } + //At this point, neither test passed nor test failed has been + // called -- either would have thrown an exception and ended the + // test, so we know we have multiple threads. + + //Test involves other threads, so sleep and wait for them to + // called pass() or fail() + try + { + Thread.sleep( sleepTime ); + //Timed out, so fail the test + throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); + } + catch (InterruptedException e) + { + if( ! testGeneratedInterrupt ) throw e; + + //reset flag in case hit this code more than once for some reason (just safety) + testGeneratedInterrupt = false; + if ( theTestPassed == false ) + { + throw new RuntimeException( failureMessage ); + } + } + + }//main + + public static synchronized void setTimeoutTo( int seconds ) + { + sleepTime = seconds * 1000; + } + + public static synchronized void pass() + { + Sysout.println( "The test passed." ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //first check if this is executing in main thread + if ( mainThread == Thread.currentThread() ) + { + //Still in the main thread, so set the flag just for kicks, + // and throw a test passed exception which will be caught + // and end the test. + theTestPassed = true; + throw new TestPassedException(); + } + //pass was called from a different thread, so set the flag and interrupt + // the main thead. + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + }//pass() + + public static synchronized void fail() + { + //test writer didn't specify why test failed, so give generic + fail( "it just plain failed! :-)" ); + } + + public static synchronized void fail( String whyFailed ) + { + Sysout.println( "The test failed: " + whyFailed ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //check if this called from main thread + if ( mainThread == Thread.currentThread() ) + { + //If main thread, fail now 'cause not sleeping + throw new RuntimeException( whyFailed ); + } + theTestPassed = false; + testGeneratedInterrupt = true; + failureMessage = whyFailed; + mainThread.interrupt(); + }//fail() + +}// class ManualMainTest + +//This exception is used to exit from any level of call nesting +// when it's determined that the test has passed, and immediately +// end the test. +class TestPassedException extends RuntimeException +{ +} + +//*********** End Standard Test Machinery Section ********** + + +//************ Begin classes defined for the test **************** + +// make listeners in a class defined here, and instantiate them in init() + +/* Example of a class which may be written as part of a test +class NewClass implements anInterface + { + static int newVar = 0; + + public void eventDispatched(AWTEvent e) + { + //Counting events to see if we get enough + eventCount++; + + if( eventCount == 20 ) + { + //got enough events, so pass + + ManualMainTest.pass(); + } + else if( tries == 20 ) + { + //tried too many times without getting enough events so fail + + ManualMainTest.fail(); + } + + }// eventDispatched() + + }// NewClass class + +*/ + + +//************** End classes defined for the test ******************* + + + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout +{ + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn, true ); + } + + public static void print( String messageIn ) + { + dialog.displayMessage( messageIn, false ); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog implements ActionListener +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + Panel buttonP = new Panel(); + Button passB = new Button( "pass" ); + Button failB = new Button( "fail" ); + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + passB = new Button( "pass" ); + passB.setActionCommand( "pass" ); + passB.addActionListener( this ); + buttonP.add( "East", passB ); + + failB = new Button( "fail" ); + failB.setActionCommand( "fail" ); + failB.addActionListener( this ); + buttonP.add( "West", failB ); + + add( "South", buttonP ); + pack(); + + setVisible(true); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn, boolean nextLine ) + { + messageText.append( messageIn + (nextLine? "\n" : "") ); + System.out.println(messageIn); + } + + //catch presses of the passed and failed buttons. + //simply call the standard pass() or fail() static methods of + //ManualMainTest + public void actionPerformed( ActionEvent e ) + { + if( e.getActionCommand() == "pass" ) + { + CloseBlocker.pass(); + } + else + { + CloseBlocker.fail(); + } + } + +}// TestDialog class diff -r 94a4cf011510 -r a67fedfd0b21 jdk/test/java/awt/Modal/WsDisabledStyle/OverBlocker/OverBlocker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Modal/WsDisabledStyle/OverBlocker/OverBlocker.java Mon Mar 24 06:33:16 2008 -0700 @@ -0,0 +1,456 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test %I% %E% + @bug 4080029 + @summary Modal Dialog block input to all frame windows not just its parent. + @author dmitry.cherepanov: area=awt.modal + @run main/manual OverBlocker +*/ + +/** + * OverBlocker.java + * + * summary: The test verifies that if user tries to activate the blocked dialog + * then the blocker dialog appears over the other windows + */ + +import java.awt.*; +import java.awt.event.*; + +public class OverBlocker +{ + + private static void init() + { + //*** Create instructions for the user here *** + + String[] instructions = + { + " the test will be run 4 times, to start next test just close all ", + " windows of previous; the instructions are the same for all tests: ", + " 1) there is a frame with 'show modal' button, ", + " 2) press the button to show a dialog, ", + " 3) activate any non-Java application, move the app over the dialog, ", + " 4) click on the frame by mouse, ", + " 5) make sure that the dialog comes up from the application and ", + " now the dialog overlaps the app as well as the frame, ", + " if it's true, then the test passed, otherwise, it failed. ", + " Press 'pass' button only after all of the 4 tests are completed, ", + " the number of the currently executed test is displayed on the ", + " output window. " + }; + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + test(false, true); + test(true, true); + test(true, false); + test(false, false); + + }//End init() + + private static final Object obj = new Object(); + private static int counter = 0; + + /* + * The ownerless parameter indicates whether the blocker dialog + * has owner. The usual parameter indicates whether the blocker + * dialog is a Java dialog (non-native dialog like file dialog). + */ + private static void test(final boolean ownerless, final boolean usual) { + + Sysout.print(" * test #" + (++counter) + " is running ... "); + + final Frame frame = new Frame(); + Button button = new Button("show modal"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + Dialog dialog = null; + Frame parent = ownerless ? null : frame; + if (usual) { + dialog = new Dialog(parent, "Sample", true); + } else { + dialog = new FileDialog(parent, "Sample", FileDialog.LOAD); + } + dialog.addWindowListener(new WindowAdapter(){ + public void windowClosing(WindowEvent e){ + e.getWindow().dispose(); + } + }); + dialog.setBounds(200, 200, 200, 200); + dialog.setVisible(true); + } + }); + frame.add(button); + frame.setBounds(400, 400, 200, 200); + frame.addWindowListener(new WindowAdapter(){ + public void windowClosing(WindowEvent e){ + e.getWindow().dispose(); + synchronized(obj) { + obj.notify(); + } + } + }); + frame.setVisible(true); + + synchronized(obj) { + try{ + obj.wait(); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + Sysout.println(" completed. "); + + } + + /***************************************************** + * Standard Test Machinery Section + * DO NOT modify anything in this section -- it's a + * standard chunk of code which has all of the + * synchronisation necessary for the test harness. + * By keeping it the same in all tests, it is easier + * to read and understand someone else's test, as + * well as insuring that all tests behave correctly + * with the test harness. + * There is a section following this for test-defined + * classes + ******************************************************/ + private static boolean theTestPassed = false; + private static boolean testGeneratedInterrupt = false; + private static String failureMessage = ""; + + private static Thread mainThread = null; + + private static int sleepTime = 300000; + + public static void main( String args[] ) throws InterruptedException + { + mainThread = Thread.currentThread(); + try + { + init(); + } + catch( TestPassedException e ) + { + //The test passed, so just return from main and harness will + // interepret this return as a pass + return; + } + //At this point, neither test passed nor test failed has been + // called -- either would have thrown an exception and ended the + // test, so we know we have multiple threads. + + //Test involves other threads, so sleep and wait for them to + // called pass() or fail() + try + { + Thread.sleep( sleepTime ); + //Timed out, so fail the test + throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); + } + catch (InterruptedException e) + { + if( ! testGeneratedInterrupt ) throw e; + + //reset flag in case hit this code more than once for some reason (just safety) + testGeneratedInterrupt = false; + if ( theTestPassed == false ) + { + throw new RuntimeException( failureMessage ); + } + } + + }//main + + public static synchronized void setTimeoutTo( int seconds ) + { + sleepTime = seconds * 1000; + } + + public static synchronized void pass() + { + Sysout.println( "The test passed." ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //first check if this is executing in main thread + if ( mainThread == Thread.currentThread() ) + { + //Still in the main thread, so set the flag just for kicks, + // and throw a test passed exception which will be caught + // and end the test. + theTestPassed = true; + throw new TestPassedException(); + } + //pass was called from a different thread, so set the flag and interrupt + // the main thead. + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + }//pass() + + public static synchronized void fail() + { + //test writer didn't specify why test failed, so give generic + fail( "it just plain failed! :-)" ); + } + + public static synchronized void fail( String whyFailed ) + { + Sysout.println( "The test failed: " + whyFailed ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //check if this called from main thread + if ( mainThread == Thread.currentThread() ) + { + //If main thread, fail now 'cause not sleeping + throw new RuntimeException( whyFailed ); + } + theTestPassed = false; + testGeneratedInterrupt = true; + failureMessage = whyFailed; + mainThread.interrupt(); + }//fail() + +}// class ManualMainTest + +//This exception is used to exit from any level of call nesting +// when it's determined that the test has passed, and immediately +// end the test. +class TestPassedException extends RuntimeException +{ +} + +//*********** End Standard Test Machinery Section ********** + + +//************ Begin classes defined for the test **************** + +// make listeners in a class defined here, and instantiate them in init() + +/* Example of a class which may be written as part of a test +class NewClass implements anInterface + { + static int newVar = 0; + + public void eventDispatched(AWTEvent e) + { + //Counting events to see if we get enough + eventCount++; + + if( eventCount == 20 ) + { + //got enough events, so pass + + ManualMainTest.pass(); + } + else if( tries == 20 ) + { + //tried too many times without getting enough events so fail + + ManualMainTest.fail(); + } + + }// eventDispatched() + + }// NewClass class + +*/ + + +//************** End classes defined for the test ******************* + + + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout +{ + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn, true ); + } + + public static void print( String messageIn ) + { + dialog.displayMessage( messageIn, false ); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog implements ActionListener +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + Panel buttonP = new Panel(); + Button passB = new Button( "pass" ); + Button failB = new Button( "fail" ); + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + passB = new Button( "pass" ); + passB.setActionCommand( "pass" ); + passB.addActionListener( this ); + buttonP.add( "East", passB ); + + failB = new Button( "fail" ); + failB.setActionCommand( "fail" ); + failB.addActionListener( this ); + buttonP.add( "West", failB ); + + add( "South", buttonP ); + pack(); + + setVisible(true); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn, boolean nextLine ) + { + messageText.append( messageIn + (nextLine? "\n" : "") ); + System.out.println(messageIn); + } + + //catch presses of the passed and failed buttons. + //simply call the standard pass() or fail() static methods of + //ManualMainTest + public void actionPerformed( ActionEvent e ) + { + if( e.getActionCommand() == "pass" ) + { + OverBlocker.pass(); + } + else + { + OverBlocker.fail(); + } + } + +}// TestDialog class diff -r 94a4cf011510 -r a67fedfd0b21 jdk/test/java/awt/Modal/WsDisabledStyle/Winkey/Winkey.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Modal/WsDisabledStyle/Winkey/Winkey.java Mon Mar 24 06:33:16 2008 -0700 @@ -0,0 +1,403 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test %I% %E% + @bug 6572263 6571808 + @summary PIT:FileDialog minimized to taskbar(through 'Show Desktop')selecting the fileDialog using windowList + @author dmitry.cherepanov: area=awt.modal + @run main/manual Winkey +*/ + +/** + * Winkey.java + * + * summary: the test verifies that pressing combination of Windows key + * and M key to minimize all windows doesn't break AWT modality + */ + +import java.awt.*; +import java.awt.event.*; + +public class Winkey +{ + + private static void init() + { + //*** Create instructions for the user here *** + + String[] instructions = + { + " 1. there is a frame with a 'show modal' button, ", + " 2. press the button to show a modal dialog, ", + " 3. the modal dialog will be shown over the frame, ", + " 4. please verify that all (5.1, 5.2.1, 5.2.2) the following tests pass: ", + " ", + " 5.1. press combination Windows Key and M key to minimize all windows, ", + " 5.2. press combination Windows Key and D key to show desktop, ", + " 5.2.1. restore the dialog by choosing this one in the ALT-TAB list, ", + " 5.2.2. restore the dialog by mouse click on taskbar (on java or any other item)", + " ", + " 6. make sure that the dialog and the frame are visible, ", + " the bounds of the windows should be the same as before, ", + " if it's true, then the test passed; otherwise, it failed. " + }; + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + final Frame frame = new Frame(); + Button button = new Button("show modal"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + FileDialog dialog = new FileDialog((Frame)null, "Sample", FileDialog.LOAD); + dialog.setVisible(true); + } + }); + frame.add(button); + frame.setBounds(400, 400, 200, 200); + frame.setVisible(true); + + }//End init() + + /***************************************************** + * Standard Test Machinery Section + * DO NOT modify anything in this section -- it's a + * standard chunk of code which has all of the + * synchronisation necessary for the test harness. + * By keeping it the same in all tests, it is easier + * to read and understand someone else's test, as + * well as insuring that all tests behave correctly + * with the test harness. + * There is a section following this for test-defined + * classes + ******************************************************/ + private static boolean theTestPassed = false; + private static boolean testGeneratedInterrupt = false; + private static String failureMessage = ""; + + private static Thread mainThread = null; + + private static int sleepTime = 300000; + + public static void main( String args[] ) throws InterruptedException + { + mainThread = Thread.currentThread(); + try + { + init(); + } + catch( TestPassedException e ) + { + //The test passed, so just return from main and harness will + // interepret this return as a pass + return; + } + //At this point, neither test passed nor test failed has been + // called -- either would have thrown an exception and ended the + // test, so we know we have multiple threads. + + //Test involves other threads, so sleep and wait for them to + // called pass() or fail() + try + { + Thread.sleep( sleepTime ); + //Timed out, so fail the test + throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); + } + catch (InterruptedException e) + { + if( ! testGeneratedInterrupt ) throw e; + + //reset flag in case hit this code more than once for some reason (just safety) + testGeneratedInterrupt = false; + if ( theTestPassed == false ) + { + throw new RuntimeException( failureMessage ); + } + } + + }//main + + public static synchronized void setTimeoutTo( int seconds ) + { + sleepTime = seconds * 1000; + } + + public static synchronized void pass() + { + Sysout.println( "The test passed." ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //first check if this is executing in main thread + if ( mainThread == Thread.currentThread() ) + { + //Still in the main thread, so set the flag just for kicks, + // and throw a test passed exception which will be caught + // and end the test. + theTestPassed = true; + throw new TestPassedException(); + } + //pass was called from a different thread, so set the flag and interrupt + // the main thead. + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + }//pass() + + public static synchronized void fail() + { + //test writer didn't specify why test failed, so give generic + fail( "it just plain failed! :-)" ); + } + + public static synchronized void fail( String whyFailed ) + { + Sysout.println( "The test failed: " + whyFailed ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //check if this called from main thread + if ( mainThread == Thread.currentThread() ) + { + //If main thread, fail now 'cause not sleeping + throw new RuntimeException( whyFailed ); + } + theTestPassed = false; + testGeneratedInterrupt = true; + failureMessage = whyFailed; + mainThread.interrupt(); + }//fail() + +}// class ManualMainTest + +//This exception is used to exit from any level of call nesting +// when it's determined that the test has passed, and immediately +// end the test. +class TestPassedException extends RuntimeException +{ +} + +//*********** End Standard Test Machinery Section ********** + + +//************ Begin classes defined for the test **************** + +// make listeners in a class defined here, and instantiate them in init() + +/* Example of a class which may be written as part of a test +class NewClass implements anInterface + { + static int newVar = 0; + + public void eventDispatched(AWTEvent e) + { + //Counting events to see if we get enough + eventCount++; + + if( eventCount == 20 ) + { + //got enough events, so pass + + ManualMainTest.pass(); + } + else if( tries == 20 ) + { + //tried too many times without getting enough events so fail + + ManualMainTest.fail(); + } + + }// eventDispatched() + + }// NewClass class + +*/ + + +//************** End classes defined for the test ******************* + + + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout +{ + private static TestDialog dialog; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + dialog.displayMessage( messageIn ); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog implements ActionListener +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + Panel buttonP = new Panel(); + Button passB = new Button( "pass" ); + Button failB = new Button( "fail" ); + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + passB = new Button( "pass" ); + passB.setActionCommand( "pass" ); + passB.addActionListener( this ); + buttonP.add( "East", passB ); + + failB = new Button( "fail" ); + failB.setActionCommand( "fail" ); + failB.addActionListener( this ); + buttonP.add( "West", failB ); + + add( "South", buttonP ); + pack(); + + setVisible(true); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + System.out.println(messageIn); + } + + //catch presses of the passed and failed buttons. + //simply call the standard pass() or fail() static methods of + //ManualMainTest + public void actionPerformed( ActionEvent e ) + { + if( e.getActionCommand() == "pass" ) + { + Winkey.pass(); + } + else + { + Winkey.fail(); + } + } + +}// TestDialog class diff -r 94a4cf011510 -r a67fedfd0b21 jdk/test/java/awt/event/MouseEvent/SmoothWheel/SmoothWheel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/event/MouseEvent/SmoothWheel/SmoothWheel.java Mon Mar 24 06:33:16 2008 -0700 @@ -0,0 +1,432 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + @test %W% %E% %I%, %G% + @bug 6524352 + @summary support for high-resolution mouse wheel + @author dmitry cherepanov: area=awt.event + @run main/manual SmoothWheel +*/ + +/** + * SmoothWheel.java + * + * summary: + */ + +import java.awt.*; +import java.awt.event.*; + +public class SmoothWheel +{ + + //*** test-writer defined static variables go here *** + + + private static void init() + { + String[] instructions = + { + "1. the test is for high-resolution mouse wheel only, ", + " refer to the cr# 6524352 for more info about such devices, ", + "2. you'll see a frame, the frame contains a checkbox, ", + "3. initially, the state of the checkbox is off, ", + " use mouse wheel over the frame, ", + " and the frame will change its size gradually, ", + "4. turn on the checkbox, ", + " use mouse wheel again over the frame, ", + " now the frame will change its size smoothly, ", + "5. if the frame has always the same size or", + " if the frame changes its size equally in 3,4 cases, ", + " then the test failed. Otherwise, it passed." + }; + + Sysout.createDialog( ); + Sysout.printInstructions( instructions ); + + final Frame frame = new Frame(); + final Checkbox checkbox = new Checkbox("smooth wheel?"); + checkbox.setState(false); + + frame.setLayout (new FlowLayout()); + frame.add(checkbox); + + frame.addMouseWheelListener(new MouseWheelListener() { + public void mouseWheelMoved(MouseWheelEvent e) { + Sysout.println(e.toString()); + double wheelRotation = 0; + if (checkbox.getState()) { + wheelRotation = e.getPreciseWheelRotation(); + } else { + wheelRotation = e.getWheelRotation(); + } + Dimension size = frame.getSize(); + size.width += 10 * wheelRotation; + size.height += 10 * wheelRotation; + frame.setSize(size); + } + }); + + frame.setBounds(200, 200, 200, 200); + frame.setVisible(true); + + }//End init() + + + + /***************************************************** + * Standard Test Machinery Section + * DO NOT modify anything in this section -- it's a + * standard chunk of code which has all of the + * synchronisation necessary for the test harness. + * By keeping it the same in all tests, it is easier + * to read and understand someone else's test, as + * well as insuring that all tests behave correctly + * with the test harness. + * There is a section following this for test-defined + * classes + ******************************************************/ + private static boolean theTestPassed = false; + private static boolean testGeneratedInterrupt = false; + private static String failureMessage = ""; + + private static Thread mainThread = null; + + private static int sleepTime = 300000; + + public static void main( String args[] ) throws InterruptedException + { + mainThread = Thread.currentThread(); + try + { + init(); + } + catch( TestPassedException e ) + { + //The test passed, so just return from main and harness will + // interepret this return as a pass + return; + } + //At this point, neither test passed nor test failed has been + // called -- either would have thrown an exception and ended the + // test, so we know we have multiple threads. + + //Test involves other threads, so sleep and wait for them to + // called pass() or fail() + try + { + Thread.sleep( sleepTime ); + //Timed out, so fail the test + throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); + } + catch (InterruptedException e) + { + if( ! testGeneratedInterrupt ) throw e; + + //reset flag in case hit this code more than once for some reason (just safety) + testGeneratedInterrupt = false; + if ( theTestPassed == false ) + { + throw new RuntimeException( failureMessage ); + } + } + + }//main + + public static synchronized void setTimeoutTo( int seconds ) + { + sleepTime = seconds * 1000; + } + + public static synchronized void pass() + { + Sysout.println( "The test passed." ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //first check if this is executing in main thread + if ( mainThread == Thread.currentThread() ) + { + //Still in the main thread, so set the flag just for kicks, + // and throw a test passed exception which will be caught + // and end the test. + theTestPassed = true; + throw new TestPassedException(); + } + //pass was called from a different thread, so set the flag and interrupt + // the main thead. + theTestPassed = true; + testGeneratedInterrupt = true; + if (mainThread != null){ + mainThread.interrupt(); + } + }//pass() + + public static synchronized void fail() + { + //test writer didn't specify why test failed, so give generic + fail( "it just plain failed! :-)" ); + } + + public static synchronized void fail( String whyFailed ) + { + Sysout.println( "The test failed: " + whyFailed ); + Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); + //check if this called from main thread + if ( mainThread == Thread.currentThread() ) + { + //If main thread, fail now 'cause not sleeping + throw new RuntimeException( whyFailed ); + } + theTestPassed = false; + testGeneratedInterrupt = true; + failureMessage = whyFailed; + mainThread.interrupt(); + }//fail() + +}// class ManualMainTest + +//This exception is used to exit from any level of call nesting +// when it's determined that the test has passed, and immediately +// end the test. +class TestPassedException extends RuntimeException +{ +} + +//*********** End Standard Test Machinery Section ********** + + +//************ Begin classes defined for the test **************** + +// make listeners in a class defined here, and instantiate them in init() + +/* Example of a class which may be written as part of a test +class NewClass implements anInterface + { + static int newVar = 0; + + public void eventDispatched(AWTEvent e) + { + //Counting events to see if we get enough + eventCount++; + + if( eventCount == 20 ) + { + //got enough events, so pass + + ManualMainTest.pass(); + } + else if( tries == 20 ) + { + //tried too many times without getting enough events so fail + + ManualMainTest.fail(); + } + + }// eventDispatched() + + }// NewClass class + +*/ + + +//************** End classes defined for the test ******************* + + + + +/**************************************************** + Standard Test Machinery + DO NOT modify anything below -- it's a standard + chunk of code whose purpose is to make user + interaction uniform, and thereby make it simpler + to read and understand someone else's test. + ****************************************************/ + +/** + This is part of the standard test machinery. + It creates a dialog (with the instructions), and is the interface + for sending text messages to the user. + To print the instructions, send an array of strings to Sysout.createDialog + WithInstructions method. Put one line of instructions per array entry. + To display a message for the tester to see, simply call Sysout.println + with the string to be displayed. + This mimics System.out.println but works within the test harness as well + as standalone. + */ + +class Sysout +{ + private static TestDialog dialog; + private static boolean numbering = false; + private static int messageNumber = 0; + + public static void createDialogWithInstructions( String[] instructions ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + dialog.printInstructions( instructions ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + public static void createDialog( ) + { + dialog = new TestDialog( new Frame(), "Instructions" ); + String[] defInstr = { "Instructions will appear here. ", "" } ; + dialog.printInstructions( defInstr ); + dialog.setVisible(true); + println( "Any messages for the tester will display here." ); + } + + + /* Enables message counting for the tester. */ + public static void enableNumbering(boolean enable){ + numbering = enable; + } + + public static void printInstructions( String[] instructions ) + { + dialog.printInstructions( instructions ); + } + + + public static void println( String messageIn ) + { + if (numbering) { + messageIn = "" + messageNumber + " " + messageIn; + messageNumber++; + } + dialog.displayMessage( messageIn ); + } + +}// Sysout class + +/** + This is part of the standard test machinery. It provides a place for the + test instructions to be displayed, and a place for interactive messages + to the user to be displayed. + To have the test instructions displayed, see Sysout. + To have a message to the user be displayed, see Sysout. + Do not call anything in this dialog directly. + */ +class TestDialog extends Dialog implements ActionListener +{ + + TextArea instructionsText; + TextArea messageText; + int maxStringLength = 80; + Panel buttonP = new Panel(); + Button passB = new Button( "pass" ); + Button failB = new Button( "fail" ); + + //DO NOT call this directly, go through Sysout + public TestDialog( Frame frame, String name ) + { + super( frame, name ); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); + add( "North", instructionsText ); + + messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); + add("Center", messageText); + + passB = new Button( "pass" ); + passB.setActionCommand( "pass" ); + passB.addActionListener( this ); + buttonP.add( "East", passB ); + + failB = new Button( "fail" ); + failB.setActionCommand( "fail" ); + failB.addActionListener( this ); + buttonP.add( "West", failB ); + + add( "South", buttonP ); + pack(); + + setVisible(true); + }// TestDialog() + + //DO NOT call this directly, go through Sysout + public void printInstructions( String[] instructions ) + { + //Clear out any current instructions + instructionsText.setText( "" ); + + //Go down array of instruction strings + + String printStr, remainingStr; + for( int i=0; i < instructions.length; i++ ) + { + //chop up each into pieces maxSringLength long + remainingStr = instructions[ i ]; + while( remainingStr.length() > 0 ) + { + //if longer than max then chop off first max chars to print + if( remainingStr.length() >= maxStringLength ) + { + //Try to chop on a word boundary + int posOfSpace = remainingStr. + lastIndexOf( ' ', maxStringLength - 1 ); + + if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + + printStr = remainingStr.substring( 0, posOfSpace + 1 ); + remainingStr = remainingStr.substring( posOfSpace + 1 ); + } + //else just print + else + { + printStr = remainingStr; + remainingStr = ""; + } + + instructionsText.append( printStr + "\n" ); + + }// while + + }// for + + }//printInstructions() + + //DO NOT call this directly, go through Sysout + public void displayMessage( String messageIn ) + { + messageText.append( messageIn + "\n" ); + System.out.println(messageIn); + } + + //catch presses of the passed and failed buttons. + //simply call the standard pass() or fail() static methods of + //ManualMainTest + public void actionPerformed( ActionEvent e ) + { + if( e.getActionCommand() == "pass" ) + { + SmoothWheel.pass(); + } + else + { + SmoothWheel.fail(); + } + } + +}// TestDialog class