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