changeset 1971:ca34cfff70a4

6402325: Swing toolbars vs native toolbars on Windows Summary: Introduce support for different window types: NORMAL, UTILITY, POPUP Reviewed-by: art, dcherepanov
author anthony
date Fri, 27 Nov 2009 16:07:32 +0300
parents e6b46fc235b0
children 6ffb01da29ce
files src/share/classes/java/awt/Window.java src/share/classes/javax/swing/Popup.java src/share/classes/sun/awt/SunToolkit.java src/solaris/classes/sun/awt/X11/InfoWindow.java src/solaris/classes/sun/awt/X11/XDecoratedPeer.java src/solaris/classes/sun/awt/X11/XNETProtocol.java src/solaris/classes/sun/awt/X11/XToolkit.java src/solaris/classes/sun/awt/X11/XTrayIconPeer.java src/solaris/classes/sun/awt/X11/XWindowPeer.java src/windows/classes/sun/awt/windows/WDialogPeer.java src/windows/classes/sun/awt/windows/WFramePeer.java src/windows/classes/sun/awt/windows/WWindowPeer.java src/windows/native/sun/windows/awt_Dialog.cpp src/windows/native/sun/windows/awt_Window.cpp src/windows/native/sun/windows/awt_Window.h test/java/awt/Window/WindowType/WindowType.java
diffstat 16 files changed, 308 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/awt/Window.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/share/classes/javax/swing/Popup.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/share/classes/sun/awt/SunToolkit.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/solaris/classes/sun/awt/X11/InfoWindow.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/solaris/classes/sun/awt/X11/XNETProtocol.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/solaris/classes/sun/awt/X11/XToolkit.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/solaris/classes/sun/awt/X11/XTrayIconPeer.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/solaris/classes/sun/awt/X11/XWindowPeer.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/windows/classes/sun/awt/windows/WDialogPeer.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/windows/classes/sun/awt/windows/WFramePeer.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/windows/classes/sun/awt/windows/WWindowPeer.java	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/windows/native/sun/windows/awt_Dialog.cpp	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/windows/native/sun/windows/awt_Window.cpp	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/src/windows/native/sun/windows/awt_Window.h	Fri Nov 27 15:26:07 2009 +0300
+++ b/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/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);
+    }
+}