From 7628a594141102e8ed200ea483af496b024bdf9b Mon Sep 17 00:00:00 2001 From: Dmitry Cherepanov Date: Mon, 12 Oct 2009 19:07:43 +0400 Subject: [PATCH 01/13] 6796915: Deadlock in XAWT when switching virtual desktops Reviewed-by: art, anthony --- .../sun/awt/X11/XDropTargetRegistry.java | 88 +++++++++---------- .../classes/sun/awt/X11/XWindowPeer.java | 52 +++++++---- 2 files changed, 78 insertions(+), 62 deletions(-) diff --git a/jdk/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java b/jdk/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java index 1678d92a6bd..84f67fb01b2 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XDropTargetRegistry.java @@ -534,71 +534,71 @@ final class XDropTargetRegistry { return entry.getSite(x, y); } + /* + * Note: this method should be called under AWT lock. + */ public void registerDropSite(long window) { + assert XToolkit.isAWTLockHeldByCurrentThread(); + if (window == 0) { throw new IllegalArgumentException(); } XDropTargetEventProcessor.activate(); - XToolkit.awtLock(); - try { - long toplevel = getToplevelWindow(window); + long toplevel = getToplevelWindow(window); - /* - * No window with WM_STATE property is found. - * Since the window can be a plugin window reparented to the browser - * toplevel, we cannot determine which window will eventually have - * WM_STATE property set. So we schedule a timer callback that will - * periodically attempt to find an ancestor with WM_STATE and - * register the drop site appropriately. - */ - if (toplevel == 0) { - addDelayedRegistrationEntry(window); - return; + /* + * No window with WM_STATE property is found. + * Since the window can be a plugin window reparented to the browser + * toplevel, we cannot determine which window will eventually have + * WM_STATE property set. So we schedule a timer callback that will + * periodically attempt to find an ancestor with WM_STATE and + * register the drop site appropriately. + */ + if (toplevel == 0) { + addDelayedRegistrationEntry(window); + return; + } + + if (toplevel == window) { + Iterator dropTargetProtocols = + XDragAndDropProtocols.getDropTargetProtocols(); + + while (dropTargetProtocols.hasNext()) { + XDropTargetProtocol dropTargetProtocol = + (XDropTargetProtocol)dropTargetProtocols.next(); + dropTargetProtocol.registerDropTarget(toplevel); } - - if (toplevel == window) { - Iterator dropTargetProtocols = - XDragAndDropProtocols.getDropTargetProtocols(); - - while (dropTargetProtocols.hasNext()) { - XDropTargetProtocol dropTargetProtocol = - (XDropTargetProtocol)dropTargetProtocols.next(); - dropTargetProtocol.registerDropTarget(toplevel); - } - } else { - registerEmbeddedDropSite(toplevel, window); - } - } finally { - XToolkit.awtUnlock(); + } else { + registerEmbeddedDropSite(toplevel, window); } } + /* + * Note: this method should be called under AWT lock. + */ public void unregisterDropSite(long window) { + assert XToolkit.isAWTLockHeldByCurrentThread(); + if (window == 0) { throw new IllegalArgumentException(); } - XToolkit.awtLock(); - try { - long toplevel = getToplevelWindow(window); + long toplevel = getToplevelWindow(window); - if (toplevel == window) { - Iterator dropProtocols = - XDragAndDropProtocols.getDropTargetProtocols(); + if (toplevel == window) { + Iterator dropProtocols = + XDragAndDropProtocols.getDropTargetProtocols(); - removeDelayedRegistrationEntry(window); + removeDelayedRegistrationEntry(window); - while (dropProtocols.hasNext()) { - XDropTargetProtocol dropProtocol = (XDropTargetProtocol)dropProtocols.next(); - dropProtocol.unregisterDropTarget(window); - } - } else { - unregisterEmbeddedDropSite(toplevel, window); + while (dropProtocols.hasNext()) { + XDropTargetProtocol dropProtocol = (XDropTargetProtocol)dropProtocols.next(); + dropProtocol.unregisterDropTarget(window); } - } finally { - XToolkit.awtUnlock(); + } else { + unregisterEmbeddedDropSite(toplevel, window); } } diff --git a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java index b1646413b79..076526fd653 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java @@ -1757,25 +1757,36 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, } } + // should be synchronized on awtLock private int dropTargetCount = 0; - public synchronized void addDropTarget() { - if (dropTargetCount == 0) { - long window = getWindow(); - if (window != 0) { - XDropTargetRegistry.getRegistry().registerDropSite(window); + public void addDropTarget() { + XToolkit.awtLock(); + try { + if (dropTargetCount == 0) { + long window = getWindow(); + if (window != 0) { + XDropTargetRegistry.getRegistry().registerDropSite(window); + } } + dropTargetCount++; + } finally { + XToolkit.awtUnlock(); } - dropTargetCount++; } - public synchronized void removeDropTarget() { - dropTargetCount--; - if (dropTargetCount == 0) { - long window = getWindow(); - if (window != 0) { - XDropTargetRegistry.getRegistry().unregisterDropSite(window); + public void removeDropTarget() { + XToolkit.awtLock(); + try { + dropTargetCount--; + if (dropTargetCount == 0) { + long window = getWindow(); + if (window != 0) { + XDropTargetRegistry.getRegistry().unregisterDropSite(window); + } } + } finally { + XToolkit.awtUnlock(); } } void addRootPropertyEventDispatcher() { @@ -1838,13 +1849,18 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, } } - protected synchronized void updateDropTarget() { - if (dropTargetCount > 0) { - long window = getWindow(); - if (window != 0) { - XDropTargetRegistry.getRegistry().unregisterDropSite(window); - XDropTargetRegistry.getRegistry().registerDropSite(window); + protected void updateDropTarget() { + XToolkit.awtLock(); + try { + if (dropTargetCount > 0) { + long window = getWindow(); + if (window != 0) { + XDropTargetRegistry.getRegistry().unregisterDropSite(window); + XDropTargetRegistry.getRegistry().registerDropSite(window); + } } + } finally { + XToolkit.awtUnlock(); } } From 99d8a50297bb8489d0b11b4dc6a452d9f64f021b Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Wed, 14 Oct 2009 15:46:13 +0400 Subject: [PATCH 02/13] 6684916: jframe.setMaximizedBounds() has no effect in linux Specification should indicate that the feature may be unsupported on some platforms. Reviewed-by: art, dcherepanov --- jdk/src/share/classes/java/awt/Frame.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/java/awt/Frame.java b/jdk/src/share/classes/java/awt/Frame.java index 761b9b8420b..ea8c6154cf1 100644 --- a/jdk/src/share/classes/java/awt/Frame.java +++ b/jdk/src/share/classes/java/awt/Frame.java @@ -845,8 +845,11 @@ public class Frame extends Window implements MenuContainer { * others by setting those fields you want to accept from system * to Integer.MAX_VALUE. *

- * On some systems only the size portion of the bounds is taken - * into account. + * Note, the given maximized bounds are used as a hint for the native + * system, because the underlying platform may not support setting the + * location and/or size of the maximized windows. If that is the case, the + * provided values do not affect the appearance of the frame in the + * maximized state. * * @param bounds bounds for the maximized state * @see #getMaximizedBounds() From 370b3a923b84cc59cf3258544c25b31ed0ceeac0 Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Wed, 14 Oct 2009 16:19:46 +0400 Subject: [PATCH 03/13] 6711717: PIT: Security Icon is hidden for FullScreen apps, WinXP Force hiding the security warning in FS exclusive mode. Reviewed-by: art, tdv --- .../share/classes/java/awt/AWTPermission.java | 12 ++++- .../solaris/classes/sun/awt/X11/XWindow.java | 20 ++++++++ .../classes/sun/awt/X11/XWindowPeer.java | 38 ++++++++------ .../classes/sun/awt/X11ComponentPeer.java | 3 +- .../classes/sun/awt/X11GraphicsDevice.java | 4 +- .../classes/sun/awt/Win32GraphicsDevice.java | 16 +++--- .../classes/sun/awt/windows/WWindowPeer.java | 3 ++ .../windows/native/sun/windows/awt_Window.cpp | 51 ++++++++++++++++++- .../windows/native/sun/windows/awt_Window.h | 11 ++++ 9 files changed, 132 insertions(+), 26 deletions(-) diff --git a/jdk/src/share/classes/java/awt/AWTPermission.java b/jdk/src/share/classes/java/awt/AWTPermission.java index b6eb03f62c7..84b400f53d9 100644 --- a/jdk/src/share/classes/java/awt/AWTPermission.java +++ b/jdk/src/share/classes/java/awt/AWTPermission.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 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,7 +92,15 @@ import java.security.BasicPermission; * Enter full-screen exclusive mode * Entering full-screen exclusive mode allows direct access to * low-level graphics card memory. This could be used to spoof the - * system, since the program is in direct control of rendering. + * system, since the program is in direct control of rendering. Depending on + * the implementation, the security warning may not be shown for the windows + * used to enter the full-screen exclusive mode (assuming that the {@code + * fullScreenExclusive} permission has been granted to this application). Note + * that this behavior does not mean that the {@code + * showWindowWithoutWarningBanner} permission will be automatically granted to + * the application which has the {@code fullScreenExclusive} permission: + * non-full-screen windows will continue to be shown with the security + * warning. * * * diff --git a/jdk/src/solaris/classes/sun/awt/X11/XWindow.java b/jdk/src/solaris/classes/sun/awt/X11/XWindow.java index f1c3c675b6c..9081aa5e545 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XWindow.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindow.java @@ -1510,4 +1510,24 @@ public class XWindow extends XBaseWindow implements X11ComponentPeer { return new XAtomList(); } + /** + * Indicates if the window is currently in the FSEM. + * Synchronization: state lock. + */ + private boolean fullScreenExclusiveModeState = false; + + // Implementation of the X11ComponentPeer + @Override + public void setFullScreenExclusiveModeState(boolean state) { + synchronized (getStateLock()) { + fullScreenExclusiveModeState = state; + } + } + + public final boolean isFullScreenExclusiveMode() { + synchronized (getStateLock()) { + return fullScreenExclusiveModeState; + } + } + } diff --git a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java index 076526fd653..51c55b96c2b 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java @@ -1080,31 +1080,39 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, updateSecurityWarningVisibility(); } + @Override + public void setFullScreenExclusiveModeState(boolean state) { + super.setFullScreenExclusiveModeState(state); + updateSecurityWarningVisibility(); + } + public void updateSecurityWarningVisibility() { if (warningWindow == null) { return; } - boolean show = false; - - int state = getWMState(); - if (!isVisible()) { return; // The warning window should already be hidden. } - // getWMState() always returns 0 (Withdrawn) for simple windows. Hence - // we ignore the state for such windows. - if (isVisible() && (state == XUtilConstants.NormalState || isSimpleWindow())) { - if (XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow() == - getTarget()) - { - show = true; - } + boolean show = false; - if (isMouseAbove() || warningWindow.isMouseAbove()) - { - show = true; + if (!isFullScreenExclusiveMode()) { + int state = getWMState(); + + // getWMState() always returns 0 (Withdrawn) for simple windows. Hence + // we ignore the state for such windows. + if (isVisible() && (state == XUtilConstants.NormalState || isSimpleWindow())) { + if (XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow() == + getTarget()) + { + show = true; + } + + if (isMouseAbove() || warningWindow.isMouseAbove()) + { + show = true; + } } } diff --git a/jdk/src/solaris/classes/sun/awt/X11ComponentPeer.java b/jdk/src/solaris/classes/sun/awt/X11ComponentPeer.java index a4a07506894..24b24809285 100644 --- a/jdk/src/solaris/classes/sun/awt/X11ComponentPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11ComponentPeer.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 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,4 +39,5 @@ public interface X11ComponentPeer { Rectangle getBounds(); Graphics getGraphics(); Object getTarget(); + void setFullScreenExclusiveModeState(boolean state); } diff --git a/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java b/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java index ed495b177ec..a009a16e234 100644 --- a/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java +++ b/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 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 @@ -306,12 +306,14 @@ public class X11GraphicsDevice X11ComponentPeer peer = (X11ComponentPeer)w.getPeer(); if (peer != null) { enterFullScreenExclusive(peer.getContentWindow()); + peer.setFullScreenExclusiveModeState(true); } } private static void exitFullScreenExclusive(Window w) { X11ComponentPeer peer = (X11ComponentPeer)w.getPeer(); if (peer != null) { + peer.setFullScreenExclusiveModeState(false); exitFullScreenExclusive(peer.getContentWindow()); } } diff --git a/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java b/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java index 1da339ce9f1..7d8c17e6987 100644 --- a/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java +++ b/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java @@ -353,6 +353,7 @@ public class Win32GraphicsDevice extends GraphicsDevice implements } WWindowPeer peer = (WWindowPeer)old.getPeer(); if (peer != null) { + peer.setFullScreenExclusiveModeState(false); // we used to destroy the buffers on exiting fs mode, this // is no longer needed since fs change will cause a surface // data replacement @@ -370,12 +371,15 @@ public class Win32GraphicsDevice extends GraphicsDevice implements addFSWindowListener(w); // Enter full screen exclusive mode. WWindowPeer peer = (WWindowPeer)w.getPeer(); - synchronized(peer) { - enterFullScreenExclusive(screen, peer); - // Note: removed replaceSurfaceData() call because - // changing the window size or making it visible - // will cause this anyway, and both of these events happen - // as part of switching into fullscreen mode. + if (peer != null) { + synchronized(peer) { + enterFullScreenExclusive(screen, peer); + // Note: removed replaceSurfaceData() call because + // changing the window size or making it visible + // will cause this anyway, and both of these events happen + // as part of switching into fullscreen mode. + } + peer.setFullScreenExclusiveModeState(true); } // fix for 4868278 diff --git a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java index fbb7442ba7d..3f11839e8cc 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java @@ -510,6 +510,9 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer, private native int getScreenImOn(); + // Used in Win32GraphicsDevice. + public final native void setFullScreenExclusiveModeState(boolean state); + /* * ----END DISPLAY CHANGE SUPPORT---- */ diff --git a/jdk/src/windows/native/sun/windows/awt_Window.cpp b/jdk/src/windows/native/sun/windows/awt_Window.cpp index 4c902c3fb47..8bb5c900219 100644 --- a/jdk/src/windows/native/sun/windows/awt_Window.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Window.cpp @@ -143,6 +143,11 @@ struct RepositionSecurityWarningStruct { jobject window; }; +struct SetFullScreenExclusiveModeStateStruct { + jobject window; + jboolean isFSEMState; +}; + /************************************************************************ * AwtWindow fields @@ -915,7 +920,9 @@ void AwtWindow::UpdateSecurityWarningVisibility() bool show = false; - if (IsVisible() && currentWmSizeState != SIZE_MINIMIZED) { + if (IsVisible() && currentWmSizeState != SIZE_MINIMIZED && + !isFullScreenExclusiveMode()) + { if (AwtComponent::GetFocusedWindow() == GetHWnd()) { show = true; } @@ -2954,6 +2961,25 @@ void AwtWindow::_UpdateWindow(void* param) delete uws; } +void AwtWindow::_SetFullScreenExclusiveModeState(void *param) +{ + JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); + + SetFullScreenExclusiveModeStateStruct * data = + (SetFullScreenExclusiveModeStateStruct*)param; + jobject self = data->window; + jboolean state = data->isFSEMState; + + PDATA pData; + JNI_CHECK_PEER_GOTO(self, ret); + AwtWindow *window = (AwtWindow *)pData; + + window->setFullScreenExclusiveModeState(state != 0); + + ret: + env->DeleteGlobalRef(self); + delete data; +} extern "C" { @@ -3333,6 +3359,29 @@ Java_sun_awt_windows_WWindowPeer_getScreenImOn(JNIEnv *env, jobject self) CATCH_BAD_ALLOC_RET(-1); } +/* + * Class: sun_awt_windows_WWindowPeer + * Method: setFullScreenExclusiveModeState + * Signature: (Z)V + */ +JNIEXPORT void JNICALL +Java_sun_awt_windows_WWindowPeer_setFullScreenExclusiveModeState(JNIEnv *env, + jobject self, jboolean state) +{ + TRY; + + SetFullScreenExclusiveModeStateStruct *data = + new SetFullScreenExclusiveModeStateStruct; + data->window = env->NewGlobalRef(self); + data->isFSEMState = state; + + AwtToolkit::GetInstance().SyncCall( + AwtWindow::_SetFullScreenExclusiveModeState, data); + // global ref and data are deleted in the invoked method + + CATCH_BAD_ALLOC; +} + /* * Class: sun_awt_windows_WWindowPeer * Method: modalDisable diff --git a/jdk/src/windows/native/sun/windows/awt_Window.h b/jdk/src/windows/native/sun/windows/awt_Window.h index 1d238b44dac..001062835e3 100644 --- a/jdk/src/windows/native/sun/windows/awt_Window.h +++ b/jdk/src/windows/native/sun/windows/awt_Window.h @@ -229,6 +229,7 @@ public: static void _SetOpaque(void* param); static void _UpdateWindow(void* param); static void _RepositionSecurityWarning(void* param); + static void _SetFullScreenExclusiveModeState(void* param); inline static BOOL IsResizing() { return sm_resizing; @@ -331,6 +332,16 @@ private: static void SetLayered(HWND window, bool layered); static bool IsLayered(HWND window); + BOOL fullScreenExclusiveModeState; + inline void setFullScreenExclusiveModeState(BOOL isEntered) { + fullScreenExclusiveModeState = isEntered; + UpdateSecurityWarningVisibility(); + } + inline BOOL isFullScreenExclusiveMode() { + return fullScreenExclusiveModeState; + } + + public: void UpdateSecurityWarningVisibility(); static bool IsWarningWindow(HWND hWnd); From b32d27a2532735a5508ec748c0e530bdee7f7fd0 Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Wed, 14 Oct 2009 16:32:38 +0400 Subject: [PATCH 04/13] 6885735: closed/java/awt/Component/DisablingLWDisabledHW/DisablingLWDisabledHW.html fails Use isRecursivelyVisibleUpToHeavyweightContainer() instead of isRecursivelyVisible() to determine if the peer needs to be hidden. Reviewed-by: art, dcherepanov --- jdk/src/share/classes/java/awt/Component.java | 11 +++++----- jdk/src/share/classes/java/awt/Container.java | 21 +++++++++++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/jdk/src/share/classes/java/awt/Component.java b/jdk/src/share/classes/java/awt/Component.java index 59a43e7fe80..2c1d08596be 100644 --- a/jdk/src/share/classes/java/awt/Component.java +++ b/jdk/src/share/classes/java/awt/Component.java @@ -6720,12 +6720,13 @@ public abstract class Component implements ImageObserver, MenuContainer, } } } else { - // It's native. If the parent is lightweight it - // will need some help. - Container parent = this.parent; - if (parent != null && parent.peer instanceof LightweightPeer) { + // It's native. If the parent is lightweight it will need some + // help. + Container parent = getContainer(); + if (parent != null && parent.isLightweight()) { relocateComponent(); - if (!isRecursivelyVisible()) { + if (!parent.isRecursivelyVisibleUpToHeavyweightContainer()) + { peer.setVisible(false); } } diff --git a/jdk/src/share/classes/java/awt/Container.java b/jdk/src/share/classes/java/awt/Container.java index e3372409c06..5d4e95d9df5 100644 --- a/jdk/src/share/classes/java/awt/Container.java +++ b/jdk/src/share/classes/java/awt/Container.java @@ -4092,16 +4092,29 @@ public class Container extends Component { } } - /* + /** + * Checks if the container and its direct lightweight containers are + * visible. + * * Consider the heavyweight container hides or shows the HW descendants * automatically. Therefore we care of LW containers' visibility only. + * + * This method MUST be invoked under the TreeLock. */ - private boolean isRecursivelyVisibleUpToHeavyweightContainer() { + final boolean isRecursivelyVisibleUpToHeavyweightContainer() { if (!isLightweight()) { return true; } - return isVisible() && (getContainer() == null || - getContainer().isRecursivelyVisibleUpToHeavyweightContainer()); + + for (Container cont = getContainer(); + cont != null && cont.isLightweight(); + cont = cont.getContainer()) + { + if (!cont.isVisible()) { + return false; + } + } + return true; } @Override From e507e02d67793bcadc4a527adccd2f5aa1190a6d Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Wed, 14 Oct 2009 19:23:15 +0400 Subject: [PATCH 05/13] 6884960: java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java fails Support painting heavyweight components in transparent windows. Reviewed-by: art, alexp --- .../share/classes/javax/swing/JComponent.java | 20 +++++++++---- .../sun/awt/windows/WComponentPeer.java | 28 ++++++++++++++++++- .../classes/sun/awt/windows/WWindowPeer.java | 8 +++++- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/JComponent.java b/jdk/src/share/classes/javax/swing/JComponent.java index f0be74509f9..6c97ebd5e71 100644 --- a/jdk/src/share/classes/javax/swing/JComponent.java +++ b/jdk/src/share/classes/javax/swing/JComponent.java @@ -795,7 +795,6 @@ public abstract class JComponent extends Container implements Serializable, * @see java.awt.Container#paint */ protected void paintChildren(Graphics g) { - boolean isJComponent; Graphics sg = g; synchronized(getTreeLock()) { @@ -826,12 +825,21 @@ public abstract class JComponent extends Container implements Serializable, } } boolean printing = getFlag(IS_PRINTING); + final Window window = SwingUtilities.getWindowAncestor(this); + final boolean isWindowOpaque = window == null || window.isOpaque(); for (; i >= 0 ; i--) { Component comp = getComponent(i); - isJComponent = (comp instanceof JComponent); - if (comp != null && - (isJComponent || isLightweightComponent(comp)) && - (comp.isVisible() == true)) { + if (comp == null) { + continue; + } + + final boolean isJComponent = comp instanceof JComponent; + + // Enable painting of heavyweights in non-opaque windows. + // See 6884960 + if ((!isWindowOpaque || isJComponent || + isLightweightComponent(comp)) && comp.isVisible()) + { Rectangle cr; cr = comp.getBounds(tmpRect); @@ -887,6 +895,8 @@ public abstract class JComponent extends Container implements Serializable, } } } else { + // The component is either lightweight, or + // heavyweight in a non-opaque window if (!printing) { comp.paint(cg); } diff --git a/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java b/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java index 04b3e99c26b..66ec4558f1e 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java @@ -551,8 +551,34 @@ public abstract class WComponentPeer extends WObjectPeer final static Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); public Graphics getGraphics() { + if (isDisposed()) { + return null; + } + + Component target = (Component)getTarget(); + Window window = SunToolkit.getContainingWindow(target); + if (window != null && !window.isOpaque()) { + // Non-opaque windows do not support heavyweight children. + // Redirect all painting to the Window's Graphics instead. + // The caller is responsible for calling the + // WindowPeer.updateWindow() after painting has finished. + int x = 0, y = 0; + for (Component c = target; c != window; c = c.getParent()) { + x += c.getX(); + y += c.getY(); + } + + Graphics g = + ((WWindowPeer)window.getPeer()).getTranslucentGraphics(); + + g.translate(x, y); + g.clipRect(0, 0, target.getWidth(), target.getHeight()); + + return g; + } + SurfaceData surfaceData = this.surfaceData; - if (!isDisposed() && surfaceData != null) { + if (surfaceData != null) { /* Fix for bug 4746122. Color and Font shouldn't be null */ Color bgColor = background; if (bgColor == null) { diff --git a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java index 3f11839e8cc..26fe048cdca 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java +++ b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java @@ -578,11 +578,17 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer, } } + public final Graphics getTranslucentGraphics() { + synchronized (getStateLock()) { + return isOpaque ? null : painter.getBackBuffer(false).getGraphics(); + } + } + @Override public Graphics getGraphics() { synchronized (getStateLock()) { if (!isOpaque) { - return painter.getBackBuffer(false).getGraphics(); + return getTranslucentGraphics(); } } return super.getGraphics(); From a77b6a72e03c2b151af3ecab5e73c1c759fd46ad Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Mon, 19 Oct 2009 16:06:41 +0400 Subject: [PATCH 06/13] 6891483: XToolkit.getEnv() checks for NULL on a wrong symbol Reviewed-by: dcherepanov --- jdk/src/solaris/native/sun/xawt/XToolkit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/solaris/native/sun/xawt/XToolkit.c b/jdk/src/solaris/native/sun/xawt/XToolkit.c index 6ce5876c544..a4323b31995 100644 --- a/jdk/src/solaris/native/sun/xawt/XToolkit.c +++ b/jdk/src/solaris/native/sun/xawt/XToolkit.c @@ -677,7 +677,7 @@ JNIEXPORT jstring JNICALL Java_sun_awt_X11_XToolkit_getEnv jstring ret = NULL; keystr = JNU_GetStringPlatformChars(env, key, NULL); - if (key) { + if (keystr) { ptr = getenv(keystr); if (ptr) { ret = JNU_NewStringPlatform(env, (const char *) ptr); From b50342c24e1b9b32b9fa5d747efa9e688a27adaf Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Wed, 21 Oct 2009 17:06:41 +0400 Subject: [PATCH 07/13] 6852592: invalidate() must be smarter Introduce validate roots in AWT Reviewed-by: alexp, art, dcherepanov --- jdk/src/share/classes/java/applet/Applet.java | 15 ++ jdk/src/share/classes/java/awt/Component.java | 40 ++++- jdk/src/share/classes/java/awt/Container.java | 144 ++++++++++++++---- jdk/src/share/classes/java/awt/Window.java | 19 ++- .../share/classes/javax/swing/JComponent.java | 2 + .../share/classes/javax/swing/JRootPane.java | 2 + .../classes/javax/swing/JScrollPane.java | 2 + .../share/classes/javax/swing/JSplitPane.java | 2 + .../share/classes/javax/swing/JTextField.java | 2 + .../share/classes/javax/swing/JViewport.java | 39 +---- .../classes/javax/swing/RepaintManager.java | 38 +---- .../classes/javax/swing/SwingUtilities.java | 50 ++++++ .../InvalidateMustRespectValidateRoots.java | 114 ++++++++++++++ 13 files changed, 355 insertions(+), 114 deletions(-) create mode 100644 jdk/test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java diff --git a/jdk/src/share/classes/java/applet/Applet.java b/jdk/src/share/classes/java/applet/Applet.java index 0e2bcb87b56..b12e6fb3081 100644 --- a/jdk/src/share/classes/java/applet/Applet.java +++ b/jdk/src/share/classes/java/applet/Applet.java @@ -229,6 +229,21 @@ public class Applet extends Panel { resize(d.width, d.height); } + /** + * Indicates if this container is a validate root. + *

+ * {@code Applet} objects are the validate roots, and, therefore, they + * override this method to return {@code true}. + * + * @return {@code true} + * @since 1.7 + * @see java.awt.Container#isValidateRoot + */ + @Override + public boolean isValidateRoot() { + return true; + } + /** * Requests that the argument string be displayed in the * "status window". Many browsers and applet viewers diff --git a/jdk/src/share/classes/java/awt/Component.java b/jdk/src/share/classes/java/awt/Component.java index 42093d16c9c..6a942e9ec5d 100644 --- a/jdk/src/share/classes/java/awt/Component.java +++ b/jdk/src/share/classes/java/awt/Component.java @@ -2764,8 +2764,11 @@ public abstract class Component implements ImageObserver, MenuContainer, } /** - * Ensures that this component has a valid layout. This method is - * primarily intended to operate on instances of Container. + * Validates this component. + *

+ * The meaning of the term validating is defined by the ancestors of + * this class. See {@link Container#validate} for more details. + * * @see #invalidate * @see #doLayout() * @see LayoutManager @@ -2794,12 +2797,24 @@ public abstract class Component implements ImageObserver, MenuContainer, } /** - * Invalidates this component. This component and all parents - * above it are marked as needing to be laid out. This method can - * be called often, so it needs to execute quickly. + * Invalidates this component and its ancestors. + *

+ * All the ancestors of this component up to the nearest validate root are + * marked invalid also. If there is no a validate root container for this + * component, all of its ancestors up to the root of the hierarchy are + * marked invalid as well. Marking a container invalid indicates + * that the container needs to be laid out. + *

+ * This method is called automatically when any layout-related information + * changes (e.g. setting the bounds of the component, or adding the + * component to a container). + *

+ * This method might be called often, so it should work fast. + * * @see #validate * @see #doLayout * @see LayoutManager + * @see java.awt.Container#isValidateRoot * @since JDK1.0 */ public void invalidate() { @@ -2818,9 +2833,18 @@ public abstract class Component implements ImageObserver, MenuContainer, if (!isMaximumSizeSet()) { maxSize = null; } - if (parent != null) { - parent.invalidateIfValid(); - } + invalidateParent(); + } + } + + /** + * Invalidates the parent of this component if any. + * + * This method MUST BE invoked under the TreeLock. + */ + void invalidateParent() { + if (parent != null) { + parent.invalidateIfValid(); } } diff --git a/jdk/src/share/classes/java/awt/Container.java b/jdk/src/share/classes/java/awt/Container.java index 706cffa89dc..84334c9973e 100644 --- a/jdk/src/share/classes/java/awt/Container.java +++ b/jdk/src/share/classes/java/awt/Container.java @@ -1492,20 +1492,59 @@ public class Container extends Component { } /** - * Invalidates the container. The container and all parents - * above it are marked as needing to be laid out. This method can - * be called often, so it needs to execute quickly. + * Indicates if this container is a validate root. + *

+ * Layout-related changes, such as bounds of the validate root descendants, + * do not affect the layout of the validate root parent. This peculiarity + * enables the {@code invalidate()} method to stop invalidating the + * component hierarchy when the method encounters a validate root. + *

+ * If a component hierarchy contains validate roots, the {@code validate()} + * method must be invoked on the validate root of a previously invalidated + * component, rather than on the top-level container (such as a {@code + * Frame} object) to restore the validity of the hierarchy later. + *

+ * The {@code Window} class and the {@code Applet} class are the validate + * roots in AWT. Swing introduces more validate roots. * - *

If the {@code LayoutManager} installed on this container is - * an instance of {@code LayoutManager2}, then - * {@link LayoutManager2#invalidateLayout(Container)} is invoked on - * it supplying this {@code Container} as the argument. + * @return whether this container is a validate root + * @see #invalidate + * @see java.awt.Component#invalidate + * @see javax.swing.JComponent#isValidateRoot + * @see javax.swing.JComponent#revalidate + * @since 1.7 + */ + public boolean isValidateRoot() { + return false; + } + + /** + * Invalidates the parent of the container unless the container + * is a validate root. + */ + @Override + void invalidateParent() { + if (!isValidateRoot()) { + super.invalidateParent(); + } + } + + /** + * Invalidates the container. + *

+ * If the {@code LayoutManager} installed on this container is an instance + * of the {@code LayoutManager2} interface, then + * the {@link LayoutManager2#invalidateLayout(Container)} method is invoked + * on it supplying this {@code Container} as the argument. + *

+ * Afterwards this method marks this container invalid, and invalidates its + * ancestors. See the {@link Component#invalidate} method for more details. * * @see #validate * @see #layout - * @see LayoutManager - * @see LayoutManager2#invalidateLayout(Container) + * @see LayoutManager2 */ + @Override public void invalidate() { LayoutManager layoutMgr = this.layoutMgr; if (layoutMgr instanceof LayoutManager2) { @@ -1518,35 +1557,39 @@ public class Container extends Component { /** * Validates this container and all of its subcomponents. *

- * The validate method is used to cause a container - * to lay out its subcomponents again. It should be invoked when - * this container's subcomponents are modified (added to or - * removed from the container, or layout-related information - * changed) after the container has been displayed. - * - *

If this {@code Container} is not valid, this method invokes + * Validating a container means laying out its subcomponents. + * Layout-related changes, such as setting the bounds of a component, or + * adding a component to the container, invalidate the container + * automatically. Note that the ancestors of the container may be + * invalidated also (see {@link Component#invalidate} for details.) + * Therefore, to restore the validity of the hierarchy, the {@code + * validate()} method should be invoked on a validate root of an + * invalidated component, or on the top-most container if the hierarchy + * does not contain validate roots. + *

+ * Validating the container may be a quite time-consuming operation. For + * performance reasons a developer may postpone the validation of the + * hierarchy till a set of layout-related operations completes, e.g. after + * adding all the children to the container. + *

+ * If this {@code Container} is not valid, this method invokes * the {@code validateTree} method and marks this {@code Container} * as valid. Otherwise, no action is performed. - *

- * Note that the {@code invalidate()} method may invalidate not only the - * component it is called upon, but also the parents of the component. - * Therefore, to restore the validity of the hierarchy, the {@code - * validate()} method must be invoked on the top-most invalid container of - * the hierarchy. For performance reasons a developer may postpone the - * validation of the hierarchy till a bunch of layout-related operations - * completes, e.g. after adding all the children to the container. * * @see #add(java.awt.Component) * @see #invalidate + * @see Container#isValidateRoot * @see javax.swing.JComponent#revalidate() * @see #validateTree */ public void validate() { /* Avoid grabbing lock unless really necessary. */ - if (!isValid()) { + if (!isValid() || descendUnconditionallyWhenValidating) { boolean updateCur = false; synchronized (getTreeLock()) { - if (!isValid() && peer != null) { + if ((!isValid() || descendUnconditionallyWhenValidating) + && peer != null) + { ContainerPeer p = null; if (peer instanceof ContainerPeer) { p = (ContainerPeer) peer; @@ -1557,7 +1600,11 @@ public class Container extends Component { validateTree(); if (p != null) { p.endValidate(); - updateCur = isVisible(); + // Avoid updating cursor if this is an internal call. + // See validateUnconditionally() for details. + if (!descendUnconditionallyWhenValidating) { + updateCur = isVisible(); + } } } } @@ -1567,6 +1614,39 @@ public class Container extends Component { } } + /** + * Indicates whether valid containers should also traverse their + * children and call the validateTree() method on them. + * + * Synchronization: TreeLock. + * + * The field is allowed to be static as long as the TreeLock itself is + * static. + * + * @see #validateUnconditionally() + */ + private static boolean descendUnconditionallyWhenValidating = false; + + /** + * Unconditionally validate the component hierarchy. + */ + final void validateUnconditionally() { + boolean updateCur = false; + synchronized (getTreeLock()) { + descendUnconditionallyWhenValidating = true; + + validate(); + if (peer instanceof ContainerPeer) { + updateCur = isVisible(); + } + + descendUnconditionallyWhenValidating = false; + } + if (updateCur) { + updateCursorImmediately(); + } + } + /** * Recursively descends the container tree and recomputes the * layout for any subtrees marked as needing it (those marked as @@ -1578,16 +1658,20 @@ public class Container extends Component { */ protected void validateTree() { checkTreeLock(); - if (!isValid()) { + if (!isValid() || descendUnconditionallyWhenValidating) { if (peer instanceof ContainerPeer) { ((ContainerPeer)peer).beginLayout(); } - doLayout(); + if (!isValid()) { + doLayout(); + } for (int i = 0; i < component.size(); i++) { Component comp = component.get(i); if ( (comp instanceof Container) && !(comp instanceof Window) - && !comp.isValid()) { + && (!comp.isValid() || + descendUnconditionallyWhenValidating)) + { ((Container)comp).validateTree(); } else { comp.validate(); diff --git a/jdk/src/share/classes/java/awt/Window.java b/jdk/src/share/classes/java/awt/Window.java index 8ea9ec821d8..c039a717984 100644 --- a/jdk/src/share/classes/java/awt/Window.java +++ b/jdk/src/share/classes/java/awt/Window.java @@ -767,7 +767,7 @@ public class Window extends Container implements Accessible { isPacked = true; } - validate(); + validateUnconditionally(); } /** @@ -943,7 +943,7 @@ public class Window extends Container implements Accessible { if (peer == null) { addNotify(); } - validate(); + validateUnconditionally(); isInShow = true; if (visible) { @@ -2599,6 +2599,21 @@ public class Window extends Container implements Accessible { super.addPropertyChangeListener(propertyName, listener); } + /** + * Indicates if this container is a validate root. + *

+ * {@code Window} objects are the validate roots, and, therefore, they + * override this method to return {@code true}. + * + * @return {@code true} + * @since 1.7 + * @see java.awt.Container#isValidateRoot + */ + @Override + public boolean isValidateRoot() { + return true; + } + /** * Dispatches an event to this window or one of its sub components. * @param e the event diff --git a/jdk/src/share/classes/javax/swing/JComponent.java b/jdk/src/share/classes/javax/swing/JComponent.java index 6c97ebd5e71..37f7e7d4730 100644 --- a/jdk/src/share/classes/javax/swing/JComponent.java +++ b/jdk/src/share/classes/javax/swing/JComponent.java @@ -4878,7 +4878,9 @@ public abstract class JComponent extends Container implements Serializable, * @see #revalidate * @see java.awt.Component#invalidate * @see java.awt.Container#validate + * @see java.awt.Container#isValidateRoot */ + @Override public boolean isValidateRoot() { return false; } diff --git a/jdk/src/share/classes/javax/swing/JRootPane.java b/jdk/src/share/classes/javax/swing/JRootPane.java index a210c3791c4..f6964f728ef 100644 --- a/jdk/src/share/classes/javax/swing/JRootPane.java +++ b/jdk/src/share/classes/javax/swing/JRootPane.java @@ -725,8 +725,10 @@ public class JRootPane extends JComponent implements Accessible { * because both classes override isValidateRoot to return true. * * @see JComponent#isValidateRoot + * @see java.awt.Container#isValidateRoot * @return true */ + @Override public boolean isValidateRoot() { return true; } diff --git a/jdk/src/share/classes/javax/swing/JScrollPane.java b/jdk/src/share/classes/javax/swing/JScrollPane.java index b2be43cd15f..b813d4fccdc 100644 --- a/jdk/src/share/classes/javax/swing/JScrollPane.java +++ b/jdk/src/share/classes/javax/swing/JScrollPane.java @@ -453,10 +453,12 @@ public class JScrollPane extends JComponent implements ScrollPaneConstants, Acce * @see java.awt.Container#validate * @see JComponent#revalidate * @see JComponent#isValidateRoot + * @see java.awt.Container#isValidateRoot * * @beaninfo * hidden: true */ + @Override public boolean isValidateRoot() { return true; } diff --git a/jdk/src/share/classes/javax/swing/JSplitPane.java b/jdk/src/share/classes/javax/swing/JSplitPane.java index b5d8ec7d2b5..f3baff66492 100644 --- a/jdk/src/share/classes/javax/swing/JSplitPane.java +++ b/jdk/src/share/classes/javax/swing/JSplitPane.java @@ -947,10 +947,12 @@ public class JSplitPane extends JComponent implements Accessible * * @return true * @see JComponent#revalidate + * @see java.awt.Container#isValidateRoot * * @beaninfo * hidden: true */ + @Override public boolean isValidateRoot() { return true; } diff --git a/jdk/src/share/classes/javax/swing/JTextField.java b/jdk/src/share/classes/javax/swing/JTextField.java index de408914d22..12fc0a70c4f 100644 --- a/jdk/src/share/classes/javax/swing/JTextField.java +++ b/jdk/src/share/classes/javax/swing/JTextField.java @@ -288,7 +288,9 @@ public class JTextField extends JTextComponent implements SwingConstants { * * @see JComponent#revalidate * @see JComponent#isValidateRoot + * @see java.awt.Container#isValidateRoot */ + @Override public boolean isValidateRoot() { return SwingUtilities2.getViewport(this) == null; } diff --git a/jdk/src/share/classes/javax/swing/JViewport.java b/jdk/src/share/classes/javax/swing/JViewport.java index 734e80a0557..5073a891af4 100644 --- a/jdk/src/share/classes/javax/swing/JViewport.java +++ b/jdk/src/share/classes/javax/swing/JViewport.java @@ -469,49 +469,12 @@ public class JViewport extends JComponent implements Accessible * is the synchronous version of a revalidate. */ private void validateView() { - Component validateRoot = null; + Component validateRoot = SwingUtilities.getValidateRoot(this, false); - /* Find the first JComponent ancestor of this component whose - * isValidateRoot() method returns true. - */ - for(Component c = this; c != null; c = c.getParent()) { - if ((c instanceof CellRendererPane) || (c.getPeer() == null)) { - return; - } - if ((c instanceof JComponent) && - (((JComponent)c).isValidateRoot())) { - validateRoot = c; - break; - } - } - - // If no validateRoot, nothing to validate from. if (validateRoot == null) { return; } - // Make sure all ancestors are visible. - Component root = null; - - for(Component c = validateRoot; c != null; c = c.getParent()) { - // We don't check isVisible here, otherwise if the component - // is contained in something like a JTabbedPane when the - // component is made visible again it won't have scrolled - // to the correct location. - if (c.getPeer() == null) { - return; - } - if ((c instanceof Window) || (c instanceof Applet)) { - root = c; - break; - } - } - - // Make sure there is a Window ancestor. - if (root == null) { - return; - } - // Validate the root. validateRoot.validate(); diff --git a/jdk/src/share/classes/javax/swing/RepaintManager.java b/jdk/src/share/classes/javax/swing/RepaintManager.java index a988b99fbd3..c8607d2e4b9 100644 --- a/jdk/src/share/classes/javax/swing/RepaintManager.java +++ b/jdk/src/share/classes/javax/swing/RepaintManager.java @@ -310,47 +310,13 @@ public class RepaintManager delegate.addInvalidComponent(invalidComponent); return; } - Component validateRoot = null; + Component validateRoot = + SwingUtilities.getValidateRoot(invalidComponent, true); - /* Find the first JComponent ancestor of this component whose - * isValidateRoot() method returns true. - */ - for(Component c = invalidComponent; c != null; c = c.getParent()) { - if ((c instanceof CellRendererPane) || (c.getPeer() == null)) { - return; - } - if ((c instanceof JComponent) && (((JComponent)c).isValidateRoot())) { - validateRoot = c; - break; - } - } - - /* There's no validateRoot to apply validate to, so we're done. - */ if (validateRoot == null) { return; } - /* If the validateRoot and all of its ancestors aren't visible - * then we don't do anything. While we're walking up the tree - * we find the root Window or Applet. - */ - Component root = null; - - for(Component c = validateRoot; c != null; c = c.getParent()) { - if (!c.isVisible() || (c.getPeer() == null)) { - return; - } - if ((c instanceof Window) || (c instanceof Applet)) { - root = c; - break; - } - } - - if (root == null) { - return; - } - /* Lazily create the invalidateComponents vector and add the * validateRoot if it's not there already. If this validateRoot * is already in the vector, we're done. diff --git a/jdk/src/share/classes/javax/swing/SwingUtilities.java b/jdk/src/share/classes/javax/swing/SwingUtilities.java index d7a26a0dd72..54ac2f55680 100644 --- a/jdk/src/share/classes/javax/swing/SwingUtilities.java +++ b/jdk/src/share/classes/javax/swing/SwingUtilities.java @@ -1967,4 +1967,54 @@ public class SwingUtilities implements SwingConstants SwingUtilities.updateComponentTreeUI(component); } } + + /** + * Retrieves the validate root of a given container. + * + * If the container is contained within a {@code CellRendererPane}, this + * method returns {@code null} due to the synthetic nature of the {@code + * CellRendererPane}. + *

+ * The component hierarchy must be displayable up to the toplevel component + * (either a {@code Frame} or an {@code Applet} object.) Otherwise this + * method returns {@code null}. + *

+ * If the {@code visibleOnly} argument is {@code true}, the found validate + * root and all its parents up to the toplevel component must also be + * visible. Otherwise this method returns {@code null}. + * + * @return the validate root of the given container or null + * @see java.awt.Component#isDisplayable() + * @see java.awt.Component#isVisible() + * @since 1.7 + */ + static Container getValidateRoot(Container c, boolean visibleOnly) { + Container root = null; + + for (; c != null; c = c.getParent()) + { + if (!c.isDisplayable() || c instanceof CellRendererPane) { + return null; + } + if (c.isValidateRoot()) { + root = c; + break; + } + } + + if (root == null) { + return null; + } + + for (; c != null; c = c.getParent()) { + if (!c.isDisplayable() || (visibleOnly && !c.isVisible())) { + return null; + } + if (c instanceof Window || c instanceof Applet) { + return root; + } + } + + return null; + } } diff --git a/jdk/test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java b/jdk/test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java new file mode 100644 index 00000000000..7bf34012dd9 --- /dev/null +++ b/jdk/test/java/awt/Container/ValidateRoot/InvalidateMustRespectValidateRoots.java @@ -0,0 +1,114 @@ +/* + * Copyright 2009 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 6852592 + @summary invalidate() must stop when it encounters a validate root + @author anthony.petrov@sun.com + @run main InvalidateMustRespectValidateRoots +*/ + +import javax.swing.*; +import java.awt.event.*; + +public class InvalidateMustRespectValidateRoots { + private static volatile JRootPane rootPane; + + public static void main(String args[]) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + // The JRootPane is a validate root. We'll check if + // invalidate() stops on the root pane, or goes further + // up to the frame. + JFrame frame = new JFrame(); + final JButton button = new JButton(); + + frame.add(button); + + // To enable running the test manually: use the Ctrl-Shift-F1 + // to print the component hierarchy to the console + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + if (button.isValid()) { + button.invalidate(); + } else { + button.revalidate(); + } + } + }); + + rootPane = frame.getRootPane(); + + // Now the component hierarchy looks like: + // frame + // --> rootPane + // --> layered pane + // --> content pane + // --> button + + // Make all components valid first via showing the frame + // We have to make the frame visible. Otherwise revalidate() is + // useless (see RepaintManager.addInvalidComponent()). + frame.pack(); // To enable running this test manually + frame.setVisible(true); + + if (!frame.isValid()) { + throw new RuntimeException( + "setVisible(true) failed to validate the frame"); + } + + // Now invalidate the button + button.invalidate(); + + // Check if the 'valid' status is what we expect it to be + if (rootPane.isValid()) { + throw new RuntimeException( + "invalidate() failed to invalidate the root pane"); + } + + if (!frame.isValid()) { + throw new RuntimeException( + "invalidate() invalidated the frame"); + } + + // Now validate the hierarchy again + button.revalidate(); + + // Now let the validation happen on the EDT + } + }); + + Thread.sleep(1000); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + // Check if the root pane finally became valid + if (!rootPane.isValid()) { + throw new RuntimeException( + "revalidate() failed to validate the hierarchy"); + } + } + }); + } +} From 4b2a80c711ff59b3ae082df54ad8571f47566f7d Mon Sep 17 00:00:00 2001 From: Dmitry Cherepanov Date: Thu, 22 Oct 2009 13:27:28 +0400 Subject: [PATCH 08/13] 6707273: TrayIcon does not support 8-bit alpha channel in Windows XP Reviewed-by: uta, ant --- .../native/sun/windows/awt_TrayIcon.cpp | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/jdk/src/windows/native/sun/windows/awt_TrayIcon.cpp b/jdk/src/windows/native/sun/windows/awt_TrayIcon.cpp index 9165314bbc5..6b4f8b6bcfc 100644 --- a/jdk/src/windows/native/sun/windows/awt_TrayIcon.cpp +++ b/jdk/src/windows/native/sun/windows/awt_TrayIcon.cpp @@ -59,7 +59,7 @@ struct DisplayMessageStruct { }; typedef struct tagBitmapheader { - BITMAPINFOHEADER bmiHeader; + BITMAPV5HEADER bmiHeader; DWORD dwMasks[256]; } Bitmapheader, *LPBITMAPHEADER; @@ -638,12 +638,12 @@ void AwtTrayIcon::UnlinkObjects() HBITMAP AwtTrayIcon::CreateBMP(HWND hW,int* imageData,int nSS, int nW, int nH) { - Bitmapheader bmhHeader; + Bitmapheader bmhHeader = {0}; HDC hDC; char *ptrImageData; HBITMAP hbmpBitmap; HBITMAP hBitmap; - int nNumChannels = 3; + int nNumChannels = 4; if (!hW) { hW = ::GetDesktopWindow(); @@ -653,14 +653,20 @@ HBITMAP AwtTrayIcon::CreateBMP(HWND hW,int* imageData,int nSS, int nW, int nH) return NULL; } - memset(&bmhHeader, 0, sizeof(Bitmapheader)); - bmhHeader.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmhHeader.bmiHeader.biWidth = nW; - bmhHeader.bmiHeader.biHeight = -nH; - bmhHeader.bmiHeader.biPlanes = 1; + bmhHeader.bmiHeader.bV5Size = sizeof(BITMAPV5HEADER); + bmhHeader.bmiHeader.bV5Width = nW; + bmhHeader.bmiHeader.bV5Height = -nH; + bmhHeader.bmiHeader.bV5Planes = 1; - bmhHeader.bmiHeader.biBitCount = 24; - bmhHeader.bmiHeader.biCompression = BI_RGB; + bmhHeader.bmiHeader.bV5BitCount = 32; + bmhHeader.bmiHeader.bV5Compression = BI_BITFIELDS; + + // The following mask specification specifies a supported 32 BPP + // alpha format for Windows XP. + bmhHeader.bmiHeader.bV5RedMask = 0x00FF0000; + bmhHeader.bmiHeader.bV5GreenMask = 0x0000FF00; + bmhHeader.bmiHeader.bV5BlueMask = 0x000000FF; + bmhHeader.bmiHeader.bV5AlphaMask = 0xFF000000; hbmpBitmap = ::CreateDIBSection(hDC, (BITMAPINFO*)&(bmhHeader), DIB_RGB_COLORS, @@ -674,6 +680,7 @@ HBITMAP AwtTrayIcon::CreateBMP(HWND hW,int* imageData,int nSS, int nW, int nH) } for (int nOutern = 0; nOutern < nH; nOutern++) { for (int nInner = 0; nInner < nSS; nInner++) { + dstPtr[3] = (*srcPtr >> 0x18) & 0xFF; dstPtr[2] = (*srcPtr >> 0x10) & 0xFF; dstPtr[1] = (*srcPtr >> 0x08) & 0xFF; dstPtr[0] = *srcPtr & 0xFF; From 85e10718ce8960f347340a549bdfce17151797cb Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Fri, 23 Oct 2009 14:52:55 +0400 Subject: [PATCH 09/13] 6887249: Get rid of double-check for isValid() idiom in validate() methods Reviewed-by: art, dcherepanov --- jdk/src/share/classes/java/awt/Container.java | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/jdk/src/share/classes/java/awt/Container.java b/jdk/src/share/classes/java/awt/Container.java index 84334c9973e..94273ade4cb 100644 --- a/jdk/src/share/classes/java/awt/Container.java +++ b/jdk/src/share/classes/java/awt/Container.java @@ -1583,34 +1583,31 @@ public class Container extends Component { * @see #validateTree */ public void validate() { - /* Avoid grabbing lock unless really necessary. */ - if (!isValid() || descendUnconditionallyWhenValidating) { - boolean updateCur = false; - synchronized (getTreeLock()) { - if ((!isValid() || descendUnconditionallyWhenValidating) - && peer != null) - { - ContainerPeer p = null; - if (peer instanceof ContainerPeer) { - p = (ContainerPeer) peer; - } - if (p != null) { - p.beginValidate(); - } - validateTree(); - if (p != null) { - p.endValidate(); - // Avoid updating cursor if this is an internal call. - // See validateUnconditionally() for details. - if (!descendUnconditionallyWhenValidating) { - updateCur = isVisible(); - } + boolean updateCur = false; + synchronized (getTreeLock()) { + if ((!isValid() || descendUnconditionallyWhenValidating) + && peer != null) + { + ContainerPeer p = null; + if (peer instanceof ContainerPeer) { + p = (ContainerPeer) peer; + } + if (p != null) { + p.beginValidate(); + } + validateTree(); + if (p != null) { + p.endValidate(); + // Avoid updating cursor if this is an internal call. + // See validateUnconditionally() for details. + if (!descendUnconditionallyWhenValidating) { + updateCur = isVisible(); } } } - if (updateCur) { - updateCursorImmediately(); - } + } + if (updateCur) { + updateCursorImmediately(); } } From 1fbf7057398a125410129307e87aba43f8afd92e Mon Sep 17 00:00:00 2001 From: Dmitry Cherepanov Date: Wed, 11 Nov 2009 17:46:58 +0300 Subject: [PATCH 10/13] 6852111: Unhandled 'spurious wakeup' in java.awt.EventQueue.invokeAndWait() Introduced InvocationEvent.isDispatched method Reviewed-by: art, anthony --- .../share/classes/java/awt/EventQueue.java | 4 +- .../java/awt/event/InvocationEvent.java | 97 ++++++++++++++----- .../sun/awt/im/InputMethodManager.java | 4 +- .../InvocationEvent/InvocationEventTest.java | 68 +++++++++++++ 4 files changed, 149 insertions(+), 24 deletions(-) create mode 100644 jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java diff --git a/jdk/src/share/classes/java/awt/EventQueue.java b/jdk/src/share/classes/java/awt/EventQueue.java index 3e9febf79b7..b5635f4a25c 100644 --- a/jdk/src/share/classes/java/awt/EventQueue.java +++ b/jdk/src/share/classes/java/awt/EventQueue.java @@ -1027,7 +1027,9 @@ public class EventQueue { synchronized (lock) { Toolkit.getEventQueue().postEvent(event); - lock.wait(); + while (!event.isDispatched()) { + lock.wait(); + } } Throwable eventThrowable = event.getThrowable(); diff --git a/jdk/src/share/classes/java/awt/event/InvocationEvent.java b/jdk/src/share/classes/java/awt/event/InvocationEvent.java index 0959a86cb35..e21adf352bb 100644 --- a/jdk/src/share/classes/java/awt/event/InvocationEvent.java +++ b/jdk/src/share/classes/java/awt/event/InvocationEvent.java @@ -78,10 +78,21 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { /** * The (potentially null) Object whose notifyAll() method will be called - * immediately after the Runnable.run() method returns. + * immediately after the Runnable.run() method has returned or thrown an exception. + * + * @see #isDispatched */ protected Object notifier; + /** + * Indicates whether the run() method of the runnable + * was executed or not. + * + * @see #isDispatched + * @since 1.7 + */ + private volatile boolean dispatched = false; + /** * Set to true if dispatch() catches Throwable and stores it in the * exception instance variable. If false, Throwables are propagated up @@ -144,7 +155,7 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * source which will execute the runnable's run * method when dispatched. If notifier is non-null, * notifyAll() will be called on it - * immediately after run returns. + * immediately after run has returned or thrown an exception. *

An invocation of the form InvocationEvent(source, * runnable, notifier, catchThrowables) * behaves in exactly the same way as the invocation of @@ -159,7 +170,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * executed * @param notifier The {@code Object} whose notifyAll * method will be called after - * Runnable.run has returned + * Runnable.run has returned or + * thrown an exception * @param catchThrowables Specifies whether dispatch * should catch Throwable when executing * the Runnable's run @@ -180,8 +192,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * Constructs an InvocationEvent with the specified * source and ID which will execute the runnable's run * method when dispatched. If notifier is non-null, - * notifyAll will be called on it - * immediately after run returns. + * notifyAll will be called on it immediately after + * run has returned or thrown an exception. *

This method throws an * IllegalArgumentException if source * is null. @@ -195,7 +207,8 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * run method will be executed * @param notifier The Object whose notifyAll * method will be called after - * Runnable.run has returned + * Runnable.run has returned or + * thrown an exception * @param catchThrowables Specifies whether dispatch * should catch Throwable when executing the * Runnable's run @@ -217,27 +230,33 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { /** * Executes the Runnable's run() method and notifies the - * notifier (if any) when run() returns. + * notifier (if any) when run() has returned or thrown an exception. + * + * @see #isDispatched */ public void dispatch() { - if (catchExceptions) { - try { + try { + if (catchExceptions) { + try { + runnable.run(); + } + catch (Throwable t) { + if (t instanceof Exception) { + exception = (Exception) t; + } + throwable = t; + } + } + else { runnable.run(); } - catch (Throwable t) { - if (t instanceof Exception) { - exception = (Exception) t; - } - throwable = t; - } - } - else { - runnable.run(); - } + } finally { + dispatched = true; - if (notifier != null) { - synchronized (notifier) { - notifier.notifyAll(); + if (notifier != null) { + synchronized (notifier) { + notifier.notifyAll(); + } } } } @@ -277,6 +296,40 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { return when; } + /** + * Returns {@code true} if the event is dispatched or any exception is + * thrown while dispatching, {@code false} otherwise. The method should + * be called by a waiting thread that calls the {@code notifier.wait()} method. + * Since spurious wakeups are possible (as explained in {@link Object#wait()}), + * this method should be used in a waiting loop to ensure that the event + * got dispatched: + *

+     *     while (!event.isDispatched()) {
+     *         notifier.wait();
+     *     }
+     * 
+ * If the waiting thread wakes up without dispatching the event, + * the {@code isDispatched()} method returns {@code false}, and + * the {@code while} loop executes once more, thus, causing + * the awakened thread to revert to the waiting mode. + *

+ * If the {@code notifier.notifyAll()} happens before the waiting thread + * enters the {@code notifier.wait()} method, the {@code while} loop ensures + * that the waiting thread will not enter the {@code notifier.wait()} method. + * Otherwise, there is no guarantee that the waiting thread will ever be woken + * from the wait. + * + * @return {@code true} if the event has been dispatched, or any exception + * has been thrown while dispatching, {@code false} otherwise + * @see #dispatch + * @see #notifier + * @see #catchExceptions + * @since 1.7 + */ + public boolean isDispatched() { + return dispatched; + } + /** * Returns a parameter string identifying this event. * This method is useful for event-logging and for debugging. diff --git a/jdk/src/share/classes/sun/awt/im/InputMethodManager.java b/jdk/src/share/classes/sun/awt/im/InputMethodManager.java index caba8d6a152..9ee45e28e53 100644 --- a/jdk/src/share/classes/sun/awt/im/InputMethodManager.java +++ b/jdk/src/share/classes/sun/awt/im/InputMethodManager.java @@ -358,7 +358,9 @@ class ExecutableInputMethodManager extends InputMethodManager AppContext requesterAppContext = SunToolkit.targetToAppContext(requester); synchronized (lock) { SunToolkit.postEvent(requesterAppContext, event); - lock.wait(); + while (!event.isDispatched()) { + lock.wait(); + } } Throwable eventThrowable = event.getThrowable(); diff --git a/jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java b/jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java new file mode 100644 index 00000000000..5fb83d10acf --- /dev/null +++ b/jdk/test/java/awt/event/InvocationEvent/InvocationEventTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2009 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 6852111 + @summary Unhandled 'spurious wakeup' in java.awt.EventQueue.invokeAndWait() + @author dmitry.cherepanov@sun.com: area=awt.event + @run main InvocationEventTest +*/ + +/** + * InvocationEventTest.java + * + * summary: Tests new isDispatched method of the InvocationEvent class + */ + +import java.awt.*; +import java.awt.event.*; + +public class InvocationEventTest +{ + public static void main(String []s) throws Exception + { + Toolkit tk = Toolkit.getDefaultToolkit(); + Runnable runnable = new Runnable() { + public void run() { + } + }; + Object lock = new Object(); + InvocationEvent event = new InvocationEvent(tk, runnable, lock, true); + + if (event.isDispatched()) { + throw new RuntimeException(" Initially, the event shouldn't be dispatched "); + } + + synchronized(lock) { + tk.getSystemEventQueue().postEvent(event); + while(!event.isDispatched()) { + lock.wait(); + } + } + + if(!event.isDispatched()) { + throw new RuntimeException(" Finally, the event should be dispatched "); + } + } +} From 67ffb33afaa55a2662d11a12ba4d62d03a7b7431 Mon Sep 17 00:00:00 2001 From: Dmitry Cherepanov Date: Wed, 11 Nov 2009 19:18:27 +0300 Subject: [PATCH 11/13] 6880694: GraphicsDevice.setFullScreenWindow(null) throws NPE if there's a fullscreen window displayed Handle "empty" refresh rates Reviewed-by: art, anthony --- jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c index 7afdf1681c6..5dfb0ff2875 100644 --- a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c +++ b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c @@ -1654,6 +1654,7 @@ Java_sun_awt_X11GraphicsEnvironment_getXineramaCenterPoint(JNIEnv *env, #ifndef HEADLESS #define BIT_DEPTH_MULTI java_awt_DisplayMode_BIT_DEPTH_MULTI +#define REFRESH_RATE_UNKNOWN java_awt_DisplayMode_REFRESH_RATE_UNKNOWN typedef Status (*XRRQueryVersionType) (Display *dpy, int *major_versionp, int *minor_versionp); @@ -1765,6 +1766,7 @@ X11GD_CreateDisplayMode(JNIEnv *env, jint width, jint height, { jclass displayModeClass; jmethodID cid; + jint validRefreshRate = refreshRate; displayModeClass = (*env)->FindClass(env, "java/awt/DisplayMode"); if (JNU_IsNull(env, displayModeClass)) { @@ -1780,8 +1782,13 @@ X11GD_CreateDisplayMode(JNIEnv *env, jint width, jint height, return NULL; } + // early versions of xrandr may report "empty" rates (6880694) + if (validRefreshRate <= 0) { + validRefreshRate = REFRESH_RATE_UNKNOWN; + } + return (*env)->NewObject(env, displayModeClass, cid, - width, height, bitDepth, refreshRate); + width, height, bitDepth, validRefreshRate); } static void @@ -1926,8 +1933,7 @@ Java_sun_awt_X11GraphicsDevice_getCurrentDisplayMode curRate = awt_XRRConfigCurrentRate(config); if ((sizes != NULL) && - (curSizeIndex < nsizes) && - (curRate > 0)) + (curSizeIndex < nsizes)) { XRRScreenSize curSize = sizes[curSizeIndex]; displayMode = X11GD_CreateDisplayMode(env, From 58c459c32e91b92234788048ee0def26a1a9488f Mon Sep 17 00:00:00 2001 From: Dmitry Cherepanov Date: Thu, 12 Nov 2009 12:06:46 +0300 Subject: [PATCH 12/13] 6882909: Resetting a full-screen window to normal rotates screen to normal orientation Retain rotation upon change to full screen mode Reviewed-by: art, anthony --- jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c index 5dfb0ff2875..ef4fa15afa5 100644 --- a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c +++ b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c @@ -1681,6 +1681,9 @@ typedef Status Rotation rotation, short rate, Time timestamp); +typedef Rotation + (*XRRConfigRotationsType)(XRRScreenConfiguration *config, + Rotation *current_rotation); static XRRQueryVersionType awt_XRRQueryVersion; static XRRGetScreenInfoType awt_XRRGetScreenInfo; @@ -1690,6 +1693,7 @@ static XRRConfigCurrentRateType awt_XRRConfigCurrentRate; static XRRConfigSizesType awt_XRRConfigSizes; static XRRConfigCurrentConfigurationType awt_XRRConfigCurrentConfiguration; static XRRSetScreenConfigAndRateType awt_XRRSetScreenConfigAndRate; +static XRRConfigRotationsType awt_XRRConfigRotations; #define LOAD_XRANDR_FUNC(f) \ do { \ @@ -1756,6 +1760,7 @@ X11GD_InitXrandrFuncs(JNIEnv *env) LOAD_XRANDR_FUNC(XRRConfigSizes); LOAD_XRANDR_FUNC(XRRConfigCurrentConfiguration); LOAD_XRANDR_FUNC(XRRSetScreenConfigAndRate); + LOAD_XRANDR_FUNC(XRRConfigRotations); return JNI_TRUE; } @@ -2010,6 +2015,7 @@ Java_sun_awt_X11GraphicsDevice_configDisplayMode jboolean success = JNI_FALSE; XRRScreenConfiguration *config; Drawable root; + Rotation currentRotation = RR_Rotate_0; AWT_LOCK(); @@ -2021,6 +2027,7 @@ Java_sun_awt_X11GraphicsDevice_configDisplayMode short chosenRate = -1; int nsizes; XRRScreenSize *sizes = awt_XRRConfigSizes(config, &nsizes); + awt_XRRConfigRotations(config, ¤tRotation); if (sizes != NULL) { int i, j; @@ -2054,7 +2061,7 @@ Java_sun_awt_X11GraphicsDevice_configDisplayMode Status status = awt_XRRSetScreenConfigAndRate(awt_display, config, root, chosenSizeIndex, - RR_Rotate_0, + currentRotation, chosenRate, CurrentTime); From 69fbaac381a92454bef364f4d4d279f9d67fc38a Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Mon, 16 Nov 2009 18:13:15 +0000 Subject: [PATCH 13/13] 6890458: Datatransfer API should not require RMI to be present Reviewed-by: uta --- .../java/awt/datatransfer/DataFlavor.java | 2 +- .../sun/awt/datatransfer/DataTransferer.java | 112 +++++++++++++++++- 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java b/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java index 0e559e5d359..36378882e15 100644 --- a/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java +++ b/jdk/src/share/classes/java/awt/datatransfer/DataFlavor.java @@ -1184,7 +1184,7 @@ public class DataFlavor implements Externalizable, Cloneable { */ public boolean isRepresentationClassRemote() { - return java.rmi.Remote.class.isAssignableFrom(representationClass); + return DataTransferer.isRemote(representationClass); } /** diff --git a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java index 521e691024c..277d3bd9e28 100644 --- a/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java +++ b/jdk/src/share/classes/sun/awt/datatransfer/DataTransferer.java @@ -63,8 +63,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.rmi.MarshalledObject; - import java.security.AccessControlContext; import java.security.AccessControlException; import java.security.AccessController; @@ -493,6 +491,13 @@ public abstract class DataTransferer { } } + /** + * Returns {@code true} if the given type is a java.rmi.Remote. + */ + public static boolean isRemote(Class type) { + return RMI.isRemote(type); + } + /** * Returns an Iterator which traverses a SortedSet of Strings which are * a total order of the standard character sets supported by the JRE. The @@ -1360,7 +1365,7 @@ search: // Source data is an RMI object } else if (flavor.isRepresentationClassRemote()) { - MarshalledObject mo = new MarshalledObject(obj); + Object mo = RMI.newMarshalledObject(obj); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(mo); oos.close(); @@ -1671,7 +1676,7 @@ search: try { byte[] ba = inputStreamToByteArray(str); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(ba)); - Object ret = ((MarshalledObject)(ois.readObject())).get(); + Object ret = RMI.getMarshalledObject(ois.readObject()); ois.close(); str.close(); return ret; @@ -2669,8 +2674,12 @@ search: Integer.valueOf(0)); nonTextRepresentationsMap.put(java.io.Serializable.class, Integer.valueOf(1)); - nonTextRepresentationsMap.put(java.rmi.Remote.class, - Integer.valueOf(2)); + + Class remoteClass = RMI.remoteClass(); + if (remoteClass != null) { + nonTextRepresentationsMap.put(remoteClass, + Integer.valueOf(2)); + } nonTextRepresentations = Collections.unmodifiableMap(nonTextRepresentationsMap); @@ -2900,4 +2909,95 @@ search: } } } + + /** + * A class that provides access to java.rmi.Remote and java.rmi.MarshalledObject + * without creating a static dependency. + */ + private static class RMI { + private static final Class remoteClass = getClass("java.rmi.Remote"); + private static final Class marshallObjectClass = + getClass("java.rmi.MarshalledObject"); + private static final Constructor marshallCtor = + getConstructor(marshallObjectClass, Object.class); + private static final Method marshallGet = + getMethod(marshallObjectClass, "get"); + + private static Class getClass(String name) { + try { + return Class.forName(name, true, null); + } catch (ClassNotFoundException e) { + return null; + } + } + + private static Constructor getConstructor(Class c, Class... types) { + try { + return (c == null) ? null : c.getDeclaredConstructor(types); + } catch (NoSuchMethodException x) { + throw new AssertionError(x); + } + } + + private static Method getMethod(Class c, String name, Class... types) { + try { + return (c == null) ? null : c.getMethod(name, types); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + /** + * Returns {@code true} if the given class is java.rmi.Remote. + */ + static boolean isRemote(Class c) { + return (remoteClass == null) ? null : remoteClass.isAssignableFrom(c); + } + + /** + * Returns java.rmi.Remote.class if RMI is present; otherwise {@code null}. + */ + static Class remoteClass() { + return remoteClass; + } + + /** + * Returns a new MarshalledObject containing the serialized representation + * of the given object. + */ + static Object newMarshalledObject(Object obj) throws IOException { + try { + return marshallCtor.newInstance(obj); + } catch (InstantiationException x) { + throw new AssertionError(x); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw (IOException)cause; + throw new AssertionError(x); + } + } + + /** + * Returns a new copy of the contained marshalled object. + */ + static Object getMarshalledObject(Object obj) + throws IOException, ClassNotFoundException + { + try { + return marshallGet.invoke(obj); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw (IOException)cause; + if (cause instanceof ClassNotFoundException) + throw (ClassNotFoundException)cause; + throw new AssertionError(x); + } + } + } }