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