Print this page
rev 54883 : JDK-8220154 Improve java2d rendering performance on macOS by using Metal framework
Split |
Close |
Expand all |
Collapse all |
--- old/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java
+++ new/src/java.desktop/macosx/classes/sun/lwawt/LWComponentPeer.java
1 1 /*
2 2 * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 package sun.lwawt;
27 27
28 28 import java.awt.AWTEvent;
29 29 import java.awt.AWTException;
30 30 import java.awt.BufferCapabilities;
31 31 import java.awt.Color;
32 32 import java.awt.Component;
33 33 import java.awt.Container;
34 34 import java.awt.Cursor;
35 35 import java.awt.Dimension;
36 36 import java.awt.Font;
37 37 import java.awt.FontMetrics;
38 38 import java.awt.Graphics;
39 39 import java.awt.GraphicsConfiguration;
40 40 import java.awt.Image;
41 41 import java.awt.Point;
42 42 import java.awt.Rectangle;
43 43 import java.awt.Toolkit;
44 44 import java.awt.Window;
45 45 import java.awt.dnd.DropTarget;
46 46 import java.awt.dnd.peer.DropTargetPeer;
47 47 import java.awt.event.AWTEventListener;
48 48 import java.awt.event.ComponentEvent;
49 49 import java.awt.event.FocusEvent;
50 50 import java.awt.event.InputEvent;
51 51 import java.awt.event.KeyEvent;
52 52 import java.awt.event.MouseEvent;
53 53 import java.awt.event.MouseWheelEvent;
54 54 import java.awt.event.PaintEvent;
55 55 import java.awt.image.ColorModel;
56 56 import java.awt.image.ImageObserver;
57 57 import java.awt.image.ImageProducer;
58 58 import java.awt.image.VolatileImage;
59 59 import java.awt.peer.ComponentPeer;
60 60 import java.awt.peer.ContainerPeer;
61 61 import java.awt.peer.KeyboardFocusManagerPeer;
62 62 import java.lang.reflect.Field;
63 63 import java.security.AccessController;
64 64 import java.security.PrivilegedAction;
65 65 import java.util.concurrent.atomic.AtomicBoolean;
66 66
67 67 import javax.swing.JComponent;
68 68 import javax.swing.RepaintManager;
69 69 import javax.swing.SwingUtilities;
↓ open down ↓ |
69 lines elided |
↑ open up ↑ |
70 70
71 71 import com.sun.java.swing.SwingUtilities3;
72 72 import sun.awt.AWTAccessor;
73 73 import sun.awt.PaintEventDispatcher;
74 74 import sun.awt.RepaintArea;
75 75 import sun.awt.SunToolkit;
76 76 import sun.awt.event.IgnorePaintEvent;
77 77 import sun.awt.image.SunVolatileImage;
78 78 import sun.awt.image.ToolkitImage;
79 79 import sun.java2d.SunGraphics2D;
80 +import sun.java2d.macos.MacOSFlags;
81 +import sun.java2d.metal.MTLRenderQueue;
80 82 import sun.java2d.opengl.OGLRenderQueue;
81 83 import sun.java2d.pipe.Region;
84 +import sun.java2d.pipe.RenderQueue;
82 85 import sun.util.logging.PlatformLogger;
83 86
84 87 public abstract class LWComponentPeer<T extends Component, D extends JComponent>
85 88 implements ComponentPeer, DropTargetPeer
86 89 {
87 90 private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWComponentPeer");
88 91
89 92 /**
90 93 * State lock is to be used for modifications to this peer's fields (e.g.
91 94 * bounds, background, font, etc.) It should be the last lock in the lock
92 95 * chain
93 96 */
94 97 private final Object stateLock = new Object();
95 98
96 99 /**
97 100 * The lock to operate with the peers hierarchy. AWT tree lock is not used
98 101 * as there are many peers related ops to be done on the toolkit thread, and
99 102 * we don't want to depend on a public lock on this thread
100 103 */
101 104 private static final Object peerTreeLock = new Object();
102 105
103 106 /**
104 107 * The associated AWT object.
105 108 */
106 109 private final T target;
107 110
108 111 /**
109 112 * Container peer. It may not be the peer of the target's direct parent, for
110 113 * example, in the case of hw/lw mixing. However, let's skip this scenario
111 114 * for the time being. We also assume the container peer is not null, which
112 115 * might also be false if addNotify() is called for a component outside of
113 116 * the hierarchy. The exception is LWWindowPeers: their containers are
114 117 * always null
115 118 */
116 119 private final LWContainerPeer<?, ?> containerPeer;
117 120
118 121 /**
119 122 * Handy reference to the top-level window peer. Window peer is borrowed
120 123 * from the containerPeer in constructor, and should also be updated when
121 124 * the component is reparented to another container
122 125 */
123 126 private final LWWindowPeer windowPeer;
124 127
125 128 private final AtomicBoolean disposed = new AtomicBoolean(false);
126 129
127 130 // Bounds are relative to parent peer
128 131 private final Rectangle bounds = new Rectangle();
129 132 private Region region;
130 133
131 134 // Component state. Should be accessed under the state lock
132 135 private boolean visible = false;
133 136 private boolean enabled = true;
134 137
135 138 private Color background;
136 139 private Color foreground;
137 140 private Font font;
138 141
139 142 /**
140 143 * Paint area to coalesce all the paint events and store the target dirty
141 144 * area.
142 145 */
143 146 private final RepaintArea targetPaintArea;
144 147
145 148 // private volatile boolean paintPending;
146 149 private volatile boolean isLayouting;
147 150
148 151 private final D delegate;
149 152 private Container delegateContainer;
150 153 private Component delegateDropTarget;
151 154 private final Object dropTargetLock = new Object();
152 155
153 156 private int fNumDropTargets = 0;
154 157 private PlatformDropTarget fDropTarget = null;
155 158
156 159 private final PlatformComponent platformComponent;
157 160
158 161 /**
159 162 * Character with reasonable value between the minimum width and maximum.
160 163 */
161 164 static final char WIDE_CHAR = '0';
162 165
163 166 /**
164 167 * The back buffer provide user with a BufferStrategy.
165 168 */
166 169 private Image backBuffer;
167 170
168 171 /**
169 172 * All Swing delegates use delegateContainer as a parent. This container
170 173 * intentionally do not use parent of the peer.
171 174 */
172 175 @SuppressWarnings("serial")// Safe: outer class is non-serializable.
173 176 private final class DelegateContainer extends Container {
174 177 {
175 178 enableEvents(0xFFFFFFFF);
176 179 }
177 180
178 181 @Override
179 182 public boolean isLightweight() {
180 183 return false;
181 184 }
182 185
183 186 @Override
184 187 public Point getLocation() {
185 188 return getLocationOnScreen();
186 189 }
187 190
188 191 @Override
189 192 public Point getLocationOnScreen() {
190 193 return LWComponentPeer.this.getLocationOnScreen();
191 194 }
192 195
193 196 @Override
194 197 public int getX() {
195 198 return getLocation().x;
196 199 }
197 200
198 201 @Override
199 202 public int getY() {
200 203 return getLocation().y;
201 204 }
202 205 }
203 206
204 207 LWComponentPeer(final T target, final PlatformComponent platformComponent) {
205 208 targetPaintArea = new LWRepaintArea();
206 209 this.target = target;
207 210 this.platformComponent = platformComponent;
208 211
209 212 // Container peer is always null for LWWindowPeers, so
210 213 // windowPeer is always null for them as well. On the other
211 214 // hand, LWWindowPeer shouldn't use windowPeer at all
212 215 final Container container = SunToolkit.getNativeContainer(target);
213 216 containerPeer = (LWContainerPeer) LWToolkit.targetToPeer(container);
214 217 windowPeer = containerPeer != null ? containerPeer.getWindowPeerOrSelf()
215 218 : null;
216 219 // don't bother about z-order here as updateZOrder()
217 220 // will be called from addNotify() later anyway
218 221 if (containerPeer != null) {
219 222 containerPeer.addChildPeer(this);
220 223 }
221 224
222 225 // the delegate must be created after the target is set
223 226 AWTEventListener toolkitListener = null;
224 227 synchronized (Toolkit.getDefaultToolkit()) {
225 228 try {
226 229 toolkitListener = getToolkitAWTEventListener();
227 230 setToolkitAWTEventListener(null);
228 231
229 232 synchronized (getDelegateLock()) {
230 233 delegate = createDelegate();
231 234 if (delegate != null) {
232 235 delegate.setVisible(false);
233 236 delegateContainer = new DelegateContainer();
234 237 delegateContainer.add(delegate);
235 238 delegateContainer.addNotify();
236 239 delegate.addNotify();
237 240 resetColorsAndFont(delegate);
238 241 delegate.setOpaque(true);
239 242 } else {
240 243 return;
241 244 }
242 245 }
243 246
244 247 } finally {
245 248 setToolkitAWTEventListener(toolkitListener);
246 249 }
247 250
248 251 // todo swing: later on we will probably have one global RM
249 252 SwingUtilities3.setDelegateRepaintManager(delegate, new RepaintManager() {
250 253 @Override
251 254 public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {
252 255 repaintPeer(SwingUtilities.convertRectangle(
253 256 c, new Rectangle(x, y, w, h), getDelegate()));
254 257 }
255 258 });
256 259 }
257 260 }
258 261
259 262 /**
260 263 * This method must be called under Toolkit.getDefaultToolkit() lock
261 264 * and followed by setToolkitAWTEventListener()
262 265 */
263 266 protected final AWTEventListener getToolkitAWTEventListener() {
264 267 return AccessController.doPrivileged(new PrivilegedAction<AWTEventListener>() {
265 268 public AWTEventListener run() {
266 269 Toolkit toolkit = Toolkit.getDefaultToolkit();
267 270 try {
268 271 Field field = Toolkit.class.getDeclaredField("eventListener");
269 272 field.setAccessible(true);
270 273 return (AWTEventListener) field.get(toolkit);
271 274 } catch (Exception e) {
272 275 throw new InternalError(e.toString());
273 276 }
274 277 }
275 278 });
276 279 }
277 280
278 281 protected final void setToolkitAWTEventListener(final AWTEventListener listener) {
279 282 AccessController.doPrivileged(new PrivilegedAction<Void>() {
280 283 public Void run() {
281 284 Toolkit toolkit = Toolkit.getDefaultToolkit();
282 285 try {
283 286 Field field = Toolkit.class.getDeclaredField("eventListener");
284 287 field.setAccessible(true);
285 288 field.set(toolkit, listener);
286 289 } catch (Exception e) {
287 290 throw new InternalError(e.toString());
288 291 }
289 292 return null;
290 293 }
291 294 });
292 295 }
293 296
294 297 /**
295 298 * This method is called under getDelegateLock().
296 299 * Overridden in subclasses.
297 300 */
298 301 D createDelegate() {
299 302 return null;
300 303 }
301 304
302 305 final D getDelegate() {
303 306 return delegate;
304 307 }
305 308
306 309 /**
307 310 * This method should be called under getDelegateLock().
308 311 */
309 312 Component getDelegateFocusOwner() {
310 313 return getDelegate();
311 314 }
312 315
313 316 /**
314 317 * Initializes this peer. The call to initialize() is not placed to
315 318 * LWComponentPeer ctor to let the subclass ctor to finish completely first.
316 319 * Instead, it's the LWToolkit object who is responsible for initialization.
317 320 * Note that we call setVisible() at the end of initialization.
318 321 */
319 322 public final void initialize() {
320 323 platformComponent.initialize(getPlatformWindow());
321 324 initializeImpl();
322 325 setVisible(target.isVisible());
323 326 }
324 327
325 328 /**
326 329 * Fetching general properties from the target. Should be overridden in
327 330 * subclasses to initialize specific peers properties.
328 331 */
329 332 void initializeImpl() {
330 333 // note that these methods can be overridden by the user and
331 334 // can return some strange values like null.
332 335 setBackground(target.getBackground());
333 336 setForeground(target.getForeground());
334 337 setFont(target.getFont());
335 338 setBounds(target.getBounds());
336 339 setEnabled(target.isEnabled());
337 340 }
338 341
339 342 private static void resetColorsAndFont(final Container c) {
340 343 c.setBackground(null);
341 344 c.setForeground(null);
342 345 c.setFont(null);
343 346 for (int i = 0; i < c.getComponentCount(); i++) {
344 347 resetColorsAndFont((Container) c.getComponent(i));
345 348 }
346 349 }
347 350
348 351 final Object getStateLock() {
349 352 return stateLock;
350 353 }
351 354
352 355 /**
353 356 * Synchronize all operations with the Swing delegates under AWT tree lock,
354 357 * using a new separate lock to synchronize access to delegates may lead
355 358 * deadlocks. Think of it as a 'virtual EDT'.
356 359 *
357 360 * @return DelegateLock
358 361 */
359 362 final Object getDelegateLock() {
360 363 return getTarget().getTreeLock();
361 364 }
362 365
363 366 protected static final Object getPeerTreeLock() {
364 367 return peerTreeLock;
365 368 }
366 369
367 370 public final T getTarget() {
368 371 return target;
369 372 }
370 373
371 374 // Just a helper method
372 375 // Returns the window peer or null if this is a window peer
373 376 protected final LWWindowPeer getWindowPeer() {
374 377 return windowPeer;
375 378 }
376 379
377 380 // Returns the window peer or 'this' if this is a window peer
378 381 protected LWWindowPeer getWindowPeerOrSelf() {
379 382 return getWindowPeer();
380 383 }
381 384
382 385 // Just a helper method
383 386 protected final LWContainerPeer<?, ?> getContainerPeer() {
384 387 return containerPeer;
385 388 }
386 389
387 390 public PlatformWindow getPlatformWindow() {
388 391 LWWindowPeer windowPeer = getWindowPeer();
389 392 return windowPeer.getPlatformWindow();
390 393 }
391 394
392 395 // ---- PEER METHODS ---- //
393 396
394 397 // Just a helper method
395 398 public LWToolkit getLWToolkit() {
396 399 return LWToolkit.getLWToolkit();
397 400 }
398 401
399 402 @Override
400 403 public final void dispose() {
401 404 if (disposed.compareAndSet(false, true)) {
402 405 disposeImpl();
403 406 }
404 407 }
405 408
406 409 protected void disposeImpl() {
407 410 destroyBuffers();
408 411 LWContainerPeer<?, ?> cp = getContainerPeer();
409 412 if (cp != null) {
410 413 cp.removeChildPeer(this);
411 414 }
412 415 platformComponent.dispose();
413 416 LWToolkit.targetDisposedPeer(getTarget(), this);
414 417 }
415 418
416 419 public final boolean isDisposed() {
417 420 return disposed.get();
418 421 }
419 422
420 423 /*
421 424 * GraphicsConfiguration is borrowed from the parent peer. The
422 425 * return value must not be null.
423 426 *
424 427 * Overridden in LWWindowPeer.
425 428 */
426 429 @Override
427 430 public GraphicsConfiguration getGraphicsConfiguration() {
428 431 // Don't check windowPeer for null as it can only happen
429 432 // for windows, but this method is overridden in
430 433 // LWWindowPeer and doesn't call super()
431 434 return getWindowPeer().getGraphicsConfiguration();
432 435 }
433 436
434 437
435 438 // Just a helper method
436 439 public final LWGraphicsConfig getLWGC() {
437 440 return (LWGraphicsConfig) getGraphicsConfiguration();
438 441 }
439 442
440 443 /*
441 444 * Overridden in LWWindowPeer to replace its surface
442 445 * data and back buffer.
443 446 */
444 447 @Override
445 448 public boolean updateGraphicsData(GraphicsConfiguration gc) {
446 449 // TODO: not implemented
447 450 // throw new RuntimeException("Has not been implemented yet.");
448 451 return false;
449 452 }
450 453
451 454 @Override
452 455 public Graphics getGraphics() {
453 456 final Graphics g = getOnscreenGraphics();
454 457 if (g != null) {
455 458 synchronized (getPeerTreeLock()){
456 459 applyConstrain(g);
457 460 }
458 461 }
459 462 return g;
460 463 }
461 464
462 465 /*
463 466 * Peer Graphics is borrowed from the parent peer, while
464 467 * foreground and background colors and font are specific to
465 468 * this peer.
466 469 */
467 470 public final Graphics getOnscreenGraphics() {
468 471 final LWWindowPeer wp = getWindowPeerOrSelf();
469 472 return wp.getOnscreenGraphics(getForeground(), getBackground(),
470 473 getFont());
471 474
472 475 }
473 476
474 477 private void applyConstrain(final Graphics g) {
475 478 final SunGraphics2D sg2d = (SunGraphics2D) g;
476 479 final Rectangle size = localToWindow(getSize());
477 480 sg2d.constrain(size.x, size.y, size.width, size.height, getVisibleRegion());
478 481 }
479 482
480 483 Region getVisibleRegion() {
481 484 return computeVisibleRect(this, getRegion());
482 485 }
483 486
484 487 static final Region computeVisibleRect(final LWComponentPeer<?, ?> c,
485 488 Region region) {
486 489 final LWContainerPeer<?, ?> p = c.getContainerPeer();
487 490 if (p != null) {
488 491 final Rectangle r = c.getBounds();
489 492 region = region.getTranslatedRegion(r.x, r.y);
490 493 region = region.getIntersection(p.getRegion());
491 494 region = region.getIntersection(p.getContentSize());
492 495 region = p.cutChildren(region, c);
493 496 region = computeVisibleRect(p, region);
494 497 region = region.getTranslatedRegion(-r.x, -r.y);
495 498 }
496 499 return region;
497 500 }
498 501
499 502 @Override
500 503 public ColorModel getColorModel() {
501 504 // Is it a correct implementation?
502 505 return getGraphicsConfiguration().getColorModel();
503 506 }
504 507
505 508 public boolean isTranslucent() {
506 509 // Translucent windows of the top level are supported only
507 510 return false;
508 511 }
509 512
510 513 @Override
511 514 public final void createBuffers(int numBuffers, BufferCapabilities caps)
512 515 throws AWTException {
513 516 getLWGC().assertOperationSupported(numBuffers, caps);
514 517 final Image buffer = getLWGC().createBackBuffer(this);
515 518 synchronized (getStateLock()) {
516 519 backBuffer = buffer;
517 520 }
518 521 }
519 522
520 523 @Override
521 524 public final Image getBackBuffer() {
522 525 synchronized (getStateLock()) {
523 526 if (backBuffer != null) {
524 527 return backBuffer;
525 528 }
526 529 }
527 530 throw new IllegalStateException("Buffers have not been created");
528 531 }
529 532
530 533 @Override
531 534 public final void flip(int x1, int y1, int x2, int y2,
532 535 BufferCapabilities.FlipContents flipAction) {
533 536 getLWGC().flip(this, getBackBuffer(), x1, y1, x2, y2, flipAction);
534 537 }
535 538
536 539 @Override
537 540 public final void destroyBuffers() {
538 541 final Image oldBB;
539 542 synchronized (getStateLock()) {
540 543 oldBB = backBuffer;
541 544 backBuffer = null;
542 545 }
543 546 getLWGC().destroyBackBuffer(oldBB);
544 547 }
545 548
546 549 // Helper method
547 550 public void setBounds(Rectangle r) {
548 551 setBounds(r.x, r.y, r.width, r.height, SET_BOUNDS);
549 552 }
550 553
551 554 /**
552 555 * This method could be called on the toolkit thread.
553 556 */
554 557 @Override
555 558 public void setBounds(int x, int y, int w, int h, int op) {
556 559 setBounds(x, y, w, h, op, true, false);
557 560 }
558 561
559 562 protected void setBounds(int x, int y, int w, int h, int op, boolean notify,
560 563 final boolean updateTarget) {
561 564 Rectangle oldBounds;
562 565 synchronized (getStateLock()) {
563 566 oldBounds = new Rectangle(bounds);
564 567 if ((op & (SET_LOCATION | SET_BOUNDS)) != 0) {
565 568 bounds.x = x;
566 569 bounds.y = y;
567 570 }
568 571 if ((op & (SET_SIZE | SET_BOUNDS)) != 0) {
569 572 bounds.width = w;
570 573 bounds.height = h;
571 574 }
572 575 }
573 576 boolean moved = (oldBounds.x != x) || (oldBounds.y != y);
574 577 boolean resized = (oldBounds.width != w) || (oldBounds.height != h);
575 578 if (!moved && !resized) {
576 579 return;
577 580 }
578 581 final D delegate = getDelegate();
579 582 if (delegate != null) {
580 583 synchronized (getDelegateLock()) {
581 584 delegateContainer.setBounds(0, 0, w, h);
582 585 delegate.setBounds(delegateContainer.getBounds());
583 586 // TODO: the following means that the delegateContainer NEVER gets validated. That's WRONG!
584 587 delegate.validate();
585 588 }
586 589 }
587 590
588 591 final Point locationInWindow = localToWindow(0, 0);
589 592 platformComponent.setBounds(locationInWindow.x, locationInWindow.y, w,
590 593 h);
591 594 if (notify) {
592 595 repaintOldNewBounds(oldBounds);
593 596 if (resized) {
594 597 handleResize(w, h, updateTarget);
595 598 }
596 599 if (moved) {
597 600 handleMove(x, y, updateTarget);
598 601 }
599 602 }
600 603 }
601 604
602 605 public final Rectangle getBounds() {
603 606 synchronized (getStateLock()) {
604 607 // Return a copy to prevent subsequent modifications
605 608 return bounds.getBounds();
606 609 }
607 610 }
608 611
609 612 public final Rectangle getSize() {
610 613 synchronized (getStateLock()) {
611 614 // Return a copy to prevent subsequent modifications
612 615 return new Rectangle(bounds.width, bounds.height);
613 616 }
614 617 }
615 618
616 619 @Override
617 620 public Point getLocationOnScreen() {
618 621 Point windowLocation = getWindowPeer().getLocationOnScreen();
619 622 Point locationInWindow = localToWindow(0, 0);
620 623 return new Point(windowLocation.x + locationInWindow.x,
621 624 windowLocation.y + locationInWindow.y);
622 625 }
623 626
624 627 /**
625 628 * Returns the cursor of the peer, which is cursor of the target by default,
626 629 * but peer can override this behavior.
627 630 *
628 631 * @param p Point relative to the peer.
629 632 * @return Cursor of the peer or null if default cursor should be used.
630 633 */
631 634 Cursor getCursor(final Point p) {
632 635 return getTarget().getCursor();
633 636 }
634 637
635 638 @Override
636 639 public void setBackground(final Color c) {
637 640 final Color oldBg = getBackground();
638 641 if (oldBg == c || (oldBg != null && oldBg.equals(c))) {
639 642 return;
640 643 }
641 644 synchronized (getStateLock()) {
642 645 background = c;
643 646 }
644 647 final D delegate = getDelegate();
645 648 if (delegate != null) {
646 649 synchronized (getDelegateLock()) {
647 650 // delegate will repaint the target
648 651 delegate.setBackground(c);
649 652 }
650 653 } else {
651 654 repaintPeer();
652 655 }
653 656 }
654 657
655 658 public final Color getBackground() {
656 659 synchronized (getStateLock()) {
657 660 return background;
658 661 }
659 662 }
660 663
661 664 @Override
662 665 public void setForeground(final Color c) {
663 666 final Color oldFg = getForeground();
664 667 if (oldFg == c || (oldFg != null && oldFg.equals(c))) {
665 668 return;
666 669 }
667 670 synchronized (getStateLock()) {
668 671 foreground = c;
669 672 }
670 673 final D delegate = getDelegate();
671 674 if (delegate != null) {
672 675 synchronized (getDelegateLock()) {
673 676 // delegate will repaint the target
674 677 delegate.setForeground(c);
675 678 }
676 679 } else {
677 680 repaintPeer();
678 681 }
679 682 }
680 683
681 684 protected final Color getForeground() {
682 685 synchronized (getStateLock()) {
683 686 return foreground;
684 687 }
685 688 }
686 689
687 690 @Override
688 691 public void setFont(final Font f) {
689 692 final Font oldF = getFont();
690 693 if (oldF == f || (oldF != null && oldF.equals(f))) {
691 694 return;
692 695 }
693 696 synchronized (getStateLock()) {
694 697 font = f;
695 698 }
696 699 final D delegate = getDelegate();
697 700 if (delegate != null) {
698 701 synchronized (getDelegateLock()) {
699 702 // delegate will repaint the target
700 703 delegate.setFont(f);
701 704 }
702 705 } else {
703 706 repaintPeer();
704 707 }
705 708 }
706 709
707 710 protected final Font getFont() {
708 711 synchronized (getStateLock()) {
709 712 return font;
710 713 }
711 714 }
712 715
713 716 @Override
714 717 public FontMetrics getFontMetrics(final Font f) {
715 718 // Borrow the metrics from the top-level window
716 719 // return getWindowPeer().getFontMetrics(f);
717 720 // Obtain the metrics from the offscreen window where this peer is
718 721 // mostly drawn to.
719 722 // TODO: check for "use platform metrics" settings
720 723 final Graphics g = getOnscreenGraphics();
721 724 if (g != null) {
722 725 try {
723 726 return g.getFontMetrics(f);
724 727 } finally {
725 728 g.dispose();
726 729 }
727 730 }
728 731 synchronized (getDelegateLock()) {
729 732 return delegateContainer.getFontMetrics(f);
730 733 }
731 734 }
732 735
733 736 @Override
734 737 public void setEnabled(final boolean e) {
735 738 boolean status = e;
736 739 final LWComponentPeer<?, ?> cp = getContainerPeer();
737 740 if (cp != null) {
738 741 status &= cp.isEnabled();
739 742 }
740 743 synchronized (getStateLock()) {
741 744 if (enabled == status) {
742 745 return;
743 746 }
744 747 enabled = status;
745 748 }
746 749
747 750 final D delegate = getDelegate();
748 751
749 752 if (delegate != null) {
750 753 synchronized (getDelegateLock()) {
751 754 delegate.setEnabled(status);
752 755 }
753 756 } else {
754 757 repaintPeer();
755 758 }
756 759 }
757 760
758 761 // Helper method
759 762 public final boolean isEnabled() {
760 763 synchronized (getStateLock()) {
761 764 return enabled;
762 765 }
763 766 }
764 767
765 768 @Override
766 769 public void setVisible(final boolean v) {
767 770 synchronized (getStateLock()) {
768 771 if (visible == v) {
769 772 return;
770 773 }
771 774 visible = v;
772 775 }
773 776 setVisibleImpl(v);
774 777 }
775 778
776 779 protected void setVisibleImpl(final boolean v) {
777 780 final D delegate = getDelegate();
778 781
779 782 if (delegate != null) {
780 783 synchronized (getDelegateLock()) {
781 784 delegate.setVisible(v);
782 785 }
783 786 }
784 787 if (visible) {
785 788 repaintPeer();
786 789 } else {
787 790 repaintParent(getBounds());
788 791 }
789 792 }
790 793
791 794 // Helper method
792 795 public final boolean isVisible() {
793 796 synchronized (getStateLock()) {
794 797 return visible;
795 798 }
796 799 }
797 800
798 801 @Override
799 802 public void paint(final Graphics g) {
800 803 getTarget().paint(g);
801 804 }
802 805
803 806 @Override
804 807 public void print(final Graphics g) {
805 808 getTarget().print(g);
806 809 }
807 810
808 811 @Override
809 812 public void reparent(ContainerPeer newContainer) {
810 813 // TODO: not implemented
811 814 throw new UnsupportedOperationException("ComponentPeer.reparent()");
812 815 }
813 816
814 817 @Override
815 818 public boolean isReparentSupported() {
816 819 // TODO: not implemented
817 820 return false;
818 821 }
819 822
820 823 @Override
821 824 public void setZOrder(final ComponentPeer above) {
822 825 LWContainerPeer<?, ?> cp = getContainerPeer();
823 826 // Don't check containerPeer for null as it can only happen
824 827 // for windows, but this method is overridden in
825 828 // LWWindowPeer and doesn't call super()
826 829 cp.setChildPeerZOrder(this, (LWComponentPeer<?, ?>) above);
827 830 }
828 831
829 832 @Override
830 833 public void coalescePaintEvent(PaintEvent e) {
831 834 if (!(e instanceof IgnorePaintEvent)) {
832 835 Rectangle r = e.getUpdateRect();
833 836 if ((r != null) && !r.isEmpty()) {
834 837 targetPaintArea.add(r, e.getID());
835 838 }
836 839 }
837 840 }
838 841
839 842 /*
840 843 * Should be overridden in subclasses which use complex Swing components.
841 844 */
842 845 @Override
843 846 public void layout() {
844 847 // TODO: not implemented
845 848 }
846 849
847 850 @Override
848 851 public boolean isObscured() {
849 852 // TODO: not implemented
850 853 return false;
851 854 }
852 855
853 856 @Override
854 857 public boolean canDetermineObscurity() {
855 858 // TODO: not implemented
856 859 return false;
857 860 }
858 861
859 862 /**
860 863 * Determines the preferred size of the component. By default forwards the
861 864 * request to the Swing helper component. Should be overridden in subclasses
862 865 * if required.
863 866 */
864 867 @Override
865 868 public Dimension getPreferredSize() {
866 869 final Dimension size;
867 870 synchronized (getDelegateLock()) {
868 871 size = getDelegate().getPreferredSize();
869 872 }
870 873 return validateSize(size);
871 874 }
872 875
873 876 /**
874 877 * Determines the minimum size of the component. By default forwards the
875 878 * request to the Swing helper component. Should be overridden in subclasses
876 879 * if required.
877 880 */
878 881 @Override
879 882 public Dimension getMinimumSize() {
880 883 final Dimension size;
881 884 synchronized (getDelegateLock()) {
882 885 size = getDelegate().getMinimumSize();
883 886 }
884 887 return validateSize(size);
885 888 }
886 889
887 890 /**
888 891 * In some situations delegates can return empty minimum/preferred size.
889 892 * (For example: empty JLabel, etc), but awt components never should be
890 893 * empty. In the XPeers or WPeers we use some magic constants, but here we
891 894 * try to use something more useful,
892 895 */
893 896 private Dimension validateSize(final Dimension size) {
894 897 if (size.width == 0 || size.height == 0) {
895 898 final FontMetrics fm = getFontMetrics(getFont());
896 899 size.width = fm.charWidth(WIDE_CHAR);
897 900 size.height = fm.getHeight();
898 901 }
899 902 return size;
900 903 }
901 904
902 905 @Override
903 906 public void updateCursorImmediately() {
904 907 getLWToolkit().getCursorManager().updateCursor();
905 908 }
906 909
907 910 @Override
908 911 public boolean isFocusable() {
909 912 // Overridden in focusable subclasses like buttons
910 913 return false;
911 914 }
912 915
913 916 @Override
914 917 public boolean requestFocus(Component lightweightChild, boolean temporary,
915 918 boolean focusedWindowChangeAllowed, long time,
916 919 FocusEvent.Cause cause)
917 920 {
918 921 if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {
919 922 focusLog.finest("lightweightChild=" + lightweightChild + ", temporary=" + temporary +
920 923 ", focusedWindowChangeAllowed=" + focusedWindowChangeAllowed +
921 924 ", time= " + time + ", cause=" + cause);
922 925 }
923 926 if (LWKeyboardFocusManagerPeer.processSynchronousLightweightTransfer(
924 927 getTarget(), lightweightChild, temporary,
925 928 focusedWindowChangeAllowed, time)) {
926 929 return true;
927 930 }
928 931
929 932 int result = LWKeyboardFocusManagerPeer.shouldNativelyFocusHeavyweight(
930 933 getTarget(), lightweightChild, temporary,
931 934 focusedWindowChangeAllowed, time, cause);
932 935 switch (result) {
933 936 case LWKeyboardFocusManagerPeer.SNFH_FAILURE:
934 937 return false;
935 938 case LWKeyboardFocusManagerPeer.SNFH_SUCCESS_PROCEED:
936 939 Window parentWindow = SunToolkit.getContainingWindow(getTarget());
937 940 if (parentWindow == null) {
938 941 focusLog.fine("request rejected, parentWindow is null");
939 942 LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());
940 943 return false;
941 944 }
942 945 final LWWindowPeer parentPeer =
943 946 AWTAccessor.getComponentAccessor()
944 947 .getPeer(parentWindow);
945 948 if (parentPeer == null) {
946 949 focusLog.fine("request rejected, parentPeer is null");
947 950 LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());
948 951 return false;
949 952 }
950 953
951 954 // A fix for 7145768. Ensure the parent window is currently natively focused.
952 955 // The more evident place to perform this check is in KFM.shouldNativelyFocusHeavyweight,
953 956 // however that is the shared code and this particular problem's reproducibility has
954 957 // platform specifics. So, it was decided to narrow down the fix to lwawt (OSX) in
955 958 // current release. TODO: consider fixing it in the shared code.
956 959 if (!focusedWindowChangeAllowed) {
957 960 LWWindowPeer decoratedPeer = parentPeer.isSimpleWindow() ?
958 961 LWWindowPeer.getOwnerFrameDialog(parentPeer) : parentPeer;
959 962
960 963 if (decoratedPeer == null || !decoratedPeer.getPlatformWindow().isActive()) {
961 964 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
962 965 focusLog.fine("request rejected, focusedWindowChangeAllowed==false, " +
963 966 "decoratedPeer is inactive: " + decoratedPeer);
964 967 }
965 968 LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());
966 969 return false;
967 970 }
968 971 }
969 972
970 973 boolean res = parentPeer.requestWindowFocus(cause);
971 974 // If parent window can be made focused and has been made focused (synchronously)
972 975 // then we can proceed with children, otherwise we retreat
973 976 if (!res || !parentWindow.isFocused()) {
974 977 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
975 978 focusLog.fine("request rejected, res= " + res + ", parentWindow.isFocused()=" +
976 979 parentWindow.isFocused());
977 980 }
978 981 LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());
979 982 return false;
980 983 }
981 984
982 985 KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
983 986 Component focusOwner = kfmPeer.getCurrentFocusOwner();
984 987 return LWKeyboardFocusManagerPeer.deliverFocus(lightweightChild,
985 988 getTarget(), temporary,
986 989 focusedWindowChangeAllowed,
987 990 time, cause, focusOwner);
988 991
989 992 case LWKeyboardFocusManagerPeer.SNFH_SUCCESS_HANDLED:
990 993 return true;
991 994 }
992 995
993 996 return false;
994 997 }
995 998
996 999 @Override
997 1000 public final Image createImage(final ImageProducer producer) {
998 1001 return new ToolkitImage(producer);
999 1002 }
1000 1003
1001 1004 @Override
1002 1005 public final Image createImage(final int width, final int height) {
1003 1006 return getLWGC().createAcceleratedImage(getTarget(), width, height);
1004 1007 }
1005 1008
1006 1009 @Override
1007 1010 public final VolatileImage createVolatileImage(final int w, final int h) {
1008 1011 return new SunVolatileImage(getTarget(), w, h);
1009 1012 }
1010 1013
1011 1014 @Override
1012 1015 public boolean prepareImage(Image img, int w, int h, ImageObserver o) {
1013 1016 // TODO: is it a right/complete implementation?
1014 1017 return Toolkit.getDefaultToolkit().prepareImage(img, w, h, o);
1015 1018 }
1016 1019
1017 1020 @Override
1018 1021 public int checkImage(Image img, int w, int h, ImageObserver o) {
1019 1022 // TODO: is it a right/complete implementation?
1020 1023 return Toolkit.getDefaultToolkit().checkImage(img, w, h, o);
1021 1024 }
1022 1025
1023 1026 @Override
1024 1027 public boolean handlesWheelScrolling() {
1025 1028 // TODO: not implemented
1026 1029 return false;
1027 1030 }
1028 1031
1029 1032 @Override
1030 1033 public final void applyShape(final Region shape) {
1031 1034 synchronized (getStateLock()) {
1032 1035 if (region == shape || (region != null && region.equals(shape))) {
1033 1036 return;
1034 1037 }
1035 1038 }
1036 1039 applyShapeImpl(shape);
1037 1040 }
1038 1041
1039 1042 void applyShapeImpl(final Region shape) {
1040 1043 synchronized (getStateLock()) {
1041 1044 if (shape != null) {
1042 1045 region = Region.WHOLE_REGION.getIntersection(shape);
1043 1046 } else {
1044 1047 region = null;
1045 1048 }
1046 1049 }
1047 1050 repaintParent(getBounds());
1048 1051 }
1049 1052
1050 1053 protected final Region getRegion() {
1051 1054 synchronized (getStateLock()) {
1052 1055 return isShaped() ? region : Region.getInstance(getSize());
1053 1056 }
1054 1057 }
1055 1058
1056 1059 public boolean isShaped() {
1057 1060 synchronized (getStateLock()) {
1058 1061 return region != null;
1059 1062 }
1060 1063 }
1061 1064
1062 1065 // DropTargetPeer Method
1063 1066 @Override
1064 1067 public void addDropTarget(DropTarget dt) {
1065 1068 LWWindowPeer winPeer = getWindowPeerOrSelf();
1066 1069 if (winPeer != null && winPeer != this) {
1067 1070 // We need to register the DropTarget in the
1068 1071 // peer of the window ancestor of the component
1069 1072 winPeer.addDropTarget(dt);
1070 1073 } else {
1071 1074 synchronized (dropTargetLock) {
1072 1075 // 10-14-02 VL: Windows WComponentPeer would add (or remove) the drop target only
1073 1076 // if it's the first (or last) one for the component. Otherwise this call is a no-op.
1074 1077 if (++fNumDropTargets == 1) {
1075 1078 // Having a non-null drop target would be an error but let's check just in case:
1076 1079 if (fDropTarget != null) {
1077 1080 throw new IllegalStateException("Current drop target is not null");
1078 1081 }
1079 1082 // Create a new drop target:
1080 1083 fDropTarget = LWToolkit.getLWToolkit().createDropTarget(dt, target, this);
1081 1084 }
1082 1085 }
1083 1086 }
1084 1087 }
1085 1088
1086 1089 // DropTargetPeer Method
1087 1090 @Override
1088 1091 public void removeDropTarget(DropTarget dt) {
1089 1092 LWWindowPeer winPeer = getWindowPeerOrSelf();
1090 1093 if (winPeer != null && winPeer != this) {
1091 1094 // We need to unregister the DropTarget in the
1092 1095 // peer of the window ancestor of the component
1093 1096 winPeer.removeDropTarget(dt);
1094 1097 } else {
1095 1098 synchronized (dropTargetLock){
1096 1099 // 10-14-02 VL: Windows WComponentPeer would add (or remove) the drop target only
1097 1100 // if it's the first (or last) one for the component. Otherwise this call is a no-op.
1098 1101 if (--fNumDropTargets == 0) {
1099 1102 // Having a null drop target would be an error but let's check just in case:
1100 1103 if (fDropTarget != null) {
1101 1104 // Dispose of the drop target:
1102 1105 fDropTarget.dispose();
1103 1106 fDropTarget = null;
1104 1107 } else
1105 1108 System.err.println("CComponent.removeDropTarget(): current drop target is null.");
1106 1109 }
1107 1110 }
1108 1111 }
1109 1112 }
1110 1113
1111 1114 // ---- PEER NOTIFICATIONS ---- //
1112 1115
1113 1116 /**
1114 1117 * Called when this peer's location has been changed either as a result
1115 1118 * of target.setLocation() or as a result of user actions (window is
1116 1119 * dragged with mouse).
1117 1120 *
1118 1121 * This method could be called on the toolkit thread.
1119 1122 */
1120 1123 protected final void handleMove(final int x, final int y,
1121 1124 final boolean updateTarget) {
1122 1125 if (updateTarget) {
1123 1126 AWTAccessor.getComponentAccessor().setLocation(getTarget(), x, y);
1124 1127 postEvent(new ComponentEvent(getTarget(),
1125 1128 ComponentEvent.COMPONENT_MOVED));
1126 1129 }
1127 1130 }
1128 1131
1129 1132 /**
1130 1133 * Called when this peer's size has been changed either as a result of
1131 1134 * target.setSize() or as a result of user actions (window is resized).
1132 1135 *
1133 1136 * This method could be called on the toolkit thread.
1134 1137 */
1135 1138 protected final void handleResize(final int w, final int h,
1136 1139 final boolean updateTarget) {
1137 1140 Image oldBB = null;
1138 1141 synchronized (getStateLock()) {
1139 1142 if (backBuffer != null) {
1140 1143 oldBB = backBuffer;
1141 1144 backBuffer = getLWGC().createBackBuffer(this);
1142 1145 }
1143 1146 }
1144 1147 getLWGC().destroyBackBuffer(oldBB);
1145 1148
1146 1149 if (updateTarget) {
1147 1150 AWTAccessor.getComponentAccessor().setSize(getTarget(), w, h);
1148 1151 postEvent(new ComponentEvent(getTarget(),
1149 1152 ComponentEvent.COMPONENT_RESIZED));
1150 1153 }
1151 1154 }
1152 1155
1153 1156 protected final void repaintOldNewBounds(final Rectangle oldB) {
1154 1157 repaintParent(oldB);
1155 1158 repaintPeer(getSize());
1156 1159 }
1157 1160
1158 1161 protected final void repaintParent(final Rectangle oldB) {
1159 1162 final LWContainerPeer<?, ?> cp = getContainerPeer();
1160 1163 if (cp != null) {
1161 1164 // Repaint unobscured part of the parent
1162 1165 cp.repaintPeer(cp.getContentSize().intersection(oldB));
1163 1166 }
1164 1167 }
1165 1168
1166 1169 // ---- EVENTS ---- //
1167 1170
1168 1171 /**
1169 1172 * Post an event to the proper Java EDT.
1170 1173 */
1171 1174 public void postEvent(final AWTEvent event) {
1172 1175 LWToolkit.postEvent(event);
1173 1176 }
1174 1177
1175 1178 protected void postPaintEvent(int x, int y, int w, int h) {
1176 1179 // TODO: call getIgnoreRepaint() directly with the right ACC
1177 1180 if (AWTAccessor.getComponentAccessor().getIgnoreRepaint(target)) {
1178 1181 return;
1179 1182 }
1180 1183 PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher().
1181 1184 createPaintEvent(getTarget(), x, y, w, h);
1182 1185 if (event != null) {
1183 1186 postEvent(event);
1184 1187 }
1185 1188 }
1186 1189
1187 1190 /*
1188 1191 * Gives a chance for the peer to handle the event after it's been
1189 1192 * processed by the target.
1190 1193 */
1191 1194 @Override
1192 1195 public void handleEvent(AWTEvent e) {
1193 1196 if ((e instanceof InputEvent) && ((InputEvent) e).isConsumed()) {
1194 1197 return;
1195 1198 }
1196 1199 switch (e.getID()) {
1197 1200 case FocusEvent.FOCUS_GAINED:
1198 1201 case FocusEvent.FOCUS_LOST:
1199 1202 handleJavaFocusEvent((FocusEvent) e);
1200 1203 break;
1201 1204 case PaintEvent.PAINT:
1202 1205 // Got a native paint event
1203 1206 // paintPending = false;
1204 1207 // fall through to the next statement
1205 1208 case PaintEvent.UPDATE:
1206 1209 handleJavaPaintEvent();
1207 1210 break;
1208 1211 case MouseEvent.MOUSE_PRESSED:
1209 1212 handleJavaMouseEvent((MouseEvent)e);
1210 1213 }
1211 1214
1212 1215 sendEventToDelegate(e);
1213 1216 }
1214 1217
1215 1218 protected void sendEventToDelegate(final AWTEvent e) {
1216 1219 if (getDelegate() == null || !isShowing() || !isEnabled()) {
1217 1220 return;
1218 1221 }
1219 1222 synchronized (getDelegateLock()) {
1220 1223 AWTEvent delegateEvent = createDelegateEvent(e);
1221 1224 if (delegateEvent != null) {
1222 1225 AWTAccessor.getComponentAccessor()
1223 1226 .processEvent((Component) delegateEvent.getSource(),
1224 1227 delegateEvent);
1225 1228 if (delegateEvent instanceof KeyEvent) {
1226 1229 KeyEvent ke = (KeyEvent) delegateEvent;
1227 1230 SwingUtilities.processKeyBindings(ke);
1228 1231 }
1229 1232 }
1230 1233 }
1231 1234 }
1232 1235
1233 1236 /**
1234 1237 * Changes the target of the AWTEvent from awt component to appropriate
1235 1238 * swing delegate.
1236 1239 */
1237 1240 @SuppressWarnings("deprecation")
1238 1241 private AWTEvent createDelegateEvent(final AWTEvent e) {
1239 1242 // TODO modifiers should be changed to getModifiers()|getModifiersEx()?
1240 1243 AWTEvent delegateEvent = null;
1241 1244 if (e instanceof MouseWheelEvent) {
1242 1245 MouseWheelEvent me = (MouseWheelEvent) e;
1243 1246 delegateEvent = new MouseWheelEvent(
1244 1247 delegate, me.getID(), me.getWhen(),
1245 1248 me.getModifiers(),
1246 1249 me.getX(), me.getY(),
1247 1250 me.getXOnScreen(), me.getYOnScreen(),
1248 1251 me.getClickCount(),
1249 1252 me.isPopupTrigger(),
1250 1253 me.getScrollType(),
1251 1254 me.getScrollAmount(),
1252 1255 me.getWheelRotation(),
1253 1256 me.getPreciseWheelRotation());
1254 1257 } else if (e instanceof MouseEvent) {
1255 1258 MouseEvent me = (MouseEvent) e;
1256 1259
1257 1260 Component eventTarget = SwingUtilities.getDeepestComponentAt(delegate, me.getX(), me.getY());
1258 1261
1259 1262 if (me.getID() == MouseEvent.MOUSE_DRAGGED) {
1260 1263 if (delegateDropTarget == null) {
1261 1264 delegateDropTarget = eventTarget;
1262 1265 } else {
1263 1266 eventTarget = delegateDropTarget;
1264 1267 }
1265 1268 }
1266 1269 if (me.getID() == MouseEvent.MOUSE_RELEASED && delegateDropTarget != null) {
1267 1270 eventTarget = delegateDropTarget;
1268 1271 delegateDropTarget = null;
1269 1272 }
1270 1273 if (eventTarget == null) {
1271 1274 eventTarget = delegate;
1272 1275 }
1273 1276 delegateEvent = SwingUtilities.convertMouseEvent(getTarget(), me, eventTarget);
1274 1277 } else if (e instanceof KeyEvent) {
1275 1278 KeyEvent ke = (KeyEvent) e;
1276 1279 delegateEvent = new KeyEvent(getDelegateFocusOwner(), ke.getID(), ke.getWhen(),
1277 1280 ke.getModifiers(), ke.getKeyCode(), ke.getKeyChar(), ke.getKeyLocation());
1278 1281 AWTAccessor.getKeyEventAccessor().setExtendedKeyCode((KeyEvent) delegateEvent,
1279 1282 ke.getExtendedKeyCode());
1280 1283 } else if (e instanceof FocusEvent) {
1281 1284 FocusEvent fe = (FocusEvent) e;
1282 1285 delegateEvent = new FocusEvent(getDelegateFocusOwner(), fe.getID(), fe.isTemporary());
1283 1286 }
1284 1287 return delegateEvent;
1285 1288 }
1286 1289
1287 1290 protected void handleJavaMouseEvent(MouseEvent e) {
1288 1291 Component target = getTarget();
1289 1292 assert (e.getSource() == target);
1290 1293
1291 1294 if (!target.isFocusOwner() && LWKeyboardFocusManagerPeer.shouldFocusOnClick(target)) {
1292 1295 LWKeyboardFocusManagerPeer.requestFocusFor(target, FocusEvent.Cause.MOUSE_EVENT);
1293 1296 }
1294 1297 }
1295 1298
1296 1299 /**
1297 1300 * Handler for FocusEvents.
1298 1301 */
1299 1302 void handleJavaFocusEvent(final FocusEvent e) {
1300 1303 // Note that the peer receives all the FocusEvents from
1301 1304 // its lightweight children as well
1302 1305 KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
1303 1306 kfmPeer.setCurrentFocusOwner(e.getID() == FocusEvent.FOCUS_GAINED ? getTarget() : null);
1304 1307 }
1305 1308
1306 1309 /**
1307 1310 * All peers should clear background before paint.
1308 1311 *
1309 1312 * @return false on components that DO NOT require a clearRect() before
1310 1313 * painting.
1311 1314 */
1312 1315 protected final boolean shouldClearRectBeforePaint() {
1313 1316 // TODO: sun.awt.noerasebackground
1314 1317 return true;
1315 1318 }
1316 1319
1317 1320 /**
1318 1321 * Handler for PAINT and UPDATE PaintEvents.
1319 1322 */
1320 1323 private void handleJavaPaintEvent() {
1321 1324 // Skip all painting while layouting and all UPDATEs
1322 1325 // while waiting for native paint
1323 1326 // if (!isLayouting && !paintPending) {
1324 1327 if (!isLayouting()) {
1325 1328 targetPaintArea.paint(getTarget(), shouldClearRectBeforePaint());
1326 1329 }
1327 1330 }
1328 1331
1329 1332 // ---- UTILITY METHODS ---- //
1330 1333
1331 1334 /**
1332 1335 * Finds a top-most visible component for the given point. The location is
1333 1336 * specified relative to the peer's parent.
1334 1337 */
1335 1338 LWComponentPeer<?, ?> findPeerAt(final int x, final int y) {
1336 1339 final Rectangle r = getBounds();
1337 1340 final Region sh = getRegion();
1338 1341 final boolean found = isVisible() && sh.contains(x - r.x, y - r.y);
1339 1342 return found ? this : null;
1340 1343 }
1341 1344
1342 1345 /*
1343 1346 * Translated the given point in Window coordinates to the point in
1344 1347 * coordinates local to this component. The given window peer must be
1345 1348 * the window where this component is in.
1346 1349 */
1347 1350 public Point windowToLocal(int x, int y, LWWindowPeer wp) {
1348 1351 return windowToLocal(new Point(x, y), wp);
1349 1352 }
1350 1353
1351 1354 public Point windowToLocal(Point p, LWWindowPeer wp) {
1352 1355 LWComponentPeer<?, ?> cp = this;
1353 1356 while (cp != wp) {
1354 1357 Rectangle cpb = cp.getBounds();
1355 1358 p.x -= cpb.x;
1356 1359 p.y -= cpb.y;
1357 1360 cp = cp.getContainerPeer();
1358 1361 }
1359 1362 // Return a copy to prevent subsequent modifications
1360 1363 return new Point(p);
1361 1364 }
1362 1365
1363 1366 public Rectangle windowToLocal(Rectangle r, LWWindowPeer wp) {
1364 1367 Point p = windowToLocal(r.getLocation(), wp);
1365 1368 return new Rectangle(p, r.getSize());
1366 1369 }
1367 1370
1368 1371 public Point localToWindow(int x, int y) {
1369 1372 return localToWindow(new Point(x, y));
1370 1373 }
1371 1374
1372 1375 public Point localToWindow(Point p) {
1373 1376 LWComponentPeer<?, ?> cp = getContainerPeer();
1374 1377 Rectangle r = getBounds();
1375 1378 while (cp != null) {
1376 1379 p.x += r.x;
1377 1380 p.y += r.y;
1378 1381 r = cp.getBounds();
1379 1382 cp = cp.getContainerPeer();
1380 1383 }
1381 1384 // Return a copy to prevent subsequent modifications
1382 1385 return new Point(p);
1383 1386 }
1384 1387
1385 1388 public Rectangle localToWindow(Rectangle r) {
1386 1389 Point p = localToWindow(r.getLocation());
1387 1390 return new Rectangle(p, r.getSize());
1388 1391 }
1389 1392
1390 1393 public final void repaintPeer() {
1391 1394 repaintPeer(getSize());
1392 1395 }
1393 1396
1394 1397 void repaintPeer(final Rectangle r) {
1395 1398 final Rectangle toPaint = getSize().intersection(r);
1396 1399 if (!isShowing() || toPaint.isEmpty()) {
1397 1400 return;
1398 1401 }
1399 1402
1400 1403 postPaintEvent(toPaint.x, toPaint.y, toPaint.width, toPaint.height);
1401 1404 }
1402 1405
1403 1406 /**
1404 1407 * Determines whether this peer is showing on screen. This means that the
1405 1408 * peer must be visible, and it must be in a container that is visible and
1406 1409 * showing.
1407 1410 *
1408 1411 * @see #isVisible()
1409 1412 */
1410 1413 protected final boolean isShowing() {
1411 1414 synchronized (getPeerTreeLock()) {
1412 1415 if (isVisible()) {
1413 1416 final LWContainerPeer<?, ?> container = getContainerPeer();
1414 1417 return (container == null) || container.isShowing();
1415 1418 }
1416 1419 }
1417 1420 return false;
1418 1421 }
1419 1422
1420 1423 /**
1421 1424 * Paints the peer. Delegate the actual painting to Swing components.
1422 1425 */
1423 1426 protected final void paintPeer(final Graphics g) {
1424 1427 final D delegate = getDelegate();
1425 1428 if (delegate != null) {
1426 1429 if (!SwingUtilities.isEventDispatchThread()) {
↓ open down ↓ |
1335 lines elided |
↑ open up ↑ |
1427 1430 throw new InternalError("Painting must be done on EDT");
1428 1431 }
1429 1432 synchronized (getDelegateLock()) {
1430 1433 // JComponent.print() is guaranteed to not affect the double buffer
1431 1434 getDelegate().print(g);
1432 1435 }
1433 1436 }
1434 1437 }
1435 1438
1436 1439 protected static final void flushOnscreenGraphics(){
1437 - final OGLRenderQueue rq = OGLRenderQueue.getInstance();
1440 + RenderQueue rq = MacOSFlags.isMetalEnabled() ?
1441 + MTLRenderQueue.getInstance() : OGLRenderQueue.getInstance();
1438 1442 rq.lock();
1439 1443 try {
1440 1444 rq.flushNow();
1441 1445 } finally {
1442 1446 rq.unlock();
1443 1447 }
1444 1448 }
1445 1449
1446 1450 /**
1447 1451 * Used by ContainerPeer to skip all the paint events during layout.
1448 1452 *
1449 1453 * @param isLayouting layouting state.
1450 1454 */
1451 1455 protected final void setLayouting(final boolean isLayouting) {
1452 1456 this.isLayouting = isLayouting;
1453 1457 }
1454 1458
1455 1459 /**
1456 1460 * Returns layouting state. Used by ComponentPeer to skip all the paint
1457 1461 * events during layout.
1458 1462 *
1459 1463 * @return true during layout, false otherwise.
1460 1464 */
1461 1465 private boolean isLayouting() {
1462 1466 return isLayouting;
1463 1467 }
1464 1468 }
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX