6402325: Swing toolbars vs native toolbars on Windows
Summary: Introduce support for different window types: NORMAL, UTILITY, POPUP
Reviewed-by: art, dcherepanov
--- a/jdk/src/share/classes/java/awt/Window.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/share/classes/java/awt/Window.java Fri Nov 27 16:07:32 2009 +0300
@@ -148,6 +148,51 @@
public class Window extends Container implements Accessible {
/**
+ * Enumeration of available <i>window types</i>.
+ *
+ * A window type defines the generic visual appearance and behavior of a
+ * top-level window. For example, the type may affect the kind of
+ * decorations of a decorated {@code Frame} or {@code Dialog} instance.
+ * <p>
+ * Some platforms may not fully support a certain window type. Depending on
+ * the level of support, some properties of the window type may be
+ * disobeyed.
+ *
+ * @see #getType
+ * @see #setType
+ * @since 1.7
+ */
+ public static enum Type {
+ /**
+ * Represents a <i>normal</i> window.
+ *
+ * This is the default type for objects of the {@code Window} class or
+ * its descendants. Use this type for regular top-level windows.
+ */
+ NORMAL,
+
+ /**
+ * Represents a <i>utility</i> window.
+ *
+ * A utility window is usually a small window such as a toolbar or a
+ * palette. The native system may render the window with smaller
+ * title-bar if the window is either a {@code Frame} or a {@code
+ * Dialog} object, and if it has its decorations enabled.
+ */
+ UTILITY,
+
+ /**
+ * Represents a <i>popup</i> window.
+ *
+ * A popup window is a temporary window such as a drop-down menu or a
+ * tooltip. On some platforms, windows of that type may be forcibly
+ * made undecorated even if they are instances of the {@code Frame} or
+ * {@code Dialog} class, and have decorations enabled.
+ */
+ POPUP
+ }
+
+ /**
* This represents the warning message that is
* to be displayed in a non secure window. ie :
* a window that has a security manager installed for
@@ -2718,6 +2763,52 @@
}
/**
+ * Window type.
+ *
+ * Synchronization: ObjectLock
+ */
+ private Type type = Type.NORMAL;
+
+ /**
+ * Sets the type of the window.
+ *
+ * This method can only be called while the window is not displayable.
+ *
+ * @throws IllegalComponentStateException if the window
+ * is displayable.
+ * @throws IllegalArgumentException if the type is {@code null}
+ * @see Component#isDisplayable
+ * @see #getType
+ * @since 1.7
+ */
+ public void setType(Type type) {
+ if (type == null) {
+ throw new IllegalArgumentException("type should not be null.");
+ }
+ synchronized (getTreeLock()) {
+ if (isDisplayable()) {
+ throw new IllegalComponentStateException(
+ "The window is displayable.");
+ }
+ synchronized (getObjectLock()) {
+ this.type = type;
+ }
+ }
+ }
+
+ /**
+ * Returns the type of the window.
+ *
+ * @see #setType
+ * @since 1.7
+ */
+ public Type getType() {
+ synchronized (getObjectLock()) {
+ return type;
+ }
+ }
+
+ /**
* The window serialized data version.
*
* @serial
--- a/jdk/src/share/classes/javax/swing/Popup.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/share/classes/javax/swing/Popup.java Fri Nov 27 16:07:32 2009 +0300
@@ -227,12 +227,8 @@
HeavyWeightWindow(Window parent) {
super(parent);
setFocusableWindowState(false);
- Toolkit tk = Toolkit.getDefaultToolkit();
- if (tk instanceof SunToolkit) {
- // all the short-lived windows like Popups should be
- // OverrideRedirect on X11 platforms
- ((SunToolkit)tk).setOverrideRedirect(this);
- }
+ setType(Window.Type.POPUP);
+
// Popups are typically transient and most likely won't benefit
// from true double buffering. Turn it off here.
getRootPane().setUseTrueDoubleBuffering(false);
--- a/jdk/src/share/classes/sun/awt/SunToolkit.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/share/classes/sun/awt/SunToolkit.java Fri Nov 27 16:07:32 2009 +0300
@@ -800,14 +800,6 @@
}
- /**
- * Makes the window OverrideRedirect, on X11 platforms. See
- * ICCCM specification for more details about OverrideRedirect
- * windows. Implemented in XToolkit, no-op in WToolkit.
- */
- public void setOverrideRedirect(Window target) {
- }
-
static SoftCache imgCache = new SoftCache();
static synchronized Image getImageFromHash(Toolkit tk, URL url) {
--- a/jdk/src/solaris/classes/sun/awt/X11/InfoWindow.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/InfoWindow.java Fri Nov 27 16:07:32 2009 +0300
@@ -45,6 +45,7 @@
protected InfoWindow(Frame parent, Color borderColor) {
super(parent);
+ setType(Window.Type.POPUP);
container = new Container() {
@Override
public Insets getInsets() {
--- a/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java Fri Nov 27 16:07:32 2009 +0300
@@ -1099,9 +1099,9 @@
return false;
}
+ @Override
boolean isOverrideRedirect() {
-// return false;
- return ((XToolkit)Toolkit.getDefaultToolkit()).isOverrideRedirect((Window)target);
+ return Window.Type.POPUP.equals(getWindowType());
}
public boolean requestWindowFocus(long time, boolean timeProvided) {
--- a/jdk/src/solaris/classes/sun/awt/X11/XNETProtocol.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XNETProtocol.java Fri Nov 27 16:07:32 2009 +0300
@@ -252,8 +252,11 @@
XAtom XA_NET_WM_STATE_SKIP_TASKBAR = XAtom.get("_NET_WM_STATE_SKIP_TASKBAR");
XAtom XA_NET_WM_STATE_SKIP_PAGER = XAtom.get("_NET_WM_STATE_SKIP_PAGER");
- XAtom XA_NET_WM_WINDOW_TYPE = XAtom.get("_NET_WM_WINDOW_TYPE");
- XAtom XA_NET_WM_WINDOW_TYPE_DIALOG = XAtom.get("_NET_WM_WINDOW_TYPE_DIALOG");
+ public final XAtom XA_NET_WM_WINDOW_TYPE = XAtom.get("_NET_WM_WINDOW_TYPE");
+ public final XAtom XA_NET_WM_WINDOW_TYPE_NORMAL = XAtom.get("_NET_WM_WINDOW_TYPE_NORMAL");
+ public final XAtom XA_NET_WM_WINDOW_TYPE_DIALOG = XAtom.get("_NET_WM_WINDOW_TYPE_DIALOG");
+ public final XAtom XA_NET_WM_WINDOW_TYPE_UTILITY = XAtom.get("_NET_WM_WINDOW_TYPE_UTILITY");
+ public final XAtom XA_NET_WM_WINDOW_TYPE_POPUP_MENU = XAtom.get("_NET_WM_WINDOW_TYPE_POPUP_MENU");
XAtom XA_NET_WM_WINDOW_OPACITY = XAtom.get("_NET_WM_WINDOW_OPACITY");
--- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Fri Nov 27 16:07:32 2009 +0300
@@ -109,11 +109,6 @@
static int awt_multiclick_time;
static boolean securityWarningEnabled;
- // WeakSet should be used here, but there is no such class
- // in JDK (at least in JDK6 and earlier versions)
- private WeakHashMap<Window, Boolean> overrideRedirectWindows =
- new WeakHashMap<Window, Boolean>();
-
private static int screenWidth = -1, screenHeight = -1; // Dimensions of default screen
static long awt_defaultFg; // Pixel
private static XMouseInfoPeer xPeer;
@@ -1316,19 +1311,6 @@
}
}
- @Override
- public void setOverrideRedirect(Window target) {
- synchronized (overrideRedirectWindows) {
- overrideRedirectWindows.put(target, true);
- }
- }
-
- public boolean isOverrideRedirect(Window target) {
- synchronized (overrideRedirectWindows) {
- return overrideRedirectWindows.containsKey(target);
- }
- }
-
static void dumpPeers() {
if (log.isLoggable(PlatformLogger.FINE)) {
log.fine("Mapped windows:");
--- a/jdk/src/solaris/classes/sun/awt/X11/XTrayIconPeer.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XTrayIconPeer.java Fri Nov 27 16:07:32 2009 +0300
@@ -483,12 +483,6 @@
}
}
- static boolean isTrayIconStuffWindow(Window w) {
- return (w instanceof InfoWindow.Tooltip) ||
- (w instanceof InfoWindow.Balloon) ||
- (w instanceof XTrayIconEmbeddedFrame);
- }
-
// ***************************************
// Special embedded frame for tray icon
// ***************************************
--- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java Fri Nov 27 16:07:32 2009 +0300
@@ -53,7 +53,6 @@
import sun.awt.AWTAccessor;
import sun.awt.ComponentAccessor;
import sun.awt.WindowAccessor;
-import sun.awt.AWTAccessor;
import sun.awt.DisplayChangedListener;
import sun.awt.SunToolkit;
import sun.awt.X11GraphicsDevice;
@@ -106,6 +105,18 @@
private boolean isBeforeFirstMapNotify = false; // Is the window (being shown) between
// setVisible(true) & handleMapNotify().
+ /**
+ * The type of the window.
+ *
+ * The type is supposed to be immutable while the peer object exists.
+ * The value gets initialized in the preInit() method.
+ */
+ private Window.Type windowType = Window.Type.NORMAL;
+
+ public final Window.Type getWindowType() {
+ return windowType;
+ }
+
// It need to be accessed from XFramePeer.
protected Vector <ToplevelStateListener> toplevelStateListeners = new Vector<ToplevelStateListener>();
XWindowPeer(XCreateWindowParams params) {
@@ -137,6 +148,7 @@
void preInit(XCreateWindowParams params) {
target = (Component)params.get(TARGET);
+ windowType = ((Window)target).getType();
params.put(REPARENTED,
Boolean.valueOf(isOverrideRedirect() || isSimpleWindow()));
super.preInit(params);
@@ -1128,9 +1140,8 @@
}
boolean isOverrideRedirect() {
- return (XWM.getWMID() == XWM.OPENLOOK_WM ? true : false) ||
- ((XToolkit)Toolkit.getDefaultToolkit()).isOverrideRedirect((Window)target) ||
- XTrayIconPeer.isTrayIconStuffWindow((Window)target);
+ return XWM.getWMID() == XWM.OPENLOOK_WM ||
+ Window.Type.POPUP.equals(getWindowType());
}
final boolean isOLWMDecorBug() {
@@ -1826,12 +1837,49 @@
void setActualFocusedWindow(XWindowPeer actualFocusedWindow) {
}
+ /**
+ * Applies the current window type.
+ */
+ private void applyWindowType() {
+ XNETProtocol protocol = XWM.getWM().getNETProtocol();
+ if (protocol == null) {
+ return;
+ }
+
+ XAtom typeAtom = null;
+
+ switch (getWindowType())
+ {
+ case NORMAL:
+ typeAtom = protocol.XA_NET_WM_WINDOW_TYPE_NORMAL;
+ break;
+ case UTILITY:
+ typeAtom = protocol.XA_NET_WM_WINDOW_TYPE_UTILITY;
+ break;
+ case POPUP:
+ typeAtom = protocol.XA_NET_WM_WINDOW_TYPE_POPUP_MENU;
+ break;
+ }
+
+ if (typeAtom != null) {
+ XAtomList wtype = new XAtomList();
+ wtype.add(typeAtom);
+ protocol.XA_NET_WM_WINDOW_TYPE.
+ setAtomListProperty(getWindow(), wtype);
+ } else {
+ protocol.XA_NET_WM_WINDOW_TYPE.
+ DeleteProperty(getWindow());
+ }
+ }
+
+ @Override
public void xSetVisible(boolean visible) {
if (log.isLoggable(PlatformLogger.FINE)) log.fine("Setting visible on " + this + " to " + visible);
XToolkit.awtLock();
try {
this.visible = visible;
if (visible) {
+ applyWindowType();
XlibWrapper.XMapRaised(XToolkit.getDisplay(), getWindow());
} else {
XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), getWindow());
--- a/jdk/src/windows/classes/sun/awt/windows/WDialogPeer.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/windows/classes/sun/awt/windows/WDialogPeer.java Fri Nov 27 16:07:32 2009 +0300
@@ -53,7 +53,12 @@
}
}
- native void create(WComponentPeer parent);
+ native void createAwtDialog(WComponentPeer parent);
+ void create(WComponentPeer parent) {
+ preCreate(parent);
+ createAwtDialog(parent);
+ }
+
native void showModal();
native void endModal();
--- a/jdk/src/windows/classes/sun/awt/windows/WFramePeer.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/windows/classes/sun/awt/windows/WFramePeer.java Fri Nov 27 16:07:32 2009 +0300
@@ -136,6 +136,7 @@
native void createAwtFrame(WComponentPeer parent);
void create(WComponentPeer parent) {
+ preCreate(parent);
createAwtFrame(parent);
}
--- a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java Fri Nov 27 16:07:32 2009 +0300
@@ -199,7 +199,17 @@
}
native void createAwtWindow(WComponentPeer parent);
+
+ private volatile Window.Type windowType = Window.Type.NORMAL;
+
+ // This method must be called for Window, Dialog, and Frame before creating
+ // the hwnd
+ void preCreate(WComponentPeer parent) {
+ windowType = ((Window)target).getType();
+ }
+
void create(WComponentPeer parent) {
+ preCreate(parent);
createAwtWindow(parent);
}
--- a/jdk/src/windows/native/sun/windows/awt_Dialog.cpp Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/windows/native/sun/windows/awt_Dialog.cpp Fri Nov 27 16:07:32 2009 +0300
@@ -760,7 +760,7 @@
* Signature: (Lsun/awt/windows/WComponentPeer;)V
*/
JNIEXPORT void JNICALL
-Java_sun_awt_windows_WDialogPeer_create(JNIEnv *env, jobject self,
+Java_sun_awt_windows_WDialogPeer_createAwtDialog(JNIEnv *env, jobject self,
jobject parent)
{
TRY;
--- a/jdk/src/windows/native/sun/windows/awt_Window.cpp Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/windows/native/sun/windows/awt_Window.cpp Fri Nov 27 16:07:32 2009 +0300
@@ -163,9 +163,11 @@
jfieldID AwtWindow::sysYID;
jfieldID AwtWindow::sysWID;
jfieldID AwtWindow::sysHID;
+jfieldID AwtWindow::windowTypeID;
jmethodID AwtWindow::getWarningStringMID;
jmethodID AwtWindow::calculateSecurityWarningPositionMID;
+jmethodID AwtWindow::windowTypeNameMID;
int AwtWindow::ms_instanceCounter = 0;
HHOOK AwtWindow::ms_hCBTFilter;
@@ -216,6 +218,8 @@
hContentBitmap = NULL;
::InitializeCriticalSection(&contentBitmapCS);
+
+ m_windowType = Type::NORMAL;
}
AwtWindow::~AwtWindow()
@@ -475,6 +479,9 @@
}
env->DeleteLocalRef(target);
+ InitType(env, peer);
+ TweakStyle(windowStyle, windowExStyle);
+
AwtCanvas::CreateHWnd(env, title,
windowStyle,
windowExStyle,
@@ -982,6 +989,50 @@
delete rsws;
}
+void AwtWindow::InitType(JNIEnv *env, jobject peer)
+{
+ jobject type = env->GetObjectField(peer, windowTypeID);
+ if (type == NULL) {
+ return;
+ }
+
+ jstring value = (jstring)env->CallObjectMethod(type, windowTypeNameMID);
+ if (value == NULL) {
+ env->DeleteLocalRef(type);
+ return;
+ }
+
+ const char* valueNative = env->GetStringUTFChars(value, 0);
+ if (valueNative == NULL) {
+ env->DeleteLocalRef(value);
+ env->DeleteLocalRef(type);
+ return;
+ }
+
+ if (strcmp(valueNative, "UTILITY") == 0) {
+ m_windowType = Type::UTILITY;
+ } else if (strcmp(valueNative, "POPUP") == 0) {
+ m_windowType = Type::POPUP;
+ }
+
+ env->ReleaseStringUTFChars(value, valueNative);
+ env->DeleteLocalRef(value);
+ env->DeleteLocalRef(type);
+}
+
+void AwtWindow::TweakStyle(DWORD & style, DWORD & exStyle)
+{
+ switch (GetType()) {
+ case Type::UTILITY:
+ exStyle |= WS_EX_TOOLWINDOW;
+ break;
+ case Type::POPUP:
+ style &= ~WS_OVERLAPPED;
+ style |= WS_POPUP;
+ break;
+ }
+}
+
/* Create a new AwtWindow object and window. */
AwtWindow* AwtWindow::Create(jobject self, jobject parent)
{
@@ -3008,6 +3059,11 @@
AwtWindow::calculateSecurityWarningPositionMID =
env->GetMethodID(cls, "calculateSecurityWarningPosition", "(DDDD)Ljava/awt/geom/Point2D;");
+ jclass windowTypeClass = env->FindClass("java/awt/Window$Type");
+ AwtWindow::windowTypeNameMID =
+ env->GetMethodID(windowTypeClass, "name", "()Ljava/lang/String;");
+ env->DeleteLocalRef(windowTypeClass);
+
CATCH_BAD_ALLOC;
}
@@ -3035,6 +3091,9 @@
AwtWindow::sysWID = env->GetFieldID(cls, "sysW", "I");
AwtWindow::sysHID = env->GetFieldID(cls, "sysH", "I");
+ AwtWindow::windowTypeID = env->GetFieldID(cls, "windowType",
+ "Ljava/awt/Window$Type;");
+
CATCH_BAD_ALLOC;
}
--- a/jdk/src/windows/native/sun/windows/awt_Window.h Fri Nov 27 15:26:07 2009 +0300
+++ b/jdk/src/windows/native/sun/windows/awt_Window.h Fri Nov 27 16:07:32 2009 +0300
@@ -63,8 +63,11 @@
static jfieldID sysWID;
static jfieldID sysHID;
+ static jfieldID windowTypeID;
+
static jmethodID getWarningStringMID;
static jmethodID calculateSecurityWarningPositionMID;
+ static jmethodID windowTypeNameMID;
AwtWindow();
virtual ~AwtWindow();
@@ -362,10 +365,24 @@
void EnableTranslucency(BOOL enable);
+ // Native representation of the java.awt.Window.Type enum
+ enum Type {
+ NORMAL, UTILITY, POPUP
+ };
+
+ inline Type GetType() { return m_windowType; }
+
private:
int m_screenNum;
void InitOwner(AwtWindow *owner);
+
+ Type m_windowType;
+ void InitType(JNIEnv *env, jobject peer);
+
+ // Tweak the style according to the type of the window
+ void TweakStyle(DWORD & style, DWORD & exStyle);
+
};
#endif /* AWT_WINDOW_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Window/WindowType/WindowType.java Fri Nov 27 16:07:32 2009 +0300
@@ -0,0 +1,61 @@
+/*
+ * 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 6402325
+ @summary Test showing windows of different types
+ @author anthony.petrov@sun.com: area=awt.toplevel
+ @library ../../regtesthelpers
+ @build Util
+ @run main WindowType
+*/
+
+import java.awt.*;
+import test.java.awt.regtesthelpers.Util;
+
+/**
+ * WindowType.java
+ * Summary: Test showing windows of different types.
+ */
+public class WindowType {
+ private static void test(Window window, Window.Type type) {
+ window.setType(type);
+
+ window.setVisible(true);
+ Util.waitForIdle(null);
+ window.setVisible(false);
+ }
+
+ private static void test(Window.Type type) {
+ test(new Window((Frame)null), type);
+ test(new Frame(), type);
+ test(new Dialog((Frame)null), type);
+ }
+
+ public static void main(String[] args) {
+ test(Window.Type.NORMAL);
+ test(Window.Type.UTILITY);
+ test(Window.Type.POPUP);
+ }
+}