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 }