Path: blob/master/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java
41153 views
/*1* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.lwawt;2627import java.awt.AlphaComposite;28import java.awt.Color;29import java.awt.Component;30import java.awt.Dialog;31import java.awt.Dimension;32import java.awt.Font;33import java.awt.FontMetrics;34import java.awt.Frame;35import java.awt.Graphics;36import java.awt.Graphics2D;37import java.awt.GraphicsConfiguration;38import java.awt.GraphicsDevice;39import java.awt.GraphicsEnvironment;40import java.awt.Insets;41import java.awt.KeyboardFocusManager;42import java.awt.MenuBar;43import java.awt.Point;44import java.awt.Rectangle;45import java.awt.Shape;46import java.awt.SystemColor;47import java.awt.Toolkit;48import java.awt.Window;49import java.awt.event.FocusEvent;50import java.awt.event.KeyEvent;51import java.awt.event.MouseEvent;52import java.awt.event.MouseWheelEvent;53import java.awt.event.WindowEvent;54import java.awt.peer.ComponentPeer;55import java.awt.peer.DialogPeer;56import java.awt.peer.FramePeer;57import java.awt.peer.KeyboardFocusManagerPeer;58import java.awt.peer.WindowPeer;59import java.util.List;6061import javax.swing.JComponent;6263import sun.awt.AWTAccessor;64import sun.awt.AWTAccessor.ComponentAccessor;65import sun.awt.AppContext;66import sun.awt.CGraphicsDevice;67import sun.awt.DisplayChangedListener;68import sun.awt.ExtendedKeyCodes;69import sun.awt.FullScreenCapable;70import sun.awt.SunToolkit;71import sun.awt.TimedWindowEvent;72import sun.awt.UngrabEvent;73import sun.java2d.NullSurfaceData;74import sun.java2d.SunGraphics2D;75import sun.java2d.SunGraphicsEnvironment;76import sun.java2d.SurfaceData;77import sun.java2d.loops.Blit;78import sun.java2d.loops.CompositeType;79import sun.java2d.pipe.Region;80import sun.util.logging.PlatformLogger;8182public class LWWindowPeer83extends LWContainerPeer<Window, JComponent>84implements FramePeer, DialogPeer, FullScreenCapable, DisplayChangedListener, PlatformEventNotifier85{86public enum PeerType {87SIMPLEWINDOW,88FRAME,89DIALOG,90EMBEDDED_FRAME,91VIEW_EMBEDDED_FRAME,92LW_FRAME93}9495private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWWindowPeer");9697private final PlatformWindow platformWindow;9899private static final int MINIMUM_WIDTH = 1;100private static final int MINIMUM_HEIGHT = 1;101102private Insets insets = new Insets(0, 0, 0, 0);103private Rectangle maximizedBounds;104105private GraphicsDevice graphicsDevice;106private GraphicsConfiguration graphicsConfig;107108private SurfaceData surfaceData;109private final Object surfaceDataLock = new Object();110111private volatile int windowState = Frame.NORMAL;112113// check that the mouse is over the window114private volatile boolean isMouseOver = false;115116// A peer where the last mouse event came to. Used by cursor manager to117// find the component under cursor118private static volatile LWComponentPeer<?, ?> lastCommonMouseEventPeer;119120// A peer where the last mouse event came to. Used to generate121// MOUSE_ENTERED/EXITED notifications122private volatile LWComponentPeer<?, ?> lastMouseEventPeer;123124// Peers where all dragged/released events should come to,125// depending on what mouse button is being dragged according to Cocoa126private static final LWComponentPeer<?, ?>[] mouseDownTarget = new LWComponentPeer<?, ?>[3];127128// A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events129// on MOUSE_RELEASE. Click events are only generated if there were no drag130// events between MOUSE_PRESSED and MOUSE_RELEASED for particular button131private static int mouseClickButtons = 0;132133private volatile boolean isOpaque = true;134135private static final Font DEFAULT_FONT = new Font("Lucida Grande", Font.PLAIN, 13);136137private static LWWindowPeer grabbingWindow;138139private volatile boolean skipNextFocusChange;140141private static final Color nonOpaqueBackground = new Color(0, 0, 0, 0);142143private volatile boolean textured;144145private final PeerType peerType;146147private final SecurityWarningWindow warningWindow;148149private volatile boolean targetFocusable;150151/**152* Current modal blocker or null.153*154* Synchronization: peerTreeLock.155*/156private LWWindowPeer blocker;157158public LWWindowPeer(Window target, PlatformComponent platformComponent,159PlatformWindow platformWindow, PeerType peerType)160{161super(target, platformComponent);162this.platformWindow = platformWindow;163this.peerType = peerType;164165Window owner = target.getOwner();166LWWindowPeer ownerPeer = owner == null ? null :167(LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(owner);168PlatformWindow ownerDelegate = (ownerPeer != null) ? ownerPeer.getPlatformWindow() : null;169170// The delegate.initialize() needs a non-null GC on X11.171GraphicsConfiguration gc = getTarget().getGraphicsConfiguration();172synchronized (getStateLock()) {173// graphicsConfig should be updated according to the real window174// bounds when the window is shown, see 4868278175this.graphicsConfig = gc;176}177178if (!target.isFontSet()) {179target.setFont(DEFAULT_FONT);180}181182if (!target.isBackgroundSet()) {183target.setBackground(SystemColor.window);184} else {185// first we check if user provided alpha for background. This is186// similar to what Apple's Java do.187// Since JDK7 we should rely on setOpacity() only.188// this.opacity = c.getAlpha();189}190191if (!target.isForegroundSet()) {192target.setForeground(SystemColor.windowText);193// we should not call setForeground because it will call a repaint194// which the peer may not be ready to do yet.195}196197platformWindow.initialize(target, this, ownerDelegate);198199// Init warning window(for applets)200SecurityWarningWindow warn = null;201if (target.getWarningString() != null) {202// accessSystemTray permission allows to display TrayIcon, TrayIcon tooltip203// and TrayIcon balloon windows without a warning window.204if (!AWTAccessor.getWindowAccessor().isTrayIconWindow(target)) {205LWToolkit toolkit = (LWToolkit)Toolkit.getDefaultToolkit();206warn = toolkit.createSecurityWarning(target, this);207}208}209210warningWindow = warn;211}212213@Override214void initializeImpl() {215super.initializeImpl();216217218if (getTarget() instanceof Frame) {219Frame frame = (Frame) getTarget();220setTitle(frame.getTitle());221setState(frame.getExtendedState());222setMaximizedBounds(frame.getMaximizedBounds());223} else if (getTarget() instanceof Dialog) {224setTitle(((Dialog) getTarget()).getTitle());225}226227updateAlwaysOnTopState();228updateMinimumSize();229updateFocusableWindowState();230231final Shape shape = getTarget().getShape();232if (shape != null) {233applyShape(Region.getInstance(shape, null));234}235236final float opacity = getTarget().getOpacity();237if (opacity < 1.0f) {238setOpacity(opacity);239}240241setOpaque(getTarget().isOpaque());242243updateInsets(platformWindow.getInsets());244if (getSurfaceData() == null) {245replaceSurfaceData(false);246}247activateDisplayListener();248}249250// Just a helper method251@Override252public PlatformWindow getPlatformWindow() {253return platformWindow;254}255256@Override257protected LWWindowPeer getWindowPeerOrSelf() {258return this;259}260261// ---- PEER METHODS ---- //262263@Override264protected void disposeImpl() {265deactivateDisplayListener();266SurfaceData oldData = getSurfaceData();267synchronized (surfaceDataLock){268surfaceData = null;269}270if (oldData != null) {271oldData.invalidate();272}273if (isGrabbing()) {274ungrab();275}276if (warningWindow != null) {277warningWindow.dispose();278}279280platformWindow.dispose();281super.disposeImpl();282}283284@Override285protected void setVisibleImpl(final boolean visible) {286if (!visible && warningWindow != null) {287warningWindow.setVisible(false, false);288}289updateFocusableWindowState();290super.setVisibleImpl(visible);291// TODO: update graphicsConfig, see 4868278292platformWindow.setVisible(visible);293if (isSimpleWindow()) {294KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();295if (visible) {296if (!getTarget().isAutoRequestFocus()) {297return;298} else {299requestWindowFocus(FocusEvent.Cause.ACTIVATION);300}301// Focus the owner in case this window is focused.302} else if (kfmPeer.getCurrentFocusedWindow() == getTarget()) {303// Transfer focus to the owner.304LWWindowPeer owner = getOwnerFrameDialog(LWWindowPeer.this);305if (owner != null) {306owner.requestWindowFocus(FocusEvent.Cause.ACTIVATION);307}308}309}310}311312@Override313public final GraphicsConfiguration getGraphicsConfiguration() {314synchronized (getStateLock()) {315return graphicsConfig;316}317}318319@Override320public boolean updateGraphicsData(GraphicsConfiguration gc) {321setGraphicsConfig(gc);322return false;323}324325protected final Graphics getOnscreenGraphics(Color fg, Color bg, Font f) {326SurfaceData surfaceData = getSurfaceData();327if (surfaceData == null) {328return null;329}330if (fg == null) {331fg = SystemColor.windowText;332}333if (bg == null) {334bg = SystemColor.window;335}336if (f == null) {337f = DEFAULT_FONT;338}339return new SunGraphics2D(surfaceData, fg, bg, f);340}341342@Override343public void setBounds(int x, int y, int w, int h, int op) {344345if((op & NO_EMBEDDED_CHECK) == 0 && getPeerType() == PeerType.VIEW_EMBEDDED_FRAME) {346return;347}348349if ((op & SET_CLIENT_SIZE) != 0) {350// SET_CLIENT_SIZE is only applicable to window peers, so handle it here351// instead of pulling 'insets' field up to LWComponentPeer352// no need to add insets since Window's notion of width and height includes insets.353op &= ~SET_CLIENT_SIZE;354op |= SET_SIZE;355}356357// Don't post ComponentMoved/Resized and Paint events358// until we've got a notification from the delegate359Rectangle cb = constrainBounds(x, y, w, h);360361Rectangle newBounds = new Rectangle(getBounds());362if ((op & (SET_LOCATION | SET_BOUNDS)) != 0) {363newBounds.x = cb.x;364newBounds.y = cb.y;365}366if ((op & (SET_SIZE | SET_BOUNDS)) != 0) {367newBounds.width = cb.width;368newBounds.height = cb.height;369}370// Native system could constraint bounds, so the peer wold be updated in the callback371platformWindow.setBounds(newBounds.x, newBounds.y, newBounds.width, newBounds.height);372}373374public Rectangle constrainBounds(Rectangle bounds) {375return constrainBounds(bounds.x, bounds.y, bounds.width, bounds.height);376}377378public Rectangle constrainBounds(int x, int y, int w, int h) {379380if (w < MINIMUM_WIDTH) {381w = MINIMUM_WIDTH;382}383384if (h < MINIMUM_HEIGHT) {385h = MINIMUM_HEIGHT;386}387388final int maxW = getLWGC().getMaxTextureWidth();389final int maxH = getLWGC().getMaxTextureHeight();390391if (w > maxW) {392w = maxW;393}394if (h > maxH) {395h = maxH;396}397398return new Rectangle(x, y, w, h);399}400401@Override402public Point getLocationOnScreen() {403return platformWindow.getLocationOnScreen();404}405406/**407* Overridden from LWContainerPeer to return the correct insets.408* Insets are queried from the delegate and are kept up to date by409* requiering when needed (i.e. when the window geometry is changed).410*/411@Override412public Insets getInsets() {413synchronized (getStateLock()) {414return insets;415}416}417418@Override419public FontMetrics getFontMetrics(Font f) {420// TODO: check for "use platform metrics" settings421return platformWindow.getFontMetrics(f);422}423424@Override425public void toFront() {426platformWindow.toFront();427}428429@Override430public void toBack() {431platformWindow.toBack();432}433434@Override435public void setZOrder(ComponentPeer above) {436throw new RuntimeException("not implemented");437}438439@Override440public void updateAlwaysOnTopState() {441platformWindow.setAlwaysOnTop(getTarget().isAlwaysOnTop());442}443444@Override445public void updateFocusableWindowState() {446targetFocusable = getTarget().isFocusableWindow();447platformWindow.updateFocusableWindowState();448}449450@Override451public void setModalBlocked(Dialog blocker, boolean blocked) {452synchronized (getPeerTreeLock()) {453ComponentPeer peer = AWTAccessor.getComponentAccessor().getPeer(blocker);454if (blocked && (peer instanceof LWWindowPeer)) {455this.blocker = (LWWindowPeer) peer;456} else {457this.blocker = null;458}459}460461platformWindow.setModalBlocked(blocked);462}463464@Override465public void updateMinimumSize() {466final Dimension min;467if (getTarget().isMinimumSizeSet()) {468min = getTarget().getMinimumSize();469min.width = Math.max(min.width, MINIMUM_WIDTH);470min.height = Math.max(min.height, MINIMUM_HEIGHT);471} else {472min = new Dimension(MINIMUM_WIDTH, MINIMUM_HEIGHT);473}474475final Dimension max;476if (getTarget().isMaximumSizeSet()) {477max = getTarget().getMaximumSize();478max.width = Math.min(max.width, getLWGC().getMaxTextureWidth());479max.height = Math.min(max.height, getLWGC().getMaxTextureHeight());480} else {481max = new Dimension(getLWGC().getMaxTextureWidth(),482getLWGC().getMaxTextureHeight());483}484485platformWindow.setSizeConstraints(min.width, min.height, max.width, max.height);486}487488@Override489public void updateIconImages() {490getPlatformWindow().updateIconImages();491}492493@Override494public void setOpacity(float opacity) {495getPlatformWindow().setOpacity(opacity);496repaintPeer();497}498499@Override500public final void setOpaque(final boolean isOpaque) {501if (this.isOpaque != isOpaque) {502this.isOpaque = isOpaque;503updateOpaque();504}505}506507private void updateOpaque() {508getPlatformWindow().setOpaque(!isTranslucent());509replaceSurfaceData(false);510repaintPeer();511}512513@Override514public void updateWindow() {515}516517public final boolean isTextured() {518return textured;519}520521public final void setTextured(final boolean isTextured) {522textured = isTextured;523}524525@Override526public final boolean isTranslucent() {527synchronized (getStateLock()) {528/*529* Textured window is a special case of translucent window.530* The difference is only in nswindow background. So when we set531* texture property our peer became fully translucent. It doesn't532* fill background, create non opaque backbuffers and layer etc.533*/534return !isOpaque || isShaped() || isTextured();535}536}537538@Override539final void applyShapeImpl(final Region shape) {540super.applyShapeImpl(shape);541updateOpaque();542}543544@Override545public void repositionSecurityWarning() {546if (warningWindow != null) {547ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();548Window target = getTarget();549int x = compAccessor.getX(target);550int y = compAccessor.getY(target);551int width = compAccessor.getWidth(target);552int height = compAccessor.getHeight(target);553warningWindow.reposition(x, y, width, height);554}555}556557// ---- FRAME PEER METHODS ---- //558559@Override // FramePeer and DialogPeer560public void setTitle(String title) {561platformWindow.setTitle(title == null ? "" : title);562}563564@Override565public void setMenuBar(MenuBar mb) {566platformWindow.setMenuBar(mb);567}568569@Override // FramePeer and DialogPeer570public void setResizable(boolean resizable) {571platformWindow.setResizable(resizable);572}573574@Override575public void setState(int state) {576platformWindow.setWindowState(state);577}578579@Override580public int getState() {581return windowState;582}583584private boolean isMaximizedBoundsSet() {585synchronized (getStateLock()) {586return maximizedBounds != null;587}588}589590private Rectangle getDefaultMaximizedBounds() {591GraphicsConfiguration config = getGraphicsConfiguration();592Insets screenInsets = ((CGraphicsDevice) config.getDevice())593.getScreenInsets();594Rectangle gcBounds = config.getBounds();595return new Rectangle(596gcBounds.x + screenInsets.left,597gcBounds.y + screenInsets.top,598gcBounds.width - screenInsets.left - screenInsets.right,599gcBounds.height - screenInsets.top - screenInsets.bottom);600}601602@Override603public void setMaximizedBounds(Rectangle bounds) {604boolean isMaximizedBoundsSet;605synchronized (getStateLock()) {606this.maximizedBounds = (isMaximizedBoundsSet = (bounds != null))607? constrainBounds(bounds) : null;608}609610setPlatformMaximizedBounds(isMaximizedBoundsSet ? maximizedBounds611: getDefaultMaximizedBounds());612}613614public Rectangle getMaximizedBounds() {615synchronized (getStateLock()) {616return (maximizedBounds == null)617? getDefaultMaximizedBounds()618: maximizedBounds;619}620}621622private void setPlatformMaximizedBounds(Rectangle bounds) {623platformWindow.setMaximizedBounds(624bounds.x, bounds.y,625bounds.width, bounds.height);626}627628@Override629public void setBoundsPrivate(int x, int y, int width, int height) {630setBounds(x, y, width, height, SET_BOUNDS | NO_EMBEDDED_CHECK);631}632633@Override634public Rectangle getBoundsPrivate() {635throw new RuntimeException("not implemented");636}637638// ---- DIALOG PEER METHODS ---- //639640@Override641public void blockWindows(List<Window> windows) {642//TODO: LWX will probably need some collectJavaToplevels to speed this up643for (Window w : windows) {644WindowPeer wp = AWTAccessor.getComponentAccessor().getPeer(w);645if (wp != null) {646wp.setModalBlocked((Dialog)getTarget(), true);647}648}649}650651// ---- PEER NOTIFICATIONS ---- //652653@Override654public void notifyIconify(boolean iconify) {655//The toplevel target is Frame and states are applicable to it.656//Otherwise, the target is Window and it don't have state property.657//Hopefully, no such events are posted in the queue so consider the658//target as Frame in all cases.659660// REMIND: should we send it anyway if the state not changed since last661// time?662WindowEvent iconifyEvent = new WindowEvent(getTarget(),663iconify ? WindowEvent.WINDOW_ICONIFIED664: WindowEvent.WINDOW_DEICONIFIED);665postEvent(iconifyEvent);666667int newWindowState = iconify ? Frame.ICONIFIED : Frame.NORMAL;668postWindowStateChangedEvent(newWindowState);669670// REMIND: RepaintManager doesn't repaint iconified windows and671// hence ignores any repaint request during deiconification.672// So, we need to repaint window explicitly when it becomes normal.673if (!iconify) {674repaintPeer();675}676}677678@Override679public void notifyZoom(boolean isZoomed) {680int newWindowState = isZoomed ? Frame.MAXIMIZED_BOTH : Frame.NORMAL;681postWindowStateChangedEvent(newWindowState);682}683684/**685* Called by the {@code PlatformWindow} when any part of the window should686* be repainted.687*/688@Override689public void notifyExpose(final Rectangle r) {690repaintPeer(r);691}692693/**694* Called by the {@code PlatformWindow} when this window is moved/resized by695* user or window insets are changed. There's no notifyReshape() in696* LWComponentPeer as the only components which could be resized by user are697* top-level windows.698* <p>699* We need to update the target and post the events, if the peer was moved700* or resized, or if the target is out of sync with this peer.701*/702@Override703public void notifyReshape(int x, int y, int w, int h) {704final Rectangle pBounds = getBounds();705final boolean invalid = updateInsets(platformWindow.getInsets());706final boolean pMoved = (x != pBounds.x) || (y != pBounds.y);707final boolean pResized = (w != pBounds.width) || (h != pBounds.height);708709final ComponentAccessor accessor = AWTAccessor.getComponentAccessor();710final Rectangle tBounds = accessor.getBounds(getTarget());711final boolean tMoved = (x != tBounds.x) || (y != tBounds.y);712final boolean tResized = (w != tBounds.width) || (h != tBounds.height);713714// Check if anything changed715if (!tMoved && !tResized && !pMoved && !pResized && !invalid) {716// Native window(NSWindow)/LWWindowPeer/Target are in sync717return;718}719// First, update peer's bounds720setBounds(x, y, w, h, SET_BOUNDS, false, false);721722// Second, update the graphics config and surface data723final boolean isNewDevice = updateGraphicsDevice();724if (isNewDevice && !isMaximizedBoundsSet()) {725setPlatformMaximizedBounds(getDefaultMaximizedBounds());726}727728if (pResized || isNewDevice || invalid) {729replaceSurfaceData();730updateMinimumSize();731}732733// Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events734if (tMoved || pMoved || invalid) {735handleMove(x, y, true);736}737if (tResized || pResized || invalid || isNewDevice) {738handleResize(w, h, true);739repaintPeer();740}741742repositionSecurityWarning();743}744745private void clearBackground(final int w, final int h) {746final Graphics g = getOnscreenGraphics(getForeground(), getBackground(),747getFont());748if (g != null) {749try {750if (g instanceof Graphics2D) {751((Graphics2D) g).setComposite(AlphaComposite.Src);752}753if (isTranslucent()) {754g.setColor(nonOpaqueBackground);755g.fillRect(0, 0, w, h);756}757if (!isTextured()) {758if (g instanceof SunGraphics2D) {759((SunGraphics2D) g).constrain(0, 0, w, h, getRegion());760}761g.setColor(getBackground());762g.fillRect(0, 0, w, h);763}764} finally {765g.dispose();766}767}768}769770@Override771public void notifyUpdateCursor() {772getLWToolkit().getCursorManager().updateCursorLater(this);773}774775@Override776public void notifyActivation(boolean activation, LWWindowPeer opposite) {777Window oppositeWindow = (opposite == null)? null : opposite.getTarget();778changeFocusedWindow(activation, oppositeWindow);779}780781// MouseDown in non-client area782@Override783public void notifyNCMouseDown() {784// Ungrab except for a click on a Dialog with the grabbing owner785if (grabbingWindow != null &&786!grabbingWindow.isOneOfOwnersOf(this))787{788grabbingWindow.ungrab();789}790}791792// ---- EVENTS ---- //793794/*795* Called by the delegate to dispatch the event to Java. Event796* coordinates are relative to non-client window are, i.e. the top-left797* point of the client area is (insets.top, insets.left).798*/799@Override800public void notifyMouseEvent(int id, long when, int button,801int x, int y, int absX, int absY,802int modifiers, int clickCount, boolean popupTrigger,803byte[] bdata)804{805// TODO: fill "bdata" member of AWTEvent806Rectangle r = getBounds();807// findPeerAt() expects parent coordinates808LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y);809810if (id == MouseEvent.MOUSE_EXITED) {811isMouseOver = false;812if (lastMouseEventPeer != null) {813if (lastMouseEventPeer.isEnabled()) {814Point lp = lastMouseEventPeer.windowToLocal(x, y,815this);816Component target = lastMouseEventPeer.getTarget();817postMouseExitedEvent(target, when, modifiers, lp,818absX, absY, clickCount, popupTrigger, button);819}820821// Sometimes we may get MOUSE_EXITED after lastCommonMouseEventPeer is switched822// to a peer from another window. So we must first check if this peer is823// the same as lastWindowPeer824if (lastCommonMouseEventPeer != null && lastCommonMouseEventPeer.getWindowPeerOrSelf() == this) {825lastCommonMouseEventPeer = null;826}827lastMouseEventPeer = null;828}829} else if(id == MouseEvent.MOUSE_ENTERED) {830isMouseOver = true;831if (targetPeer != null) {832if (targetPeer.isEnabled()) {833Point lp = targetPeer.windowToLocal(x, y, this);834Component target = targetPeer.getTarget();835postMouseEnteredEvent(target, when, modifiers, lp,836absX, absY, clickCount, popupTrigger, button);837}838lastCommonMouseEventPeer = targetPeer;839lastMouseEventPeer = targetPeer;840}841} else {842PlatformWindow topmostPlatformWindow = LWToolkit.getLWToolkit().getPlatformWindowUnderMouse();843844LWWindowPeer topmostWindowPeer =845topmostPlatformWindow != null ? topmostPlatformWindow.getPeer() : null;846847// topmostWindowPeer == null condition is added for the backward848// compatibility with applets. It can be removed when the849// getTopmostPlatformWindowUnderMouse() method will be properly850// implemented in CPlatformEmbeddedFrame class851if (topmostWindowPeer == this || topmostWindowPeer == null) {852generateMouseEnterExitEventsForComponents(when, button, x, y,853absX, absY, modifiers, clickCount, popupTrigger,854targetPeer);855} else {856LWComponentPeer<?, ?> topmostTargetPeer = topmostWindowPeer.findPeerAt(r.x + x, r.y + y);857topmostWindowPeer.generateMouseEnterExitEventsForComponents(when, button, x, y,858absX, absY, modifiers, clickCount, popupTrigger,859topmostTargetPeer);860}861862// TODO: fill "bdata" member of AWTEvent863864int eventButtonMask = (button > 0)? MouseEvent.getMaskForButton(button) : 0;865int otherButtonsPressed = modifiers & ~eventButtonMask;866867// For pressed/dragged/released events OS X treats other868// mouse buttons as if they were BUTTON2, so we do the same869int targetIdx = (button > 3) ? MouseEvent.BUTTON2 - 1 : button - 1;870871// MOUSE_ENTERED/EXITED are generated for the components strictly under872// mouse even when dragging. That's why we first update lastMouseEventPeer873// based on initial targetPeer value and only then recalculate targetPeer874// for MOUSE_DRAGGED/RELEASED events875if (id == MouseEvent.MOUSE_PRESSED) {876877// Ungrab only if this window is not an owned window of the grabbing one.878if (!isGrabbing() && grabbingWindow != null &&879!grabbingWindow.isOneOfOwnersOf(this))880{881grabbingWindow.ungrab();882}883if (otherButtonsPressed == 0) {884mouseClickButtons = eventButtonMask;885} else {886mouseClickButtons |= eventButtonMask;887}888889// The window should be focused on mouse click. If it gets activated by the native platform,890// this request will be no op. It will take effect when:891// 1. A simple not focused window is clicked.892// 2. An active but not focused owner frame/dialog is clicked.893// The mouse event then will trigger a focus request "in window" to the component, so the window894// should gain focus before.895requestWindowFocus(FocusEvent.Cause.MOUSE_EVENT);896897mouseDownTarget[targetIdx] = targetPeer;898} else if (id == MouseEvent.MOUSE_DRAGGED) {899// Cocoa dragged event has the information about which mouse900// button is being dragged. Use it to determine the peer that901// should receive the dragged event.902targetPeer = mouseDownTarget[targetIdx];903mouseClickButtons &= ~modifiers;904} else if (id == MouseEvent.MOUSE_RELEASED) {905// TODO: currently, mouse released event goes to the same component906// that received corresponding mouse pressed event. For most cases,907// it's OK, however, we need to make sure that our behavior is consistent908// with 1.6 for cases where component in question have been909// hidden/removed in between of mouse pressed/released events.910targetPeer = mouseDownTarget[targetIdx];911912if ((modifiers & eventButtonMask) == 0) {913mouseDownTarget[targetIdx] = null;914}915916// mouseClickButtons is updated below, after MOUSE_CLICK is sent917}918919if (targetPeer == null) {920//TODO This can happen if this window is invisible. this is correct behavior in this case?921targetPeer = this;922}923924925Point lp = targetPeer.windowToLocal(x, y, this);926if (targetPeer.isEnabled()) {927MouseEvent event = new MouseEvent(targetPeer.getTarget(), id,928when, modifiers, lp.x, lp.y,929absX, absY, clickCount,930popupTrigger, button);931postEvent(event);932}933934if (id == MouseEvent.MOUSE_RELEASED) {935if ((mouseClickButtons & eventButtonMask) != 0936&& targetPeer.isEnabled()) {937postEvent(new MouseEvent(targetPeer.getTarget(),938MouseEvent.MOUSE_CLICKED,939when, modifiers,940lp.x, lp.y, absX, absY,941clickCount, popupTrigger, button));942}943mouseClickButtons &= ~eventButtonMask;944}945}946notifyUpdateCursor();947}948949private void generateMouseEnterExitEventsForComponents(long when,950int button, int x, int y, int screenX, int screenY,951int modifiers, int clickCount, boolean popupTrigger,952final LWComponentPeer<?, ?> targetPeer) {953954if (!isMouseOver || targetPeer == lastMouseEventPeer) {955return;956}957958// Generate Mouse Exit for components959if (lastMouseEventPeer != null && lastMouseEventPeer.isEnabled()) {960Point oldp = lastMouseEventPeer.windowToLocal(x, y, this);961Component target = lastMouseEventPeer.getTarget();962postMouseExitedEvent(target, when, modifiers, oldp, screenX, screenY,963clickCount, popupTrigger, button);964}965lastCommonMouseEventPeer = targetPeer;966lastMouseEventPeer = targetPeer;967968// Generate Mouse Enter for components969if (targetPeer != null && targetPeer.isEnabled()) {970Point newp = targetPeer.windowToLocal(x, y, this);971Component target = targetPeer.getTarget();972postMouseEnteredEvent(target, when, modifiers, newp, screenX, screenY, clickCount, popupTrigger, button);973}974}975976private void postMouseEnteredEvent(Component target, long when, int modifiers,977Point loc, int xAbs, int yAbs,978int clickCount, boolean popupTrigger, int button) {979980updateSecurityWarningVisibility();981982postEvent(new MouseEvent(target,983MouseEvent.MOUSE_ENTERED,984when, modifiers,985loc.x, loc.y, xAbs, yAbs,986clickCount, popupTrigger, button));987}988989private void postMouseExitedEvent(Component target, long when, int modifiers,990Point loc, int xAbs, int yAbs,991int clickCount, boolean popupTrigger, int button) {992993updateSecurityWarningVisibility();994995postEvent(new MouseEvent(target,996MouseEvent.MOUSE_EXITED,997when, modifiers,998loc.x, loc.y, xAbs, yAbs,999clickCount, popupTrigger, button));1000}10011002@Override1003public void notifyMouseWheelEvent(long when, int x, int y, int absX,1004int absY, int modifiers, int scrollType,1005int scrollAmount, int wheelRotation,1006double preciseWheelRotation, byte[] bdata)1007{1008// TODO: could we just use the last mouse event target here?1009Rectangle r = getBounds();1010// findPeerAt() expects parent coordinates1011final LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y);1012if (targetPeer == null || !targetPeer.isEnabled()) {1013return;1014}10151016Point lp = targetPeer.windowToLocal(x, y, this);1017// TODO: fill "bdata" member of AWTEvent1018postEvent(new MouseWheelEvent(targetPeer.getTarget(),1019MouseEvent.MOUSE_WHEEL,1020when, modifiers,1021lp.x, lp.y,1022absX, absY, /* absX, absY */10230 /* clickCount */, false /* popupTrigger */,1024scrollType, scrollAmount,1025wheelRotation, preciseWheelRotation));1026}10271028/*1029* Called by the delegate when a key is pressed.1030*/1031@Override1032public void notifyKeyEvent(int id, long when, int modifiers,1033int keyCode, char keyChar, int keyLocation)1034{1035LWKeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();1036Component focusOwner = kfmPeer.getCurrentFocusOwner();10371038if (focusOwner == null) {1039focusOwner = kfmPeer.getCurrentFocusedWindow();1040if (focusOwner == null) {1041focusOwner = this.getTarget();1042}1043}10441045KeyEvent keyEvent = new KeyEvent(focusOwner, id, when, modifiers,1046keyCode, keyChar, keyLocation);1047AWTAccessor.getKeyEventAccessor().setExtendedKeyCode(keyEvent,1048(keyChar == KeyEvent.CHAR_UNDEFINED) ? keyCode1049: ExtendedKeyCodes.getExtendedKeyCodeForChar(keyChar));1050postEvent(keyEvent);1051}10521053// ---- UTILITY METHODS ---- //10541055private void activateDisplayListener() {1056final GraphicsEnvironment ge =1057GraphicsEnvironment.getLocalGraphicsEnvironment();1058((SunGraphicsEnvironment) ge).addDisplayChangedListener(this);1059}10601061private void deactivateDisplayListener() {1062final GraphicsEnvironment ge =1063GraphicsEnvironment.getLocalGraphicsEnvironment();1064((SunGraphicsEnvironment) ge).removeDisplayChangedListener(this);1065}10661067private void postWindowStateChangedEvent(int newWindowState) {1068if (getTarget() instanceof Frame) {1069AWTAccessor.getFrameAccessor().setExtendedState(1070(Frame)getTarget(), newWindowState);1071}10721073WindowEvent stateChangedEvent = new WindowEvent(getTarget(),1074WindowEvent.WINDOW_STATE_CHANGED,1075windowState, newWindowState);1076postEvent(stateChangedEvent);1077windowState = newWindowState;10781079updateSecurityWarningVisibility();1080}10811082private static int getGraphicsConfigScreen(GraphicsConfiguration gc) {1083// TODO: this method can be implemented in a more1084// efficient way by forwarding to the delegate1085GraphicsDevice gd = gc.getDevice();1086GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();1087GraphicsDevice[] gds = ge.getScreenDevices();1088for (int i = 0; i < gds.length; i++) {1089if (gds[i] == gd) {1090return i;1091}1092}1093// Should never happen if gc is a screen device config1094return 0;1095}10961097/*1098* This method is called when window's graphics config is changed from1099* the app code (e.g. when the window is made non-opaque) or when1100* the window is moved to another screen by user.1101*1102* Returns true if the graphics config has been changed, false otherwise.1103*/1104private boolean setGraphicsConfig(GraphicsConfiguration gc) {1105synchronized (getStateLock()) {1106if (graphicsConfig == gc) {1107return false;1108}1109// If window's graphics config is changed from the app code, the1110// config correspond to the same device as before; when the window1111// is moved by user, graphicsDevice is updated in notifyReshape().1112// In either case, there's nothing to do with screenOn here1113graphicsConfig = gc;1114}1115// SurfaceData is replaced later in updateGraphicsData()1116return true;1117}11181119/**1120* Returns true if the GraphicsDevice has been changed, false otherwise.1121*/1122public boolean updateGraphicsDevice() {1123GraphicsDevice newGraphicsDevice = platformWindow.getGraphicsDevice();1124synchronized (getStateLock()) {1125if (graphicsDevice == newGraphicsDevice) {1126return false;1127}1128graphicsDevice = newGraphicsDevice;1129}11301131final GraphicsConfiguration newGC = newGraphicsDevice.getDefaultConfiguration();11321133if (!setGraphicsConfig(newGC)) return false;11341135SunToolkit.executeOnEventHandlerThread(getTarget(), new Runnable() {1136public void run() {1137AWTAccessor.getComponentAccessor().setGraphicsConfiguration(getTarget(), newGC);1138}1139});1140return true;1141}11421143@Override1144public final void displayChanged() {1145if (updateGraphicsDevice()) {1146updateMinimumSize();1147if (!isMaximizedBoundsSet()) {1148setPlatformMaximizedBounds(getDefaultMaximizedBounds());1149}1150}1151// Replace surface unconditionally, because internal state of the1152// GraphicsDevice could be changed.1153replaceSurfaceData();1154repaintPeer();1155}11561157@Override1158public final void paletteChanged() {1159// components do not need to react to this event.1160}11611162/*1163* May be called by delegate to provide SD to Java2D code.1164*/1165public SurfaceData getSurfaceData() {1166synchronized (surfaceDataLock) {1167return surfaceData;1168}1169}11701171private void replaceSurfaceData() {1172replaceSurfaceData(true);1173}11741175private void replaceSurfaceData(final boolean blit) {1176synchronized (surfaceDataLock) {1177final SurfaceData oldData = getSurfaceData();1178surfaceData = platformWindow.replaceSurfaceData();1179final Rectangle size = getSize();1180if (getSurfaceData() != null && oldData != getSurfaceData()) {1181clearBackground(size.width, size.height);1182}11831184if (blit) {1185blitSurfaceData(oldData, getSurfaceData());1186}11871188if (oldData != null && oldData != getSurfaceData()) {1189// TODO: drop oldData for D3D/WGL pipelines1190// This can only happen when this peer is being created1191oldData.flush();1192}1193}1194flushOnscreenGraphics();1195}11961197private void blitSurfaceData(final SurfaceData src, final SurfaceData dst) {1198//TODO blit. proof-of-concept1199if (src != dst && src != null && dst != null1200&& !(dst instanceof NullSurfaceData)1201&& !(src instanceof NullSurfaceData)1202&& src.getSurfaceType().equals(dst.getSurfaceType())1203&& src.getDefaultScaleX() == dst.getDefaultScaleX()1204&& src.getDefaultScaleY() == dst.getDefaultScaleY())1205{1206final Rectangle size = src.getBounds();1207final Blit blit = Blit.locate(src.getSurfaceType(),1208CompositeType.Src,1209dst.getSurfaceType());1210if (blit != null) {1211blit.Blit(src, dst, AlphaComposite.Src, null, 0, 0, 0, 0,1212size.width, size.height);1213}1214}1215}12161217/**1218* Request the window insets from the delegate and compares it with the1219* current one. This method is mostly called by the delegate, e.g. when the1220* window state is changed and insets should be recalculated.1221* <p/>1222* This method may be called on the toolkit thread.1223*/1224public final boolean updateInsets(final Insets newInsets) {1225synchronized (getStateLock()) {1226if (insets.equals(newInsets)) {1227return false;1228}1229insets = newInsets;1230}1231return true;1232}12331234public static LWWindowPeer getWindowUnderCursor() {1235return lastCommonMouseEventPeer != null ? lastCommonMouseEventPeer.getWindowPeerOrSelf() : null;1236}12371238public static LWComponentPeer<?, ?> getPeerUnderCursor() {1239return lastCommonMouseEventPeer;1240}12411242/*1243* Requests platform to set native focus on a frame/dialog.1244* In case of a simple window, triggers appropriate java focus change.1245*/1246public boolean requestWindowFocus(FocusEvent.Cause cause) {1247if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {1248focusLog.fine("requesting native focus to " + this);1249}12501251if (!focusAllowedFor()) {1252focusLog.fine("focus is not allowed");1253return false;1254}12551256if (platformWindow.rejectFocusRequest(cause)) {1257return false;1258}12591260AppContext targetAppContext = AWTAccessor.getComponentAccessor().getAppContext(getTarget());1261KeyboardFocusManager kfm = AWTAccessor.getKeyboardFocusManagerAccessor()1262.getCurrentKeyboardFocusManager(targetAppContext);1263Window currentActive = kfm.getActiveWindow();126412651266Window opposite = LWKeyboardFocusManagerPeer.getInstance().1267getCurrentFocusedWindow();12681269// Make the owner active window.1270if (isSimpleWindow()) {1271LWWindowPeer owner = getOwnerFrameDialog(this);12721273// If owner is not natively active, request native1274// activation on it w/o sending events up to java.1275if (owner != null && !owner.platformWindow.isActive()) {1276if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {1277focusLog.fine("requesting native focus to the owner " + owner);1278}1279LWWindowPeer currentActivePeer = currentActive == null ? null :1280(LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(1281currentActive);12821283// Ensure the opposite is natively active and suppress sending events.1284if (currentActivePeer != null && currentActivePeer.platformWindow.isActive()) {1285if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {1286focusLog.fine("the opposite is " + currentActivePeer);1287}1288currentActivePeer.skipNextFocusChange = true;1289}1290owner.skipNextFocusChange = true;12911292owner.platformWindow.requestWindowFocus();1293}12941295// DKFM will synthesize all the focus/activation events correctly.1296changeFocusedWindow(true, opposite);1297return true;12981299// In case the toplevel is active but not focused, change focus directly,1300// as requesting native focus on it will not have effect.1301} else if (getTarget() == currentActive && !getTarget().hasFocus()) {13021303changeFocusedWindow(true, opposite);1304return true;1305}13061307return platformWindow.requestWindowFocus();1308}13091310protected boolean focusAllowedFor() {1311Window window = getTarget();1312// TODO: check if modal blocked1313return window.isVisible() && window.isEnabled() && isFocusableWindow();1314}13151316private boolean isFocusableWindow() {1317boolean focusable = targetFocusable;1318if (isSimpleWindow()) {1319LWWindowPeer ownerPeer = getOwnerFrameDialog(this);1320if (ownerPeer == null) {1321return false;1322}1323return focusable && ownerPeer.targetFocusable;1324}1325return focusable;1326}13271328public boolean isSimpleWindow() {1329Window window = getTarget();1330return !(window instanceof Dialog || window instanceof Frame);1331}13321333@Override1334public void emulateActivation(boolean activate) {1335changeFocusedWindow(activate, null);1336}13371338@SuppressWarnings("deprecation")1339private boolean isOneOfOwnersOf(LWWindowPeer peer) {1340Window owner = (peer != null ? peer.getTarget().getOwner() : null);1341while (owner != null) {1342final ComponentAccessor acc = AWTAccessor.getComponentAccessor();1343if (acc.getPeer(owner) == this) {1344return true;1345}1346owner = owner.getOwner();1347}1348return false;1349}13501351/*1352* Changes focused window on java level.1353*/1354protected void changeFocusedWindow(boolean becomesFocused, Window opposite) {1355if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {1356focusLog.fine((becomesFocused?"gaining":"loosing") + " focus window: " + this);1357}1358if (skipNextFocusChange) {1359focusLog.fine("skipping focus change");1360skipNextFocusChange = false;1361return;1362}1363if (!isFocusableWindow() && becomesFocused) {1364focusLog.fine("the window is not focusable");1365return;1366}1367if (becomesFocused) {1368synchronized (getPeerTreeLock()) {1369if (blocker != null) {1370if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {1371focusLog.finest("the window is blocked by " + blocker);1372}1373return;1374}1375}1376}13771378// Note, the method is not called:1379// - when the opposite (gaining focus) window is an owned/owner window.1380// - for a simple window in any case.1381if (!becomesFocused &&1382(isGrabbing() || this.isOneOfOwnersOf(grabbingWindow)))1383{1384if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {1385focusLog.fine("ungrabbing on " + grabbingWindow);1386}1387// ungrab a simple window if its owner looses activation.1388grabbingWindow.ungrab();1389}13901391KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();13921393if (!becomesFocused && kfmPeer.getCurrentFocusedWindow() != getTarget()) {1394// late window focus lost event - ingoring1395return;1396}13971398kfmPeer.setCurrentFocusedWindow(becomesFocused ? getTarget() : null);13991400int eventID = becomesFocused ? WindowEvent.WINDOW_GAINED_FOCUS : WindowEvent.WINDOW_LOST_FOCUS;1401WindowEvent windowEvent = new TimedWindowEvent(getTarget(), eventID, opposite, System.currentTimeMillis());14021403// TODO: wrap in SequencedEvent1404postEvent(windowEvent);1405}14061407/*1408* Retrieves the owner of the peer.1409* Note: this method returns the owner which can be activated, (i.e. the instance1410* of Frame or Dialog may be returned).1411*/1412static LWWindowPeer getOwnerFrameDialog(LWWindowPeer peer) {1413Window owner = (peer != null ? peer.getTarget().getOwner() : null);1414while (owner != null && !(owner instanceof Frame || owner instanceof Dialog)) {1415owner = owner.getOwner();1416}1417return owner == null ? null : AWTAccessor.getComponentAccessor()1418.getPeer(owner);1419}14201421/**1422* Returns the foremost modal blocker of this window, or null.1423*/1424public LWWindowPeer getBlocker() {1425synchronized (getPeerTreeLock()) {1426LWWindowPeer blocker = this.blocker;1427if (blocker == null) {1428return null;1429}1430while (blocker.blocker != null) {1431blocker = blocker.blocker;1432}1433return blocker;1434}1435}14361437@Override1438public void enterFullScreenMode() {1439platformWindow.enterFullScreenMode();1440updateSecurityWarningVisibility();1441}14421443@Override1444public void exitFullScreenMode() {1445platformWindow.exitFullScreenMode();1446updateSecurityWarningVisibility();1447}14481449public long getLayerPtr() {1450return getPlatformWindow().getLayerPtr();1451}14521453void grab() {1454if (grabbingWindow != null && !isGrabbing()) {1455grabbingWindow.ungrab();1456}1457grabbingWindow = this;1458}14591460final void ungrab(boolean doPost) {1461if (isGrabbing()) {1462grabbingWindow = null;1463if (doPost) {1464postEvent(new UngrabEvent(getTarget()));1465}1466}1467}14681469void ungrab() {1470ungrab(true);1471}14721473private boolean isGrabbing() {1474return this == grabbingWindow;1475}14761477public PeerType getPeerType() {1478return peerType;1479}14801481public void updateSecurityWarningVisibility() {1482if (warningWindow == null) {1483return;1484}14851486if (!isVisible()) {1487return; // The warning window should already be hidden.1488}14891490boolean show = false;14911492if (!platformWindow.isFullScreenMode()) {1493if (isVisible()) {1494if (LWKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() ==1495getTarget()) {1496show = true;1497}14981499if (platformWindow.isUnderMouse() || warningWindow.isUnderMouse()) {1500show = true;1501}1502}1503}15041505warningWindow.setVisible(show, true);1506}15071508@Override1509public String toString() {1510return super.toString() + " [target is " + getTarget() + "]";1511}1512}151315141515