Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java
38827 views
/*1* Copyright (c) 2011, 2014, 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.*;28import java.awt.event.*;29import java.awt.peer.*;30import java.util.List;3132import javax.swing.*;3334import sun.awt.*;35import sun.java2d.*;36import sun.java2d.loops.Blit;37import sun.java2d.loops.CompositeType;38import sun.java2d.pipe.Region;39import sun.util.logging.PlatformLogger;4041public class LWWindowPeer42extends LWContainerPeer<Window, JComponent>43implements FramePeer, DialogPeer, FullScreenCapable, DisplayChangedListener, PlatformEventNotifier44{45public enum PeerType {46SIMPLEWINDOW,47FRAME,48DIALOG,49EMBEDDED_FRAME,50VIEW_EMBEDDED_FRAME,51LW_FRAME52}5354private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWWindowPeer");5556private final PlatformWindow platformWindow;5758private static final int MINIMUM_WIDTH = 1;59private static final int MINIMUM_HEIGHT = 1;6061private Insets insets = new Insets(0, 0, 0, 0);6263private GraphicsDevice graphicsDevice;64private GraphicsConfiguration graphicsConfig;6566private SurfaceData surfaceData;67private final Object surfaceDataLock = new Object();6869private volatile int windowState = Frame.NORMAL;7071// check that the mouse is over the window72private volatile boolean isMouseOver = false;7374// A peer where the last mouse event came to. Used by cursor manager to75// find the component under cursor76private static volatile LWComponentPeer<?, ?> lastCommonMouseEventPeer;7778// A peer where the last mouse event came to. Used to generate79// MOUSE_ENTERED/EXITED notifications80private volatile LWComponentPeer<?, ?> lastMouseEventPeer;8182// Peers where all dragged/released events should come to,83// depending on what mouse button is being dragged according to Cocoa84private static final LWComponentPeer<?, ?>[] mouseDownTarget = new LWComponentPeer<?, ?>[3];8586// A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events87// on MOUSE_RELEASE. Click events are only generated if there were no drag88// events between MOUSE_PRESSED and MOUSE_RELEASED for particular button89private static int mouseClickButtons = 0;9091private volatile boolean isOpaque = true;9293private static final Font DEFAULT_FONT = new Font("Lucida Grande", Font.PLAIN, 13);9495private static LWWindowPeer grabbingWindow;9697private volatile boolean skipNextFocusChange;9899private static final Color nonOpaqueBackground = new Color(0, 0, 0, 0);100101private volatile boolean textured;102103private final PeerType peerType;104105private final SecurityWarningWindow warningWindow;106107private volatile boolean targetFocusable;108109/**110* Current modal blocker or null.111*112* Synchronization: peerTreeLock.113*/114private LWWindowPeer blocker;115116public LWWindowPeer(Window target, PlatformComponent platformComponent,117PlatformWindow platformWindow, PeerType peerType)118{119super(target, platformComponent);120this.platformWindow = platformWindow;121this.peerType = peerType;122123Window owner = target.getOwner();124LWWindowPeer ownerPeer = owner == null ? null :125(LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(owner);126PlatformWindow ownerDelegate = (ownerPeer != null) ? ownerPeer.getPlatformWindow() : null;127128// The delegate.initialize() needs a non-null GC on X11.129GraphicsConfiguration gc = getTarget().getGraphicsConfiguration();130synchronized (getStateLock()) {131// graphicsConfig should be updated according to the real window132// bounds when the window is shown, see 4868278133this.graphicsConfig = gc;134}135136if (!target.isFontSet()) {137target.setFont(DEFAULT_FONT);138}139140if (!target.isBackgroundSet()) {141target.setBackground(SystemColor.window);142} else {143// first we check if user provided alpha for background. This is144// similar to what Apple's Java do.145// Since JDK7 we should rely on setOpacity() only.146// this.opacity = c.getAlpha();147}148149if (!target.isForegroundSet()) {150target.setForeground(SystemColor.windowText);151// we should not call setForeground because it will call a repaint152// which the peer may not be ready to do yet.153}154155platformWindow.initialize(target, this, ownerDelegate);156157// Init warning window(for applets)158SecurityWarningWindow warn = null;159if (target.getWarningString() != null) {160// accessSystemTray permission allows to display TrayIcon, TrayIcon tooltip161// and TrayIcon balloon windows without a warning window.162if (!AWTAccessor.getWindowAccessor().isTrayIconWindow(target)) {163LWToolkit toolkit = (LWToolkit)Toolkit.getDefaultToolkit();164warn = toolkit.createSecurityWarning(target, this);165}166}167168warningWindow = warn;169}170171@Override172void initializeImpl() {173super.initializeImpl();174175176if (getTarget() instanceof Frame) {177setTitle(((Frame) getTarget()).getTitle());178setState(((Frame) getTarget()).getExtendedState());179} else if (getTarget() instanceof Dialog) {180setTitle(((Dialog) getTarget()).getTitle());181}182183updateAlwaysOnTopState();184updateMinimumSize();185updateFocusableWindowState();186187final Shape shape = getTarget().getShape();188if (shape != null) {189applyShape(Region.getInstance(shape, null));190}191192final float opacity = getTarget().getOpacity();193if (opacity < 1.0f) {194setOpacity(opacity);195}196197setOpaque(getTarget().isOpaque());198199updateInsets(platformWindow.getInsets());200if (getSurfaceData() == null) {201replaceSurfaceData(false);202}203activateDisplayListener();204}205206// Just a helper method207@Override208public PlatformWindow getPlatformWindow() {209return platformWindow;210}211212@Override213protected LWWindowPeer getWindowPeerOrSelf() {214return this;215}216217// ---- PEER METHODS ---- //218219@Override220protected void disposeImpl() {221deactivateDisplayListener();222SurfaceData oldData = getSurfaceData();223synchronized (surfaceDataLock){224surfaceData = null;225}226if (oldData != null) {227oldData.invalidate();228}229if (isGrabbing()) {230ungrab();231}232if (warningWindow != null) {233warningWindow.dispose();234}235236platformWindow.dispose();237super.disposeImpl();238}239240@Override241protected void setVisibleImpl(final boolean visible) {242if (!visible && warningWindow != null) {243warningWindow.setVisible(false, false);244}245updateFocusableWindowState();246super.setVisibleImpl(visible);247// TODO: update graphicsConfig, see 4868278248platformWindow.setVisible(visible);249if (isSimpleWindow()) {250KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();251if (visible) {252if (!getTarget().isAutoRequestFocus()) {253return;254} else {255requestWindowFocus(CausedFocusEvent.Cause.ACTIVATION);256}257// Focus the owner in case this window is focused.258} else if (kfmPeer.getCurrentFocusedWindow() == getTarget()) {259// Transfer focus to the owner.260LWWindowPeer owner = getOwnerFrameDialog(LWWindowPeer.this);261if (owner != null) {262owner.requestWindowFocus(CausedFocusEvent.Cause.ACTIVATION);263}264}265}266}267268@Override269public final GraphicsConfiguration getGraphicsConfiguration() {270synchronized (getStateLock()) {271return graphicsConfig;272}273}274275@Override276public boolean updateGraphicsData(GraphicsConfiguration gc) {277setGraphicsConfig(gc);278return false;279}280281protected final Graphics getOnscreenGraphics(Color fg, Color bg, Font f) {282if (getSurfaceData() == null) {283return null;284}285if (fg == null) {286fg = SystemColor.windowText;287}288if (bg == null) {289bg = SystemColor.window;290}291if (f == null) {292f = DEFAULT_FONT;293}294return platformWindow.transformGraphics(new SunGraphics2D(getSurfaceData(), fg, bg, f));295}296297@Override298public void setBounds(int x, int y, int w, int h, int op) {299300if((op & NO_EMBEDDED_CHECK) == 0 && getPeerType() == PeerType.VIEW_EMBEDDED_FRAME) {301return;302}303304if ((op & SET_CLIENT_SIZE) != 0) {305// SET_CLIENT_SIZE is only applicable to window peers, so handle it here306// instead of pulling 'insets' field up to LWComponentPeer307// no need to add insets since Window's notion of width and height includes insets.308op &= ~SET_CLIENT_SIZE;309op |= SET_SIZE;310}311312// Don't post ComponentMoved/Resized and Paint events313// until we've got a notification from the delegate314Rectangle cb = constrainBounds(x, y, w, h);315316Rectangle newBounds = new Rectangle(getBounds());317if ((op & (SET_LOCATION | SET_BOUNDS)) != 0) {318newBounds.x = cb.x;319newBounds.y = cb.y;320}321if ((op & (SET_SIZE | SET_BOUNDS)) != 0) {322newBounds.width = cb.width;323newBounds.height = cb.height;324}325// Native system could constraint bounds, so the peer wold be updated in the callback326platformWindow.setBounds(newBounds.x, newBounds.y, newBounds.width, newBounds.height);327}328329public Rectangle constrainBounds(Rectangle bounds) {330return constrainBounds(bounds.x, bounds.y, bounds.width, bounds.height);331}332333public Rectangle constrainBounds(int x, int y, int w, int h) {334335if (w < MINIMUM_WIDTH) {336w = MINIMUM_WIDTH;337}338339if (h < MINIMUM_HEIGHT) {340h = MINIMUM_HEIGHT;341}342343final int maxW = getLWGC().getMaxTextureWidth();344final int maxH = getLWGC().getMaxTextureHeight();345346if (w > maxW) {347w = maxW;348}349if (h > maxH) {350h = maxH;351}352353return new Rectangle(x, y, w, h);354}355356@Override357public Point getLocationOnScreen() {358return platformWindow.getLocationOnScreen();359}360361/**362* Overridden from LWContainerPeer to return the correct insets.363* Insets are queried from the delegate and are kept up to date by364* requiering when needed (i.e. when the window geometry is changed).365*/366@Override367public Insets getInsets() {368synchronized (getStateLock()) {369return insets;370}371}372373@Override374public FontMetrics getFontMetrics(Font f) {375// TODO: check for "use platform metrics" settings376return platformWindow.getFontMetrics(f);377}378379@Override380public void toFront() {381platformWindow.toFront();382}383384@Override385public void toBack() {386platformWindow.toBack();387}388389@Override390public void setZOrder(ComponentPeer above) {391throw new RuntimeException("not implemented");392}393394@Override395public void updateAlwaysOnTopState() {396platformWindow.setAlwaysOnTop(getTarget().isAlwaysOnTop());397}398399@Override400public void updateFocusableWindowState() {401targetFocusable = getTarget().isFocusableWindow();402platformWindow.updateFocusableWindowState();403}404405@Override406public void setModalBlocked(Dialog blocker, boolean blocked) {407synchronized (getPeerTreeLock()) {408ComponentPeer peer = AWTAccessor.getComponentAccessor().getPeer(blocker);409if (blocked && (peer instanceof LWWindowPeer)) {410this.blocker = (LWWindowPeer) peer;411} else {412this.blocker = null;413}414}415416platformWindow.setModalBlocked(blocked);417}418419@Override420public void updateMinimumSize() {421final Dimension min;422if (getTarget().isMinimumSizeSet()) {423min = getTarget().getMinimumSize();424min.width = Math.max(min.width, MINIMUM_WIDTH);425min.height = Math.max(min.height, MINIMUM_HEIGHT);426} else {427min = new Dimension(MINIMUM_WIDTH, MINIMUM_HEIGHT);428}429430final Dimension max;431if (getTarget().isMaximumSizeSet()) {432max = getTarget().getMaximumSize();433max.width = Math.min(max.width, getLWGC().getMaxTextureWidth());434max.height = Math.min(max.height, getLWGC().getMaxTextureHeight());435} else {436max = new Dimension(getLWGC().getMaxTextureWidth(),437getLWGC().getMaxTextureHeight());438}439440platformWindow.setSizeConstraints(min.width, min.height, max.width, max.height);441}442443@Override444public void updateIconImages() {445getPlatformWindow().updateIconImages();446}447448@Override449public void setBackground(final Color c) {450super.setBackground(c);451updateOpaque();452}453454@Override455public void setOpacity(float opacity) {456getPlatformWindow().setOpacity(opacity);457repaintPeer();458}459460@Override461public final void setOpaque(final boolean isOpaque) {462if (this.isOpaque != isOpaque) {463this.isOpaque = isOpaque;464updateOpaque();465}466}467468private void updateOpaque() {469getPlatformWindow().setOpaque(!isTranslucent());470replaceSurfaceData(false);471repaintPeer();472}473474@Override475public void updateWindow() {476}477478public final boolean isTextured() {479return textured;480}481482public final void setTextured(final boolean isTextured) {483textured = isTextured;484}485486@Override487public final boolean isTranslucent() {488synchronized (getStateLock()) {489/*490* Textured window is a special case of translucent window.491* The difference is only in nswindow background. So when we set492* texture property our peer became fully translucent. It doesn't493* fill background, create non opaque backbuffers and layer etc.494*/495return !isOpaque || isShaped() || isTextured();496}497}498499@Override500final void applyShapeImpl(final Region shape) {501super.applyShapeImpl(shape);502updateOpaque();503}504505@Override506public void repositionSecurityWarning() {507if (warningWindow != null) {508AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();509Window target = getTarget();510int x = compAccessor.getX(target);511int y = compAccessor.getY(target);512int width = compAccessor.getWidth(target);513int height = compAccessor.getHeight(target);514warningWindow.reposition(x, y, width, height);515}516}517518// ---- FRAME PEER METHODS ---- //519520@Override // FramePeer and DialogPeer521public void setTitle(String title) {522platformWindow.setTitle(title == null ? "" : title);523}524525@Override526public void setMenuBar(MenuBar mb) {527platformWindow.setMenuBar(mb);528}529530@Override // FramePeer and DialogPeer531public void setResizable(boolean resizable) {532platformWindow.setResizable(resizable);533}534535@Override536public void setState(int state) {537platformWindow.setWindowState(state);538}539540@Override541public int getState() {542return windowState;543}544545@Override546public void setMaximizedBounds(Rectangle bounds) {547// TODO: not implemented548}549550@Override551public void setBoundsPrivate(int x, int y, int width, int height) {552setBounds(x, y, width, height, SET_BOUNDS | NO_EMBEDDED_CHECK);553}554555@Override556public Rectangle getBoundsPrivate() {557throw new RuntimeException("not implemented");558}559560// ---- DIALOG PEER METHODS ---- //561562@Override563public void blockWindows(List<Window> windows) {564//TODO: LWX will probably need some collectJavaToplevels to speed this up565for (Window w : windows) {566WindowPeer wp =567(WindowPeer) AWTAccessor.getComponentAccessor().getPeer(w);568if (wp != null) {569wp.setModalBlocked((Dialog)getTarget(), true);570}571}572}573574// ---- PEER NOTIFICATIONS ---- //575576@Override577public void notifyIconify(boolean iconify) {578//The toplevel target is Frame and states are applicable to it.579//Otherwise, the target is Window and it don't have state property.580//Hopefully, no such events are posted in the queue so consider the581//target as Frame in all cases.582583// REMIND: should we send it anyway if the state not changed since last584// time?585WindowEvent iconifyEvent = new WindowEvent(getTarget(),586iconify ? WindowEvent.WINDOW_ICONIFIED587: WindowEvent.WINDOW_DEICONIFIED);588postEvent(iconifyEvent);589590int newWindowState = iconify ? Frame.ICONIFIED : Frame.NORMAL;591postWindowStateChangedEvent(newWindowState);592593// REMIND: RepaintManager doesn't repaint iconified windows and594// hence ignores any repaint request during deiconification.595// So, we need to repaint window explicitly when it becomes normal.596if (!iconify) {597repaintPeer();598}599}600601@Override602public void notifyZoom(boolean isZoomed) {603int newWindowState = isZoomed ? Frame.MAXIMIZED_BOTH : Frame.NORMAL;604postWindowStateChangedEvent(newWindowState);605}606607/**608* Called by the {@code PlatformWindow} when any part of the window should609* be repainted.610*/611@Override612public void notifyExpose(final Rectangle r) {613repaintPeer(r);614}615616/**617* Called by the {@code PlatformWindow} when this window is moved/resized by618* user or window insets are changed. There's no notifyReshape() in619* LWComponentPeer as the only components which could be resized by user are620* top-level windows.621*/622@Override623public void notifyReshape(int x, int y, int w, int h) {624Rectangle oldBounds = getBounds();625final boolean invalid = updateInsets(platformWindow.getInsets());626final boolean moved = (x != oldBounds.x) || (y != oldBounds.y);627final boolean resized = (w != oldBounds.width) || (h != oldBounds.height);628629// Check if anything changed630if (!moved && !resized && !invalid) {631return;632}633// First, update peer's bounds634setBounds(x, y, w, h, SET_BOUNDS, false, false);635636// Second, update the graphics config and surface data637final boolean isNewDevice = updateGraphicsDevice();638if (resized || isNewDevice) {639replaceSurfaceData();640updateMinimumSize();641}642643// Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events644if (moved || invalid) {645handleMove(x, y, true);646}647if (resized || invalid || isNewDevice) {648handleResize(w, h, true);649repaintPeer();650}651652repositionSecurityWarning();653}654655private void clearBackground(final int w, final int h) {656final Graphics g = getOnscreenGraphics(getForeground(), getBackground(),657getFont());658if (g != null) {659try {660if (g instanceof Graphics2D) {661((Graphics2D) g).setComposite(AlphaComposite.Src);662}663if (isTranslucent()) {664g.setColor(nonOpaqueBackground);665g.fillRect(0, 0, w, h);666}667if (!isTextured()) {668if (g instanceof SunGraphics2D) {669((SunGraphics2D) g).constrain(0, 0, w, h, getRegion());670}671g.setColor(getBackground());672g.fillRect(0, 0, w, h);673}674} finally {675g.dispose();676}677}678}679680@Override681public void notifyUpdateCursor() {682getLWToolkit().getCursorManager().updateCursorLater(this);683}684685@Override686public void notifyActivation(boolean activation, LWWindowPeer opposite) {687Window oppositeWindow = (opposite == null)? null : opposite.getTarget();688changeFocusedWindow(activation, oppositeWindow);689}690691// MouseDown in non-client area692@Override693public void notifyNCMouseDown() {694// Ungrab except for a click on a Dialog with the grabbing owner695if (grabbingWindow != null &&696!grabbingWindow.isOneOfOwnersOf(this))697{698grabbingWindow.ungrab();699}700}701702// ---- EVENTS ---- //703704/*705* Called by the delegate to dispatch the event to Java. Event706* coordinates are relative to non-client window are, i.e. the top-left707* point of the client area is (insets.top, insets.left).708*/709@Override710public void notifyMouseEvent(int id, long when, int button,711int x, int y, int screenX, int screenY,712int modifiers, int clickCount, boolean popupTrigger,713byte[] bdata)714{715// TODO: fill "bdata" member of AWTEvent716Rectangle r = getBounds();717// findPeerAt() expects parent coordinates718LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y);719720if (id == MouseEvent.MOUSE_EXITED) {721isMouseOver = false;722if (lastMouseEventPeer != null) {723if (lastMouseEventPeer.isEnabled()) {724Point lp = lastMouseEventPeer.windowToLocal(x, y,725this);726Component target = lastMouseEventPeer.getTarget();727postMouseExitedEvent(target, when, modifiers, lp,728screenX, screenY, clickCount, popupTrigger, button);729}730731// Sometimes we may get MOUSE_EXITED after lastCommonMouseEventPeer is switched732// to a peer from another window. So we must first check if this peer is733// the same as lastWindowPeer734if (lastCommonMouseEventPeer != null && lastCommonMouseEventPeer.getWindowPeerOrSelf() == this) {735lastCommonMouseEventPeer = null;736}737lastMouseEventPeer = null;738}739} else if(id == MouseEvent.MOUSE_ENTERED) {740isMouseOver = true;741if (targetPeer != null) {742if (targetPeer.isEnabled()) {743Point lp = targetPeer.windowToLocal(x, y, this);744Component target = targetPeer.getTarget();745postMouseEnteredEvent(target, when, modifiers, lp,746screenX, screenY, clickCount, popupTrigger, button);747}748lastCommonMouseEventPeer = targetPeer;749lastMouseEventPeer = targetPeer;750}751} else {752PlatformWindow topmostPlatformWindow = LWToolkit.getLWToolkit().getPlatformWindowUnderMouse();753754LWWindowPeer topmostWindowPeer =755topmostPlatformWindow != null ? topmostPlatformWindow.getPeer() : null;756757// topmostWindowPeer == null condition is added for the backward758// compatibility with applets. It can be removed when the759// getTopmostPlatformWindowUnderMouse() method will be properly760// implemented in CPlatformEmbeddedFrame class761if (topmostWindowPeer == this || topmostWindowPeer == null) {762generateMouseEnterExitEventsForComponents(when, button, x, y,763screenX, screenY, modifiers, clickCount, popupTrigger,764targetPeer);765} else {766LWComponentPeer<?, ?> topmostTargetPeer = topmostWindowPeer.findPeerAt(r.x + x, r.y + y);767topmostWindowPeer.generateMouseEnterExitEventsForComponents(when, button, x, y,768screenX, screenY, modifiers, clickCount, popupTrigger,769topmostTargetPeer);770}771772// TODO: fill "bdata" member of AWTEvent773774int eventButtonMask = (button > 0)? MouseEvent.getMaskForButton(button) : 0;775int otherButtonsPressed = modifiers & ~eventButtonMask;776777// For pressed/dragged/released events OS X treats other778// mouse buttons as if they were BUTTON2, so we do the same779int targetIdx = (button > 3) ? MouseEvent.BUTTON2 - 1 : button - 1;780781// MOUSE_ENTERED/EXITED are generated for the components strictly under782// mouse even when dragging. That's why we first update lastMouseEventPeer783// based on initial targetPeer value and only then recalculate targetPeer784// for MOUSE_DRAGGED/RELEASED events785if (id == MouseEvent.MOUSE_PRESSED) {786787// Ungrab only if this window is not an owned window of the grabbing one.788if (!isGrabbing() && grabbingWindow != null &&789!grabbingWindow.isOneOfOwnersOf(this))790{791grabbingWindow.ungrab();792}793if (otherButtonsPressed == 0) {794mouseClickButtons = eventButtonMask;795} else {796mouseClickButtons |= eventButtonMask;797}798799// The window should be focused on mouse click. If it gets activated by the native platform,800// this request will be no op. It will take effect when:801// 1. A simple not focused window is clicked.802// 2. An active but not focused owner frame/dialog is clicked.803// The mouse event then will trigger a focus request "in window" to the component, so the window804// should gain focus before.805requestWindowFocus(CausedFocusEvent.Cause.MOUSE_EVENT);806807mouseDownTarget[targetIdx] = targetPeer;808} else if (id == MouseEvent.MOUSE_DRAGGED) {809// Cocoa dragged event has the information about which mouse810// button is being dragged. Use it to determine the peer that811// should receive the dragged event.812targetPeer = mouseDownTarget[targetIdx];813mouseClickButtons &= ~modifiers;814} else if (id == MouseEvent.MOUSE_RELEASED) {815// TODO: currently, mouse released event goes to the same component816// that received corresponding mouse pressed event. For most cases,817// it's OK, however, we need to make sure that our behavior is consistent818// with 1.6 for cases where component in question have been819// hidden/removed in between of mouse pressed/released events.820targetPeer = mouseDownTarget[targetIdx];821822if ((modifiers & eventButtonMask) == 0) {823mouseDownTarget[targetIdx] = null;824}825826// mouseClickButtons is updated below, after MOUSE_CLICK is sent827}828829if (targetPeer == null) {830//TODO This can happen if this window is invisible. this is correct behavior in this case?831targetPeer = this;832}833834835Point lp = targetPeer.windowToLocal(x, y, this);836if (targetPeer.isEnabled()) {837MouseEvent event = new MouseEvent(targetPeer.getTarget(), id,838when, modifiers, lp.x, lp.y,839screenX, screenY, clickCount,840popupTrigger, button);841postEvent(event);842}843844if (id == MouseEvent.MOUSE_RELEASED) {845if ((mouseClickButtons & eventButtonMask) != 0846&& targetPeer.isEnabled()) {847postEvent(new MouseEvent(targetPeer.getTarget(),848MouseEvent.MOUSE_CLICKED,849when, modifiers,850lp.x, lp.y, screenX, screenY,851clickCount, popupTrigger, button));852}853mouseClickButtons &= ~eventButtonMask;854}855}856notifyUpdateCursor();857}858859private void generateMouseEnterExitEventsForComponents(long when,860int button, int x, int y, int screenX, int screenY,861int modifiers, int clickCount, boolean popupTrigger,862final LWComponentPeer<?, ?> targetPeer) {863864if (!isMouseOver || targetPeer == lastMouseEventPeer) {865return;866}867868// Generate Mouse Exit for components869if (lastMouseEventPeer != null && lastMouseEventPeer.isEnabled()) {870Point oldp = lastMouseEventPeer.windowToLocal(x, y, this);871Component target = lastMouseEventPeer.getTarget();872postMouseExitedEvent(target, when, modifiers, oldp, screenX, screenY,873clickCount, popupTrigger, button);874}875lastCommonMouseEventPeer = targetPeer;876lastMouseEventPeer = targetPeer;877878// Generate Mouse Enter for components879if (targetPeer != null && targetPeer.isEnabled()) {880Point newp = targetPeer.windowToLocal(x, y, this);881Component target = targetPeer.getTarget();882postMouseEnteredEvent(target, when, modifiers, newp, screenX, screenY, clickCount, popupTrigger, button);883}884}885886private void postMouseEnteredEvent(Component target, long when, int modifiers,887Point loc, int xAbs, int yAbs,888int clickCount, boolean popupTrigger, int button) {889890updateSecurityWarningVisibility();891892postEvent(new MouseEvent(target,893MouseEvent.MOUSE_ENTERED,894when, modifiers,895loc.x, loc.y, xAbs, yAbs,896clickCount, popupTrigger, button));897}898899private void postMouseExitedEvent(Component target, long when, int modifiers,900Point loc, int xAbs, int yAbs,901int clickCount, boolean popupTrigger, int button) {902903updateSecurityWarningVisibility();904905postEvent(new MouseEvent(target,906MouseEvent.MOUSE_EXITED,907when, modifiers,908loc.x, loc.y, xAbs, yAbs,909clickCount, popupTrigger, button));910}911912@Override913public void notifyMouseWheelEvent(long when, int x, int y, int modifiers,914int scrollType, int scrollAmount,915int wheelRotation, double preciseWheelRotation,916byte[] bdata)917{918// TODO: could we just use the last mouse event target here?919Rectangle r = getBounds();920// findPeerAt() expects parent coordinates921final LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y);922if (targetPeer == null || !targetPeer.isEnabled()) {923return;924}925926Point lp = targetPeer.windowToLocal(x, y, this);927// TODO: fill "bdata" member of AWTEvent928// TODO: screenX/screenY929postEvent(new MouseWheelEvent(targetPeer.getTarget(),930MouseEvent.MOUSE_WHEEL,931when, modifiers,932lp.x, lp.y,9330, 0, /* screenX, Y */9340 /* clickCount */, false /* popupTrigger */,935scrollType, scrollAmount,936wheelRotation, preciseWheelRotation));937}938939/*940* Called by the delegate when a key is pressed.941*/942@Override943public void notifyKeyEvent(int id, long when, int modifiers,944int keyCode, char keyChar, int keyLocation)945{946LWKeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();947Component focusOwner = kfmPeer.getCurrentFocusOwner();948949if (focusOwner == null) {950focusOwner = kfmPeer.getCurrentFocusedWindow();951if (focusOwner == null) {952focusOwner = this.getTarget();953}954}955956KeyEvent keyEvent = new KeyEvent(focusOwner, id, when, modifiers,957keyCode, keyChar, keyLocation);958AWTAccessor.getKeyEventAccessor().setExtendedKeyCode(keyEvent,959(keyChar == KeyEvent.CHAR_UNDEFINED) ? keyCode960: ExtendedKeyCodes.getExtendedKeyCodeForChar(keyChar));961postEvent(keyEvent);962}963964// ---- UTILITY METHODS ---- //965966private void activateDisplayListener() {967final GraphicsEnvironment ge =968GraphicsEnvironment.getLocalGraphicsEnvironment();969((SunGraphicsEnvironment) ge).addDisplayChangedListener(this);970}971972private void deactivateDisplayListener() {973final GraphicsEnvironment ge =974GraphicsEnvironment.getLocalGraphicsEnvironment();975((SunGraphicsEnvironment) ge).removeDisplayChangedListener(this);976}977978private void postWindowStateChangedEvent(int newWindowState) {979if (getTarget() instanceof Frame) {980AWTAccessor.getFrameAccessor().setExtendedState(981(Frame)getTarget(), newWindowState);982}983984WindowEvent stateChangedEvent = new WindowEvent(getTarget(),985WindowEvent.WINDOW_STATE_CHANGED,986windowState, newWindowState);987postEvent(stateChangedEvent);988windowState = newWindowState;989990updateSecurityWarningVisibility();991}992993private static int getGraphicsConfigScreen(GraphicsConfiguration gc) {994// TODO: this method can be implemented in a more995// efficient way by forwarding to the delegate996GraphicsDevice gd = gc.getDevice();997GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();998GraphicsDevice[] gds = ge.getScreenDevices();999for (int i = 0; i < gds.length; i++) {1000if (gds[i] == gd) {1001return i;1002}1003}1004// Should never happen if gc is a screen device config1005return 0;1006}10071008/*1009* This method is called when window's graphics config is changed from1010* the app code (e.g. when the window is made non-opaque) or when1011* the window is moved to another screen by user.1012*1013* Returns true if the graphics config has been changed, false otherwise.1014*/1015private boolean setGraphicsConfig(GraphicsConfiguration gc) {1016synchronized (getStateLock()) {1017if (graphicsConfig == gc) {1018return false;1019}1020// If window's graphics config is changed from the app code, the1021// config correspond to the same device as before; when the window1022// is moved by user, graphicsDevice is updated in notifyReshape().1023// In either case, there's nothing to do with screenOn here1024graphicsConfig = gc;1025}1026// SurfaceData is replaced later in updateGraphicsData()1027return true;1028}10291030/**1031* Returns true if the GraphicsDevice has been changed, false otherwise.1032*/1033public boolean updateGraphicsDevice() {1034GraphicsDevice newGraphicsDevice = platformWindow.getGraphicsDevice();1035synchronized (getStateLock()) {1036if (graphicsDevice == newGraphicsDevice) {1037return false;1038}1039graphicsDevice = newGraphicsDevice;1040}10411042final GraphicsConfiguration newGC = newGraphicsDevice.getDefaultConfiguration();10431044if (!setGraphicsConfig(newGC)) return false;10451046SunToolkit.executeOnEventHandlerThread(getTarget(), new Runnable() {1047public void run() {1048AWTAccessor.getComponentAccessor().setGraphicsConfiguration(getTarget(), newGC);1049}1050});1051return true;1052}10531054@Override1055public final void displayChanged() {1056if (updateGraphicsDevice()) {1057updateMinimumSize();1058}1059// Replace surface unconditionally, because internal state of the1060// GraphicsDevice could be changed.1061replaceSurfaceData();1062repaintPeer();1063}10641065@Override1066public final void paletteChanged() {1067// components do not need to react to this event.1068}10691070/*1071* May be called by delegate to provide SD to Java2D code.1072*/1073public SurfaceData getSurfaceData() {1074synchronized (surfaceDataLock) {1075return surfaceData;1076}1077}10781079private void replaceSurfaceData() {1080replaceSurfaceData(true);1081}10821083private void replaceSurfaceData(final boolean blit) {1084synchronized (surfaceDataLock) {1085final SurfaceData oldData = getSurfaceData();1086surfaceData = platformWindow.replaceSurfaceData();1087final Rectangle size = getSize();1088if (getSurfaceData() != null && oldData != getSurfaceData()) {1089clearBackground(size.width, size.height);1090}10911092if (blit) {1093blitSurfaceData(oldData, getSurfaceData());1094}10951096if (oldData != null && oldData != getSurfaceData()) {1097// TODO: drop oldData for D3D/WGL pipelines1098// This can only happen when this peer is being created1099oldData.flush();1100}1101}1102flushOnscreenGraphics();1103}11041105private void blitSurfaceData(final SurfaceData src, final SurfaceData dst) {1106//TODO blit. proof-of-concept1107if (src != dst && src != null && dst != null1108&& !(dst instanceof NullSurfaceData)1109&& !(src instanceof NullSurfaceData)1110&& src.getSurfaceType().equals(dst.getSurfaceType())1111&& src.getDefaultScale() == dst.getDefaultScale()) {1112final Rectangle size = src.getBounds();1113final Blit blit = Blit.locate(src.getSurfaceType(),1114CompositeType.Src,1115dst.getSurfaceType());1116if (blit != null) {1117blit.Blit(src, dst, AlphaComposite.Src, null, 0, 0, 0, 0,1118size.width, size.height);1119}1120}1121}11221123/**1124* Request the window insets from the delegate and compares it with the1125* current one. This method is mostly called by the delegate, e.g. when the1126* window state is changed and insets should be recalculated.1127* <p/>1128* This method may be called on the toolkit thread.1129*/1130public final boolean updateInsets(final Insets newInsets) {1131synchronized (getStateLock()) {1132if (insets.equals(newInsets)) {1133return false;1134}1135insets = newInsets;1136}1137return true;1138}11391140public static LWWindowPeer getWindowUnderCursor() {1141return lastCommonMouseEventPeer != null ? lastCommonMouseEventPeer.getWindowPeerOrSelf() : null;1142}11431144public static LWComponentPeer<?, ?> getPeerUnderCursor() {1145return lastCommonMouseEventPeer;1146}11471148/*1149* Requests platform to set native focus on a frame/dialog.1150* In case of a simple window, triggers appropriate java focus change.1151*/1152public boolean requestWindowFocus(CausedFocusEvent.Cause cause) {1153if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {1154focusLog.fine("requesting native focus to " + this);1155}11561157if (!focusAllowedFor()) {1158focusLog.fine("focus is not allowed");1159return false;1160}11611162if (platformWindow.rejectFocusRequest(cause)) {1163return false;1164}11651166AppContext targetAppContext = AWTAccessor.getComponentAccessor().getAppContext(getTarget());1167KeyboardFocusManager kfm = AWTAccessor.getKeyboardFocusManagerAccessor()1168.getCurrentKeyboardFocusManager(targetAppContext);1169Window currentActive = kfm.getActiveWindow();117011711172Window opposite = LWKeyboardFocusManagerPeer.getInstance().1173getCurrentFocusedWindow();11741175// Make the owner active window.1176if (isSimpleWindow()) {1177LWWindowPeer owner = getOwnerFrameDialog(this);11781179// If owner is not natively active, request native1180// activation on it w/o sending events up to java.1181if (owner != null && !owner.platformWindow.isActive()) {1182if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {1183focusLog.fine("requesting native focus to the owner " + owner);1184}1185LWWindowPeer currentActivePeer = currentActive == null ? null :1186(LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(1187currentActive);11881189// Ensure the opposite is natively active and suppress sending events.1190if (currentActivePeer != null && currentActivePeer.platformWindow.isActive()) {1191if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {1192focusLog.fine("the opposite is " + currentActivePeer);1193}1194currentActivePeer.skipNextFocusChange = true;1195}1196owner.skipNextFocusChange = true;11971198owner.platformWindow.requestWindowFocus();1199}12001201// DKFM will synthesize all the focus/activation events correctly.1202changeFocusedWindow(true, opposite);1203return true;12041205// In case the toplevel is active but not focused, change focus directly,1206// as requesting native focus on it will not have effect.1207} else if (getTarget() == currentActive && !getTarget().hasFocus()) {12081209changeFocusedWindow(true, opposite);1210return true;1211}12121213return platformWindow.requestWindowFocus();1214}12151216protected boolean focusAllowedFor() {1217Window window = getTarget();1218// TODO: check if modal blocked1219return window.isVisible() && window.isEnabled() && isFocusableWindow();1220}12211222private boolean isFocusableWindow() {1223boolean focusable = targetFocusable;1224if (isSimpleWindow()) {1225LWWindowPeer ownerPeer = getOwnerFrameDialog(this);1226if (ownerPeer == null) {1227return false;1228}1229return focusable && ownerPeer.targetFocusable;1230}1231return focusable;1232}12331234public boolean isSimpleWindow() {1235Window window = getTarget();1236return !(window instanceof Dialog || window instanceof Frame);1237}12381239@Override1240public void emulateActivation(boolean activate) {1241changeFocusedWindow(activate, null);1242}12431244private boolean isOneOfOwnersOf(LWWindowPeer peer) {1245Window owner = (peer != null ? peer.getTarget().getOwner() : null);1246while (owner != null) {1247if ((LWWindowPeer)owner.getPeer() == this) {1248return true;1249}1250owner = owner.getOwner();1251}1252return false;1253}12541255/*1256* Changes focused window on java level.1257*/1258protected void changeFocusedWindow(boolean becomesFocused, Window opposite) {1259if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {1260focusLog.fine((becomesFocused?"gaining":"loosing") + " focus window: " + this);1261}1262if (skipNextFocusChange) {1263focusLog.fine("skipping focus change");1264skipNextFocusChange = false;1265return;1266}1267if (!isFocusableWindow() && becomesFocused) {1268focusLog.fine("the window is not focusable");1269return;1270}1271if (becomesFocused) {1272synchronized (getPeerTreeLock()) {1273if (blocker != null) {1274if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {1275focusLog.finest("the window is blocked by " + blocker);1276}1277return;1278}1279}1280}12811282// Note, the method is not called:1283// - when the opposite (gaining focus) window is an owned/owner window.1284// - for a simple window in any case.1285if (!becomesFocused &&1286(isGrabbing() || this.isOneOfOwnersOf(grabbingWindow)))1287{1288if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {1289focusLog.fine("ungrabbing on " + grabbingWindow);1290}1291// ungrab a simple window if its owner looses activation.1292grabbingWindow.ungrab();1293}12941295KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();12961297if (!becomesFocused && kfmPeer.getCurrentFocusedWindow() != getTarget()) {1298// late window focus lost event - ingoring1299return;1300}13011302kfmPeer.setCurrentFocusedWindow(becomesFocused ? getTarget() : null);13031304int eventID = becomesFocused ? WindowEvent.WINDOW_GAINED_FOCUS : WindowEvent.WINDOW_LOST_FOCUS;1305WindowEvent windowEvent = new TimedWindowEvent(getTarget(), eventID, opposite, System.currentTimeMillis());13061307// TODO: wrap in SequencedEvent1308postEvent(windowEvent);1309}13101311/*1312* Retrieves the owner of the peer.1313* Note: this method returns the owner which can be activated, (i.e. the instance1314* of Frame or Dialog may be returned).1315*/1316static LWWindowPeer getOwnerFrameDialog(LWWindowPeer peer) {1317Window owner = (peer != null ? peer.getTarget().getOwner() : null);1318while (owner != null && !(owner instanceof Frame || owner instanceof Dialog)) {1319owner = owner.getOwner();1320}1321return owner == null ? null :1322(LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(owner);1323}13241325/**1326* Returns the foremost modal blocker of this window, or null.1327*/1328public LWWindowPeer getBlocker() {1329synchronized (getPeerTreeLock()) {1330LWWindowPeer blocker = this.blocker;1331if (blocker == null) {1332return null;1333}1334while (blocker.blocker != null) {1335blocker = blocker.blocker;1336}1337return blocker;1338}1339}13401341@Override1342public void enterFullScreenMode() {1343platformWindow.enterFullScreenMode();1344updateSecurityWarningVisibility();1345}13461347@Override1348public void exitFullScreenMode() {1349platformWindow.exitFullScreenMode();1350updateSecurityWarningVisibility();1351}13521353public long getLayerPtr() {1354return getPlatformWindow().getLayerPtr();1355}13561357void grab() {1358if (grabbingWindow != null && !isGrabbing()) {1359grabbingWindow.ungrab();1360}1361grabbingWindow = this;1362}13631364final void ungrab(boolean doPost) {1365if (isGrabbing()) {1366grabbingWindow = null;1367if (doPost) {1368postEvent(new UngrabEvent(getTarget()));1369}1370}1371}13721373void ungrab() {1374ungrab(true);1375}13761377private boolean isGrabbing() {1378return this == grabbingWindow;1379}13801381public PeerType getPeerType() {1382return peerType;1383}13841385public void updateSecurityWarningVisibility() {1386if (warningWindow == null) {1387return;1388}13891390if (!isVisible()) {1391return; // The warning window should already be hidden.1392}13931394boolean show = false;13951396if (!platformWindow.isFullScreenMode()) {1397if (isVisible()) {1398if (LWKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() ==1399getTarget()) {1400show = true;1401}14021403if (platformWindow.isUnderMouse() || warningWindow.isUnderMouse()) {1404show = true;1405}1406}1407}14081409warningWindow.setVisible(show, true);1410}14111412@Override1413public String toString() {1414return super.toString() + " [target is " + getTarget() + "]";1415}1416}141714181419