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