LWWindowPeer.java revision 5295
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public class LWWindowPeer
{
public static enum PeerType {
}
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWWindowPeer");
private PlatformWindow platformWindow;
// Window bounds reported by the native system (as opposed to
// regular bounds inherited from LWComponentPeer which are
// requested by user and may haven't been applied yet because
// of asynchronous requests to the windowing system)
private int sysX;
private int sysY;
private int sysW;
private int sysH;
private static final int MINIMUM_WIDTH = 1;
private static final int MINIMUM_HEIGHT = 1;
private GraphicsDevice graphicsDevice;
private GraphicsConfiguration graphicsConfig;
private SurfaceData surfaceData;
private int backBufferCount;
private BufferCapabilities backBufferCaps;
// The back buffer is used for two purposes:
// 1. To render all the lightweight peers
// 2. To provide user with a BufferStrategy
// Need to check if a single back buffer can be used for both
// TODO: VolatileImage
// private VolatileImage backBuffer;
private volatile BufferedImage backBuffer;
// A peer where the last mouse event came to. Used to generate
// MOUSE_ENTERED/EXITED notifications and by cursor manager to
// find the component under cursor
// depending on what mouse button is being dragged according to Cocoa
// A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events
// on MOUSE_RELEASE. Click events are only generated if there were no drag
// events between MOUSE_PRESSED and MOUSE_RELEASED for particular button
private static int mouseClickButtons = 0;
private volatile boolean isOpaque = true;
private static LWWindowPeer grabbingWindow;
private volatile boolean skipNextFocusChange;
private volatile boolean textured;
/**
* Current modal blocker or null.
*
* Synchronization: peerTreeLock.
*/
private LWWindowPeer blocker;
{
super(target, platformComponent);
this.platformWindow = platformWindow;
// The delegate.initialize() needs a non-null GC on X11.
synchronized (getStateLock()) {
// graphicsConfig should be updated according to the real window
// bounds when the window is shown, see 4868278
this.graphicsConfig = gc;
}
}
if (!target.isBackgroundSet()) {
} else {
// first we check if user provided alpha for background. This is
// similar to what Apple's Java do.
// Since JDK7 we should rely on setOpacity() only.
// this.opacity = c.getAlpha();
}
if (!target.isForegroundSet()) {
// we should not call setForeground because it will call a repaint
// which the peer may not be ready to do yet.
}
}
void initializeImpl() {
super.initializeImpl();
}
}
if (opacity < 1.0f) {
}
if (getSurfaceData() == null) {
replaceSurfaceData(false);
}
}
// Just a helper method
public PlatformWindow getPlatformWindow() {
return platformWindow;
}
protected LWWindowPeer getWindowPeerOrSelf() {
return this;
}
protected void initializeContainerPeer() {
// No-op as LWWindowPeer doesn't have any containerPeer
}
// ---- PEER METHODS ---- //
protected void disposeImpl() {
synchronized (surfaceDataLock){
surfaceData = null;
}
}
if (isGrabbing()) {
ungrab();
}
super.disposeImpl();
}
protected void setVisibleImpl(final boolean visible) {
super.setVisibleImpl(visible);
// TODO: update graphicsConfig, see 4868278
if (isSimpleWindow()) {
if (visible) {
if (!getTarget().isAutoRequestFocus()) {
return;
} else {
}
// Transfer focus to the owner.
}
}
}
}
public GraphicsConfiguration getGraphicsConfiguration() {
return graphicsConfig;
}
return false;
}
if (getSurfaceData() == null) {
return null;
}
}
}
if (f == null) {
f = DEFAULT_FONT;
}
}
throws AWTException
{
try {
// Assume this method is never called with numBuffers <= 1, as 0 is
// unsupported, and 1 corresponds to a SingleBufferStrategy which
// doesn't depend on the peer. Screen is considered as a separate
// "buffer", that's why numBuffers - 1
assert numBuffers > 1;
} catch (InvalidPipeException z) {
throw new AWTException(z.toString());
}
}
public final Image getBackBuffer() {
synchronized (getStateLock()) {
return backBuffer;
}
}
{
throw new IllegalStateException("Buffers have not been created");
}
final Graphics g = getGraphics();
try {
} finally {
g.dispose();
}
try {
} finally {
}
}
}
public final void destroyBuffers() {
synchronized (getStateLock()) {
backBuffer = null;
}
}
}
// SET_CLIENT_SIZE is only applicable to window peers, so handle it here
// instead of pulling 'insets' field up to LWComponentPeer
// no need to add insets since Window's notion of width and height includes insets.
op &= ~SET_CLIENT_SIZE;
}
if (w < MINIMUM_WIDTH) {
w = MINIMUM_WIDTH;
}
if (h < MINIMUM_HEIGHT) {
h = MINIMUM_HEIGHT;
}
if (graphicsConfig instanceof TextureSizeConstraining) {
if (w > maxW) {
w = maxW;
}
if (h > maxH) {
h = maxH;
}
}
// Don't post ComponentMoved/Resized and Paint events
// until we've got a notification from the delegate
// Get updated bounds, so we don't have to handle 'op' here manually
}
public Point getLocationOnScreen() {
return platformWindow.getLocationOnScreen();
}
/**
* Overridden from LWContainerPeer to return the correct insets.
* Insets are queried from the delegate and are kept up to date by
* requiering when needed (i.e. when the window geometry is changed).
*/
synchronized (getStateLock()) {
return insets;
}
}
// TODO: check for "use platform metrics" settings
return platformWindow.getFontMetrics(f);
}
public void toFront() {
}
public void toBack() {
}
throw new RuntimeException("not implemented");
}
public void setAlwaysOnTop(boolean value) {
}
public void updateFocusableWindowState() {
}
synchronized (getPeerTreeLock()) {
} else {
}
}
}
public void updateMinimumSize() {
if (getTarget().isMinimumSizeSet()) {
} else {
}
if (graphicsConfig instanceof TextureSizeConstraining) {
} else {
}
if (getTarget().isMaximumSizeSet()) {
} else {
}
}
public void updateIconImages() {
}
public void setOpacity(float opacity) {
repaintPeer();
}
updateOpaque();
}
}
private void updateOpaque() {
replaceSurfaceData(false);
repaintPeer();
}
public void updateWindow() {
}
public final boolean isTextured() {
return textured;
}
public final void setTextured(final boolean isTextured) {
}
public final boolean isTranslucent() {
synchronized (getStateLock()) {
/*
* Textured window is a special case of translucent window.
* The difference is only in nswindow background. So when we set
* texture property our peer became fully translucent. It doesn't
* fill background, create non opaque backbuffers and layer etc.
*/
}
}
super.applyShapeImpl(shape);
updateOpaque();
}
public void repositionSecurityWarning() {
throw new RuntimeException("not implemented");
}
// ---- FRAME PEER METHODS ---- //
@Override // FramePeer and DialogPeer
}
}
@Override // FramePeer and DialogPeer
public void setResizable(boolean resizable) {
}
}
public int getState() {
return windowState;
}
// TODO: not implemented
}
}
public Rectangle getBoundsPrivate() {
throw new RuntimeException("not implemented");
}
// ---- DIALOG PEER METHODS ---- //
//TODO: LWX will probably need some collectJavaToplevels to speed this up
}
}
}
// ---- PEER NOTIFICATIONS ---- //
public void notifyIconify(boolean iconify) {
//The toplevel target is Frame and states are applicable to it.
//Otherwise, the target is Window and it don't have state property.
//Hopefully, no such events are posted in the queue so consider the
//target as Frame in all cases.
// REMIND: should we send it anyway if the state not changed since last
// time?
// REMIND: RepaintManager doesn't repaint iconified windows and
// hence ignores any repaint request during deiconification.
// So, we need to repaint window explicitly when it becomes normal.
if (!iconify) {
repaintPeer();
}
}
public void notifyZoom(boolean isZoomed) {
}
/**
* Called by the delegate when any part of the window should be repainted.
*/
public void notifyExpose(final int x, final int y, final int w, final int h) {
// TODO: there's a serious problem with Swing here: it handles
// the exposition internally, so SwingPaintEventDispatcher always
// return null from createPaintEvent(). However, we flush the
// back buffer here unconditionally, so some flickering may appear.
// A possible solution is to split postPaintEvent() into two parts,
// and override that part which is only called after if
// createPaintEvent() returned non-null value and flush the buffer
// from the overridden method
repaintPeer(new Rectangle(x, y, w, h));
}
/**
* There's no notifyReshape() in LWComponentPeer as the only
* components which could be resized by user are top-level windows.
*/
public final void notifyReshape(int x, int y, int w, int h) {
boolean moved = false;
boolean resized = false;
synchronized (getStateLock()) {
sysX = x;
sysY = y;
sysW = w;
sysH = h;
}
// Check if anything changed
return;
}
// First, update peer's bounds
setBounds(x, y, w, h, SET_BOUNDS, false, false);
// Second, update the graphics config and surface data
if (resized) {
}
// Third, COMPONENT_MOVED/COMPONENT_RESIZED events
if (moved) {
handleMove(x, y, true);
}
if (resized) {
handleResize(w, h,true);
}
}
private void clearBackground(final int w, final int h) {
getFont());
if (g != null) {
try {
if (g instanceof Graphics2D) {
}
if (isTranslucent()) {
}
if (!isTextured()) {
if (g instanceof SunGraphics2D) {
}
g.setColor(getBackground());
}
} finally {
g.dispose();
}
}
}
public void notifyUpdateCursor() {
}
public void notifyActivation(boolean activation) {
}
// MouseDown in non-client area
public void notifyNCMouseDown() {
// Ungrab except for a click on a Dialog with the grabbing owner
if (grabbingWindow != null &&
grabbingWindow != getOwnerFrameDialog(this))
{
}
}
// ---- EVENTS ---- //
/*
* Called by the delegate to dispatch the event to Java. Event
* coordinates are relative to non-client window are, i.e. the top-left
* point of the client area is (insets.top, insets.left).
*/
byte[] bdata)
{
// TODO: fill "bdata" member of AWTEvent
// findPeerAt() expects parent coordinates
// Sometimes we may get MOUSE_EXITED after lastMouseEventPeer is switched
// to a peer from another window. So we must first check if this peer is
// the same as lastWindowPeer
if (lastWindowPeer == this) {
if (isEnabled()) {
button));
}
}
} else {
if (targetPeer != lastMouseEventPeer) {
// lastMouseEventPeer may be null if mouse was out of Java windows
// Sometimes, MOUSE_EXITED is not sent by delegate (or is sent a bit
// later), in which case lastWindowPeer is another window
if (lastWindowPeer != this) {
// Additionally translate from this to lastWindowPeer coordinates
} else {
}
}
}
}
// TODO: fill "bdata" member of AWTEvent
// mouse buttons as if they were BUTTON2, so we do the same
// MOUSE_ENTERED/EXITED are generated for the components strictly under
// mouse even when dragging. That's why we first update lastMouseEventPeer
// based on initial targetPeer value and only then recalculate targetPeer
// for MOUSE_DRAGGED/RELEASED events
// Ungrab only if this window is not an owned window of the grabbing one.
grabbingWindow != getOwnerFrameDialog(this))
{
}
if (otherButtonsPressed == 0) {
} else {
}
// Cocoa dragged event has the information about which mouse
// button is being dragged. Use it to determine the peer that
// should receive the dragged event.
// TODO: currently, mouse released event goes to the same component
// that received corresponding mouse pressed event. For most cases,
// it's OK, however, we need to make sure that our behavior is consistent
// with 1.6 for cases where component in question have been
}
// mouseClickButtons is updated below, after MOUSE_CLICK is sent
}
// check if we receive mouseEvent from outside the window's bounds
// it can be either mouseDragged or mouseReleased
if (curWindowPeer == null) {
//TODO This can happen if this window is invisible. this is correct behavior in this case?
curWindowPeer = this;
}
if (targetPeer == null) {
//TODO This can happen if this window is invisible. this is correct behavior in this case?
targetPeer = this;
}
if (targetPeer.isEnabled()) {
}
&& targetPeer.isEnabled()) {
}
}
}
}
int scrollType, int scrollAmount,
int wheelRotation, double preciseWheelRotation,
byte[] bdata)
{
// TODO: could we just use the last mouse event target here?
// findPeerAt() expects parent coordinates
return;
}
// TODO: fill "bdata" member of AWTEvent
0, 0, /* screenX, Y */
0 /* clickCount */, false /* popupTrigger */,
}
/*
* Called by the delegate when a key is pressed.
*/
{
// Null focus owner may receive key event when
// application hides the focused window upon ESC press
// may come to already hidden window. This check eliminates NPE.
if (focusOwner != null) {
}
}
// ---- UTILITY METHODS ---- //
private void postWindowStateChangedEvent(int newWindowState) {
}
}
// TODO: this method can be implemented in a more
// efficient way by forwarding to the delegate
return i;
}
}
// Should never happen if gc is a screen device config
return 0;
}
/*
* This method is called when window's graphics config is changed from
* the app code (e.g. when the window is made non-opaque) or when
* the window is moved to another screen by user.
*
* Returns true if the graphics config has been changed, false otherwise.
*/
synchronized (getStateLock()) {
if (graphicsConfig == gc) {
return false;
}
// If window's graphics config is changed from the app code, the
// config correspond to the same device as before; when the window
// is moved by user, graphicsDevice is updated in checkIfOnNewScreen().
// In either case, there's nothing to do with screenOn here
graphicsConfig = gc;
}
// SurfaceData is replaced later in updateGraphicsData()
return true;
}
private void checkIfOnNewScreen() {
synchronized (getStateLock()) {
if (graphicsDevice == newGraphicsDevice) {
return;
}
}
// TODO: DisplayChangedListener stuff
if (!setGraphicsConfig(newGC)) return;
public void run() {
}
});
}
/*
* May be called by delegate to provide SD to Java2D code.
*/
public SurfaceData getSurfaceData() {
synchronized (surfaceDataLock) {
return surfaceData;
}
}
private void replaceSurfaceData() {
replaceSurfaceData(true);
}
private void replaceSurfaceData(boolean blit) {
}
private void replaceSurfaceData(int newBackBufferCount,
boolean blit) {
synchronized (surfaceDataLock) {
// TODO: volatile image
// VolatileImage oldBB = backBuffer;
}
if (blit) {
}
// This can only happen when this peer is being created
}
// TODO: volatile image
// backBuffer = (VolatileImage)delegate.createBackBuffer();
if (backBuffer != null) {
try {
if (g instanceof Graphics2D) {
}
if (g instanceof SunGraphics2D) {
}
if (!isTextured()) {
g.setColor(getBackground());
}
// Draw the old back buffer to the new one
}
} finally {
g.dispose();
}
}
}
}
//TODO blit. proof-of-concept
&& !(dst instanceof NullSurfaceData)
&& !(src instanceof NullSurfaceData)
dst.getSurfaceType());
}
}
}
public int getBackBufferCount() {
return backBufferCount;
}
public BufferCapabilities getBackBufferCaps() {
return backBufferCaps;
}
/*
* Request the window insets from the delegate and compares it
* with the current one. This method is mostly called by the
* delegate, e.g. when the window state is changed and insets
* should be recalculated.
*
* This method may be called on the toolkit thread.
*/
boolean changed = false;
synchronized (getStateLock()) {
}
if (changed) {
repaintPeer();
}
return changed;
}
public static LWWindowPeer getWindowUnderCursor() {
}
public static LWComponentPeer<?, ?> getPeerUnderCursor() {
return lastMouseEventPeer;
}
/*
* In case of a simple window, triggers appropriate java focus change.
*/
}
if (!focusAllowedFor()) {
return false;
}
return false;
}
// Make the owner active window.
if (isSimpleWindow()) {
// If owner is not natively active, request native
// activation on it w/o sending events up to java.
}
// Ensure the opposite is natively active and suppress sending events.
}
currentActivePeer.skipNextFocusChange = true;
}
owner.skipNextFocusChange = true;
}
// DKFM will synthesize all the focus/activation events correctly.
changeFocusedWindow(true);
return true;
// In case the toplevel is active but not focused, change focus directly,
// as requesting native focus on it will not have effect.
changeFocusedWindow(true);
return true;
}
return platformWindow.requestWindowFocus();
}
private boolean focusAllowedFor() {
// TODO: check if modal blocked
}
private boolean isFocusableWindow() {
if (isSimpleWindow()) {
return false;
}
}
return focusable;
}
public boolean isSimpleWindow() {
}
/*
* Changes focused window on java level.
*/
private void changeFocusedWindow(boolean becomesFocused) {
}
if (skipNextFocusChange) {
skipNextFocusChange = false;
return;
}
if (!isFocusableWindow() && becomesFocused) {
return;
}
if (becomesFocused) {
synchronized (getPeerTreeLock()) {
}
return;
}
}
}
// Note, the method is not called:
// - for a simple window in any case.
if (!becomesFocused &&
{
// ungrab a simple window if its owner looses activation.
}
// TODO: wrap in SequencedEvent
}
}
}
/**
* Returns the foremost modal blocker of this window, or null.
*/
public LWWindowPeer getBlocker() {
synchronized (getPeerTreeLock()) {
return null;
}
}
return blocker;
}
}
public void enterFullScreenMode() {
}
public void exitFullScreenMode() {
}
public long getLayerPtr() {
return getPlatformWindow().getLayerPtr();
}
void grab() {
}
grabbingWindow = this;
}
void ungrab() {
if (isGrabbing()) {
}
}
private boolean isGrabbing() {
return this == grabbingWindow;
}
}
}