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