提交 f2e7d1ce 编写于 作者: A anthony

6693253: Security Warning appearance requires enhancements

6779717: A Window does not show applet security warning icon on X platforms
6785058: Parent dn't get the focus after dialog is closed if security warning is applied
Summary: Forward-port from 6u10-6u14
Reviewed-by: art, dcherepanov
上级 c13259e7
......@@ -71,6 +71,7 @@ STUBFILES = \
$(STUBDIR)/Ole2.h \
$(STUBDIR)/Zmouse.h \
$(STUBDIR)/cderr.h \
$(STUBDIR)/commctrl.h \
$(STUBDIR)/commdlg.h \
$(STUBDIR)/direct.h \
$(STUBDIR)/d3dcom.h \
......
......@@ -200,5 +200,6 @@ FILES_cpp = \
ShellFolder2.cpp \
ThemeReader.cpp \
ComCtl32Util.cpp \
DllUtil.cpp \
initIDs.cpp \
MouseInfo.cpp
......@@ -6,11 +6,9 @@ runtime, it will probably work with other versions of that compiler.
Included in this project is a generated file, make.depend, which lists
all interdependencies of the source files. This file is generated *on
Solaris* with the following commands:
Solaris or Linux* with the following command:
% sccs edit make.depend
% gnumake -f Depend.mak
% sccs delget make.depend
This step only needs to be run when new files are added to the project,
or include statements are changed.
......
此差异已折叠。
......@@ -78,4 +78,5 @@ FILES_c = \
awt_Plugin.c \
gtk2_interface.c \
swing_GTKEngine.c \
swing_GTKStyle.c
swing_GTKStyle.c \
rect.c
......@@ -79,6 +79,7 @@ vpath %.c $(SHARE_SRC)/native/sun/java2d
vpath %.c $(SHARE_SRC)/native/sun/java2d/loops
vpath %.c $(SHARE_SRC)/native/sun/java2d/pipe
vpath %.c $(SHARE_SRC)/native/sun/awt/medialib
vpath %.c $(SHARE_SRC)/native/sun/awt/utility
vpath %.cpp $(SHARE_SRC)/native/sun/image
vpath %.c $(SHARE_SRC)/native/sun/font
vpath %.c $(PLATFORM_SRC)/native/sun/awt/robot_child
......@@ -274,6 +275,23 @@ ICONS = \
$(ICONS_PATH_PREFIX)/classes/sun/awt/X11/java-icon32.png \
$(ICONS_PATH_PREFIX)/classes/sun/awt/X11/java-icon48.png
ICONPATH=$(PLATFORM_SRC)/classes/sun/awt/X11
ICONS += \
$(ICONPATH)/security-icon-bw16.png \
$(ICONPATH)/security-icon-interim16.png \
$(ICONPATH)/security-icon-yellow16.png \
$(ICONPATH)/security-icon-bw24.png \
$(ICONPATH)/security-icon-interim24.png \
$(ICONPATH)/security-icon-yellow24.png \
$(ICONPATH)/security-icon-bw32.png \
$(ICONPATH)/security-icon-interim32.png \
$(ICONPATH)/security-icon-yellow32.png \
$(ICONPATH)/security-icon-bw48.png \
$(ICONPATH)/security-icon-interim48.png \
$(ICONPATH)/security-icon-yellow48.png
TEMPDIR_CLASSES = $(TEMPDIR)/classes
$(TEMPDIR_CLASSES)/sun/awt/X11/ToBin.class: ToBin.java
......
......@@ -93,6 +93,8 @@ SUNWprivate_1.1 {
Java_sun_awt_X11_XlibWrapper_XGetWMHints;
Java_sun_awt_X11_XlibWrapper_XShapeQueryExtension;
Java_sun_awt_X11_XlibWrapper_SetRectangularShape;
Java_sun_awt_X11_XlibWrapper_SetBitmapShape;
Java_sun_awt_X11_XlibWrapper_XConfigureWindow;
Java_sun_awt_X11_XlibWrapper_SetZOrder;
Java_sun_awt_X11_XToolkit_initIDs;
Java_sun_awt_X11_XWindow_getNativeColor;
......
/*
* Copyright 2008-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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.awt;
import java.awt.*;
import java.awt.geom.*;
import sun.awt.AWTAccessor;
/**
* Security Warning control interface.
*
* This class provides a couple of methods that help a developer relocate
* the AWT security warning to an appropriate position relative to the current
* window size. A "top-level window" is an instance of the {@code Window}
* class (or its descendant, such as {@code JFrame}). The security warning
* is applied to all windows created by an untrusted code. All such windows
* have a non-null "warning string" (see {@link Window#getWarningString()}).
* <p>
* <b>WARNING</b>: This class is an implementation detail and only meant
* for limited use outside of the core platform. This API may change
* drastically between update release, and it may even be
* removed or be moved to some other packages or classes.
*/
public final class SecurityWarning {
/**
* The SecurityWarning class should not be instantiated
*/
private SecurityWarning() {
}
/**
* Gets the size of the security warning.
*
* The returned value is not valid until the peer has been created. Before
* invoking this method a developer must call the {@link Window#pack()},
* {@link Window#setVisible()}, or some other method that creates the peer.
*
* @param window the window to get the security warning size for
*
* @throws NullPointerException if the window argument is null
* @throws IllegalArgumentException if the window is trusted (i.e.
* the {@code getWarningString()} returns null)
*/
public static Dimension getSize(Window window) {
if (window == null) {
throw new NullPointerException(
"The window argument should not be null.");
}
if (window.getWarningString() == null) {
throw new IllegalArgumentException(
"The window must have a non-null warning string.");
}
// We don't check for a non-null peer since it may be destroyed
// after assigning a valid value to the security warning size.
return AWTAccessor.getWindowAccessor().getSecurityWarningSize(window);
}
/**
* Sets the position of the security warning.
* <p>
* The {@code alignmentX} and {@code alignmentY} arguments specify the
* origin of the coordinate system used to calculate the position of the
* security warning. The values must be in the range [0.0f...1.0f]. The
* {@code 0.0f} value represents the left (top) edge of the rectangular
* bounds of the window. The {@code 1.0f} value represents the right
* (bottom) edge of the bounds. Whenever the size of the window changes,
* the origin of the coordinate system gets relocated accordingly. For
* convenience a developer may use the {@code Component.*_ALIGNMENT}
* constants to pass predefined values for these arguments.
* <p>
* The {@code point} argument specifies the location of the security
* warning in the coordinate system described above. If both {@code x} and
* {@code y} coordinates of the point are equal to zero, the warning will
* be located right in the origin of the coordinate system. On the other
* hand, if both {@code alignmentX} and {@code alignmentY} are equal to
* zero (i.e. the origin of the coordinate system is placed at the top-left
* corner of the window), then the {@code point} argument represents the
* absolute location of the security warning relative to the location of
* the window. The "absolute" in this case means that the position of the
* security warning is not effected by resizing of the window.
* <p>
* Note that the security warning managment code guarantees that:
* <ul>
* <li>The security warning cannot be located farther than two pixels from
* the rectangular bounds of the window (see {@link Window#getBounds}), and
* <li>The security warning is always visible on the screen.
* </ul>
* If either of the conditions is violated, the calculated position of the
* security warning is adjusted by the system to meet both these
* conditions.
* <p>
* The default position of the security warning is in the upper-right
* corner of the window, two pixels to the right from the right edge. This
* corresponds to the following arguments passed to this method:
* <ul>
* <li>{@code alignmentX = Component.RIGHT_ALIGNMENT}
* <li>{@code alignmentY = Component.TOP_ALIGNMENT}
* <li>{@code point = (2, 0)}
* </ul>
*
* @param window the window to set the position of the security warning for
* @param alignmentX the horizontal origin of the coordinate system
* @param alignmentY the vertical origin of the coordinate system
* @param point the position of the security warning in the specified
* coordinate system
*
* @throws NullPointerException if the window argument is null
* @throws NullPointerException if the point argument is null
* @throws IllegalArgumentException if the window is trusted (i.e.
* the {@code getWarningString()} returns null
* @throws IllegalArgumentException if the alignmentX or alignmentY
* arguments are not within the range [0.0f ... 1.0f]
*/
public static void setPosition(Window window, Point2D point,
float alignmentX, float alignmentY)
{
if (window == null) {
throw new NullPointerException(
"The window argument should not be null.");
}
if (window.getWarningString() == null) {
throw new IllegalArgumentException(
"The window must have a non-null warning string.");
}
if (point == null) {
throw new NullPointerException(
"The point argument must not be null");
}
if (alignmentX < 0.0f || alignmentX > 1.0f) {
throw new IllegalArgumentException(
"alignmentX must be in the range [0.0f ... 1.0f].");
}
if (alignmentY < 0.0f || alignmentY > 1.0f) {
throw new IllegalArgumentException(
"alignmentY must be in the range [0.0f ... 1.0f].");
}
AWTAccessor.getWindowAccessor().setSecurityWarningPosition(window,
point, alignmentX, alignmentY);
}
}
......@@ -857,6 +857,10 @@ public abstract class Component implements ImageObserver, MenuContainer,
public boolean canBeFocusOwner(Component comp) {
return comp.canBeFocusOwner();
}
public boolean isVisible_NoClientCode(Component comp) {
return comp.isVisible_NoClientCode();
}
});
}
......
......@@ -25,6 +25,7 @@
package java.awt;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.awt.im.InputContext;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
......@@ -326,6 +327,23 @@ public class Window extends Container implements Accessible {
transient boolean isTrayIconWindow = false;
/**
* These fields are initialized in the native peer code
* or via AWTAccessor's WindowAccessor.
*/
private transient volatile int securityWarningWidth = 0;
private transient volatile int securityWarningHeight = 0;
/**
* These fields represent the desired location for the security
* warning if this window is untrusted.
* See com.sun.awt.SecurityWarning for more details.
*/
private transient double securityWarningPointX = 2.0;
private transient double securityWarningPointY = 0.0;
private transient float securityWarningAlignmentX = RIGHT_ALIGNMENT;
private transient float securityWarningAlignmentY = TOP_ALIGNMENT;
static {
/* ensure that the necessary native libraries are loaded */
Toolkit.loadLibraries();
......@@ -2881,6 +2899,13 @@ public class Window extends Container implements Accessible {
shape = (Shape)f.get("shape", null);
opacity = (Float)f.get("opacity", 1.0f);
this.securityWarningWidth = 0;
this.securityWarningHeight = 0;
this.securityWarningPointX = 2.0;
this.securityWarningPointY = 0.0;
this.securityWarningAlignmentX = RIGHT_ALIGNMENT;
this.securityWarningAlignmentY = TOP_ALIGNMENT;
deserializeResources(s);
}
......@@ -3568,6 +3593,18 @@ public class Window extends Container implements Accessible {
// ****************** END OF MIXING CODE ********************************
// This method gets the window location/size as reported by the native
// system since the locally cached values may represent outdated data.
// NOTE: this method is invoked on the toolkit thread, and therefore
// is not supposed to become public/user-overridable.
private Point2D calculateSecurityWarningPosition(double x, double y,
double w, double h)
{
return new Point2D.Double(
x + w * securityWarningAlignmentX + securityWarningPointX,
y + h * securityWarningAlignmentY + securityWarningPointY);
}
static {
AWTAccessor.setWindowAccessor(new AWTAccessor.WindowAccessor() {
public float getOpacity(Window window) {
......@@ -3601,6 +3638,39 @@ public class Window extends Container implements Accessible {
public void updateWindow(Window window, BufferedImage backBuffer) {
window.updateWindow(backBuffer);
}
public Dimension getSecurityWarningSize(Window window) {
return new Dimension(window.securityWarningWidth,
window.securityWarningHeight);
}
public void setSecurityWarningSize(Window window, int width, int height)
{
window.securityWarningWidth = width;
window.securityWarningHeight = height;
}
public void setSecurityWarningPosition(Window window,
Point2D point, float alignmentX, float alignmentY)
{
window.securityWarningPointX = point.getX();
window.securityWarningPointY = point.getY();
window.securityWarningAlignmentX = alignmentX;
window.securityWarningAlignmentY = alignmentY;
synchronized (window.getTreeLock()) {
WindowPeer peer = (WindowPeer)window.getPeer();
if (peer != null) {
peer.repositionSecurityWarning();
}
}
}
public Point2D calculateSecurityWarningPosition(Window window,
double x, double y, double w, double h)
{
return window.calculateSecurityWarningPosition(x, y, w, h);
}
}); // WindowAccessor
} // static
......
......@@ -116,4 +116,9 @@ public interface WindowPeer extends ContainerPeer {
* @see Window#setBackground(Color)
*/
void updateWindow(BufferedImage backBuffer);
/**
* Instructs the peer to update the position of the security warning.
*/
void repositionSecurityWarning();
}
......@@ -92,6 +92,12 @@ public final class AWTAccessor {
* Determines if the component can gain focus.
*/
boolean canBeFocusOwner(Component comp);
/**
* Returns whether the component is visible without invoking
* any client code.
*/
boolean isVisible_NoClientCode(Component comp);
}
/*
......@@ -127,6 +133,26 @@ public final class AWTAccessor {
* Update the image of a non-opaque (translucent) window.
*/
void updateWindow(Window window, BufferedImage backBuffer);
/** Get the size of the security warning.
*/
Dimension getSecurityWarningSize(Window w);
/**
* Set the size of the security warning.
*/
void setSecurityWarningSize(Window w, int width, int height);
/** Set the position of the security warning.
*/
void setSecurityWarningPosition(Window w, Point2D point,
float alignmentX, float alignmentY);
/** Request to recalculate the new position of the security warning for
* the given window size/location as reported by the native system.
*/
Point2D calculateSecurityWarningPosition(Window window,
double x, double y, double w, double h);
}
/*
......
......@@ -592,5 +592,7 @@ public abstract class EmbeddedFrame extends Frame
}
public void updateWindow(BufferedImage backBuffer) {
}
public void repositionSecurityWarning() {
}
}
} // class EmbeddedFrame
/*
* 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package sun.awt.X11;
import java.awt.*;
import java.awt.event.*;
import java.awt.peer.TrayIconPeer;
import sun.awt.*;
import java.awt.image.*;
import java.text.BreakIterator;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.concurrent.ArrayBlockingQueue;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.lang.reflect.InvocationTargetException;
/**
* An utility window class. This is a base class for Tooltip and Balloon.
*/
public abstract class InfoWindow extends Window {
private Container container;
private Closer closer;
protected InfoWindow(Frame parent, Color borderColor) {
super(parent);
container = new Container() {
@Override
public Insets getInsets() {
return new Insets(1, 1, 1, 1);
}
};
setLayout(new BorderLayout());
setBackground(borderColor);
add(container, BorderLayout.CENTER);
container.setLayout(new BorderLayout());
closer = new Closer();
}
public Component add(Component c) {
container.add(c, BorderLayout.CENTER);
return c;
}
protected void setCloser(Runnable action, int time) {
closer.set(action, time);
}
// Must be executed on EDT.
protected void show(Point corner, int indent) {
assert SunToolkit.isDispatchThreadForAppContext(this);
pack();
Dimension size = getSize();
// TODO: When 6356322 is fixed we should get screen bounds in
// this way: eframe.getGraphicsConfiguration().getBounds().
Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize();
if (corner.x < scrSize.width/2 && corner.y < scrSize.height/2) { // 1st square
setLocation(corner.x + indent, corner.y + indent);
} else if (corner.x >= scrSize.width/2 && corner.y < scrSize.height/2) { // 2nd square
setLocation(corner.x - indent - size.width, corner.y + indent);
} else if (corner.x < scrSize.width/2 && corner.y >= scrSize.height/2) { // 3rd square
setLocation(corner.x + indent, corner.y - indent - size.height);
} else if (corner.x >= scrSize.width/2 && corner.y >= scrSize.height/2) { // 4th square
setLocation(corner.x - indent - size.width, corner.y - indent - size.height);
}
super.show();
closer.schedule();
}
public void hide() {
closer.close();
}
private class Closer implements Runnable {
Runnable action;
int time;
public void run() {
doClose();
}
void set(Runnable action, int time) {
this.action = action;
this.time = time;
}
void schedule() {
XToolkit.schedule(this, time);
}
void close() {
XToolkit.remove(this);
doClose();
}
// WARNING: this method may be executed on Toolkit thread.
private void doClose() {
SunToolkit.executeOnEventHandlerThread(InfoWindow.this, new Runnable() {
public void run() {
InfoWindow.super.hide();
invalidate();
if (action != null) {
action.run();
}
}
});
}
}
private interface LiveArguments {
/** Whether the target of the InfoWindow is disposed. */
boolean isDisposed();
/** The bounds of the target of the InfoWindow. */
Rectangle getBounds();
}
public static class Tooltip extends InfoWindow {
public interface LiveArguments extends InfoWindow.LiveArguments {
/** The tooltip to be displayed. */
String getTooltipString();
}
private final Object target;
private final LiveArguments liveArguments;
private final Label textLabel = new Label("");
private final Runnable starter = new Runnable() {
public void run() {
display();
}};
private final static int TOOLTIP_SHOW_TIME = 10000;
private final static int TOOLTIP_START_DELAY_TIME = 1000;
private final static int TOOLTIP_MAX_LENGTH = 64;
private final static int TOOLTIP_MOUSE_CURSOR_INDENT = 5;
private final static Color TOOLTIP_BACKGROUND_COLOR = new Color(255, 255, 220);
private final static Font TOOLTIP_TEXT_FONT = XWindow.getDefaultFont();
public Tooltip(Frame parent, Object target,
LiveArguments liveArguments)
{
super(parent, Color.black);
this.target = target;
this.liveArguments = liveArguments;
XTrayIconPeer.suppressWarningString(this);
setCloser(null, TOOLTIP_SHOW_TIME);
textLabel.setBackground(TOOLTIP_BACKGROUND_COLOR);
textLabel.setFont(TOOLTIP_TEXT_FONT);
add(textLabel);
}
/*
* WARNING: this method is executed on Toolkit thread!
*/
private void display() {
String tooltipString = liveArguments.getTooltipString();
if (tooltipString == null) {
return;
} else if (tooltipString.length() > TOOLTIP_MAX_LENGTH) {
textLabel.setText(tooltipString.substring(0, TOOLTIP_MAX_LENGTH));
} else {
textLabel.setText(tooltipString);
}
// Execute on EDT to avoid deadlock (see 6280857).
SunToolkit.executeOnEventHandlerThread(target, new Runnable() {
public void run() {
if (liveArguments.isDisposed()) {
return;
}
Point pointer = (Point)AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
if (!isPointerOverTrayIcon(liveArguments.getBounds())) {
return null;
}
return MouseInfo.getPointerInfo().getLocation();
}
});
if (pointer == null) {
return;
}
show(new Point(pointer.x, pointer.y), TOOLTIP_MOUSE_CURSOR_INDENT);
}
});
}
public void enter() {
XToolkit.schedule(starter, TOOLTIP_START_DELAY_TIME);
}
public void exit() {
XToolkit.remove(starter);
if (isVisible()) {
hide();
}
}
private boolean isPointerOverTrayIcon(Rectangle trayRect) {
Point p = MouseInfo.getPointerInfo().getLocation();
return !(p.x < trayRect.x || p.x > (trayRect.x + trayRect.width) ||
p.y < trayRect.y || p.y > (trayRect.y + trayRect.height));
}
}
public static class Balloon extends InfoWindow {
public interface LiveArguments extends InfoWindow.LiveArguments {
/** The action to be performed upon clicking the baloon. */
String getActionCommand();
}
private final LiveArguments liveArguments;
private final Object target;
private final static int BALLOON_SHOW_TIME = 10000;
private final static int BALLOON_TEXT_MAX_LENGTH = 256;
private final static int BALLOON_WORD_LINE_MAX_LENGTH = 16;
private final static int BALLOON_WORD_LINE_MAX_COUNT = 4;
private final static int BALLOON_ICON_WIDTH = 32;
private final static int BALLOON_ICON_HEIGHT = 32;
private final static int BALLOON_TRAY_ICON_INDENT = 0;
private final static Color BALLOON_CAPTION_BACKGROUND_COLOR = new Color(200, 200 ,255);
private final static Font BALLOON_CAPTION_FONT = new Font(Font.DIALOG, Font.BOLD, 12);
private Panel mainPanel = new Panel();
private Panel captionPanel = new Panel();
private Label captionLabel = new Label("");
private Button closeButton = new Button("X");
private Panel textPanel = new Panel();
private XTrayIconPeer.IconCanvas iconCanvas = new XTrayIconPeer.IconCanvas(BALLOON_ICON_WIDTH, BALLOON_ICON_HEIGHT);
private Label[] lineLabels = new Label[BALLOON_WORD_LINE_MAX_COUNT];
private ActionPerformer ap = new ActionPerformer();
private Image iconImage;
private Image errorImage;
private Image warnImage;
private Image infoImage;
private boolean gtkImagesLoaded;
private Displayer displayer = new Displayer();
public Balloon(Frame parent, Object target, LiveArguments liveArguments) {
super(parent, new Color(90, 80 ,190));
this.liveArguments = liveArguments;
this.target = target;
XTrayIconPeer.suppressWarningString(this);
setCloser(new Runnable() {
public void run() {
if (textPanel != null) {
textPanel.removeAll();
textPanel.setSize(0, 0);
iconCanvas.setSize(0, 0);
XToolkit.awtLock();
try {
displayer.isDisplayed = false;
XToolkit.awtLockNotifyAll();
} finally {
XToolkit.awtUnlock();
}
}
}
}, BALLOON_SHOW_TIME);
add(mainPanel);
captionLabel.setFont(BALLOON_CAPTION_FONT);
captionLabel.addMouseListener(ap);
captionPanel.setLayout(new BorderLayout());
captionPanel.add(captionLabel, BorderLayout.WEST);
captionPanel.add(closeButton, BorderLayout.EAST);
captionPanel.setBackground(BALLOON_CAPTION_BACKGROUND_COLOR);
captionPanel.addMouseListener(ap);
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
hide();
}
});
mainPanel.setLayout(new BorderLayout());
mainPanel.setBackground(Color.white);
mainPanel.add(captionPanel, BorderLayout.NORTH);
mainPanel.add(iconCanvas, BorderLayout.WEST);
mainPanel.add(textPanel, BorderLayout.CENTER);
iconCanvas.addMouseListener(ap);
for (int i = 0; i < BALLOON_WORD_LINE_MAX_COUNT; i++) {
lineLabels[i] = new Label();
lineLabels[i].addMouseListener(ap);
lineLabels[i].setBackground(Color.white);
}
displayer.start();
}
public void display(String caption, String text, String messageType) {
if (!gtkImagesLoaded) {
loadGtkImages();
}
displayer.display(caption, text, messageType);
}
private void _display(String caption, String text, String messageType) {
captionLabel.setText(caption);
BreakIterator iter = BreakIterator.getWordInstance();
if (text != null) {
iter.setText(text);
int start = iter.first(), end;
int nLines = 0;
do {
end = iter.next();
if (end == BreakIterator.DONE ||
text.substring(start, end).length() >= 50)
{
lineLabels[nLines].setText(text.substring(start, end == BreakIterator.DONE ?
iter.last() : end));
textPanel.add(lineLabels[nLines++]);
start = end;
}
if (nLines == BALLOON_WORD_LINE_MAX_COUNT) {
if (end != BreakIterator.DONE) {
lineLabels[nLines - 1].setText(
new String(lineLabels[nLines - 1].getText() + " ..."));
}
break;
}
} while (end != BreakIterator.DONE);
textPanel.setLayout(new GridLayout(nLines, 1));
}
if ("ERROR".equals(messageType)) {
iconImage = errorImage;
} else if ("WARNING".equals(messageType)) {
iconImage = warnImage;
} else if ("INFO".equals(messageType)) {
iconImage = infoImage;
} else {
iconImage = null;
}
if (iconImage != null) {
Dimension tpSize = textPanel.getSize();
iconCanvas.setSize(BALLOON_ICON_WIDTH, (BALLOON_ICON_HEIGHT > tpSize.height ?
BALLOON_ICON_HEIGHT : tpSize.height));
iconCanvas.validate();
}
SunToolkit.executeOnEventHandlerThread(target, new Runnable() {
public void run() {
if (liveArguments.isDisposed()) {
return;
}
Point parLoc = getParent().getLocationOnScreen();
Dimension parSize = getParent().getSize();
show(new Point(parLoc.x + parSize.width/2, parLoc.y + parSize.height/2),
BALLOON_TRAY_ICON_INDENT);
if (iconImage != null) {
iconCanvas.updateImage(iconImage); // call it after the show(..) above
}
}
});
}
public void dispose() {
displayer.interrupt();
super.dispose();
}
private void loadGtkImages() {
if (!gtkImagesLoaded) {
errorImage = (Image)Toolkit.getDefaultToolkit().getDesktopProperty(
"gtk.icon.gtk-dialog-error.6.rtl");
warnImage = (Image)Toolkit.getDefaultToolkit().getDesktopProperty(
"gtk.icon.gtk-dialog-warning.6.rtl");
infoImage = (Image)Toolkit.getDefaultToolkit().getDesktopProperty(
"gtk.icon.gtk-dialog-info.6.rtl");
gtkImagesLoaded = true;
}
}
private class ActionPerformer extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
// hide the balloon by any click
hide();
if (e.getButton() == MouseEvent.BUTTON1) {
ActionEvent aev = new ActionEvent(target, ActionEvent.ACTION_PERFORMED,
liveArguments.getActionCommand(),
e.getWhen(), e.getModifiers());
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(aev);
}
}
}
private class Displayer extends Thread {
final int MAX_CONCURRENT_MSGS = 10;
ArrayBlockingQueue<Message> messageQueue = new ArrayBlockingQueue<Message>(MAX_CONCURRENT_MSGS);
boolean isDisplayed;
Displayer() {
setDaemon(true);
}
public void run() {
while (true) {
Message msg = null;
try {
msg = (Message)messageQueue.take();
} catch (InterruptedException e) {
return;
}
/*
* Wait till the previous message is displayed if any
*/
XToolkit.awtLock();
try {
while (isDisplayed) {
try {
XToolkit.awtLockWait();
} catch (InterruptedException e) {
return;
}
}
isDisplayed = true;
} finally {
XToolkit.awtUnlock();
}
_display(msg.caption, msg.text, msg.messageType);
}
}
void display(String caption, String text, String messageType) {
messageQueue.offer(new Message(caption, text, messageType));
}
}
private static class Message {
String caption, text, messageType;
Message(String caption, String text, String messageType) {
this.caption = caption;
this.text = text;
this.messageType = messageType;
}
}
}
}
......@@ -451,7 +451,7 @@ abstract class XDecoratedPeer extends XWindowPeer {
public Insets getInsets() {
Insets in = copy(getRealInsets());
in.top += getMenuBarHeight() + getWarningWindowHeight();
in.top += getMenuBarHeight();
if (insLog.isLoggable(Level.FINEST)) {
insLog.log(Level.FINEST, "Get insets returns {0}", new Object[] {in});
}
......@@ -802,6 +802,8 @@ abstract class XDecoratedPeer extends XWindowPeer {
}
reconfigureContentWindow(newDimensions);
updateChildrenSizes();
repositionSecurityWarning();
}
private void checkShellRectSize(Rectangle shellRect) {
......
......@@ -83,8 +83,25 @@ public class XKeyboardFocusManagerPeer extends KeyboardFocusManagerPeerImpl {
public static void setCurrentNativeFocusedWindow(Window win) {
if (focusLog.isLoggable(Level.FINER)) focusLog.finer("Setting current native focused window " + win);
XWindowPeer from = null, to = null;
synchronized(lock) {
if (currentFocusedWindow != null) {
from = (XWindowPeer)currentFocusedWindow.getPeer();
}
currentFocusedWindow = win;
if (currentFocusedWindow != null) {
to = (XWindowPeer)currentFocusedWindow.getPeer();
}
}
if (from != null) {
from.updateSecurityWarningVisibility();
}
if (to != null) {
to.updateSecurityWarningVisibility();
}
}
......
......@@ -169,6 +169,34 @@ final class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProt
return ((layer == LAYER_ALWAYS_ON_TOP) || (layer == LAYER_NORMAL)) && doLayerProtocol();
}
public void requestState(XWindow window, XAtom state, boolean isAdd) {
XClientMessageEvent req = new XClientMessageEvent();
try {
req.set_type((int)XConstants.ClientMessage);
req.set_window(window.getWindow());
req.set_message_type(XA_NET_WM_STATE.getAtom());
req.set_format(32);
req.set_data(0, isAdd ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE);
req.set_data(1, state.getAtom());
// Fix for 6735584: req.data[2] must be set to 0 when only one property is changed
req.set_data(2, 0);
log.log(Level.FINE, "Setting _NET_STATE atom {0} on {1} for {2}", new Object[] {state, window, Boolean.valueOf(isAdd)});
XToolkit.awtLock();
try {
XlibWrapper.XSendEvent(XToolkit.getDisplay(),
XlibWrapper.RootWindow(XToolkit.getDisplay(), window.getScreenNumber()),
false,
XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask,
req.pData);
}
finally {
XToolkit.awtUnlock();
}
} finally {
req.dispose();
}
}
/**
* Helper function to set/reset one state in NET_WM_STATE
* If window is showing then it uses ClientMessage, otherwise adjusts NET_WM_STATE list
......@@ -181,31 +209,7 @@ final class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProt
new Object[] {Boolean.valueOf(window.isWithdrawn()), Boolean.valueOf(window.isVisible()),
Boolean.valueOf(window.isMapped()), Boolean.valueOf(window.isShowing())});
if (window.isShowing()) {
XClientMessageEvent req = new XClientMessageEvent();
try {
req.set_type((int)XConstants.ClientMessage);
req.set_window(window.getWindow());
req.set_message_type(XA_NET_WM_STATE.getAtom());
req.set_format(32);
req.set_data(0, (!set) ? _NET_WM_STATE_REMOVE : _NET_WM_STATE_ADD);
req.set_data(1, state.getAtom());
// Fix for 6735584: req.data[2] must be set to 0 when only one property is changed
req.set_data(2, 0);
log.log(Level.FINE, "Setting _NET_STATE atom {0} on {1} for {2}", new Object[] {state, window, Boolean.valueOf(set)});
XToolkit.awtLock();
try {
XlibWrapper.XSendEvent(XToolkit.getDisplay(),
XlibWrapper.RootWindow(XToolkit.getDisplay(), window.getScreenNumber()),
false,
XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask,
req.pData);
}
finally {
XToolkit.awtUnlock();
}
} finally {
req.dispose();
}
requestState(window, state, set);
} else {
XAtomList net_wm_state = window.getNETWMState();
log.log(Level.FINE, "Current state on {0} is {1}", new Object[] {window, net_wm_state});
......
......@@ -38,15 +38,18 @@ import java.security.AccessController;
import java.security.PrivilegedAction;
import java.lang.reflect.InvocationTargetException;
public class XTrayIconPeer implements TrayIconPeer {
public class XTrayIconPeer implements TrayIconPeer,
InfoWindow.Balloon.LiveArguments,
InfoWindow.Tooltip.LiveArguments
{
private static final Logger ctrLog = Logger.getLogger("sun.awt.X11.XTrayIconPeer.centering");
TrayIcon target;
TrayIconEventProxy eventProxy;
XTrayIconEmbeddedFrame eframe;
TrayIconCanvas canvas;
Balloon balloon;
Tooltip tooltip;
InfoWindow.Balloon balloon;
InfoWindow.Tooltip tooltip;
PopupMenu popup;
String tooltipString;
boolean isTrayIconDisplayed;
......@@ -255,8 +258,8 @@ public class XTrayIconPeer implements TrayIconPeer {
eframe.setVisible(true);
updateImage();
balloon = new Balloon(this, eframe);
tooltip = new Tooltip(this, eframe);
balloon = new InfoWindow.Balloon(eframe, target, this);
tooltip = new InfoWindow.Tooltip(eframe, target, this);
addListeners();
}
......@@ -300,6 +303,10 @@ public class XTrayIconPeer implements TrayIconPeer {
tooltipString = tooltip;
}
public String getTooltipString() {
return tooltipString;
}
public void updateImage() {
Runnable r = new Runnable() {
public void run() {
......@@ -385,7 +392,7 @@ public class XTrayIconPeer implements TrayIconPeer {
return eframe.getLocationOnScreen();
}
private Rectangle getBounds() {
public Rectangle getBounds() {
Point loc = getLocationOnScreen();
return new Rectangle(loc.x, loc.y, loc.x + TRAY_ICON_WIDTH, loc.y + TRAY_ICON_HEIGHT);
}
......@@ -399,10 +406,14 @@ public class XTrayIconPeer implements TrayIconPeer {
return ((XEmbeddedFramePeer)eframe.getPeer()).getWindow();
}
boolean isDisposed() {
public boolean isDisposed() {
return isDisposed;
}
public String getActionCommand() {
return target.getActionCommand();
}
static class TrayIconEventProxy implements MouseListener, MouseMotionListener {
XTrayIconPeer xtiPeer;
......@@ -474,8 +485,8 @@ public class XTrayIconPeer implements TrayIconPeer {
}
static boolean isTrayIconStuffWindow(Window w) {
return (w instanceof Tooltip) ||
(w instanceof Balloon) ||
return (w instanceof InfoWindow.Tooltip) ||
(w instanceof InfoWindow.Balloon) ||
(w instanceof XTrayIconEmbeddedFrame);
}
......@@ -530,7 +541,7 @@ public class XTrayIconPeer implements TrayIconPeer {
}
}
static class IconCanvas extends Canvas {
public static class IconCanvas extends Canvas {
volatile Image image;
IconObserver observer;
int width, height;
......@@ -608,429 +619,4 @@ public class XTrayIconPeer implements TrayIconPeer {
}
}
}
// ***************************************
// Classes for toolitp and balloon windows
// ***************************************
static class Tooltip extends InfoWindow {
XTrayIconPeer xtiPeer;
Label textLabel = new Label("");
Runnable starter = new Runnable() {
public void run() {
display();
}};
final static int TOOLTIP_SHOW_TIME = 10000;
final static int TOOLTIP_START_DELAY_TIME = 1000;
final static int TOOLTIP_MAX_LENGTH = 64;
final static int TOOLTIP_MOUSE_CURSOR_INDENT = 5;
final static Color TOOLTIP_BACKGROUND_COLOR = new Color(255, 255, 220);
final static Font TOOLTIP_TEXT_FONT = XWindow.getDefaultFont();
Tooltip(XTrayIconPeer xtiPeer, Frame parent) {
super(parent, Color.black);
this.xtiPeer = xtiPeer;
suppressWarningString(this);
setCloser(null, TOOLTIP_SHOW_TIME);
textLabel.setBackground(TOOLTIP_BACKGROUND_COLOR);
textLabel.setFont(TOOLTIP_TEXT_FONT);
add(textLabel);
}
/*
* WARNING: this method is executed on Toolkit thread!
*/
void display() {
String tip = xtiPeer.tooltipString;
if (tip == null) {
return;
} else if (tip.length() > TOOLTIP_MAX_LENGTH) {
textLabel.setText(tip.substring(0, TOOLTIP_MAX_LENGTH));
} else {
textLabel.setText(tip);
}
// Execute on EDT to avoid deadlock (see 6280857).
SunToolkit.executeOnEventHandlerThread(xtiPeer.target, new Runnable() {
public void run() {
if (xtiPeer.isDisposed()) {
return;
}
Point pointer = (Point)AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
if (!isPointerOverTrayIcon(xtiPeer.getBounds())) {
return null;
}
return MouseInfo.getPointerInfo().getLocation();
}
});
if (pointer == null) {
return;
}
show(new Point(pointer.x, pointer.y), TOOLTIP_MOUSE_CURSOR_INDENT);
}
});
}
void enter() {
XToolkit.schedule(starter, TOOLTIP_START_DELAY_TIME);
}
void exit() {
XToolkit.remove(starter);
if (isVisible()) {
hide();
}
}
boolean isPointerOverTrayIcon(Rectangle trayRect) {
Point p = MouseInfo.getPointerInfo().getLocation();
return !(p.x < trayRect.x || p.x > (trayRect.x + trayRect.width) ||
p.y < trayRect.y || p.y > (trayRect.y + trayRect.height));
}
}
static class Balloon extends InfoWindow {
final static int BALLOON_SHOW_TIME = 10000;
final static int BALLOON_TEXT_MAX_LENGTH = 256;
final static int BALLOON_WORD_LINE_MAX_LENGTH = 16;
final static int BALLOON_WORD_LINE_MAX_COUNT = 4;
final static int BALLOON_ICON_WIDTH = 32;
final static int BALLOON_ICON_HEIGHT = 32;
final static int BALLOON_TRAY_ICON_INDENT = 0;
final static Color BALLOON_CAPTION_BACKGROUND_COLOR = new Color(200, 200 ,255);
final static Font BALLOON_CAPTION_FONT = new Font(Font.DIALOG, Font.BOLD, 12);
XTrayIconPeer xtiPeer;
Panel mainPanel = new Panel();
Panel captionPanel = new Panel();
Label captionLabel = new Label("");
Button closeButton = new Button("X");
Panel textPanel = new Panel();
IconCanvas iconCanvas = new IconCanvas(BALLOON_ICON_WIDTH, BALLOON_ICON_HEIGHT);
Label[] lineLabels = new Label[BALLOON_WORD_LINE_MAX_COUNT];
ActionPerformer ap = new ActionPerformer();
Image iconImage;
Image errorImage;
Image warnImage;
Image infoImage;
boolean gtkImagesLoaded;
Displayer displayer = new Displayer();
Balloon(final XTrayIconPeer xtiPeer, Frame parent) {
super(parent, new Color(90, 80 ,190));
this.xtiPeer = xtiPeer;
suppressWarningString(this);
setCloser(new Runnable() {
public void run() {
if (textPanel != null) {
textPanel.removeAll();
textPanel.setSize(0, 0);
iconCanvas.setSize(0, 0);
XToolkit.awtLock();
try {
displayer.isDisplayed = false;
XToolkit.awtLockNotifyAll();
} finally {
XToolkit.awtUnlock();
}
}
}
}, BALLOON_SHOW_TIME);
add(mainPanel);
captionLabel.setFont(BALLOON_CAPTION_FONT);
captionLabel.addMouseListener(ap);
captionPanel.setLayout(new BorderLayout());
captionPanel.add(captionLabel, BorderLayout.WEST);
captionPanel.add(closeButton, BorderLayout.EAST);
captionPanel.setBackground(BALLOON_CAPTION_BACKGROUND_COLOR);
captionPanel.addMouseListener(ap);
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
hide();
}
});
mainPanel.setLayout(new BorderLayout());
mainPanel.setBackground(Color.white);
mainPanel.add(captionPanel, BorderLayout.NORTH);
mainPanel.add(iconCanvas, BorderLayout.WEST);
mainPanel.add(textPanel, BorderLayout.CENTER);
iconCanvas.addMouseListener(ap);
for (int i = 0; i < BALLOON_WORD_LINE_MAX_COUNT; i++) {
lineLabels[i] = new Label();
lineLabels[i].addMouseListener(ap);
lineLabels[i].setBackground(Color.white);
}
displayer.start();
}
void display(String caption, String text, String messageType) {
if (!gtkImagesLoaded) {
loadGtkImages();
}
displayer.display(caption, text, messageType);
}
private void _display(String caption, String text, String messageType) {
captionLabel.setText(caption);
BreakIterator iter = BreakIterator.getWordInstance();
if (text != null) {
iter.setText(text);
int start = iter.first(), end;
int nLines = 0;
do {
end = iter.next();
if (end == BreakIterator.DONE ||
text.substring(start, end).length() >= 50)
{
lineLabels[nLines].setText(text.substring(start, end == BreakIterator.DONE ?
iter.last() : end));
textPanel.add(lineLabels[nLines++]);
start = end;
}
if (nLines == BALLOON_WORD_LINE_MAX_COUNT) {
if (end != BreakIterator.DONE) {
lineLabels[nLines - 1].setText(
new String(lineLabels[nLines - 1].getText() + " ..."));
}
break;
}
} while (end != BreakIterator.DONE);
textPanel.setLayout(new GridLayout(nLines, 1));
}
if ("ERROR".equals(messageType)) {
iconImage = errorImage;
} else if ("WARNING".equals(messageType)) {
iconImage = warnImage;
} else if ("INFO".equals(messageType)) {
iconImage = infoImage;
} else {
iconImage = null;
}
if (iconImage != null) {
Dimension tpSize = textPanel.getSize();
iconCanvas.setSize(BALLOON_ICON_WIDTH, (BALLOON_ICON_HEIGHT > tpSize.height ?
BALLOON_ICON_HEIGHT : tpSize.height));
iconCanvas.validate();
}
SunToolkit.executeOnEventHandlerThread(xtiPeer.target, new Runnable() {
public void run() {
if (xtiPeer.isDisposed()) {
return;
}
Point parLoc = getParent().getLocationOnScreen();
Dimension parSize = getParent().getSize();
show(new Point(parLoc.x + parSize.width/2, parLoc.y + parSize.height/2),
BALLOON_TRAY_ICON_INDENT);
if (iconImage != null) {
iconCanvas.updateImage(iconImage); // call it after the show(..) above
}
}
});
}
public void dispose() {
displayer.interrupt();
super.dispose();
}
void loadGtkImages() {
if (!gtkImagesLoaded) {
errorImage = (Image)Toolkit.getDefaultToolkit().getDesktopProperty(
"gtk.icon.gtk-dialog-error.6.rtl");
warnImage = (Image)Toolkit.getDefaultToolkit().getDesktopProperty(
"gtk.icon.gtk-dialog-warning.6.rtl");
infoImage = (Image)Toolkit.getDefaultToolkit().getDesktopProperty(
"gtk.icon.gtk-dialog-info.6.rtl");
gtkImagesLoaded = true;
}
}
class ActionPerformer extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
// hide the balloon by any click
hide();
if (e.getButton() == MouseEvent.BUTTON1) {
ActionEvent aev = new ActionEvent(xtiPeer.target, ActionEvent.ACTION_PERFORMED,
xtiPeer.target.getActionCommand(),
e.getWhen(), e.getModifiers());
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(aev);
}
}
}
class Displayer extends Thread {
final int MAX_CONCURRENT_MSGS = 10;
ArrayBlockingQueue<Message> messageQueue = new ArrayBlockingQueue<Message>(MAX_CONCURRENT_MSGS);
boolean isDisplayed;
Displayer() {
setDaemon(true);
}
public void run() {
while (true) {
Message msg = null;
try {
msg = (Message)messageQueue.take();
} catch (InterruptedException e) {
return;
}
/*
* Wait till the previous message is displayed if any
*/
XToolkit.awtLock();
try {
while (isDisplayed) {
try {
XToolkit.awtLockWait();
} catch (InterruptedException e) {
return;
}
}
isDisplayed = true;
} finally {
XToolkit.awtUnlock();
}
_display(msg.caption, msg.text, msg.messageType);
}
}
void display(String caption, String text, String messageType) {
messageQueue.offer(new Message(caption, text, messageType));
}
}
class Message {
String caption, text, messageType;
Message(String caption, String text, String messageType) {
this.caption = caption;
this.text = text;
this.messageType = messageType;
}
}
}
static class InfoWindow extends Window {
Container container;
Closer closer;
InfoWindow(Frame parent, Color borderColor) {
super(parent);
container = new Container() {
public Insets getInsets() {
return new Insets(1, 1, 1, 1);
}
};
setLayout(new BorderLayout());
setBackground(borderColor);
add(container, BorderLayout.CENTER);
container.setLayout(new BorderLayout());
closer = new Closer();
}
public Component add(Component c) {
container.add(c, BorderLayout.CENTER);
return c;
}
void setCloser(Runnable action, int time) {
closer.set(action, time);
}
// Must be executed on EDT.
protected void show(Point corner, int indent) {
assert SunToolkit.isDispatchThreadForAppContext(InfoWindow.this);
pack();
Dimension size = getSize();
// TODO: When 6356322 is fixed we should get screen bounds in
// this way: eframe.getGraphicsConfiguration().getBounds().
Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize();
if (corner.x < scrSize.width/2 && corner.y < scrSize.height/2) { // 1st square
setLocation(corner.x + indent, corner.y + indent);
} else if (corner.x >= scrSize.width/2 && corner.y < scrSize.height/2) { // 2nd square
setLocation(corner.x - indent - size.width, corner.y + indent);
} else if (corner.x < scrSize.width/2 && corner.y >= scrSize.height/2) { // 3rd square
setLocation(corner.x + indent, corner.y - indent - size.height);
} else if (corner.x >= scrSize.width/2 && corner.y >= scrSize.height/2) { // 4th square
setLocation(corner.x - indent - size.width, corner.y - indent - size.height);
}
InfoWindow.super.show();
InfoWindow.this.closer.schedule();
}
public void hide() {
closer.close();
}
class Closer implements Runnable {
Runnable action;
int time;
public void run() {
doClose();
}
void set(Runnable action, int time) {
this.action = action;
this.time = time;
}
void schedule() {
XToolkit.schedule(this, time);
}
void close() {
XToolkit.remove(this);
doClose();
}
// WARNING: this method may be executed on Toolkit thread.
private void doClose() {
SunToolkit.executeOnEventHandlerThread(InfoWindow.this, new Runnable() {
public void run() {
InfoWindow.super.hide();
invalidate();
if (action != null) {
action.run();
}
}
});
}
}
}
}
......@@ -896,7 +896,7 @@ final class XWM
/*
* Set MWM decorations. Set MWM functions depending on resizability.
*/
static void setMotifDecor(XWindowPeer window, boolean resizable, int decorations, int functions) {
static void setMotifDecor(XWindow window, boolean resizable, int decorations, int functions) {
/* Apparently some WMs don't implement MWM_*_ALL semantic correctly */
if ((decorations & MWMConstants.MWM_DECOR_ALL) != 0
&& (decorations != MWMConstants.MWM_DECOR_ALL))
......
......@@ -25,16 +25,194 @@
package sun.awt.X11;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.lang.ref.WeakReference;
import sun.java2d.SunGraphics2D;
import sun.java2d.pipe.Region;
import sun.awt.AWTAccessor;
import sun.awt.SunToolkit;
class XWarningWindow extends XWindow {
final static int defaultHeight = 27;
private final static int showingDelay = 330;
private final static int hidingDelay = 2000;
Window ownerWindow;
XWarningWindow(Window ownerWindow, long parentWindow) {
super(ownerWindow, parentWindow);
private final Window ownerWindow;
private WeakReference<XWindowPeer> ownerPeer;
public final Window getOwnerWindow() {
return ownerWindow;
}
private long parentWindow;
private final static String OWNER = "OWNER";
private static XIconInfo[][] icons;
private InfoWindow.Tooltip tooltip;
private static synchronized XIconInfo getSecurityIconInfo(int size, int num) {
if (icons == null) {
icons = new XIconInfo[4][3];
if (XlibWrapper.dataModel == 32) {
icons[0][0] = new XIconInfo(XAWTIcon32_security_icon_bw16_png.security_icon_bw16_png);
icons[0][1] = new XIconInfo(XAWTIcon32_security_icon_interim16_png.security_icon_interim16_png);
icons[0][2] = new XIconInfo(XAWTIcon32_security_icon_yellow16_png.security_icon_yellow16_png);
icons[1][0] = new XIconInfo(XAWTIcon32_security_icon_bw24_png.security_icon_bw24_png);
icons[1][1] = new XIconInfo(XAWTIcon32_security_icon_interim24_png.security_icon_interim24_png);
icons[1][2] = new XIconInfo(XAWTIcon32_security_icon_yellow24_png.security_icon_yellow24_png);
icons[2][0] = new XIconInfo(XAWTIcon32_security_icon_bw32_png.security_icon_bw32_png);
icons[2][1] = new XIconInfo(XAWTIcon32_security_icon_interim32_png.security_icon_interim32_png);
icons[2][2] = new XIconInfo(XAWTIcon32_security_icon_yellow32_png.security_icon_yellow32_png);
icons[3][0] = new XIconInfo(XAWTIcon32_security_icon_bw48_png.security_icon_bw48_png);
icons[3][1] = new XIconInfo(XAWTIcon32_security_icon_interim48_png.security_icon_interim48_png);
icons[3][2] = new XIconInfo(XAWTIcon32_security_icon_yellow48_png.security_icon_yellow48_png);
} else {
icons[0][0] = new XIconInfo(XAWTIcon64_security_icon_bw16_png.security_icon_bw16_png);
icons[0][1] = new XIconInfo(XAWTIcon64_security_icon_interim16_png.security_icon_interim16_png);
icons[0][2] = new XIconInfo(XAWTIcon64_security_icon_yellow16_png.security_icon_yellow16_png);
icons[1][0] = new XIconInfo(XAWTIcon64_security_icon_bw24_png.security_icon_bw24_png);
icons[1][1] = new XIconInfo(XAWTIcon64_security_icon_interim24_png.security_icon_interim24_png);
icons[1][2] = new XIconInfo(XAWTIcon64_security_icon_yellow24_png.security_icon_yellow24_png);
icons[2][0] = new XIconInfo(XAWTIcon64_security_icon_bw32_png.security_icon_bw32_png);
icons[2][1] = new XIconInfo(XAWTIcon64_security_icon_interim32_png.security_icon_interim32_png);
icons[2][2] = new XIconInfo(XAWTIcon64_security_icon_yellow32_png.security_icon_yellow32_png);
icons[3][0] = new XIconInfo(XAWTIcon64_security_icon_bw48_png.security_icon_bw48_png);
icons[3][1] = new XIconInfo(XAWTIcon64_security_icon_interim48_png.security_icon_interim48_png);
icons[3][2] = new XIconInfo(XAWTIcon64_security_icon_yellow48_png.security_icon_yellow48_png);
}
}
final int sizeIndex = size % icons.length;
return icons[sizeIndex][num % icons[sizeIndex].length];
}
private volatile int currentIcon = 0;
/* -1 - uninitialized yet
* 0 - 16x16
* 1 - 24x24
* 2 - 32x32
* 3 - 48x48
*/
private volatile int currentSize = -1;
/** Indicates whether the shape of the window must be updated
*/
private volatile boolean sizeUpdated = true;
private synchronized boolean updateIconSize() {
int newSize = currentSize;
if (ownerWindow != null) {
Insets insets = ownerWindow.getInsets();
int max = Math.max(insets.top, Math.max(insets.bottom,
Math.max(insets.left, insets.right)));
if (max < 24) {
newSize = 0;
} else if (max < 32) {
newSize = 1;
} else if (max < 48) {
newSize = 2;
} else {
newSize = 3;
}
}
if (newSize != currentSize) {
currentSize = newSize;
sizeUpdated = true;
}
return sizeUpdated;
}
private synchronized XIconInfo getSecurityIconInfo() {
updateIconSize();
return getSecurityIconInfo(currentSize, currentIcon);
}
XWarningWindow(final Window ownerWindow, long parentWindow, XWindowPeer ownerPeer) {
super(new XCreateWindowParams(new Object[] {
TARGET, ownerWindow,
OWNER, Long.valueOf(parentWindow)
}));
this.ownerWindow = ownerWindow;
xSetVisible(true);
toFront();
this.parentWindow = parentWindow;
this.tooltip = new InfoWindow.Tooltip(null, getTarget(),
new InfoWindow.Tooltip.LiveArguments() {
public boolean isDisposed() {
return XWarningWindow.this.isDisposed();
}
public Rectangle getBounds() {
return XWarningWindow.this.getBounds();
}
public String getTooltipString() {
return XWarningWindow.this.ownerWindow.getWarningString();
}
});
this.ownerPeer = new WeakReference<XWindowPeer>(ownerPeer);
}
private void requestNoTaskbar() {
XNETProtocol netProtocol = XWM.getWM().getNETProtocol();
if (netProtocol != null) {
netProtocol.requestState(this, netProtocol.XA_NET_WM_STATE_SKIP_TASKBAR, true);
}
}
@Override
void postInit(XCreateWindowParams params) {
super.postInit(params);
XToolkit.awtLock();
try {
XWM.setMotifDecor(this, false, 0, 0);
XWM.setOLDecor(this, false, 0);
long parentWindow = ((Long)params.get(OWNER)).longValue();
XlibWrapper.XSetTransientFor(XToolkit.getDisplay(),
getWindow(), parentWindow);
XWMHints hints = getWMHints();
hints.set_flags(hints.get_flags() | (int)XUtilConstants.InputHint | (int)XUtilConstants.StateHint);
hints.set_input(false);
hints.set_initial_state(XUtilConstants.NormalState);
XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData);
initWMProtocols();
requestNoTaskbar();
} finally {
XToolkit.awtUnlock();
}
}
private void updateWarningWindowBounds() {
XWindowPeer peer = ownerPeer.get();
if (peer != null) {
synchronized (this) {
if (updateIconSize()) {
XIconInfo ico = getSecurityIconInfo();
XToolkit.awtLock();
try {
XlibWrapper.SetBitmapShape(XToolkit.getDisplay(), getWindow(),
ico.getWidth(), ico.getHeight(), ico.getIntData());
} finally {
XToolkit.awtUnlock();
}
sizeUpdated = false;
AWTAccessor.getWindowAccessor().setSecurityWarningSize(
ownerWindow, ico.getWidth(), ico.getHeight());
}
}
peer.repositionSecurityWarning();
}
}
/**
* @param x,y,w,h coordinates of the untrusted window
*/
public void reposition(int x, int y, int w, int h) {
Point2D point = AWTAccessor.getWindowAccessor().
calculateSecurityWarningPosition(ownerWindow,
x, y, w, h);
reshape((int)point.getX(), (int)point.getY(), getWidth(), getHeight());
}
protected String getWMName() {
......@@ -49,33 +227,19 @@ class XWarningWindow extends XWindow {
getFont());
}
void paint(Graphics g, int x, int y, int width, int height) {
String warningString = getWarningString();
Rectangle bounds = getBounds();
bounds.x = 0;
bounds.y = 0;
Rectangle updateRect = new Rectangle(x, y, width, height);
if (updateRect.intersects(bounds)) {
Rectangle updateArea = updateRect.intersection(bounds);
g.setClip(updateArea);
g.setColor(getBackground());
g.fillRect(updateArea.x, updateArea.y, updateArea.width, updateArea.height);
g.setColor(getColor());
g.setFont(getFont());
FontMetrics fm = g.getFontMetrics();
int warningWidth = fm.stringWidth(warningString);
int w_x = (bounds.width - warningWidth)/2;
int w_y = (bounds.height + fm.getMaxAscent() - fm.getMaxDescent())/2;
g.drawString(warningString, w_x, w_y);
g.drawLine(bounds.x, bounds.y+bounds.height-1, bounds.x+bounds.width-1, bounds.y+bounds.height-1);
}
g.drawImage(getSecurityIconInfo().getImage(), 0, 0, null);
}
String getWarningString() {
return ownerWindow.getWarningString();
}
int getWidth() {
return getSecurityIconInfo().getWidth();
}
int getHeight() {
return defaultHeight; // should implement depending on Font
return getSecurityIconInfo().getHeight();
}
Color getBackground() {
......@@ -97,6 +261,7 @@ class XWarningWindow extends XWindow {
}
}
@Override
public void handleExposeEvent(XEvent xev) {
super.handleExposeEvent(xev);
......@@ -105,18 +270,156 @@ class XWarningWindow extends XWindow {
final int y = xe.get_y();
final int width = xe.get_width();
final int height = xe.get_height();
EventQueue.invokeLater(new Runnable() {
public void run() {
Graphics g = getGraphics();
try {
paint(g, x, y, width, height);
} finally {
g.dispose();
}
}
});
SunToolkit.executeOnEventHandlerThread(target,
new Runnable() {
public void run() {
Graphics g = getGraphics();
try {
paint(g, x, y, width, height);
} finally {
g.dispose();
}
}
});
}
@Override
protected boolean isEventDisabled(XEvent e) {
return true;
}
/** Send a synthetic UnmapNotify in order to withdraw the window.
*/
private void withdraw() {
XEvent req = new XEvent();
try {
long root;
XToolkit.awtLock();
try {
root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber());
}
finally {
XToolkit.awtUnlock();
}
req.set_type(XConstants.UnmapNotify);
XUnmapEvent umev = req.get_xunmap();
umev.set_event(root);
umev.set_window(getWindow());
umev.set_from_configure(false);
XToolkit.awtLock();
try {
XlibWrapper.XSendEvent(XToolkit.getDisplay(),
root,
false,
XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask,
req.pData);
}
finally {
XToolkit.awtUnlock();
}
} finally {
req.dispose();
}
}
@Override
protected void stateChanged(long time, int oldState, int newState) {
if (newState == XUtilConstants.IconicState) {
super.xSetVisible(false);
withdraw();
}
}
@Override
protected void setMouseAbove(boolean above) {
super.setMouseAbove(above);
XWindowPeer p = ownerPeer.get();
if (p != null) {
p.updateSecurityWarningVisibility();
}
}
@Override
protected void enterNotify(long window) {
super.enterNotify(window);
if (window == getWindow()) {
tooltip.enter();
}
}
@Override
protected void leaveNotify(long window) {
super.leaveNotify(window);
if (window == getWindow()) {
tooltip.exit();
}
}
@Override
public void xSetVisible(boolean visible) {
super.xSetVisible(visible);
// The _NET_WM_STATE_SKIP_TASKBAR got reset upon hiding/showing,
// so we request it every time whenever we change the visibility.
requestNoTaskbar();
}
private final Runnable hidingTask = new Runnable() {
public void run() {
xSetVisible(false);
}
};
private final Runnable showingTask = new Runnable() {
public void run() {
new Thread() {
public void run() {
if (!isVisible()) {
xSetVisible(true);
updateWarningWindowBounds();
}
repaint();
if (currentIcon > 0) {
currentIcon--;
XToolkit.schedule(showingTask, showingDelay);
}
}}.start();
}
};
public void setSecurityWarningVisible(boolean visible) {
setSecurityWarningVisible(visible, true);
}
public void setSecurityWarningVisible(boolean visible, boolean doSchedule) {
if (visible) {
XToolkit.remove(hidingTask);
XToolkit.remove(showingTask);
if (isVisible()) {
currentIcon = 0;
} else {
currentIcon = 3;
}
if (doSchedule) {
XToolkit.schedule(showingTask, 1);
} else {
showingTask.run();
}
} else {
XToolkit.remove(showingTask);
XToolkit.remove(hidingTask);
if (!isVisible()) {
return;
}
if (doSchedule) {
XToolkit.schedule(hidingTask, hidingDelay);
} else {
hidingTask.run();
}
}
}
}
......@@ -68,6 +68,15 @@ public class XWindow extends XBaseWindow implements X11ComponentPeer {
int oldWidth = -1;
int oldHeight = -1;
protected PropMwmHints mwm_hints;
protected static XAtom wm_protocols;
protected static XAtom wm_delete_window;
protected static XAtom wm_take_focus;
private boolean stateChanged; // Indicates whether the value on savedState is valid
private int savedState; // Holds last known state of the top-level window
XWindowAttributesData winAttr;
protected X11GraphicsConfig graphicsConfig;
protected AwtGraphicsConfigData graphicsConfigData;
......@@ -218,6 +227,20 @@ public class XWindow extends XBaseWindow implements X11ComponentPeer {
}
params.putIfNull(BACKING_STORE, XToolkit.getBackingStoreType());
XToolkit.awtLock();
try {
if (wm_protocols == null) {
wm_protocols = XAtom.get("WM_PROTOCOLS");
wm_delete_window = XAtom.get("WM_DELETE_WINDOW");
wm_take_focus = XAtom.get("WM_TAKE_FOCUS");
}
}
finally {
XToolkit.awtUnlock();
}
winAttr = new XWindowAttributesData();
savedState = XUtilConstants.WithdrawnState;
}
void postInit(XCreateWindowParams params) {
......@@ -832,12 +855,42 @@ public class XWindow extends XBaseWindow implements X11ComponentPeer {
public native boolean x11inputMethodLookupString(long event, long [] keysymArray);
native boolean haveCurrentX11InputMethodInstance();
private boolean mouseAboveMe;
public boolean isMouseAbove() {
synchronized (getStateLock()) {
return mouseAboveMe;
}
}
protected void setMouseAbove(boolean above) {
synchronized (getStateLock()) {
mouseAboveMe = above;
}
}
protected void enterNotify(long window) {
if (window == getWindow()) {
setMouseAbove(true);
}
}
protected void leaveNotify(long window) {
if (window == getWindow()) {
setMouseAbove(false);
}
}
public void handleXCrossingEvent(XEvent xev) {
super.handleXCrossingEvent(xev);
XCrossingEvent xce = xev.get_xcrossing();
if (eventLog.isLoggable(Level.FINEST)) eventLog.finest(xce.toString());
if (xce.get_type() == XConstants.EnterNotify) {
enterNotify(xce.get_window());
} else { // LeaveNotify:
leaveNotify(xce.get_window());
}
// Skip event If it was caused by a grab
// This is needed because on displays with focus-follows-mouse on MousePress X system generates
// two XCrossing events with mode != NormalNotify. First of them notifies that the mouse has left
......@@ -1133,6 +1186,55 @@ public class XWindow extends XBaseWindow implements X11ComponentPeer {
}
/*
* XmNiconic and Map/UnmapNotify (that XmNiconic relies on) are
* unreliable, since mapping changes can happen for a virtual desktop
* switch or MacOS style shading that became quite popular under X as
* well. Yes, it probably should not be this way, as it violates
* ICCCM, but reality is that quite a lot of window managers abuse
* mapping state.
*/
int getWMState() {
if (stateChanged) {
stateChanged = false;
WindowPropertyGetter getter =
new WindowPropertyGetter(window, XWM.XA_WM_STATE, 0, 1, false,
XWM.XA_WM_STATE);
try {
int status = getter.execute();
if (status != XConstants.Success || getter.getData() == 0) {
return savedState = XUtilConstants.WithdrawnState;
}
if (getter.getActualType() != XWM.XA_WM_STATE.getAtom() && getter.getActualFormat() != 32) {
return savedState = XUtilConstants.WithdrawnState;
}
savedState = (int)Native.getCard32(getter.getData());
} finally {
getter.dispose();
}
}
return savedState;
}
/**
* Override this methods to get notifications when top-level window state changes. The state is
* meant in terms of ICCCM: WithdrawnState, IconicState, NormalState
*/
protected void stateChanged(long time, int oldState, int newState) {
}
@Override
public void handlePropertyNotify(XEvent xev) {
super.handlePropertyNotify(xev);
XPropertyEvent ev = xev.get_xproperty();
if (ev.get_atom() == XWM.XA_WM_STATE.getAtom()) {
// State has changed, invalidate saved value
stateChanged = true;
stateChanged(ev.get_time(), savedState, getWMState());
}
}
public void reshape(Rectangle bounds) {
reshape(bounds.x, bounds.y, bounds.width, bounds.height);
}
......@@ -1293,4 +1395,40 @@ public class XWindow extends XBaseWindow implements X11ComponentPeer {
static native int getAWTKeyCodeForKeySym(int keysym);
static native int getKeySymForAWTKeyCode(int keycode);
/* These two methods are actually applicable to toplevel windows only.
* However, the functionality is required by both the XWindowPeer and
* XWarningWindow, both of which have the XWindow as a common ancestor.
* See XWM.setMotifDecor() for details.
*/
public PropMwmHints getMWMHints() {
if (mwm_hints == null) {
mwm_hints = new PropMwmHints();
if (!XWM.XA_MWM_HINTS.getAtomData(getWindow(), mwm_hints.pData, MWMConstants.PROP_MWM_HINTS_ELEMENTS)) {
mwm_hints.zero();
}
}
return mwm_hints;
}
public void setMWMHints(PropMwmHints hints) {
mwm_hints = hints;
if (hints != null) {
XWM.XA_MWM_HINTS.setAtomData(getWindow(), mwm_hints.pData, MWMConstants.PROP_MWM_HINTS_ELEMENTS);
}
}
protected final void initWMProtocols() {
wm_protocols.setAtomListProperty(this, getWMProtocols());
}
/**
* Returns list of protocols which should be installed on this window.
* Descendants can override this method to add class-specific protocols
*/
protected XAtomList getWMProtocols() {
// No protocols on simple window
return new XAtomList();
}
}
......@@ -67,16 +67,11 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
// should be synchronized on awtLock
private static Set<XWindowPeer> windows = new HashSet<XWindowPeer>();
static XAtom wm_protocols;
static XAtom wm_delete_window;
static XAtom wm_take_focus;
XWindowAttributesData winAttr;
private boolean cachedFocusableWindow;
XWarningWindow warningWindow;
private boolean alwaysOnTop;
PropMwmHints mwm_hints;
private boolean locationByPlatform;
Dialog modalBlocker;
......@@ -93,8 +88,6 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
private boolean grab = false; // Whether to do a grab during showing
private boolean isMapped = false; // Is this window mapped or not
private boolean stateChanged; // Indicates whether the value on savedState is valid
private int savedState; // Holds last known state of the top-level window
private boolean mustControlStackPosition = false; // Am override-redirect not on top
private XEventDispatcher rootPropertyEventDispatcher = null;
......@@ -141,25 +134,18 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
super.preInit(params);
params.putIfNull(BIT_GRAVITY, Integer.valueOf(XConstants.NorthWestGravity));
savedState = XUtilConstants.WithdrawnState;
long eventMask = 0;
if (params.containsKey(EVENT_MASK)) {
eventMask = ((Long)params.get(EVENT_MASK));
}
eventMask |= XConstants.VisibilityChangeMask;
params.put(EVENT_MASK, eventMask);
XA_NET_WM_STATE = XAtom.get("_NET_WM_STATE");
winAttr = new XWindowAttributesData();
params.put(OVERRIDE_REDIRECT, Boolean.valueOf(isOverrideRedirect()));
SunToolkit.awtLock();
try {
windows.add(this);
if (wm_protocols == null) {
wm_protocols = XAtom.get("WM_PROTOCOLS");
wm_delete_window = XAtom.get("WM_DELETE_WINDOW");
wm_take_focus = XAtom.get("WM_TAKE_FOCUS");
}
}
finally {
SunToolkit.awtUnlock();
}
cachedFocusableWindow = isFocusableWindow();
Font f = target.getFont();
......@@ -192,20 +178,6 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
params.put(BOUNDS, constrainBounds(bounds.x, bounds.y, bounds.width, bounds.height));
}
private void initWMProtocols() {
wm_protocols.setAtomListProperty(this, getWMProtocols());
}
/**
* Returns list of protocols which should be installed on this window.
* Descendants can override this method to add class-specific protocols
*/
protected XAtomList getWMProtocols() {
// No protocols on simple window
return new XAtomList();
}
protected String getWMName() {
String name = target.getName();
if (name == null || name.trim().equals("")) {
......@@ -259,7 +231,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
// accessSystemTray permission allows to display TrayIcon, TrayIcon tooltip
// and TrayIcon balloon windows without a warning window.
if (!WindowAccessor.isTrayIconWindow((Window)target)) {
warningWindow = new XWarningWindow((Window)target, getWindow());
warningWindow = new XWarningWindow((Window)target, getWindow(), this);
}
}
......@@ -539,10 +511,15 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
}
if (!bounds.getSize().equals(oldBounds.getSize())) {
boolean isResized = !bounds.getSize().equals(oldBounds.getSize());
boolean isMoved = !bounds.getLocation().equals(oldBounds.getLocation());
if (isMoved || isResized) {
repositionSecurityWarning();
}
if (isResized) {
postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_RESIZED));
}
if (!bounds.getLocation().equals(oldBounds.getLocation())) {
if (isMoved) {
postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_MOVED));
}
} finally {
......@@ -565,7 +542,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
}
public Insets getInsets() {
return new Insets(getWarningWindowHeight(), 0, 0, 0);
return new Insets(0, 0, 0, 0);
}
// NOTE: This method may be called by privileged threads.
......@@ -780,6 +757,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
* Overridden to check if we need to update our GraphicsDevice/Config
* Added for 4934052.
*/
@Override
public void handleConfigureNotifyEvent(XEvent xev) {
// TODO: We create an XConfigureEvent every time we override
// handleConfigureNotify() - too many!
......@@ -793,8 +771,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
// there could be a race condition in which a ComponentListener could
// see the old screen.
super.handleConfigureNotifyEvent(xev);
// for 5085647: no applet warning window visible
updateChildrenSizes();
repositionSecurityWarning();
}
final void requestXFocus(long time) {
......@@ -1072,6 +1049,9 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
}
updateFocusability();
promoteDefaultPosition();
if (!vis && warningWindow != null) {
warningWindow.setSecurityWarningVisible(false, false);
}
super.setVisible(vis);
if (!vis && !isWithdrawn()) {
// ICCCM, 4.1.4. Changing Window State:
......@@ -1101,6 +1081,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
if (isOverrideRedirect() && vis) {
updateChildrenSizes();
}
repositionSecurityWarning();
}
protected void suppressWmTakeFocus(boolean doSuppress) {
......@@ -1118,21 +1099,64 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
return 0;
}
// The height of area used to display Applet's warning about securit
int getWarningWindowHeight() {
if (warningWindow != null) {
return warningWindow.getHeight();
} else {
return 0;
}
}
// Called when shell changes its size and requires children windows
// to update their sizes appropriately
void updateChildrenSizes() {
}
public void repositionSecurityWarning() {
// NOTE: On KWin if the window/border snapping option is enabled,
// the Java window may be swinging while it's being moved.
// This doesn't make the application unusable though looks quite ugly.
// Probobly we need to find some hint to assign to our Security
// Warning window in order to exclude it from the snapping option.
// We are not currently aware of existance of such a property.
if (warningWindow != null) {
warningWindow.reshape(0, getMenuBarHeight(), getSize().width, warningWindow.getHeight());
// We can't use the coordinates stored in the XBaseWindow since
// they are zeros for decorated frames.
int x = ComponentAccessor.getX(target);
int y = ComponentAccessor.getY(target);
int width = ComponentAccessor.getWidth(target);
int height = ComponentAccessor.getHeight(target);
warningWindow.reposition(x, y, width, height);
}
}
@Override
protected void setMouseAbove(boolean above) {
super.setMouseAbove(above);
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;
}
if (isMouseAbove() || warningWindow.isMouseAbove())
{
show = true;
}
}
warningWindow.setSecurityWarningVisible(show);
}
boolean isOverrideRedirect() {
......@@ -1184,16 +1208,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
// if (ve.get_state() == XlibWrapper.VisibilityUnobscured) {
// // raiseInputMethodWindow
// }
}
public void handlePropertyNotify(XEvent xev) {
super.handlePropertyNotify(xev);
XPropertyEvent ev = xev.get_xproperty();
if (ev.get_atom() == XWM.XA_WM_STATE.getAtom()) {
// State has changed, invalidate saved value
stateChanged = true;
stateChanged(ev.get_time(), savedState, getWMState());
}
repositionSecurityWarning();
}
void handleRootPropertyNotify(XEvent xev) {
......@@ -1294,6 +1309,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
* Override this methods to get notifications when top-level window state changes. The state is
* meant in terms of ICCCM: WithdrawnState, IconicState, NormalState
*/
@Override
protected void stateChanged(long time, int oldState, int newState) {
// Fix for 6401700, 6412803
// If this window is modal blocked, it is put into the transient_for
......@@ -1307,38 +1323,8 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
for (ToplevelStateListener topLevelListenerTmp : toplevelStateListeners) {
topLevelListenerTmp.stateChangedICCCM(oldState, newState);
}
}
/*
* XmNiconic and Map/UnmapNotify (that XmNiconic relies on) are
* unreliable, since mapping changes can happen for a virtual desktop
* switch or MacOS style shading that became quite popular under X as
* well. Yes, it probably should not be this way, as it violates
* ICCCM, but reality is that quite a lot of window managers abuse
* mapping state.
*/
int getWMState() {
if (stateChanged) {
stateChanged = false;
WindowPropertyGetter getter =
new WindowPropertyGetter(window, XWM.XA_WM_STATE, 0, 1, false,
XWM.XA_WM_STATE);
try {
int status = getter.execute();
if (status != XConstants.Success || getter.getData() == 0) {
return savedState = XUtilConstants.WithdrawnState;
}
if (getter.getActualType() != XWM.XA_WM_STATE.getAtom() && getter.getActualFormat() != 32) {
return savedState = XUtilConstants.WithdrawnState;
}
savedState = (int)Native.getCard32(getter.getData());
} finally {
getter.dispose();
}
}
return savedState;
updateSecurityWarningVisibility();
}
boolean isWithdrawn() {
......
......@@ -156,6 +156,8 @@ Window w;
static native void XLowerWindow(long display, long window);
static native void XRestackWindows(long display, long windows, int length);
static native void XConfigureWindow(long display, long window,
long value_mask, long values);
static native void XSetInputFocus(long display, long window);
static native void XSetInputFocus2(long display, long window, long time);
static native long XGetInputFocus(long display);
......@@ -533,6 +535,12 @@ static native String XSetLocaleModifiers(String modifier_list);
static native void SetRectangularShape(long display, long window,
int lox, int loy, int hix, int hiy,
sun.java2d.pipe.Region region);
/** Each int in the bitmap array is one pixel with a 32-bit color:
* R, G, B, and Alpha.
*/
static native void SetBitmapShape(long display, long window,
int width, int height, int[] bitmap);
static native void SetZOrder(long display, long window, long above);
/* Global memory area used for X lib parameter passing */
......
......@@ -43,4 +43,15 @@ typedef XRectangle RECT_T;
#define RECT_INC_HEIGHT(r) (r).height++
#if defined(__cplusplus)
extern "C" {
#endif
int BitmapToYXBandedRectangles(int bitsPerPixel, int width, int height,
unsigned char * buf, RECT_T * outBuf);
#if defined(__cplusplus)
}
#endif
#endif // _AWT_RECT_H
......@@ -42,6 +42,7 @@
#include <jvm.h>
#include <Region.h>
#include "utility/rect.h"
#if defined(DEBUG) || defined(INTERNAL_BUILD)
static jmethodID lockIsHeldMID = NULL;
......@@ -303,6 +304,20 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_XlibWrapper_XRestackWindows
}
/*
* Class: XlibWrapper
* Method: XConfigureWindow
* Signature: (JJJJ)V
*/
JNIEXPORT void JNICALL Java_sun_awt_X11_XlibWrapper_XConfigureWindow
(JNIEnv *env, jclass clazz, jlong display, jlong window, jlong value_mask,
jlong values)
{
AWT_CHECK_HAVE_LOCK();
XConfigureWindow((Display*)jlong_to_ptr(display), (Window)window,
(unsigned int)value_mask, (XWindowChanges*)jlong_to_ptr(values));
}
/*
* Class: XlibWrapper
* Method: XSetInputFocus
......@@ -1973,3 +1988,49 @@ Java_sun_awt_X11_XlibWrapper_SetZOrder
(Window)jlong_to_ptr(window),
value_mask, &wc );
}
/*
* Class: XlibWrapper
* Method: SetBitmapShape
*/
JNIEXPORT void JNICALL
Java_sun_awt_X11_XlibWrapper_SetBitmapShape
(JNIEnv *env, jclass clazz, jlong display, jlong window,
jint width, jint height, jintArray bitmap)
{
jsize len;
jint *values;
jboolean isCopy = JNI_FALSE;
size_t worstBufferSize = (size_t)((width / 2 + 1) * height);
RECT_T * pRect;
AWT_CHECK_HAVE_LOCK();
len = (*env)->GetArrayLength(env, bitmap);
if (len == 0 || len < width * height) {
return;
}
values = (*env)->GetIntArrayElements(env, bitmap, &isCopy);
if (JNU_IsNull(env, values)) {
return;
}
pRect = (RECT_T *)malloc(worstBufferSize * sizeof(RECT_T));
/* Note: the values[0] and values[1] are supposed to contain the width
* and height (see XIconInfo.getIntData() for details). So, we do +2.
*/
int numrects = BitmapToYXBandedRectangles(32, (int)width, (int)height,
(unsigned char *)(values + 2), pRect);
XShapeCombineRectangles((Display *)jlong_to_ptr(display), (Window)jlong_to_ptr(window),
ShapeClip, 0, 0, pRect, numrects, ShapeSet, YXBanded);
XShapeCombineRectangles((Display *)jlong_to_ptr(display), (Window)jlong_to_ptr(window),
ShapeBounding, 0, 0, pRect, numrects, ShapeSet, YXBanded);
free(pRect);
(*env)->ReleaseIntArrayElements(env, bitmap, values, JNI_ABORT);
}
......@@ -547,8 +547,10 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
private volatile int sysH = 0;
Rectangle constrainBounds(int x, int y, int width, int height) {
GraphicsConfiguration gc = this.winGraphicsConfig;
// We don't restrict the setBounds() operation if the code is trusted.
if (!hasWarningWindow()) {
if (!hasWarningWindow() || gc == null) {
return new Rectangle(x, y, width, height);
}
......@@ -557,24 +559,24 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
int newW = width;
int newH = height;
GraphicsConfiguration gc = ((Window)target).getGraphicsConfiguration();
Rectangle sB = gc.getBounds();
Insets sIn = ((Window)target).getToolkit().getScreenInsets(gc);
Insets sIn = Toolkit.getDefaultToolkit().getScreenInsets(gc);
int screenW = sB.width - sIn.left - sIn.right;
int screenH = sB.height - sIn.top - sIn.bottom;
// If it's undecorated or is not currently visible
if (!((Window)target).isVisible() || isTargetUndecorated()) {
if (!AWTAccessor.getComponentAccessor().isVisible_NoClientCode(
(Component)target) || isTargetUndecorated())
{
// Now check each point is within the visible part of the screen
int screenX = sB.x + sIn.left;
int screenY = sB.y + sIn.top;
// First make sure the size is withing the visible part of the screen
// First make sure the size is within the visible part of the screen
if (newW > screenW) {
newW = screenW;
}
if (newH > screenH) {
newH = screenH;
}
......@@ -585,7 +587,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
} else if (newX + newW > screenX + screenW) {
newX = screenX + screenW - newW;
}
if (newY < screenY) {
newY = screenY;
} else if (newY + newH > screenY + screenH) {
......@@ -600,7 +601,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
if (newW > maxW) {
newW = maxW;
}
if (newH > maxH) {
newH = maxH;
}
......@@ -609,6 +609,8 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
return new Rectangle(newX, newY, newW, newH);
}
public native void repositionSecurityWarning();
@Override
public void setBounds(int x, int y, int width, int height, int op) {
Rectangle newBounds = constrainBounds(x, y, width, height);
......
......@@ -27,6 +27,7 @@
#include "ComCtl32Util.h"
ComCtl32Util::ComCtl32Util() {
m_bToolTipControlInitialized = FALSE;
}
ComCtl32Util::~ComCtl32Util() {
......@@ -36,7 +37,8 @@ void ComCtl32Util::InitLibraries() {
INITCOMMONCONTROLSEX iccex;
memset(&iccex, 0, sizeof(INITCOMMONCONTROLSEX));
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
::InitCommonControlsEx(&iccex);
iccex.dwICC = ICC_TAB_CLASSES;
m_bToolTipControlInitialized = ::InitCommonControlsEx(&iccex);
}
WNDPROC ComCtl32Util::SubclassHWND(HWND hwnd, WNDPROC _WindowProc) {
......
......@@ -40,6 +40,10 @@ class ComCtl32Util
void InitLibraries();
INLINE BOOL IsToolTipControlInitialized() {
return m_bToolTipControlInitialized;
}
WNDPROC SubclassHWND(HWND hwnd, WNDPROC _WindowProc);
// DefWindowProc is the same as returned from SubclassHWND
void UnsubclassHWND(HWND hwnd, WNDPROC _WindowProc, WNDPROC _DefWindowProc);
......@@ -50,6 +54,8 @@ class ComCtl32Util
ComCtl32Util();
~ComCtl32Util();
BOOL m_bToolTipControlInitialized;
// comctl32.dll version 6 window proc
static LRESULT CALLBACK SharedWindowProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam,
......
/*
* 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
#include "DllUtil.h"
// Disable warning about using this in the initializer list.
#pragma warning( disable : 4355)
DllUtil::~DllUtil()
{
if (module != NULL) {
::FreeLibrary(module);
module = NULL;
}
}
HMODULE DllUtil::GetModule()
{
if (!module) {
module = ::LoadLibrary(name);
}
return module;
}
FARPROC DllUtil::GetProcAddress(LPCSTR name)
{
if (GetModule()) {
return ::GetProcAddress(GetModule(), name);
}
throw LibraryUnavailableException();
}
DwmAPI & DwmAPI::GetInstance()
{
static DwmAPI dll;
return dll;
}
DwmAPI::DwmAPI() :
DllUtil(_T("DWMAPI.DLL")),
DwmIsCompositionEnabledFunction((DllUtil*)this, "DwmIsCompositionEnabled"),
DwmGetWindowAttributeFunction((DllUtil*)this, "DwmGetWindowAttribute")
{
}
HRESULT DwmAPI::DwmIsCompositionEnabled(BOOL * pfEnabled)
{
if (GetInstance().DwmIsCompositionEnabledFunction()) {
return GetInstance().DwmIsCompositionEnabledFunction()(pfEnabled);
}
throw FunctionUnavailableException();
}
HRESULT DwmAPI::DwmGetWindowAttribute(HWND hwnd, DWORD dwAttribute,
PVOID pvAttribute, DWORD cbAttribute)
{
if (GetInstance().DwmGetWindowAttributeFunction()) {
return GetInstance().DwmGetWindowAttributeFunction()(hwnd, dwAttribute,
pvAttribute, cbAttribute);
}
throw FunctionUnavailableException();
}
/*
* 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
#ifndef DLLUTIL_H
#define DLLUTIL_H
#include <tchar.h>
#include <windows.h>
/**
* Utility class to handle dynamically loadable libraries.
*
* NOTE: THIS CLASS IS NOT THREAD-SAFE!
*/
class DllUtil {
public:
class Exception {};
class LibraryUnavailableException : public Exception {};
class FunctionUnavailableException : public Exception {};
FARPROC GetProcAddress(LPCSTR name);
protected:
DllUtil(const TCHAR * name) : name(name), module(NULL) {}
virtual ~DllUtil();
HMODULE GetModule();
template <class FunctionType> class Function {
public:
Function(DllUtil * dll, LPCSTR name) :
dll(dll), name(name), function(NULL) {}
inline FunctionType operator () () {
if (!function) {
function = (FunctionType)dll->GetProcAddress(name);
}
return function;
}
private:
DllUtil * const dll;
LPCSTR name;
FunctionType function;
};
private:
const TCHAR * const name;
HMODULE module;
};
class DwmAPI : public DllUtil {
public:
// See DWMWINDOWATTRIBUTE enum in dwmapi.h
static const DWORD DWMWA_EXTENDED_FRAME_BOUNDS = 9;
static HRESULT DwmIsCompositionEnabled(BOOL * pfEnabled);
static HRESULT DwmGetWindowAttribute(HWND hwnd, DWORD dwAttribute,
PVOID pvAttribute, DWORD cbAttribute);
private:
static DwmAPI & GetInstance();
DwmAPI();
typedef HRESULT (WINAPI *DwmIsCompositionEnabledType)(BOOL*);
Function<DwmIsCompositionEnabledType> DwmIsCompositionEnabledFunction;
typedef HRESULT (WINAPI *DwmGetWindowAttributeType)(HWND hwnd, DWORD dwAttribute,
PVOID pvAttribute, DWORD cbAttribute);
Function<DwmGetWindowAttributeType> DwmGetWindowAttributeFunction;
};
#endif // DLLUTIL_H
......@@ -35,6 +35,13 @@ HAND_CURSOR CURSOR DISCARDABLE "hand.cur"
AWT_ICON ICON DISCARDABLE "awt.ico"
CHECK_BITMAP BITMAP DISCARDABLE "check.bmp"
// Note: the number of icons used is specified in the
// securityWarningIconCounter constant in awt_Toolkit.cpp.
SECURITY_WARNING_0 ICON DISCARDABLE "security_warning_bw.ico"
SECURITY_WARNING_1 ICON DISCARDABLE "security_warning_int.ico"
SECURITY_WARNING_2 ICON DISCARDABLE "security_warning.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Version
......
......@@ -260,8 +260,7 @@ AwtComponent::~AwtComponent()
* the native one anymore. So we can safely destroy component's
* handle.
*/
AwtToolkit::DestroyComponentHWND(m_hwnd);
m_hwnd = NULL;
DestroyHWnd();
if (sm_getComponentCache == this) {
sm_getComponentCache = NULL;
......@@ -575,6 +574,17 @@ AwtComponent::CreateHWnd(JNIEnv *env, LPCWSTR title,
env->DeleteLocalRef(bkgrd);
}
/*
* Destroy this window's HWND
*/
void AwtComponent::DestroyHWnd() {
if (m_hwnd != NULL) {
AwtToolkit::DestroyComponentHWND(m_hwnd);
//AwtToolkit::DestroyComponent(this);
m_hwnd = NULL;
}
}
/*
* Returns hwnd for target on non Toolkit thread
*/
......@@ -4470,7 +4480,7 @@ ret:
void* AwtComponent::GetNativeFocusedWindow() {
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
AwtComponent *comp =
AwtComponent::GetComponent(AwtComponent::sm_focusedWindow);
AwtComponent::GetComponent(AwtComponent::GetFocusedWindow());
return (comp != NULL) ? comp->GetTargetAsGlobalRef(env) : NULL;
}
......@@ -4571,7 +4581,7 @@ AwtComponent::SendKeyEventToFocusOwner(jint id, jlong when,
* if focus owner is null, but focused window isn't
* we will send key event to focused window
*/
HWND hwndTarget = ((sm_focusOwner != NULL) ? sm_focusOwner : sm_focusedWindow);
HWND hwndTarget = ((sm_focusOwner != NULL) ? sm_focusOwner : AwtComponent::GetFocusedWindow());
if (hwndTarget == GetHWnd()) {
SendKeyEvent(id, when, raw, cooked, modifiers, keyLocation, msg);
......@@ -5993,6 +6003,14 @@ void AwtComponent::PostUngrabEvent() {
}
}
void AwtComponent::SetFocusedWindow(HWND window)
{
HWND old = sm_focusedWindow;
sm_focusedWindow = window;
AwtWindow::FocusedWindowChanged(old, window);
}
/************************************************************************
* Component native methods
*/
......
......@@ -137,12 +137,13 @@ public:
virtual void RegisterClass();
virtual void UnregisterClass();
void CreateHWnd(JNIEnv *env, LPCWSTR title,
virtual void CreateHWnd(JNIEnv *env, LPCWSTR title,
DWORD windowStyle, DWORD windowExStyle,
int x, int y, int w, int h,
HWND hWndParent, HMENU hMenu,
COLORREF colorForeground, COLORREF colorBackground,
jobject peer);
virtual void DestroyHWnd();
void InitPeerGraphicsConfig(JNIEnv *env, jobject peer);
virtual void Dispose();
......@@ -670,8 +671,14 @@ public:
static void _SetZOrder(void *param);
static HWND sm_focusOwner;
private:
static HWND sm_focusedWindow;
public:
static inline HWND GetFocusedWindow() { return sm_focusedWindow; }
static void SetFocusedWindow(HWND window);
static void _SetFocus(void *param);
static void *SetNativeFocusOwner(void *self);
......
......@@ -310,15 +310,20 @@ void AwtDialog::PopupOneDialog(HWND dialog, HWND blocker, BOOL isModalHook, HWND
// no beep/flash if the mouse was clicked in the taskbar menu
// or the dialog is currently inactive
if (!isModalHook && !onTaskbar && (dialog == prevFGWindow)) {
::MessageBeep(MB_OK);
// some heuristics: 3 times x 64 milliseconds
AwtWindow::FlashWindowEx(dialog, 3, 64, FLASHW_CAPTION);
AnimateModalBlocker(dialog);
}
::BringWindowToTop(dialog);
::SetForegroundWindow(dialog);
}
}
void AwtDialog::AnimateModalBlocker(HWND window)
{
::MessageBeep(MB_OK);
// some heuristics: 3 times x 64 milliseconds
AwtWindow::FlashWindowEx(window, 3, 64, FLASHW_CAPTION);
}
LRESULT CALLBACK AwtDialog::MouseHookProc_NonTT(int nCode,
WPARAM wParam, LPARAM lParam)
{
......
......@@ -76,7 +76,7 @@ public:
* Thus we don't have to perform any transitive (a blocker of a blocker) checks.
*/
INLINE virtual BOOL IsFocusedWindowModalBlocker() {
return (sm_focusedWindow != NULL) && (GetModalBlocker(sm_focusedWindow) == GetHWnd());
return (AwtComponent::GetFocusedWindow() != NULL) && (GetModalBlocker(AwtComponent::GetFocusedWindow()) == GetHWnd());
}
// finds and activates some window after the modal dialog is hidden
......@@ -132,6 +132,8 @@ public:
// example on browser's thread when running in Java Plugin
static LRESULT CALLBACK MouseHookProc_NonTT(int code,
WPARAM wParam, LPARAM lParam);
static void AnimateModalBlocker(HWND window);
};
#endif /* AWT_DIALOG_H */
......@@ -361,8 +361,8 @@ LRESULT CALLBACK AwtFrame::ProxyWindowProc(HWND hwnd, UINT message,
AwtWindow::SynthesizeWmActivate(FALSE, parent->GetHWnd(), NULL);
} else if (sm_restoreFocusAndActivation) {
if (sm_focusedWindow != NULL) {
AwtWindow *focusedWindow = (AwtWindow*)GetComponent(sm_focusedWindow);
if (AwtComponent::GetFocusedWindow() != NULL) {
AwtWindow *focusedWindow = (AwtWindow*)GetComponent(AwtComponent::GetFocusedWindow());
if (focusedWindow != NULL) {
// Will just silently restore native focus & activation.
focusedWindow->AwtSetActiveWindow();
......@@ -607,11 +607,6 @@ MsgRouting AwtFrame::WmNcMouseDown(WPARAM hitTest, int x, int y, int button) {
return AwtWindow::WmNcMouseDown(hitTest, x, y, button);
}
MsgRouting AwtFrame::WmWindowPosChanged(LPARAM windowPos) {
return mrDoDefault;
}
// Override AwtWindow::Reshape() to handle minimized/maximized
// frames (see 6525850, 4065534)
void AwtFrame::Reshape(int x, int y, int width, int height)
......@@ -848,6 +843,11 @@ MsgRouting AwtFrame::WmGetMinMaxInfo(LPMINMAXINFO lpmmi)
MsgRouting AwtFrame::WmSize(UINT type, int w, int h)
{
currentWmSizeState = type;
if (currentWmSizeState == SIZE_MINIMIZED) {
UpdateSecurityWarningVisibility();
}
if (m_ignoreWmSize) {
return mrDoDefault;
}
......@@ -941,7 +941,7 @@ MsgRouting AwtFrame::WmActivate(UINT nState, BOOL fMinimized, HWND opposite)
return mrConsume;
}
type = java_awt_event_WindowEvent_WINDOW_GAINED_FOCUS;
sm_focusedWindow = GetHWnd();
AwtComponent::SetFocusedWindow(GetHWnd());
} else {
if (!::IsWindow(AwtWindow::GetModalBlocker(opposite))) {
......@@ -967,7 +967,7 @@ MsgRouting AwtFrame::WmActivate(UINT nState, BOOL fMinimized, HWND opposite)
CheckRetainActualFocusedWindow(opposite);
type = java_awt_event_WindowEvent_WINDOW_LOST_FOCUS;
sm_focusedWindow = NULL;
AwtComponent::SetFocusedWindow(NULL);
sm_focusOwner = NULL;
}
}
......@@ -992,9 +992,9 @@ BOOL AwtFrame::CheckActivateActualFocusedWindow(HWND deactivatedOpositeHWnd)
void AwtFrame::CheckRetainActualFocusedWindow(HWND activatedOpositeHWnd)
{
// If actual focused window is not this Frame
if (sm_focusedWindow != GetHWnd()) {
if (AwtComponent::GetFocusedWindow() != GetHWnd()) {
// Make sure the actual focused window is an owned window of this frame
AwtWindow *focusedWindow = (AwtWindow *)AwtComponent::GetComponent(sm_focusedWindow);
AwtWindow *focusedWindow = (AwtWindow *)AwtComponent::GetComponent(AwtComponent::GetFocusedWindow());
if (focusedWindow != NULL && focusedWindow->GetOwningFrameOrDialog() == this) {
// Check that the opposite window is not this frame, nor an owned window of this frame
......
......@@ -108,7 +108,6 @@ public:
MsgRouting WmNcMouseDown(WPARAM hitTest, int x, int y, int button);
MsgRouting WmNcMouseUp(WPARAM hitTest, int x, int y, int button);
MsgRouting WmGetIcon(WPARAM iconType, LRESULT& retVal);
MsgRouting WmWindowPosChanged(LPARAM windowPos);
MsgRouting WmShowWindow(BOOL show, UINT status);
virtual MsgRouting WmSysCommand(UINT uCmdType, int xPos, int yPos);
......
......@@ -56,6 +56,7 @@
#include "debug_mem.h"
#include "ComCtl32Util.h"
#include "DllUtil.h"
#include "D3DPipelineManager.h"
......@@ -334,6 +335,8 @@ AwtToolkit::AwtToolkit() {
m_mouseDown = FALSE;
m_hGetMessageHook = 0;
m_hMouseLLHook = 0;
m_lastWindowUnderMouse = NULL;
m_timer = 0;
m_cmdIDs = new AwtCmdIDList();
......@@ -483,6 +486,7 @@ BOOL AwtToolkit::Dispose() {
tk.UnregisterClass();
::UnhookWindowsHookEx(tk.m_hGetMessageHook);
UninstallMouseLowLevelHook();
tk.m_mainThreadId = 0;
......@@ -960,6 +964,79 @@ LRESULT CALLBACK AwtToolkit::GetMessageFilter(int code,
CATCH_BAD_ALLOC_RET(0);
}
void AwtToolkit::InstallMouseLowLevelHook()
{
// We need the low-level hook since we need to process mouse move
// messages outside of our windows.
m_hMouseLLHook = ::SetWindowsHookEx(WH_MOUSE_LL,
(HOOKPROC)MouseLowLevelHook,
GetModuleHandle(), NULL);
// Reset the old value
m_lastWindowUnderMouse = NULL;
}
void AwtToolkit::UninstallMouseLowLevelHook()
{
if (m_hMouseLLHook != 0) {
::UnhookWindowsHookEx(m_hMouseLLHook);
m_hMouseLLHook = 0;
}
}
LRESULT CALLBACK AwtToolkit::MouseLowLevelHook(int code,
WPARAM wParam, LPARAM lParam)
{
TRY;
if (code >= 0 && wParam == WM_MOUSEMOVE) {
POINT pt = ((MSLLHOOKSTRUCT*)lParam)->pt;
// We can't use GA_ROOTOWNER since in this case we'll go up to
// the root Java toplevel, not the actual owned toplevel.
HWND hwnd = ::GetAncestor(::WindowFromPoint(pt), GA_ROOT);
AwtToolkit& tk = AwtToolkit::GetInstance();
if (tk.m_lastWindowUnderMouse != hwnd) {
AwtWindow *fw = NULL, *tw = NULL;
if (tk.m_lastWindowUnderMouse) {
fw = (AwtWindow*)
AwtComponent::GetComponent(tk.m_lastWindowUnderMouse);
}
if (hwnd) {
tw = (AwtWindow*)AwtComponent::GetComponent(hwnd);
}
tk.m_lastWindowUnderMouse = hwnd;
if (fw) {
fw->UpdateSecurityWarningVisibility();
}
// ... however, because we use GA_ROOT, we may find the warningIcon
// which is not a Java windows.
if (AwtWindow::IsWarningWindow(hwnd)) {
hwnd = ::GetParent(hwnd);
if (hwnd) {
tw = (AwtWindow*)AwtComponent::GetComponent(hwnd);
}
tk.m_lastWindowUnderMouse = hwnd;
}
if (tw) {
tw->UpdateSecurityWarningVisibility();
}
}
}
return ::CallNextHookEx(AwtToolkit::GetInstance().m_hMouseLLHook, code,
wParam, lParam);
CATCH_BAD_ALLOC_RET(0);
}
/*
* The main message loop
*/
......@@ -1376,6 +1453,47 @@ HICON AwtToolkit::GetAwtIconSm()
return defaultIconSm;
}
HICON AwtToolkit::GetSecurityWarningIcon(UINT index, UINT w, UINT h)
{
//Note: should not exceed 10 because of the current implementation.
static const int securityWarningIconCounter = 3;
static HICON securityWarningIcon[securityWarningIconCounter] = {NULL, NULL, NULL};;
static UINT securityWarningIconWidth[securityWarningIconCounter] = {0, 0, 0};
static UINT securityWarningIconHeight[securityWarningIconCounter] = {0, 0, 0};
index = AwtToolkit::CalculateWave(index, securityWarningIconCounter);
if (securityWarningIcon[index] == NULL ||
w != securityWarningIconWidth[index] ||
h != securityWarningIconHeight[index])
{
if (securityWarningIcon[index] != NULL)
{
::DestroyIcon(securityWarningIcon[index]);
}
static const wchar_t securityWarningIconName[] = L"SECURITY_WARNING_";
wchar_t iconResourceName[sizeof(securityWarningIconName) + 2];
::ZeroMemory(iconResourceName, sizeof(iconResourceName));
wcscpy(iconResourceName, securityWarningIconName);
wchar_t strIndex[2];
::ZeroMemory(strIndex, sizeof(strIndex));
strIndex[0] = L'0' + index;
wcscat(iconResourceName, strIndex);
securityWarningIcon[index] = (HICON)::LoadImage(GetModuleHandle(),
iconResourceName,
IMAGE_ICON, w, h, LR_DEFAULTCOLOR);
securityWarningIconWidth[index] = w;
securityWarningIconHeight[index] = h;
}
return securityWarningIcon[index];
}
void AwtToolkit::SetHeapCheck(long flag) {
if (flag) {
printf("heap checking not supported with this build\n");
......@@ -1428,6 +1546,49 @@ JNIEnv* AwtToolkit::GetEnv() {
(JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_2) : m_env;
}
BOOL AwtToolkit::GetScreenInsets(int screenNum, RECT * rect)
{
/* if primary display */
if (screenNum == 0) {
RECT rRW;
if (::SystemParametersInfo(SPI_GETWORKAREA,0,(void *) &rRW,0) == TRUE) {
rect->top = rRW.top;
rect->left = rRW.left;
rect->bottom = ::GetSystemMetrics(SM_CYSCREEN) - rRW.bottom;
rect->right = ::GetSystemMetrics(SM_CXSCREEN) - rRW.right;
return TRUE;
}
}
/* if additional display */
else {
MONITORINFO *miInfo;
miInfo = AwtWin32GraphicsDevice::GetMonitorInfo(screenNum);
if (miInfo) {
rect->top = miInfo->rcWork.top - miInfo->rcMonitor.top;
rect->left = miInfo->rcWork.left - miInfo->rcMonitor.left;
rect->bottom = miInfo->rcMonitor.bottom - miInfo->rcWork.bottom;
rect->right = miInfo->rcMonitor.right - miInfo->rcWork.right;
return TRUE;
}
}
return FALSE;
}
void AwtToolkit::GetWindowRect(HWND hWnd, LPRECT lpRect)
{
try {
if (S_OK == DwmAPI::DwmGetWindowAttribute(hWnd,
DwmAPI::DWMWA_EXTENDED_FRAME_BOUNDS,
lpRect, sizeof(*lpRect)))
{
return;
}
} catch (const DllUtil::Exception &) {}
::GetWindowRect(hWnd, lpRect);
}
/************************************************************************
* Toolkit native methods
*/
......@@ -1756,7 +1917,6 @@ Java_sun_awt_windows_WToolkit_getScreenHeight(JNIEnv *env, jobject self)
CATCH_BAD_ALLOC_RET(0);
}
/*
* Class: sun_awt_windows_WToolkit
* Method: getSreenInsets
......@@ -1768,34 +1928,17 @@ Java_sun_awt_windows_WToolkit_getScreenInsets(JNIEnv *env,
jint screen)
{
jobject insets = NULL;
RECT rRW;
LPMONITORINFO miInfo;
RECT rect;
TRY;
/* if primary display */
if (screen == 0) {
if (::SystemParametersInfo(SPI_GETWORKAREA,0,(void *) &rRW,0) == TRUE) {
insets = env->NewObject(env->FindClass("java/awt/Insets"),
AwtToolkit::insetsMID,
rRW.top,
rRW.left,
::GetSystemMetrics(SM_CYSCREEN) - rRW.bottom,
::GetSystemMetrics(SM_CXSCREEN) - rRW.right);
}
}
/* if additional display */
else {
miInfo = AwtWin32GraphicsDevice::GetMonitorInfo(screen);
if (miInfo) {
insets = env->NewObject(env->FindClass("java/awt/Insets"),
if (AwtToolkit::GetScreenInsets(screen, &rect)) {
insets = env->NewObject(env->FindClass("java/awt/Insets"),
AwtToolkit::insetsMID,
miInfo->rcWork.top - miInfo->rcMonitor.top,
miInfo->rcWork.left - miInfo->rcMonitor.left,
miInfo->rcMonitor.bottom - miInfo->rcWork.bottom,
miInfo->rcMonitor.right - miInfo->rcWork.right);
}
rect.top,
rect.left,
rect.bottom,
rect.right);
}
if (safe_ExceptionOccurred(env)) {
......
......@@ -210,6 +210,8 @@ public:
LPARAM lParam);
static LRESULT CALLBACK ForegroundIdleFilter(int code, WPARAM wParam,
LPARAM lParam);
static LRESULT CALLBACK MouseLowLevelHook(int code, WPARAM wParam,
LPARAM lParam);
INLINE static AwtToolkit& GetInstance() { return theInstance; }
INLINE void SetPeer(JNIEnv *env, jobject wToolkit) {
......@@ -311,6 +313,30 @@ public:
HICON GetAwtIcon();
HICON GetAwtIconSm();
// Calculate a wave-like value out of the integer 'value' and
// the specified period.
// The argument 'value' is an integer 0, 1, 2, ... *infinity*.
//
// Examples:
// Period == 3
// Generated sequence: 0 1 2 1 0 .....
//
// Period == 4
// Generated sequence: 0 1 2 3 2 1 0 .....
static inline UINT CalculateWave(UINT value, const UINT period) {
if (period < 2) {
return 0;
}
// -2 is necessary to avoid repeating extreme values (0 and period-1)
value %= period * 2 -2;
if (value >= period) {
value = period * 2 -2 - value;
}
return value;
}
HICON GetSecurityWarningIcon(UINT index, UINT w, UINT h);
/* Turns on/off dialog modality for the system. */
INLINE AwtDialog* SetModal(AwtDialog* frame) {
AwtDialog* previousDialog = m_pModalDialog;
......@@ -368,6 +394,7 @@ private:
BOOL m_mouseDown;
HHOOK m_hGetMessageHook;
HHOOK m_hMouseLLHook;
UINT_PTR m_timer;
class AwtCmdIDList* m_cmdIDs;
......@@ -411,6 +438,24 @@ public:
public:
static void SetEnv(JNIEnv *env);
static JNIEnv* GetEnv();
static BOOL GetScreenInsets(int screenNum, RECT * rect);
// If the DWM is active, this function uses
// DwmGetWindowAttribute()/DWMWA_EXTENDED_FRAME_BOUNDS.
// Otherwise, fall back to regular ::GetWindowRect().
// See 6711576 for more details.
static void GetWindowRect(HWND hWnd, LPRECT lpRect);
private:
// The window handle of a toplevel window last seen under the mouse cursor.
// See MouseLowLevelHook() for details.
HWND m_lastWindowUnderMouse;
public:
HWND GetWindowUnderMouse() { return m_lastWindowUnderMouse; }
void InstallMouseLowLevelHook();
void UninstallMouseLowLevelHook();
};
/*
......
......@@ -29,6 +29,7 @@
#include "awt_Win32GraphicsDevice.h"
#include "Devices.h"
#include "WindowsFlags.h"
#include "DllUtil.h"
BOOL DWMIsCompositionEnabled();
......@@ -89,13 +90,8 @@ void DWMResetCompositionEnabled() {
/**
* Returns true if dwm composition is enabled, false if it is not applicable
* (if the OS is not Vista) or dwm composition is disabled.
*
* Note: since DWM composition state changes are very rare we load/unload the
* dll on every change.
*/
BOOL DWMIsCompositionEnabled() {
typedef HRESULT (WINAPI DwmIsCompositionEnabledFunc)(BOOL*);
// cheaper to check than whether it's vista or not
if (dwmIsCompositionEnabled != DWM_COMP_UNDEFINED) {
return (BOOL)dwmIsCompositionEnabled;
......@@ -107,32 +103,22 @@ BOOL DWMIsCompositionEnabled() {
}
BOOL bRes = FALSE;
HMODULE hDwmApiDll = ::LoadLibrary(TEXT("dwmapi.dll"));
if (hDwmApiDll != NULL) {
DwmIsCompositionEnabledFunc *lpDwmIsCompEnabled =
(DwmIsCompositionEnabledFunc*)
GetProcAddress(hDwmApiDll, "DwmIsCompositionEnabled");
if (lpDwmIsCompEnabled != NULL) {
BOOL bEnabled;
HRESULT res = lpDwmIsCompEnabled(&bEnabled);
if (SUCCEEDED(res)) {
bRes = bEnabled;
J2dTraceLn1(J2D_TRACE_VERBOSE, " composition enabled: %d",bRes);
} else {
J2dTraceLn1(J2D_TRACE_ERROR,
"IsDWMCompositionEnabled: error %x when detecting"\
"if composition is enabled", res);
}
try {
BOOL bEnabled;
HRESULT res = DwmAPI::DwmIsCompositionEnabled(&bEnabled);
if (SUCCEEDED(res)) {
bRes = bEnabled;
J2dTraceLn1(J2D_TRACE_VERBOSE, " composition enabled: %d",bRes);
} else {
J2dTraceLn(J2D_TRACE_ERROR,
"IsDWMCompositionEnabled: no DwmIsCompositionEnabled() "\
"in dwmapi.dll");
J2dTraceLn1(J2D_TRACE_ERROR,
"IsDWMCompositionEnabled: error %x when detecting"\
"if composition is enabled", res);
}
::FreeLibrary(hDwmApiDll);
} else {
} catch (const DllUtil::Exception &) {
J2dTraceLn(J2D_TRACE_ERROR,
"IsDWMCompositionEnabled: error opening dwmapi.dll");
"IsDWMCompositionEnabled: no DwmIsCompositionEnabled() "\
"in dwmapi.dll or dwmapi.dll cannot be loaded");
}
dwmIsCompositionEnabled = bRes;
......
......@@ -54,6 +54,8 @@ public:
static jfieldID locationByPlatformID;
static jfieldID screenID; /* screen number passed over from WindowPeer */
static jfieldID autoRequestFocusID;
static jfieldID securityWarningWidthID;
static jfieldID securityWarningHeightID;
// The coordinates at the peer.
static jfieldID sysXID;
......@@ -61,6 +63,9 @@ public:
static jfieldID sysWID;
static jfieldID sysHID;
static jmethodID getWarningStringMID;
static jmethodID calculateSecurityWarningPositionMID;
AwtWindow();
virtual ~AwtWindow();
......@@ -150,6 +155,8 @@ public:
static void SetModalBlocker(HWND window, HWND blocker);
static void SetAndActivateModalBlocker(HWND window, HWND blocker);
static HWND GetTopmostModalBlocker(HWND window);
/*
* Windows message handler functions
*/
......@@ -166,13 +173,13 @@ public:
virtual MsgRouting WmSettingChange(UINT wFlag, LPCTSTR pszSection);
virtual MsgRouting WmNcCalcSize(BOOL fCalcValidRects,
LPNCCALCSIZE_PARAMS lpncsp, LRESULT& retVal);
virtual MsgRouting WmNcPaint(HRGN hrgn);
virtual MsgRouting WmNcHitTest(UINT x, UINT y, LRESULT& retVal);
virtual MsgRouting WmNcMouseDown(WPARAM hitTest, int x, int y, int button);
virtual MsgRouting WmGetIcon(WPARAM iconType, LRESULT& retVal);
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
virtual MsgRouting WmWindowPosChanging(LPARAM windowPos);
virtual MsgRouting WmWindowPosChanged(LPARAM windowPos);
virtual MsgRouting WmTimer(UINT_PTR timerID);
virtual MsgRouting HandleEvent(MSG *msg, BOOL synthetic);
virtual void WindowResized();
......@@ -221,11 +228,22 @@ public:
static void _SetOpacity(void* param);
static void _SetOpaque(void* param);
static void _UpdateWindow(void* param);
static void _RepositionSecurityWarning(void* param);
inline static BOOL IsResizing() {
return sm_resizing;
}
virtual void CreateHWnd(JNIEnv *env, LPCWSTR title,
DWORD windowStyle, DWORD windowExStyle,
int x, int y, int w, int h,
HWND hWndParent, HMENU hMenu,
COLORREF colorForeground, COLORREF colorBackground,
jobject peer);
virtual void DestroyHWnd();
static void FocusedWindowChanged(HWND from, HWND to);
private:
static int ms_instanceCounter;
static HHOOK ms_hCBTFilter;
......@@ -267,9 +285,56 @@ private:
UINT contentWidth;
UINT contentHeight;
void RedrawWindow();
void SetTranslucency(BYTE opacity, BOOL opaque);
void UpdateWindow(int width, int height, HBITMAP hBitmap);
void UpdateWindowImpl(int width, int height, HBITMAP hBitmap);
void RedrawWindow();
static UINT untrustedWindowsCounter;
WCHAR * warningString;
// The warning icon
HWND warningWindow;
// The tooltip that appears when hovering the icon
HWND securityTooltipWindow;
UINT warningWindowWidth;
UINT warningWindowHeight;
void InitSecurityWarningSize(JNIEnv *env);
HICON GetSecurityWarningIcon();
void CreateWarningWindow(JNIEnv *env);
void DestroyWarningWindow();
static LPCTSTR GetWarningWindowClassName();
void FillWarningWindowClassInfo(WNDCLASS *lpwc);
void RegisterWarningWindowClass();
void UnregisterWarningWindowClass();
static LRESULT CALLBACK WarningWindowProc(
HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static void PaintWarningWindow(HWND warningWindow);
static void PaintWarningWindow(HWND warningWindow, HDC hdc);
void RepaintWarningWindow();
void CalculateWarningWindowBounds(JNIEnv *env, LPRECT rect);
void AnimateSecurityWarning(bool enable);
UINT securityWarningAnimationStage;
enum AnimationKind {
akNone, akShow, akPreHide, akHide
};
AnimationKind securityAnimationKind;
void StartSecurityAnimation(AnimationKind kind);
void StopSecurityAnimation();
void RepositionSecurityWarning(JNIEnv *env);
public:
void UpdateSecurityWarningVisibility();
static bool IsWarningWindow(HWND hWnd);
protected:
BOOL m_isResizable;
......@@ -284,6 +349,12 @@ protected:
virtual void FillBackground(HDC hMemoryDC, SIZE &size);
virtual void FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha);
inline BOOL IsUntrusted() {
return warningString != NULL;
}
UINT currentWmSizeState;
private:
int m_screenNum;
......
/*
* Copyright 2008-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 6785058
@summary Tests that an owner is activated on closing its owned dialog with the warning icon.
@author Anton Tarasov: area=awt.focus
@library ../../regtesthelpers
@build Util
@run main/othervm/policy=java.policy -Djava.security.manager CloseDialogActivateOwnerTest
*/
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.lang.reflect.InvocationTargetException;
import test.java.awt.regtesthelpers.Util;
public class CloseDialogActivateOwnerTest extends Applet {
Robot robot;
public static void main(String[] args) {
CloseDialogActivateOwnerTest app = new CloseDialogActivateOwnerTest();
app.init();
app.start();
}
public void init() {
robot = Util.createRobot();
}
public void start() {
final Frame frame = new Frame("Owner Frame");
final Dialog dialog = new Dialog(frame, "Owned Dialog");
frame.setSize(100, 100);
dialog.setSize(100, 100);
// Show the owner. Check that it's focused.
if (!Util.trackWindowGainedFocus(frame, new Runnable() {
public void run() {
frame.setVisible(true);
}
}, 2000, false))
{
throw new TestErrorException("the owner frame hasn't been activated on show");
}
// Show the owned dialog. Check that it's focused.
if (!Util.trackWindowGainedFocus(dialog, new Runnable() {
public void run() {
dialog.setVisible(true);
}
}, 2000, true))
{
throw new TestErrorException("the owned dialog hasn't been activated on show");
}
robot.delay(2000); // wait for the warning icon is shown
// Close the dialog. Check that the owner is activated.
if (!Util.trackWindowGainedFocus(frame, new Runnable() {
public void run() {
dialog.dispose();
}
}, 2000, false))
{
throw new TestFailedException("the owner hasn't been activated on closing the owned dialog");
}
System.out.println("Test passed.");
}
}
/**
* Thrown when the behavior being verified is found wrong.
*/
class TestFailedException extends RuntimeException {
TestFailedException(String msg) {
super("Test failed: " + msg);
}
}
/**
* Thrown when an error not related to the behavior being verified is encountered.
*/
class TestErrorException extends Error {
TestErrorException(String msg) {
super("Unexpected error: " + msg);
}
}
grant {
permission java.awt.AWTPermission "createRobot";
};
/*
* Copyright 2008-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 6542975
@summary Tests that switching focus from an owned window doesn't crash.
@author anton.tarasov@sun.com: area=awt-focus
@library ../../regtesthelpers
@build Util
@run main OwnedWindowFocusIMECrashTest
*/
import java.awt.*;
import javax.swing.*;
import test.java.awt.regtesthelpers.Util;
public class OwnedWindowFocusIMECrashTest {
Robot robot;
JFrame owner = new JFrame("Owner Frame");
JFrame frame = new JFrame("Other Frame");
JWindow window = new JWindow(owner);
JButton button = new JButton("Button");
public static void main(String[] args) {
OwnedWindowFocusIMECrashTest app = new OwnedWindowFocusIMECrashTest();
app.init();
app.start();
}
public void init() {
robot = Util.createRobot();
}
public void start() {
owner.setBounds(100, 100, 200, 100);
window.setBounds(100, 250, 200, 100);
frame.setBounds(350, 100, 200, 100);
window.add(button);
owner.setVisible(true);
frame.setVisible(true);
window.setVisible(true);
Util.waitForIdle(robot);
test();
System.out.println("Test passed");
}
void test() {
Util.clickOnComp(button, robot);
if (!button.hasFocus()) {
throw new TestErrorException("the button couldn't be focused by click");
}
Util.clickOnTitle(frame, robot); // here there was a crash
}
}
/**
* Thrown when an error not related to the behavior being verified is encountered.
*/
class TestErrorException extends RuntimeException {
TestErrorException(String msg) {
super("Unexpected error: " + msg);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册