1 /*
   2  * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.lwawt;
  27 
  28 import java.awt.*;
  29 import java.awt.event.*;
  30 import java.awt.peer.*;
  31 import java.util.List;
  32 
  33 import javax.swing.*;
  34 
  35 import sun.awt.*;
  36 import sun.awt.AWTAccessor.ComponentAccessor;
  37 import sun.java2d.*;
  38 import sun.java2d.loops.Blit;
  39 import sun.java2d.loops.CompositeType;
  40 import sun.java2d.pipe.Region;
  41 import sun.util.logging.PlatformLogger;
  42 
  43 public class LWWindowPeer
  44     extends LWContainerPeer<Window, JComponent>
  45     implements FramePeer, DialogPeer, FullScreenCapable, DisplayChangedListener, PlatformEventNotifier
  46 {
  47     public enum PeerType {
  48         SIMPLEWINDOW,
  49         FRAME,
  50         DIALOG,
  51         EMBEDDED_FRAME,
  52         VIEW_EMBEDDED_FRAME,
  53         LW_FRAME
  54     }
  55 
  56     private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWWindowPeer");
  57 
  58     private final PlatformWindow platformWindow;
  59 
  60     private static final int MINIMUM_WIDTH = 1;
  61     private static final int MINIMUM_HEIGHT = 1;
  62 
  63     private Insets insets = new Insets(0, 0, 0, 0);
  64     private Rectangle maximizedBounds;
  65 
  66     private GraphicsDevice graphicsDevice;
  67     private GraphicsConfiguration graphicsConfig;
  68 
  69     private SurfaceData surfaceData;
  70     private final Object surfaceDataLock = new Object();
  71 
  72     private volatile int windowState = Frame.NORMAL;
  73 
  74     // check that the mouse is over the window
  75     private volatile boolean isMouseOver = false;
  76 
  77     // A peer where the last mouse event came to. Used by cursor manager to
  78     // find the component under cursor
  79     private static volatile LWComponentPeer<?, ?> lastCommonMouseEventPeer;
  80 
  81     // A peer where the last mouse event came to. Used to generate
  82     // MOUSE_ENTERED/EXITED notifications
  83     private volatile LWComponentPeer<?, ?> lastMouseEventPeer;
  84 
  85     // Peers where all dragged/released events should come to,
  86     // depending on what mouse button is being dragged according to Cocoa
  87     private static final LWComponentPeer<?, ?>[] mouseDownTarget = new LWComponentPeer<?, ?>[3];
  88 
  89     // A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events
  90     // on MOUSE_RELEASE. Click events are only generated if there were no drag
  91     // events between MOUSE_PRESSED and MOUSE_RELEASED for particular button
  92     private static int mouseClickButtons = 0;
  93 
  94     private volatile boolean isOpaque = true;
  95 
  96     private static final Font DEFAULT_FONT = new Font("Lucida Grande", Font.PLAIN, 13);
  97 
  98     private static LWWindowPeer grabbingWindow;
  99 
 100     private volatile boolean skipNextFocusChange;
 101 
 102     private static final Color nonOpaqueBackground = new Color(0, 0, 0, 0);
 103 
 104     private volatile boolean textured;
 105 
 106     private final PeerType peerType;
 107 
 108     private final SecurityWarningWindow warningWindow;
 109 
 110     private volatile boolean targetFocusable;
 111 
 112     /**
 113      * Current modal blocker or null.
 114      *
 115      * Synchronization: peerTreeLock.
 116      */
 117     private LWWindowPeer blocker;
 118 
 119     public LWWindowPeer(Window target, PlatformComponent platformComponent,
 120                         PlatformWindow platformWindow, PeerType peerType)
 121     {
 122         super(target, platformComponent);
 123         this.platformWindow = platformWindow;
 124         this.peerType = peerType;
 125 
 126         Window owner = target.getOwner();
 127         LWWindowPeer ownerPeer = owner == null ? null :
 128              (LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(owner);
 129         PlatformWindow ownerDelegate = (ownerPeer != null) ? ownerPeer.getPlatformWindow() : null;
 130 
 131         // The delegate.initialize() needs a non-null GC on X11.
 132         GraphicsConfiguration gc = getTarget().getGraphicsConfiguration();
 133         synchronized (getStateLock()) {
 134             // graphicsConfig should be updated according to the real window
 135             // bounds when the window is shown, see 4868278
 136             this.graphicsConfig = gc;
 137         }
 138 
 139         if (!target.isFontSet()) {
 140             target.setFont(DEFAULT_FONT);
 141         }
 142 
 143         if (!target.isBackgroundSet()) {
 144             target.setBackground(SystemColor.window);
 145         } else {
 146             // first we check if user provided alpha for background. This is
 147             // similar to what Apple's Java do.
 148             // Since JDK7 we should rely on setOpacity() only.
 149             // this.opacity = c.getAlpha();
 150         }
 151 
 152         if (!target.isForegroundSet()) {
 153             target.setForeground(SystemColor.windowText);
 154             // we should not call setForeground because it will call a repaint
 155             // which the peer may not be ready to do yet.
 156         }
 157 
 158         platformWindow.initialize(target, this, ownerDelegate);
 159 
 160         // Init warning window(for applets)
 161         SecurityWarningWindow warn = null;
 162         if (target.getWarningString() != null) {
 163             // accessSystemTray permission allows to display TrayIcon, TrayIcon tooltip
 164             // and TrayIcon balloon windows without a warning window.
 165             if (!AWTAccessor.getWindowAccessor().isTrayIconWindow(target)) {
 166                 LWToolkit toolkit = (LWToolkit)Toolkit.getDefaultToolkit();
 167                 warn = toolkit.createSecurityWarning(target, this);
 168             }
 169         }
 170 
 171         warningWindow = warn;
 172     }
 173 
 174     @Override
 175     void initializeImpl() {
 176         super.initializeImpl();
 177 
 178 
 179         if (getTarget() instanceof Frame) {
 180             Frame frame = (Frame) getTarget();
 181             setTitle(frame.getTitle());
 182             setState(frame.getExtendedState());
 183             setMaximizedBounds(frame.getMaximizedBounds());
 184         } else if (getTarget() instanceof Dialog) {
 185             setTitle(((Dialog) getTarget()).getTitle());
 186         }
 187 
 188         updateAlwaysOnTopState();
 189         updateMinimumSize();
 190         updateFocusableWindowState();
 191 
 192         final Shape shape = getTarget().getShape();
 193         if (shape != null) {
 194             applyShape(Region.getInstance(shape, null));
 195         }
 196 
 197         final float opacity = getTarget().getOpacity();
 198         if (opacity < 1.0f) {
 199             setOpacity(opacity);
 200         }
 201 
 202         setOpaque(getTarget().isOpaque());
 203 
 204         updateInsets(platformWindow.getInsets());
 205         if (getSurfaceData() == null) {
 206             replaceSurfaceData(false);
 207         }
 208         activateDisplayListener();
 209     }
 210 
 211     // Just a helper method
 212     @Override
 213     public PlatformWindow getPlatformWindow() {
 214         return platformWindow;
 215     }
 216 
 217     @Override
 218     protected LWWindowPeer getWindowPeerOrSelf() {
 219         return this;
 220     }
 221 
 222     // ---- PEER METHODS ---- //
 223 
 224     @Override
 225     protected void disposeImpl() {
 226         deactivateDisplayListener();
 227         SurfaceData oldData = getSurfaceData();
 228         synchronized (surfaceDataLock){
 229             surfaceData = null;
 230         }
 231         if (oldData != null) {
 232             oldData.invalidate();
 233         }
 234         if (isGrabbing()) {
 235             ungrab();
 236         }
 237         if (warningWindow != null) {
 238             warningWindow.dispose();
 239         }
 240 
 241         platformWindow.dispose();
 242         super.disposeImpl();
 243     }
 244 
 245     @Override
 246     protected void setVisibleImpl(final boolean visible) {
 247         if (!visible && warningWindow != null) {
 248             warningWindow.setVisible(false, false);
 249         }
 250         updateFocusableWindowState();
 251         super.setVisibleImpl(visible);
 252         // TODO: update graphicsConfig, see 4868278
 253         platformWindow.setVisible(visible);
 254         if (isSimpleWindow()) {
 255             KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
 256             if (visible) {
 257                 if (!getTarget().isAutoRequestFocus()) {
 258                     return;
 259                 } else {
 260                     requestWindowFocus(FocusEvent.Cause.ACTIVATION);
 261                 }
 262             // Focus the owner in case this window is focused.
 263             } else if (kfmPeer.getCurrentFocusedWindow() == getTarget()) {
 264                 // Transfer focus to the owner.
 265                 LWWindowPeer owner = getOwnerFrameDialog(LWWindowPeer.this);
 266                 if (owner != null) {
 267                     owner.requestWindowFocus(FocusEvent.Cause.ACTIVATION);
 268                 }
 269             }
 270         }
 271     }
 272 
 273     @Override
 274     public final GraphicsConfiguration getGraphicsConfiguration() {
 275         synchronized (getStateLock()) {
 276             return graphicsConfig;
 277         }
 278     }
 279 
 280     @Override
 281     public boolean updateGraphicsData(GraphicsConfiguration gc) {
 282         setGraphicsConfig(gc);
 283         return false;
 284     }
 285 
 286     protected final Graphics getOnscreenGraphics(Color fg, Color bg, Font f) {
 287         if (getSurfaceData() == null) {
 288             return null;
 289         }
 290         if (fg == null) {
 291             fg = SystemColor.windowText;
 292         }
 293         if (bg == null) {
 294             bg = SystemColor.window;
 295         }
 296         if (f == null) {
 297             f = DEFAULT_FONT;
 298         }
 299         return new SunGraphics2D(getSurfaceData(), fg, bg, f);
 300     }
 301 
 302     @Override
 303     public void setBounds(int x, int y, int w, int h, int op) {
 304 
 305         if((op & NO_EMBEDDED_CHECK) == 0 && getPeerType() == PeerType.VIEW_EMBEDDED_FRAME) {
 306             return;
 307         }
 308 
 309         if ((op & SET_CLIENT_SIZE) != 0) {
 310             // SET_CLIENT_SIZE is only applicable to window peers, so handle it here
 311             // instead of pulling 'insets' field up to LWComponentPeer
 312             // no need to add insets since Window's notion of width and height includes insets.
 313             op &= ~SET_CLIENT_SIZE;
 314             op |= SET_SIZE;
 315         }
 316 
 317         // Don't post ComponentMoved/Resized and Paint events
 318         // until we've got a notification from the delegate
 319         Rectangle cb = constrainBounds(x, y, w, h);
 320 
 321         Rectangle newBounds = new Rectangle(getBounds());
 322         if ((op & (SET_LOCATION | SET_BOUNDS)) != 0) {
 323             newBounds.x = cb.x;
 324             newBounds.y = cb.y;
 325         }
 326         if ((op & (SET_SIZE | SET_BOUNDS)) != 0) {
 327             newBounds.width = cb.width;
 328             newBounds.height = cb.height;
 329         }
 330         // Native system could constraint bounds, so the peer wold be updated in the callback
 331         platformWindow.setBounds(newBounds.x, newBounds.y, newBounds.width, newBounds.height);
 332     }
 333 
 334     public Rectangle constrainBounds(Rectangle bounds) {
 335         return constrainBounds(bounds.x, bounds.y, bounds.width, bounds.height);
 336     }
 337 
 338     public Rectangle constrainBounds(int x, int y, int w, int h) {
 339 
 340         if (w < MINIMUM_WIDTH) {
 341             w = MINIMUM_WIDTH;
 342         }
 343 
 344         if (h < MINIMUM_HEIGHT) {
 345             h = MINIMUM_HEIGHT;
 346         }
 347 
 348         final int maxW = getLWGC().getMaxTextureWidth();
 349         final int maxH = getLWGC().getMaxTextureHeight();
 350 
 351         if (w > maxW) {
 352             w = maxW;
 353         }
 354         if (h > maxH) {
 355             h = maxH;
 356         }
 357 
 358         return new Rectangle(x, y, w, h);
 359     }
 360 
 361     @Override
 362     public Point getLocationOnScreen() {
 363         return platformWindow.getLocationOnScreen();
 364     }
 365 
 366     /**
 367      * Overridden from LWContainerPeer to return the correct insets.
 368      * Insets are queried from the delegate and are kept up to date by
 369      * requiering when needed (i.e. when the window geometry is changed).
 370      */
 371     @Override
 372     public Insets getInsets() {
 373         synchronized (getStateLock()) {
 374             return insets;
 375         }
 376     }
 377 
 378     @Override
 379     public FontMetrics getFontMetrics(Font f) {
 380         // TODO: check for "use platform metrics" settings
 381         return platformWindow.getFontMetrics(f);
 382     }
 383 
 384     @Override
 385     public void toFront() {
 386         platformWindow.toFront();
 387     }
 388 
 389     @Override
 390     public void toBack() {
 391         platformWindow.toBack();
 392     }
 393 
 394     @Override
 395     public void setZOrder(ComponentPeer above) {
 396         throw new RuntimeException("not implemented");
 397     }
 398 
 399     @Override
 400     public void updateAlwaysOnTopState() {
 401         platformWindow.setAlwaysOnTop(getTarget().isAlwaysOnTop());
 402     }
 403 
 404     @Override
 405     public void updateFocusableWindowState() {
 406         targetFocusable = getTarget().isFocusableWindow();
 407         platformWindow.updateFocusableWindowState();
 408     }
 409 
 410     @Override
 411     public void setModalBlocked(Dialog blocker, boolean blocked) {
 412         synchronized (getPeerTreeLock()) {
 413             ComponentPeer peer =  AWTAccessor.getComponentAccessor().getPeer(blocker);
 414             if (blocked && (peer instanceof LWWindowPeer)) {
 415                 this.blocker = (LWWindowPeer) peer;
 416             } else {
 417                 this.blocker = null;
 418             }
 419         }
 420 
 421         platformWindow.setModalBlocked(blocked);
 422     }
 423 
 424     @Override
 425     public void updateMinimumSize() {
 426         final Dimension min;
 427         if (getTarget().isMinimumSizeSet()) {
 428             min = getTarget().getMinimumSize();
 429             min.width = Math.max(min.width, MINIMUM_WIDTH);
 430             min.height = Math.max(min.height, MINIMUM_HEIGHT);
 431         } else {
 432             min = new Dimension(MINIMUM_WIDTH, MINIMUM_HEIGHT);
 433         }
 434 
 435         final Dimension max;
 436         if (getTarget().isMaximumSizeSet()) {
 437             max = getTarget().getMaximumSize();
 438             max.width = Math.min(max.width, getLWGC().getMaxTextureWidth());
 439             max.height = Math.min(max.height, getLWGC().getMaxTextureHeight());
 440         } else {
 441             max = new Dimension(getLWGC().getMaxTextureWidth(),
 442                                 getLWGC().getMaxTextureHeight());
 443         }
 444 
 445         platformWindow.setSizeConstraints(min.width, min.height, max.width, max.height);
 446     }
 447 
 448     @Override
 449     public void updateIconImages() {
 450         getPlatformWindow().updateIconImages();
 451     }
 452 
 453     @Override
 454     public void setBackground(final Color c) {
 455         super.setBackground(c);
 456         updateOpaque();
 457     }
 458 
 459     @Override
 460     public void setOpacity(float opacity) {
 461         getPlatformWindow().setOpacity(opacity);
 462         repaintPeer();
 463     }
 464 
 465     @Override
 466     public final void setOpaque(final boolean isOpaque) {
 467         if (this.isOpaque != isOpaque) {
 468             this.isOpaque = isOpaque;
 469             updateOpaque();
 470         }
 471     }
 472 
 473     private void updateOpaque() {
 474         getPlatformWindow().setOpaque(!isTranslucent());
 475         replaceSurfaceData(false);
 476         repaintPeer();
 477     }
 478 
 479     @Override
 480     public void updateWindow() {
 481     }
 482 
 483     public final boolean isTextured() {
 484         return textured;
 485     }
 486 
 487     public final void setTextured(final boolean isTextured) {
 488         textured = isTextured;
 489     }
 490 
 491     @Override
 492     public final boolean isTranslucent() {
 493         synchronized (getStateLock()) {
 494             /*
 495              * Textured window is a special case of translucent window.
 496              * The difference is only in nswindow background. So when we set
 497              * texture property our peer became fully translucent. It doesn't
 498              * fill background, create non opaque backbuffers and layer etc.
 499              */
 500             return !isOpaque || isShaped() || isTextured();
 501         }
 502     }
 503 
 504     @Override
 505     final void applyShapeImpl(final Region shape) {
 506         super.applyShapeImpl(shape);
 507         updateOpaque();
 508     }
 509 
 510     @Override
 511     public void repositionSecurityWarning() {
 512         if (warningWindow != null) {
 513             ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
 514             Window target = getTarget();
 515             int x = compAccessor.getX(target);
 516             int y = compAccessor.getY(target);
 517             int width = compAccessor.getWidth(target);
 518             int height = compAccessor.getHeight(target);
 519             warningWindow.reposition(x, y, width, height);
 520         }
 521     }
 522 
 523     // ---- FRAME PEER METHODS ---- //
 524 
 525     @Override // FramePeer and DialogPeer
 526     public void setTitle(String title) {
 527         platformWindow.setTitle(title == null ? "" : title);
 528     }
 529 
 530     @Override
 531     public void setMenuBar(MenuBar mb) {
 532          platformWindow.setMenuBar(mb);
 533     }
 534 
 535     @Override // FramePeer and DialogPeer
 536     public void setResizable(boolean resizable) {
 537         platformWindow.setResizable(resizable);
 538     }
 539 
 540     @Override
 541     public void setState(int state) {
 542         platformWindow.setWindowState(state);
 543     }
 544 
 545     @Override
 546     public int getState() {
 547         return windowState;
 548     }
 549 
 550     private boolean isMaximizedBoundsSet() {
 551         synchronized (getStateLock()) {
 552             return maximizedBounds != null;
 553         }
 554     }
 555 
 556     private Rectangle getDefaultMaximizedBounds() {
 557         GraphicsConfiguration config = getGraphicsConfiguration();
 558         Insets screenInsets = ((CGraphicsDevice) config.getDevice())
 559                 .getScreenInsets();
 560         Rectangle gcBounds = config.getBounds();
 561         return new Rectangle(
 562                 gcBounds.x + screenInsets.left,
 563                 gcBounds.y + screenInsets.top,
 564                 gcBounds.width - screenInsets.left - screenInsets.right,
 565                 gcBounds.height - screenInsets.top - screenInsets.bottom);
 566     }
 567 
 568     @Override
 569     public void setMaximizedBounds(Rectangle bounds) {
 570         boolean isMaximizedBoundsSet;
 571         synchronized (getStateLock()) {
 572             this.maximizedBounds = (isMaximizedBoundsSet = (bounds != null))
 573                     ? constrainBounds(bounds) : null;
 574         }
 575 
 576         setPlatformMaximizedBounds(isMaximizedBoundsSet ? maximizedBounds
 577                 : getDefaultMaximizedBounds());
 578     }
 579 
 580     public Rectangle getMaximizedBounds() {
 581         synchronized (getStateLock()) {
 582             return (maximizedBounds == null)
 583                     ? getDefaultMaximizedBounds()
 584                     : maximizedBounds;
 585         }
 586     }
 587 
 588     private void setPlatformMaximizedBounds(Rectangle bounds) {
 589         platformWindow.setMaximizedBounds(
 590                 bounds.x, bounds.y,
 591                 bounds.width, bounds.height);
 592     }
 593 
 594     @Override
 595     public void setBoundsPrivate(int x, int y, int width, int height) {
 596         setBounds(x, y, width, height, SET_BOUNDS | NO_EMBEDDED_CHECK);
 597     }
 598 
 599     @Override
 600     public Rectangle getBoundsPrivate() {
 601         throw new RuntimeException("not implemented");
 602     }
 603 
 604     // ---- DIALOG PEER METHODS ---- //
 605 
 606     @Override
 607     public void blockWindows(List<Window> windows) {
 608         //TODO: LWX will probably need some collectJavaToplevels to speed this up
 609         for (Window w : windows) {
 610             WindowPeer wp = AWTAccessor.getComponentAccessor().getPeer(w);
 611             if (wp != null) {
 612                 wp.setModalBlocked((Dialog)getTarget(), true);
 613             }
 614         }
 615     }
 616 
 617     // ---- PEER NOTIFICATIONS ---- //
 618 
 619     @Override
 620     public void notifyIconify(boolean iconify) {
 621         //The toplevel target is Frame and states are applicable to it.
 622         //Otherwise, the target is Window and it don't have state property.
 623         //Hopefully, no such events are posted in the queue so consider the
 624         //target as Frame in all cases.
 625 
 626         // REMIND: should we send it anyway if the state not changed since last
 627         // time?
 628         WindowEvent iconifyEvent = new WindowEvent(getTarget(),
 629                 iconify ? WindowEvent.WINDOW_ICONIFIED
 630                         : WindowEvent.WINDOW_DEICONIFIED);
 631         postEvent(iconifyEvent);
 632 
 633         int newWindowState = iconify ? Frame.ICONIFIED : Frame.NORMAL;
 634         postWindowStateChangedEvent(newWindowState);
 635 
 636         // REMIND: RepaintManager doesn't repaint iconified windows and
 637         // hence ignores any repaint request during deiconification.
 638         // So, we need to repaint window explicitly when it becomes normal.
 639         if (!iconify) {
 640             repaintPeer();
 641         }
 642     }
 643 
 644     @Override
 645     public void notifyZoom(boolean isZoomed) {
 646         int newWindowState = isZoomed ? Frame.MAXIMIZED_BOTH : Frame.NORMAL;
 647         postWindowStateChangedEvent(newWindowState);
 648     }
 649 
 650     /**
 651      * Called by the {@code PlatformWindow} when any part of the window should
 652      * be repainted.
 653      */
 654     @Override
 655     public void notifyExpose(final Rectangle r) {
 656         repaintPeer(r);
 657     }
 658 
 659     /**
 660      * Called by the {@code PlatformWindow} when this window is moved/resized by
 661      * user or window insets are changed. There's no notifyReshape() in
 662      * LWComponentPeer as the only components which could be resized by user are
 663      * top-level windows.
 664      */
 665     @Override
 666     public void notifyReshape(int x, int y, int w, int h) {
 667         Rectangle oldBounds = getBounds();
 668         final boolean invalid = updateInsets(platformWindow.getInsets());
 669         final boolean moved = (x != oldBounds.x) || (y != oldBounds.y);
 670         final boolean resized = (w != oldBounds.width) || (h != oldBounds.height);
 671 
 672         // Check if anything changed
 673         if (!moved && !resized && !invalid) {
 674             return;
 675         }
 676         // First, update peer's bounds
 677         setBounds(x, y, w, h, SET_BOUNDS, false, false);
 678 
 679         // Second, update the graphics config and surface data
 680         final boolean isNewDevice = updateGraphicsDevice();
 681         if (isNewDevice && !isMaximizedBoundsSet()) {
 682             setPlatformMaximizedBounds(getDefaultMaximizedBounds());
 683         }
 684 
 685         if (resized || isNewDevice) {
 686             replaceSurfaceData();
 687             updateMinimumSize();
 688         }
 689 
 690         // Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events
 691         if (moved || invalid) {
 692             handleMove(x, y, true);
 693         }
 694         if (resized || invalid || isNewDevice) {
 695             handleResize(w, h, true);
 696             repaintPeer();
 697         }
 698 
 699         repositionSecurityWarning();
 700     }
 701 
 702     private void clearBackground(final int w, final int h) {
 703         final Graphics g = getOnscreenGraphics(getForeground(), getBackground(),
 704                                                getFont());
 705         if (g != null) {
 706             try {
 707                 if (g instanceof Graphics2D) {
 708                     ((Graphics2D) g).setComposite(AlphaComposite.Src);
 709                 }
 710                 if (isTranslucent()) {
 711                     g.setColor(nonOpaqueBackground);
 712                     g.fillRect(0, 0, w, h);
 713                 }
 714                 if (!isTextured()) {
 715                     if (g instanceof SunGraphics2D) {
 716                         ((SunGraphics2D) g).constrain(0, 0, w, h, getRegion());
 717                     }
 718                     g.setColor(getBackground());
 719                     g.fillRect(0, 0, w, h);
 720                 }
 721             } finally {
 722                 g.dispose();
 723             }
 724         }
 725     }
 726 
 727     @Override
 728     public void notifyUpdateCursor() {
 729         getLWToolkit().getCursorManager().updateCursorLater(this);
 730     }
 731 
 732     @Override
 733     public void notifyActivation(boolean activation, LWWindowPeer opposite) {
 734         Window oppositeWindow = (opposite == null)? null : opposite.getTarget();
 735         changeFocusedWindow(activation, oppositeWindow);
 736     }
 737 
 738     // MouseDown in non-client area
 739     @Override
 740     public void notifyNCMouseDown() {
 741         // Ungrab except for a click on a Dialog with the grabbing owner
 742         if (grabbingWindow != null &&
 743             !grabbingWindow.isOneOfOwnersOf(this))
 744         {
 745             grabbingWindow.ungrab();
 746         }
 747     }
 748 
 749     // ---- EVENTS ---- //
 750 
 751     /*
 752      * Called by the delegate to dispatch the event to Java. Event
 753      * coordinates are relative to non-client window are, i.e. the top-left
 754      * point of the client area is (insets.top, insets.left).
 755      */
 756     @Override
 757     public void notifyMouseEvent(int id, long when, int button,
 758                                  int x, int y, int absX, int absY,
 759                                  int modifiers, int clickCount, boolean popupTrigger,
 760                                  byte[] bdata)
 761     {
 762         // TODO: fill "bdata" member of AWTEvent
 763         Rectangle r = getBounds();
 764         // findPeerAt() expects parent coordinates
 765         LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y);
 766 
 767         if (id == MouseEvent.MOUSE_EXITED) {
 768             isMouseOver = false;
 769             if (lastMouseEventPeer != null) {
 770                 if (lastMouseEventPeer.isEnabled()) {
 771                     Point lp = lastMouseEventPeer.windowToLocal(x, y,
 772                             this);
 773                     Component target = lastMouseEventPeer.getTarget();
 774                     postMouseExitedEvent(target, when, modifiers, lp,
 775                             absX, absY, clickCount, popupTrigger, button);
 776                 }
 777 
 778                 // Sometimes we may get MOUSE_EXITED after lastCommonMouseEventPeer is switched
 779                 // to a peer from another window. So we must first check if this peer is
 780                 // the same as lastWindowPeer
 781                 if (lastCommonMouseEventPeer != null && lastCommonMouseEventPeer.getWindowPeerOrSelf() == this) {
 782                     lastCommonMouseEventPeer = null;
 783                 }
 784                 lastMouseEventPeer = null;
 785             }
 786         } else if(id == MouseEvent.MOUSE_ENTERED) {
 787             isMouseOver = true;
 788             if (targetPeer != null) {
 789                 if (targetPeer.isEnabled()) {
 790                     Point lp = targetPeer.windowToLocal(x, y, this);
 791                     Component target = targetPeer.getTarget();
 792                     postMouseEnteredEvent(target, when, modifiers, lp,
 793                             absX, absY, clickCount, popupTrigger, button);
 794                 }
 795                 lastCommonMouseEventPeer = targetPeer;
 796                 lastMouseEventPeer = targetPeer;
 797             }
 798         } else {
 799             PlatformWindow topmostPlatformWindow = LWToolkit.getLWToolkit().getPlatformWindowUnderMouse();
 800 
 801             LWWindowPeer topmostWindowPeer =
 802                     topmostPlatformWindow != null ? topmostPlatformWindow.getPeer() : null;
 803 
 804             // topmostWindowPeer == null condition is added for the backward
 805             // compatibility with applets. It can be removed when the
 806             // getTopmostPlatformWindowUnderMouse() method will be properly
 807             // implemented in CPlatformEmbeddedFrame class
 808             if (topmostWindowPeer == this || topmostWindowPeer == null) {
 809                 generateMouseEnterExitEventsForComponents(when, button, x, y,
 810                         absX, absY, modifiers, clickCount, popupTrigger,
 811                         targetPeer);
 812             } else {
 813                 LWComponentPeer<?, ?> topmostTargetPeer = topmostWindowPeer.findPeerAt(r.x + x, r.y + y);
 814                 topmostWindowPeer.generateMouseEnterExitEventsForComponents(when, button, x, y,
 815                         absX, absY, modifiers, clickCount, popupTrigger,
 816                         topmostTargetPeer);
 817             }
 818 
 819             // TODO: fill "bdata" member of AWTEvent
 820 
 821             int eventButtonMask = (button > 0)? MouseEvent.getMaskForButton(button) : 0;
 822             int otherButtonsPressed = modifiers & ~eventButtonMask;
 823 
 824             // For pressed/dragged/released events OS X treats other
 825             // mouse buttons as if they were BUTTON2, so we do the same
 826             int targetIdx = (button > 3) ? MouseEvent.BUTTON2 - 1 : button - 1;
 827 
 828             // MOUSE_ENTERED/EXITED are generated for the components strictly under
 829             // mouse even when dragging. That's why we first update lastMouseEventPeer
 830             // based on initial targetPeer value and only then recalculate targetPeer
 831             // for MOUSE_DRAGGED/RELEASED events
 832             if (id == MouseEvent.MOUSE_PRESSED) {
 833 
 834                 // Ungrab only if this window is not an owned window of the grabbing one.
 835                 if (!isGrabbing() && grabbingWindow != null &&
 836                     !grabbingWindow.isOneOfOwnersOf(this))
 837                 {
 838                     grabbingWindow.ungrab();
 839                 }
 840                 if (otherButtonsPressed == 0) {
 841                     mouseClickButtons = eventButtonMask;
 842                 } else {
 843                     mouseClickButtons |= eventButtonMask;
 844                 }
 845 
 846                 // The window should be focused on mouse click. If it gets activated by the native platform,
 847                 // this request will be no op. It will take effect when:
 848                 // 1. A simple not focused window is clicked.
 849                 // 2. An active but not focused owner frame/dialog is clicked.
 850                 // The mouse event then will trigger a focus request "in window" to the component, so the window
 851                 // should gain focus before.
 852                 requestWindowFocus(FocusEvent.Cause.MOUSE_EVENT);
 853 
 854                 mouseDownTarget[targetIdx] = targetPeer;
 855             } else if (id == MouseEvent.MOUSE_DRAGGED) {
 856                 // Cocoa dragged event has the information about which mouse
 857                 // button is being dragged. Use it to determine the peer that
 858                 // should receive the dragged event.
 859                 targetPeer = mouseDownTarget[targetIdx];
 860                 mouseClickButtons &= ~modifiers;
 861             } else if (id == MouseEvent.MOUSE_RELEASED) {
 862                 // TODO: currently, mouse released event goes to the same component
 863                 // that received corresponding mouse pressed event. For most cases,
 864                 // it's OK, however, we need to make sure that our behavior is consistent
 865                 // with 1.6 for cases where component in question have been
 866                 // hidden/removed in between of mouse pressed/released events.
 867                 targetPeer = mouseDownTarget[targetIdx];
 868 
 869                 if ((modifiers & eventButtonMask) == 0) {
 870                     mouseDownTarget[targetIdx] = null;
 871                 }
 872 
 873                 // mouseClickButtons is updated below, after MOUSE_CLICK is sent
 874             }
 875 
 876             if (targetPeer == null) {
 877                 //TODO This can happen if this window is invisible. this is correct behavior in this case?
 878                 targetPeer = this;
 879             }
 880 
 881 
 882             Point lp = targetPeer.windowToLocal(x, y, this);
 883             if (targetPeer.isEnabled()) {
 884                 MouseEvent event = new MouseEvent(targetPeer.getTarget(), id,
 885                                                   when, modifiers, lp.x, lp.y,
 886                                                   absX, absY, clickCount,
 887                                                   popupTrigger, button);
 888                 postEvent(event);
 889             }
 890 
 891             if (id == MouseEvent.MOUSE_RELEASED) {
 892                 if ((mouseClickButtons & eventButtonMask) != 0
 893                     && targetPeer.isEnabled()) {
 894                     postEvent(new MouseEvent(targetPeer.getTarget(),
 895                                              MouseEvent.MOUSE_CLICKED,
 896                                              when, modifiers,
 897                                              lp.x, lp.y, absX, absY,
 898                                              clickCount, popupTrigger, button));
 899                 }
 900                 mouseClickButtons &= ~eventButtonMask;
 901             }
 902         }
 903         notifyUpdateCursor();
 904     }
 905 
 906     private void generateMouseEnterExitEventsForComponents(long when,
 907             int button, int x, int y, int screenX, int screenY,
 908             int modifiers, int clickCount, boolean popupTrigger,
 909             final LWComponentPeer<?, ?> targetPeer) {
 910 
 911         if (!isMouseOver || targetPeer == lastMouseEventPeer) {
 912             return;
 913         }
 914 
 915         // Generate Mouse Exit for components
 916         if (lastMouseEventPeer != null && lastMouseEventPeer.isEnabled()) {
 917             Point oldp = lastMouseEventPeer.windowToLocal(x, y, this);
 918             Component target = lastMouseEventPeer.getTarget();
 919             postMouseExitedEvent(target, when, modifiers, oldp, screenX, screenY,
 920                     clickCount, popupTrigger, button);
 921         }
 922         lastCommonMouseEventPeer = targetPeer;
 923         lastMouseEventPeer = targetPeer;
 924 
 925         // Generate Mouse Enter for components
 926         if (targetPeer != null && targetPeer.isEnabled()) {
 927             Point newp = targetPeer.windowToLocal(x, y, this);
 928             Component target = targetPeer.getTarget();
 929             postMouseEnteredEvent(target, when, modifiers, newp, screenX, screenY, clickCount, popupTrigger, button);
 930         }
 931     }
 932 
 933     private void postMouseEnteredEvent(Component target, long when, int modifiers,
 934                                        Point loc, int xAbs, int yAbs,
 935                                        int clickCount, boolean popupTrigger, int button) {
 936 
 937         updateSecurityWarningVisibility();
 938 
 939         postEvent(new MouseEvent(target,
 940                 MouseEvent.MOUSE_ENTERED,
 941                 when, modifiers,
 942                 loc.x, loc.y, xAbs, yAbs,
 943                 clickCount, popupTrigger, button));
 944     }
 945 
 946     private void postMouseExitedEvent(Component target, long when, int modifiers,
 947                                       Point loc, int xAbs, int yAbs,
 948                                       int clickCount, boolean popupTrigger, int button) {
 949 
 950         updateSecurityWarningVisibility();
 951 
 952         postEvent(new MouseEvent(target,
 953                 MouseEvent.MOUSE_EXITED,
 954                 when, modifiers,
 955                 loc.x, loc.y, xAbs, yAbs,
 956                 clickCount, popupTrigger, button));
 957     }
 958 
 959     @Override
 960     public void notifyMouseWheelEvent(long when, int x, int y, int absX,
 961                                       int absY, int modifiers, int scrollType,
 962                                       int scrollAmount, int wheelRotation,
 963                                       double preciseWheelRotation, byte[] bdata)
 964     {
 965         // TODO: could we just use the last mouse event target here?
 966         Rectangle r = getBounds();
 967         // findPeerAt() expects parent coordinates
 968         final LWComponentPeer<?, ?> targetPeer = findPeerAt(r.x + x, r.y + y);
 969         if (targetPeer == null || !targetPeer.isEnabled()) {
 970             return;
 971         }
 972 
 973         Point lp = targetPeer.windowToLocal(x, y, this);
 974         // TODO: fill "bdata" member of AWTEvent
 975         postEvent(new MouseWheelEvent(targetPeer.getTarget(),
 976                                       MouseEvent.MOUSE_WHEEL,
 977                                       when, modifiers,
 978                                       lp.x, lp.y,
 979                                       absX, absY, /* absX, absY */
 980                                       0 /* clickCount */, false /* popupTrigger */,
 981                                       scrollType, scrollAmount,
 982                                       wheelRotation, preciseWheelRotation));
 983     }
 984 
 985     /*
 986      * Called by the delegate when a key is pressed.
 987      */
 988     @Override
 989     public void notifyKeyEvent(int id, long when, int modifiers,
 990                                int keyCode, char keyChar, int keyLocation)
 991     {
 992         LWKeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
 993         Component focusOwner = kfmPeer.getCurrentFocusOwner();
 994 
 995         if (focusOwner == null) {
 996             focusOwner = kfmPeer.getCurrentFocusedWindow();
 997             if (focusOwner == null) {
 998                 focusOwner = this.getTarget();
 999             }
1000         }
1001 
1002         KeyEvent keyEvent = new KeyEvent(focusOwner, id, when, modifiers,
1003             keyCode, keyChar, keyLocation);
1004         AWTAccessor.getKeyEventAccessor().setExtendedKeyCode(keyEvent,
1005                 (keyChar == KeyEvent.CHAR_UNDEFINED) ? keyCode
1006                 : ExtendedKeyCodes.getExtendedKeyCodeForChar(keyChar));
1007         postEvent(keyEvent);
1008     }
1009 
1010     // ---- UTILITY METHODS ---- //
1011 
1012     private void activateDisplayListener() {
1013         final GraphicsEnvironment ge =
1014                 GraphicsEnvironment.getLocalGraphicsEnvironment();
1015         ((SunGraphicsEnvironment) ge).addDisplayChangedListener(this);
1016     }
1017 
1018     private void deactivateDisplayListener() {
1019         final GraphicsEnvironment ge =
1020                 GraphicsEnvironment.getLocalGraphicsEnvironment();
1021         ((SunGraphicsEnvironment) ge).removeDisplayChangedListener(this);
1022     }
1023 
1024     private void postWindowStateChangedEvent(int newWindowState) {
1025         if (getTarget() instanceof Frame) {
1026             AWTAccessor.getFrameAccessor().setExtendedState(
1027                     (Frame)getTarget(), newWindowState);
1028         }
1029 
1030         WindowEvent stateChangedEvent = new WindowEvent(getTarget(),
1031                 WindowEvent.WINDOW_STATE_CHANGED,
1032                 windowState, newWindowState);
1033         postEvent(stateChangedEvent);
1034         windowState = newWindowState;
1035 
1036         updateSecurityWarningVisibility();
1037     }
1038 
1039     private static int getGraphicsConfigScreen(GraphicsConfiguration gc) {
1040         // TODO: this method can be implemented in a more
1041         // efficient way by forwarding to the delegate
1042         GraphicsDevice gd = gc.getDevice();
1043         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
1044         GraphicsDevice[] gds = ge.getScreenDevices();
1045         for (int i = 0; i < gds.length; i++) {
1046             if (gds[i] == gd) {
1047                 return i;
1048             }
1049         }
1050         // Should never happen if gc is a screen device config
1051         return 0;
1052     }
1053 
1054     /*
1055      * This method is called when window's graphics config is changed from
1056      * the app code (e.g. when the window is made non-opaque) or when
1057      * the window is moved to another screen by user.
1058      *
1059      * Returns true if the graphics config has been changed, false otherwise.
1060      */
1061     private boolean setGraphicsConfig(GraphicsConfiguration gc) {
1062         synchronized (getStateLock()) {
1063             if (graphicsConfig == gc) {
1064                 return false;
1065             }
1066             // If window's graphics config is changed from the app code, the
1067             // config correspond to the same device as before; when the window
1068             // is moved by user, graphicsDevice is updated in notifyReshape().
1069             // In either case, there's nothing to do with screenOn here
1070             graphicsConfig = gc;
1071         }
1072         // SurfaceData is replaced later in updateGraphicsData()
1073         return true;
1074     }
1075 
1076     /**
1077      * Returns true if the GraphicsDevice has been changed, false otherwise.
1078      */
1079     public boolean updateGraphicsDevice() {
1080         GraphicsDevice newGraphicsDevice = platformWindow.getGraphicsDevice();
1081         synchronized (getStateLock()) {
1082             if (graphicsDevice == newGraphicsDevice) {
1083                 return false;
1084             }
1085             graphicsDevice = newGraphicsDevice;
1086         }
1087 
1088         final GraphicsConfiguration newGC = newGraphicsDevice.getDefaultConfiguration();
1089 
1090         if (!setGraphicsConfig(newGC)) return false;
1091 
1092         SunToolkit.executeOnEventHandlerThread(getTarget(), new Runnable() {
1093             public void run() {
1094                 AWTAccessor.getComponentAccessor().setGraphicsConfiguration(getTarget(), newGC);
1095             }
1096         });
1097         return true;
1098     }
1099 
1100     @Override
1101     public final void displayChanged() {
1102         if (updateGraphicsDevice()) {
1103             updateMinimumSize();
1104             if (!isMaximizedBoundsSet()) {
1105                 setPlatformMaximizedBounds(getDefaultMaximizedBounds());
1106             }
1107         }
1108         // Replace surface unconditionally, because internal state of the
1109         // GraphicsDevice could be changed.
1110         replaceSurfaceData();
1111         repaintPeer();
1112     }
1113 
1114     @Override
1115     public final void paletteChanged() {
1116         // components do not need to react to this event.
1117     }
1118 
1119     /*
1120      * May be called by delegate to provide SD to Java2D code.
1121      */
1122     public SurfaceData getSurfaceData() {
1123         synchronized (surfaceDataLock) {
1124             return surfaceData;
1125         }
1126     }
1127 
1128     private void replaceSurfaceData() {
1129         replaceSurfaceData(true);
1130     }
1131 
1132     private void replaceSurfaceData(final boolean blit) {
1133         synchronized (surfaceDataLock) {
1134             final SurfaceData oldData = getSurfaceData();
1135             surfaceData = platformWindow.replaceSurfaceData();
1136             final Rectangle size = getSize();
1137             if (getSurfaceData() != null && oldData != getSurfaceData()) {
1138                 clearBackground(size.width, size.height);
1139             }
1140 
1141             if (blit) {
1142                 blitSurfaceData(oldData, getSurfaceData());
1143             }
1144 
1145             if (oldData != null && oldData != getSurfaceData()) {
1146                 // TODO: drop oldData for D3D/WGL pipelines
1147                 // This can only happen when this peer is being created
1148                 oldData.flush();
1149             }
1150         }
1151         flushOnscreenGraphics();
1152     }
1153 
1154     private void blitSurfaceData(final SurfaceData src, final SurfaceData dst) {
1155         //TODO blit. proof-of-concept
1156         if (src != dst && src != null && dst != null
1157             && !(dst instanceof NullSurfaceData)
1158             && !(src instanceof NullSurfaceData)
1159             && src.getSurfaceType().equals(dst.getSurfaceType())
1160             && src.getDefaultScaleX() == dst.getDefaultScaleX()
1161             && src.getDefaultScaleY() == dst.getDefaultScaleY())
1162         {
1163             final Rectangle size = src.getBounds();
1164             final Blit blit = Blit.locate(src.getSurfaceType(),
1165                                           CompositeType.Src,
1166                                           dst.getSurfaceType());
1167             if (blit != null) {
1168                 blit.Blit(src, dst, AlphaComposite.Src, null, 0, 0, 0, 0,
1169                           size.width, size.height);
1170             }
1171         }
1172     }
1173 
1174     /**
1175      * Request the window insets from the delegate and compares it with the
1176      * current one. This method is mostly called by the delegate, e.g. when the
1177      * window state is changed and insets should be recalculated.
1178      * <p/>
1179      * This method may be called on the toolkit thread.
1180      */
1181     public final boolean updateInsets(final Insets newInsets) {
1182         synchronized (getStateLock()) {
1183             if (insets.equals(newInsets)) {
1184                 return false;
1185             }
1186             insets = newInsets;
1187         }
1188         return true;
1189     }
1190 
1191     public static LWWindowPeer getWindowUnderCursor() {
1192         return lastCommonMouseEventPeer != null ? lastCommonMouseEventPeer.getWindowPeerOrSelf() : null;
1193     }
1194 
1195     public static LWComponentPeer<?, ?> getPeerUnderCursor() {
1196         return lastCommonMouseEventPeer;
1197     }
1198 
1199     /*
1200      * Requests platform to set native focus on a frame/dialog.
1201      * In case of a simple window, triggers appropriate java focus change.
1202      */
1203     public boolean requestWindowFocus(FocusEvent.Cause cause) {
1204         if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1205             focusLog.fine("requesting native focus to " + this);
1206         }
1207 
1208         if (!focusAllowedFor()) {
1209             focusLog.fine("focus is not allowed");
1210             return false;
1211         }
1212 
1213         if (platformWindow.rejectFocusRequest(cause)) {
1214             return false;
1215         }
1216 
1217         AppContext targetAppContext = AWTAccessor.getComponentAccessor().getAppContext(getTarget());
1218         KeyboardFocusManager kfm = AWTAccessor.getKeyboardFocusManagerAccessor()
1219                 .getCurrentKeyboardFocusManager(targetAppContext);
1220         Window currentActive = kfm.getActiveWindow();
1221 
1222 
1223         Window opposite = LWKeyboardFocusManagerPeer.getInstance().
1224             getCurrentFocusedWindow();
1225 
1226         // Make the owner active window.
1227         if (isSimpleWindow()) {
1228             LWWindowPeer owner = getOwnerFrameDialog(this);
1229 
1230             // If owner is not natively active, request native
1231             // activation on it w/o sending events up to java.
1232             if (owner != null && !owner.platformWindow.isActive()) {
1233                 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1234                     focusLog.fine("requesting native focus to the owner " + owner);
1235                 }
1236                 LWWindowPeer currentActivePeer = currentActive == null ? null :
1237                 (LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(
1238                         currentActive);
1239 
1240                 // Ensure the opposite is natively active and suppress sending events.
1241                 if (currentActivePeer != null && currentActivePeer.platformWindow.isActive()) {
1242                     if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1243                         focusLog.fine("the opposite is " + currentActivePeer);
1244                     }
1245                     currentActivePeer.skipNextFocusChange = true;
1246                 }
1247                 owner.skipNextFocusChange = true;
1248 
1249                 owner.platformWindow.requestWindowFocus();
1250             }
1251 
1252             // DKFM will synthesize all the focus/activation events correctly.
1253             changeFocusedWindow(true, opposite);
1254             return true;
1255 
1256         // In case the toplevel is active but not focused, change focus directly,
1257         // as requesting native focus on it will not have effect.
1258         } else if (getTarget() == currentActive && !getTarget().hasFocus()) {
1259 
1260             changeFocusedWindow(true, opposite);
1261             return true;
1262         }
1263 
1264         return platformWindow.requestWindowFocus();
1265     }
1266 
1267     protected boolean focusAllowedFor() {
1268         Window window = getTarget();
1269         // TODO: check if modal blocked
1270         return window.isVisible() && window.isEnabled() && isFocusableWindow();
1271     }
1272 
1273     private boolean isFocusableWindow() {
1274         boolean focusable  = targetFocusable;
1275         if (isSimpleWindow()) {
1276             LWWindowPeer ownerPeer = getOwnerFrameDialog(this);
1277             if (ownerPeer == null) {
1278                 return false;
1279             }
1280             return focusable && ownerPeer.targetFocusable;
1281         }
1282         return focusable;
1283     }
1284 
1285     public boolean isSimpleWindow() {
1286         Window window = getTarget();
1287         return !(window instanceof Dialog || window instanceof Frame);
1288     }
1289 
1290     @Override
1291     public void emulateActivation(boolean activate) {
1292         changeFocusedWindow(activate, null);
1293     }
1294 
1295     @SuppressWarnings("deprecation")
1296     private boolean isOneOfOwnersOf(LWWindowPeer peer) {
1297         Window owner = (peer != null ? peer.getTarget().getOwner() : null);
1298         while (owner != null) {
1299             final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
1300             if (acc.getPeer(owner) == this) {
1301                 return true;
1302             }
1303             owner = owner.getOwner();
1304         }
1305         return false;
1306     }
1307 
1308     /*
1309      * Changes focused window on java level.
1310      */
1311     protected void changeFocusedWindow(boolean becomesFocused, Window opposite) {
1312         if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1313             focusLog.fine((becomesFocused?"gaining":"loosing") + " focus window: " + this);
1314         }
1315         if (skipNextFocusChange) {
1316             focusLog.fine("skipping focus change");
1317             skipNextFocusChange = false;
1318             return;
1319         }
1320         if (!isFocusableWindow() && becomesFocused) {
1321             focusLog.fine("the window is not focusable");
1322             return;
1323         }
1324         if (becomesFocused) {
1325             synchronized (getPeerTreeLock()) {
1326                 if (blocker != null) {
1327                     if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {
1328                         focusLog.finest("the window is blocked by " + blocker);
1329                     }
1330                     return;
1331                 }
1332             }
1333         }
1334 
1335         // Note, the method is not called:
1336         // - when the opposite (gaining focus) window is an owned/owner window.
1337         // - for a simple window in any case.
1338         if (!becomesFocused &&
1339             (isGrabbing() || this.isOneOfOwnersOf(grabbingWindow)))
1340         {
1341             if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
1342                 focusLog.fine("ungrabbing on " + grabbingWindow);
1343             }
1344             // ungrab a simple window if its owner looses activation.
1345             grabbingWindow.ungrab();
1346         }
1347 
1348         KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
1349 
1350         if (!becomesFocused && kfmPeer.getCurrentFocusedWindow() != getTarget()) {
1351             // late window focus lost event - ingoring
1352             return;
1353         }
1354 
1355         kfmPeer.setCurrentFocusedWindow(becomesFocused ? getTarget() : null);
1356 
1357         int eventID = becomesFocused ? WindowEvent.WINDOW_GAINED_FOCUS : WindowEvent.WINDOW_LOST_FOCUS;
1358         WindowEvent windowEvent = new TimedWindowEvent(getTarget(), eventID, opposite, System.currentTimeMillis());
1359 
1360         // TODO: wrap in SequencedEvent
1361         postEvent(windowEvent);
1362     }
1363 
1364     /*
1365      * Retrieves the owner of the peer.
1366      * Note: this method returns the owner which can be activated, (i.e. the instance
1367      * of Frame or Dialog may be returned).
1368      */
1369     static LWWindowPeer getOwnerFrameDialog(LWWindowPeer peer) {
1370         Window owner = (peer != null ? peer.getTarget().getOwner() : null);
1371         while (owner != null && !(owner instanceof Frame || owner instanceof Dialog)) {
1372             owner = owner.getOwner();
1373         }
1374         return owner == null ? null : AWTAccessor.getComponentAccessor()
1375                                                  .getPeer(owner);
1376     }
1377 
1378     /**
1379      * Returns the foremost modal blocker of this window, or null.
1380      */
1381     public LWWindowPeer getBlocker() {
1382         synchronized (getPeerTreeLock()) {
1383             LWWindowPeer blocker = this.blocker;
1384             if (blocker == null) {
1385                 return null;
1386             }
1387             while (blocker.blocker != null) {
1388                 blocker = blocker.blocker;
1389             }
1390             return blocker;
1391         }
1392     }
1393 
1394     @Override
1395     public void enterFullScreenMode() {
1396         platformWindow.enterFullScreenMode();
1397         updateSecurityWarningVisibility();
1398     }
1399 
1400     @Override
1401     public void exitFullScreenMode() {
1402         platformWindow.exitFullScreenMode();
1403         updateSecurityWarningVisibility();
1404     }
1405 
1406     public long getLayerPtr() {
1407         return getPlatformWindow().getLayerPtr();
1408     }
1409 
1410     void grab() {
1411         if (grabbingWindow != null && !isGrabbing()) {
1412             grabbingWindow.ungrab();
1413         }
1414         grabbingWindow = this;
1415     }
1416 
1417     final void ungrab(boolean doPost) {
1418         if (isGrabbing()) {
1419             grabbingWindow = null;
1420             if (doPost) {
1421                 postEvent(new UngrabEvent(getTarget()));
1422             }
1423         }
1424     }
1425 
1426     void ungrab() {
1427         ungrab(true);
1428     }
1429 
1430     private boolean isGrabbing() {
1431         return this == grabbingWindow;
1432     }
1433 
1434     public PeerType getPeerType() {
1435         return peerType;
1436     }
1437 
1438     public void updateSecurityWarningVisibility() {
1439         if (warningWindow == null) {
1440             return;
1441         }
1442 
1443         if (!isVisible()) {
1444             return; // The warning window should already be hidden.
1445         }
1446 
1447         boolean show = false;
1448 
1449         if (!platformWindow.isFullScreenMode()) {
1450             if (isVisible()) {
1451                 if (LWKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() ==
1452                         getTarget()) {
1453                     show = true;
1454                 }
1455 
1456                 if (platformWindow.isUnderMouse() || warningWindow.isUnderMouse()) {
1457                     show = true;
1458                 }
1459             }
1460         }
1461 
1462         warningWindow.setVisible(show, true);
1463     }
1464 
1465     @Override
1466     public String toString() {
1467         return super.toString() + " [target is " + getTarget() + "]";
1468     }
1469 }