6402325: Swing toolbars vs native toolbars on Windows

Introduce support for different window types: NORMAL, UTILITY, POPUP

Reviewed-by: art, dcherepanov
This commit is contained in:
Anthony Petrov 2009-11-27 16:07:32 +03:00
parent a6dd224efd
commit d7b200bf35
16 changed files with 308 additions and 48 deletions

View File

@ -147,6 +147,51 @@ import sun.util.logging.PlatformLogger;
*/
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 :
@ -2717,6 +2762,52 @@ public class Window extends Container implements Accessible {
removeFromWindowList(appContext, weakThis);
}
/**
* 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.
*

View File

@ -227,12 +227,8 @@ public class Popup {
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);

View File

@ -800,14 +800,6 @@ public abstract class SunToolkit extends Toolkit
}
/**
* 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) {

View File

@ -45,6 +45,7 @@ public abstract class InfoWindow extends Window {
protected InfoWindow(Frame parent, Color borderColor) {
super(parent);
setType(Window.Type.POPUP);
container = new Container() {
@Override
public Insets getInsets() {

View File

@ -1099,9 +1099,9 @@ abstract class XDecoratedPeer extends XWindowPeer {
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) {

View File

@ -252,8 +252,11 @@ final class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProt
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");

View File

@ -109,11 +109,6 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
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 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
}
}
@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:");

View File

@ -483,12 +483,6 @@ public class XTrayIconPeer implements TrayIconPeer,
}
}
static boolean isTrayIconStuffWindow(Window w) {
return (w instanceof InfoWindow.Tooltip) ||
(w instanceof InfoWindow.Balloon) ||
(w instanceof XTrayIconEmbeddedFrame);
}
// ***************************************
// Special embedded frame for tray icon
// ***************************************

View File

@ -53,7 +53,6 @@ import sun.util.logging.PlatformLogger;
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 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
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 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
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 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
}
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 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
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());

View File

@ -53,7 +53,12 @@ class WDialogPeer extends WWindowPeer implements DialogPeer {
}
}
native void create(WComponentPeer parent);
native void createAwtDialog(WComponentPeer parent);
void create(WComponentPeer parent) {
preCreate(parent);
createAwtDialog(parent);
}
native void showModal();
native void endModal();

View File

@ -136,6 +136,7 @@ class WFramePeer extends WWindowPeer implements FramePeer {
native void createAwtFrame(WComponentPeer parent);
void create(WComponentPeer parent) {
preCreate(parent);
createAwtFrame(parent);
}

View File

@ -199,7 +199,17 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
}
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);
}

View File

@ -760,7 +760,7 @@ extern "C" {
* 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;

View File

@ -163,9 +163,11 @@ jfieldID AwtWindow::sysXID;
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 @@ AwtWindow::AwtWindow() {
hContentBitmap = NULL;
::InitializeCriticalSection(&contentBitmapCS);
m_windowType = Type::NORMAL;
}
AwtWindow::~AwtWindow()
@ -475,6 +479,9 @@ void AwtWindow::CreateHWnd(JNIEnv *env, LPCWSTR title,
}
env->DeleteLocalRef(target);
InitType(env, peer);
TweakStyle(windowStyle, windowExStyle);
AwtCanvas::CreateHWnd(env, title,
windowStyle,
windowExStyle,
@ -982,6 +989,50 @@ void AwtWindow::_RepositionSecurityWarning(void* param)
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 @@ Java_java_awt_Window_initIDs(JNIEnv *env, jclass cls)
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 @@ Java_sun_awt_windows_WWindowPeer_initIDs(JNIEnv *env, jclass cls)
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;
}

View File

@ -63,8 +63,11 @@ public:
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 @@ protected:
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 */

View File

@ -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);
}
}