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