Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java
41153 views
1
/*
2
* Copyright (c) 2013, 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.swing;
27
28
import java.awt.*;
29
import java.awt.dnd.DragGestureEvent;
30
import java.awt.dnd.DragGestureListener;
31
import java.awt.dnd.DragGestureRecognizer;
32
import java.awt.dnd.DragSource;
33
import java.awt.dnd.DropTarget;
34
import java.awt.dnd.InvalidDnDOperationException;
35
import java.awt.dnd.peer.DragSourceContextPeer;
36
import java.awt.event.ContainerEvent;
37
import java.awt.event.ContainerListener;
38
import java.awt.geom.AffineTransform;
39
import java.awt.image.BufferedImage;
40
import java.awt.image.DataBufferInt;
41
import java.beans.PropertyChangeEvent;
42
import java.beans.PropertyChangeListener;
43
import java.security.AccessController;
44
import javax.swing.JComponent;
45
46
import javax.swing.JLayeredPane;
47
import javax.swing.JPanel;
48
import javax.swing.JRootPane;
49
import javax.swing.LayoutFocusTraversalPolicy;
50
import javax.swing.RepaintManager;
51
import javax.swing.RootPaneContainer;
52
import javax.swing.SwingUtilities;
53
54
import sun.awt.AWTAccessor;
55
import sun.awt.DisplayChangedListener;
56
import sun.awt.LightweightFrame;
57
import sun.awt.OverrideNativeWindowHandle;
58
import sun.security.action.GetPropertyAction;
59
import sun.swing.SwingUtilities2.RepaintListener;
60
61
/**
62
* The frame serves as a lightweight container which paints its content
63
* to an offscreen image and provides access to the image's data via the
64
* {@link LightweightContent} interface. Note, that it may not be shown
65
* as a standalone toplevel frame. Its purpose is to provide functionality
66
* for lightweight embedding.
67
*
68
* @author Artem Ananiev
69
* @author Anton Tarasov
70
*/
71
@SuppressWarnings({"removal","serial"}) // JDK-implementation class
72
public final class JLightweightFrame extends LightweightFrame implements RootPaneContainer {
73
74
private final JRootPane rootPane = new JRootPane();
75
76
private LightweightContent content;
77
78
private Component component;
79
private JPanel contentPane;
80
81
private BufferedImage bbImage;
82
83
private volatile double scaleFactorX;
84
private volatile double scaleFactorY;
85
86
/**
87
* {@code copyBufferEnabled}, true by default, defines the following strategy.
88
* A duplicating (copy) buffer is created for the original pixel buffer.
89
* The copy buffer is synchronized with the original buffer every time the
90
* latter changes. {@code JLightweightFrame} passes the copy buffer array
91
* to the {@link LightweightContent#imageBufferReset} method. The code spot
92
* which synchronizes two buffers becomes the only critical section guarded
93
* by the lock (managed with the {@link LightweightContent#paintLock()},
94
* {@link LightweightContent#paintUnlock()} methods).
95
*/
96
private static boolean copyBufferEnabled;
97
private int[] copyBuffer;
98
99
private PropertyChangeListener layoutSizeListener;
100
private RepaintListener repaintListener;
101
102
static {
103
SwingAccessor.setJLightweightFrameAccessor(new SwingAccessor.JLightweightFrameAccessor() {
104
@Override
105
public void updateCursor(JLightweightFrame frame) {
106
frame.updateClientCursor();
107
}
108
});
109
copyBufferEnabled = "true".equals(AccessController.
110
doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true")));
111
}
112
113
/**
114
* Constructs a new, initially invisible {@code JLightweightFrame}
115
* instance.
116
*/
117
public JLightweightFrame() {
118
super();
119
AffineTransform defaultTransform =
120
getGraphicsConfiguration().getDefaultTransform();
121
scaleFactorX = defaultTransform.getScaleX();
122
scaleFactorY = defaultTransform.getScaleY();
123
copyBufferEnabled = "true".equals(AccessController.
124
doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true")));
125
126
add(rootPane, BorderLayout.CENTER);
127
setFocusTraversalPolicy(new LayoutFocusTraversalPolicy());
128
if (getGraphicsConfiguration().isTranslucencyCapable()) {
129
setBackground(new Color(0, 0, 0, 0));
130
}
131
132
layoutSizeListener = new PropertyChangeListener() {
133
@Override
134
public void propertyChange(PropertyChangeEvent e) {
135
Dimension d = (Dimension)e.getNewValue();
136
137
if ("preferredSize".equals(e.getPropertyName())) {
138
content.preferredSizeChanged(d.width, d.height);
139
140
} else if ("maximumSize".equals(e.getPropertyName())) {
141
content.maximumSizeChanged(d.width, d.height);
142
143
} else if ("minimumSize".equals(e.getPropertyName())) {
144
content.minimumSizeChanged(d.width, d.height);
145
}
146
}
147
};
148
149
repaintListener = (JComponent c, int x, int y, int w, int h) -> {
150
Window jlf = SwingUtilities.getWindowAncestor(c);
151
if (jlf != JLightweightFrame.this) {
152
return;
153
}
154
Point p = SwingUtilities.convertPoint(c, x, y, jlf);
155
Rectangle r = new Rectangle(p.x, p.y, w, h).intersection(
156
new Rectangle(0, 0,
157
(int)Math.round(bbImage.getWidth() / scaleFactorX),
158
(int)Math.round(bbImage.getHeight() / scaleFactorY)));
159
160
if (!r.isEmpty()) {
161
notifyImageUpdated(r.x, r.y, r.width, r.height);
162
}
163
};
164
165
SwingAccessor.getRepaintManagerAccessor().addRepaintListener(
166
RepaintManager.currentManager(this), repaintListener);
167
}
168
169
@Override
170
public void dispose() {
171
SwingAccessor.getRepaintManagerAccessor().removeRepaintListener(
172
RepaintManager.currentManager(this), repaintListener);
173
super.dispose();
174
}
175
176
/**
177
* Sets the {@link LightweightContent} instance for this frame.
178
* The {@code JComponent} object returned by the
179
* {@link LightweightContent#getComponent()} method is immediately
180
* added to the frame's content pane.
181
*
182
* @param content the {@link LightweightContent} instance
183
*/
184
public void setContent(final LightweightContent content) {
185
if (content == null) {
186
System.err.println("JLightweightFrame.setContent: content may not be null!");
187
return;
188
}
189
this.content = content;
190
this.component = content.getComponent();
191
192
Dimension d = this.component.getPreferredSize();
193
content.preferredSizeChanged(d.width, d.height);
194
195
d = this.component.getMaximumSize();
196
content.maximumSizeChanged(d.width, d.height);
197
198
d = this.component.getMinimumSize();
199
content.minimumSizeChanged(d.width, d.height);
200
201
initInterior();
202
}
203
204
@Override
205
public Graphics getGraphics() {
206
if (bbImage == null) return null;
207
208
Graphics2D g = bbImage.createGraphics();
209
g.setBackground(getBackground());
210
g.setColor(getForeground());
211
g.setFont(getFont());
212
g.scale(scaleFactorX, scaleFactorY);
213
return g;
214
}
215
216
/**
217
* {@inheritDoc}
218
*
219
* @see LightweightContent#focusGrabbed()
220
*/
221
@Override
222
public void grabFocus() {
223
if (content != null) content.focusGrabbed();
224
}
225
226
/**
227
* {@inheritDoc}
228
*
229
* @see LightweightContent#focusUngrabbed()
230
*/
231
@Override
232
public void ungrabFocus() {
233
if (content != null) content.focusUngrabbed();
234
}
235
236
@Override
237
@SuppressWarnings("deprecation")
238
public int getScaleFactor() {
239
return (int)scaleFactorX;
240
}
241
242
@Override
243
public double getScaleFactorX() {
244
return scaleFactorX;
245
}
246
247
@Override
248
public double getScaleFactorY() {
249
return scaleFactorY;
250
}
251
252
@Override
253
@SuppressWarnings("deprecation")
254
public void notifyDisplayChanged(final int scaleFactor) {
255
notifyDisplayChanged(scaleFactor, scaleFactor);
256
}
257
258
@Override
259
public void notifyDisplayChanged(final double scaleFactorX,
260
final double scaleFactorY) {
261
if (Double.compare(scaleFactorX, this.scaleFactorX) != 0 ||
262
Double.compare(scaleFactorY, this.scaleFactorY) != 0) {
263
if (!copyBufferEnabled) content.paintLock();
264
try {
265
if (bbImage != null) {
266
resizeBuffer(getWidth(), getHeight(), scaleFactorX,
267
scaleFactorY);
268
}
269
} finally {
270
if (!copyBufferEnabled) content.paintUnlock();
271
}
272
this.scaleFactorX = scaleFactorX;
273
this.scaleFactorY = scaleFactorY;
274
275
if(isVisible()) {
276
final Object peer =
277
AWTAccessor.getComponentAccessor().getPeer(this);
278
if (peer instanceof DisplayChangedListener) {
279
((DisplayChangedListener) peer).displayChanged();
280
}
281
repaint();
282
}
283
}
284
}
285
286
@Override
287
public void addNotify() {
288
super.addNotify();
289
final Object peer = AWTAccessor.getComponentAccessor().getPeer(this);
290
if (peer instanceof DisplayChangedListener) {
291
((DisplayChangedListener) peer).displayChanged();
292
}
293
}
294
295
private void syncCopyBuffer(boolean reset, int x, int y, int w, int h,
296
double scaleX, double scaleY) {
297
content.paintLock();
298
try {
299
int[] srcBuffer = ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData();
300
if (reset) {
301
copyBuffer = new int[srcBuffer.length];
302
}
303
int linestride = bbImage.getWidth();
304
305
int startX = (int)Math.floor(x * scaleX);
306
int startY = (int)Math.floor(y * scaleY);
307
int width = (int)Math.ceil((x + w) * scaleX) - startX;
308
int height = (int)Math.ceil((y + h) * scaleY) - startY;
309
if (startX + width > linestride) {
310
width = linestride - startX;
311
}
312
if (startY + height > bbImage.getHeight()) {
313
height = bbImage.getHeight() - startY;
314
}
315
316
for (int i = 0; i < height; i++) {
317
int from = (startY + i) * linestride + startX;
318
System.arraycopy(srcBuffer, from, copyBuffer, from, width);
319
}
320
} finally {
321
content.paintUnlock();
322
}
323
}
324
325
private void notifyImageUpdated(int x, int y, int width, int height) {
326
if (copyBufferEnabled) {
327
syncCopyBuffer(false, x, y, width, height, scaleFactorX,
328
scaleFactorY);
329
}
330
content.imageUpdated(x, y, width, height);
331
}
332
333
@SuppressWarnings("serial") // anonymous class inside
334
private void initInterior() {
335
contentPane = new JPanel() {
336
@Override
337
public void paint(Graphics g) {
338
if (!copyBufferEnabled) {
339
content.paintLock();
340
}
341
try {
342
super.paint(g);
343
344
final Rectangle clip = g.getClipBounds() != null ?
345
g.getClipBounds() :
346
new Rectangle(0, 0, contentPane.getWidth(), contentPane.getHeight());
347
348
clip.x = Math.max(0, clip.x);
349
clip.y = Math.max(0, clip.y);
350
clip.width = Math.min(contentPane.getWidth(), clip.width);
351
clip.height = Math.min(contentPane.getHeight(), clip.height);
352
353
EventQueue.invokeLater(new Runnable() {
354
@Override
355
public void run() {
356
Rectangle c = contentPane.getBounds().intersection(clip);
357
notifyImageUpdated(c.x, c.y, c.width, c.height);
358
}
359
});
360
} finally {
361
if (!copyBufferEnabled) {
362
content.paintUnlock();
363
}
364
}
365
}
366
@Override
367
protected boolean isPaintingOrigin() {
368
return true;
369
}
370
};
371
contentPane.setLayout(new BorderLayout());
372
contentPane.add(component);
373
if ("true".equals(AccessController.
374
doPrivileged(new GetPropertyAction("swing.jlf.contentPaneTransparent", "false"))))
375
{
376
contentPane.setOpaque(false);
377
}
378
setContentPane(contentPane);
379
380
contentPane.addContainerListener(new ContainerListener() {
381
@Override
382
public void componentAdded(ContainerEvent e) {
383
Component c = JLightweightFrame.this.component;
384
if (e.getChild() == c) {
385
c.addPropertyChangeListener("preferredSize", layoutSizeListener);
386
c.addPropertyChangeListener("maximumSize", layoutSizeListener);
387
c.addPropertyChangeListener("minimumSize", layoutSizeListener);
388
}
389
}
390
@Override
391
public void componentRemoved(ContainerEvent e) {
392
Component c = JLightweightFrame.this.component;
393
if (e.getChild() == c) {
394
c.removePropertyChangeListener(layoutSizeListener);
395
}
396
}
397
});
398
}
399
400
@SuppressWarnings("deprecation")
401
@Override public void reshape(int x, int y, int width, int height) {
402
super.reshape(x, y, width, height);
403
404
if (width == 0 || height == 0) {
405
return;
406
}
407
if (!copyBufferEnabled) {
408
content.paintLock();
409
}
410
try {
411
boolean createBB = (bbImage == null);
412
int newW = width;
413
int newH = height;
414
if (bbImage != null) {
415
int imgWidth = (int)Math.round(bbImage.getWidth() /
416
scaleFactorX);
417
int imgHeight = (int)Math.round(bbImage.getHeight() /
418
scaleFactorY);
419
if (width != imgWidth || height != imgHeight) {
420
createBB = true;
421
if (bbImage != null) {
422
int oldW = imgWidth;
423
int oldH = imgHeight;
424
if ((oldW >= newW) && (oldH >= newH)) {
425
createBB = false;
426
} else {
427
if (oldW >= newW) {
428
newW = oldW;
429
} else {
430
newW = Math.max((int)(oldW * 1.2), width);
431
}
432
if (oldH >= newH) {
433
newH = oldH;
434
} else {
435
newH = Math.max((int)(oldH * 1.2), height);
436
}
437
}
438
}
439
}
440
}
441
if (createBB) {
442
resizeBuffer(newW, newH, scaleFactorX, scaleFactorY);
443
return;
444
}
445
content.imageReshaped(0, 0, width, height);
446
447
} finally {
448
if (!copyBufferEnabled) {
449
content.paintUnlock();
450
}
451
}
452
}
453
454
private void resizeBuffer(int width, int height, double newScaleFactorX,
455
double newScaleFactorY) {
456
bbImage = new BufferedImage((int)Math.round(width * newScaleFactorX),
457
(int)Math.round(height * newScaleFactorY),
458
BufferedImage.TYPE_INT_ARGB_PRE);
459
int[] pixels= ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData();
460
if (copyBufferEnabled) {
461
syncCopyBuffer(true, 0, 0, width, height, newScaleFactorX,
462
newScaleFactorY);
463
pixels = copyBuffer;
464
}
465
content.imageBufferReset(pixels, 0, 0, width, height,
466
bbImage.getWidth(), newScaleFactorX, newScaleFactorY);
467
}
468
469
@Override
470
public JRootPane getRootPane() {
471
return rootPane;
472
}
473
474
@Override
475
public void setContentPane(Container contentPane) {
476
getRootPane().setContentPane(contentPane);
477
}
478
479
@Override
480
public Container getContentPane() {
481
return getRootPane().getContentPane();
482
}
483
484
@Override
485
public void setLayeredPane(JLayeredPane layeredPane) {
486
getRootPane().setLayeredPane(layeredPane);
487
}
488
489
@Override
490
public JLayeredPane getLayeredPane() {
491
return getRootPane().getLayeredPane();
492
}
493
494
@Override
495
public void setGlassPane(Component glassPane) {
496
getRootPane().setGlassPane(glassPane);
497
}
498
499
@Override
500
public Component getGlassPane() {
501
return getRootPane().getGlassPane();
502
}
503
504
505
/*
506
* Notifies client toolkit that it should change a cursor.
507
*
508
* Called from the peer via SwingAccessor, because the
509
* Component.updateCursorImmediately method is final
510
* and could not be overridden.
511
*/
512
private void updateClientCursor() {
513
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
514
if (pointerInfo == null) {
515
/*
516
* This can happen when multiple graphics device cannot decide
517
* which graphics device contains the current mouse position
518
* or on systems without a mouse
519
*/
520
return;
521
}
522
Point p = pointerInfo.getLocation();
523
SwingUtilities.convertPointFromScreen(p, this);
524
Component target = SwingUtilities.getDeepestComponentAt(this, p.x, p.y);
525
if (target != null) {
526
content.setCursor(target.getCursor());
527
}
528
}
529
530
//Called by reflection by SwingNode
531
public void overrideNativeWindowHandle(long handle, Runnable closeWindow) {
532
final Object peer = AWTAccessor.getComponentAccessor().getPeer(this);
533
if (peer instanceof OverrideNativeWindowHandle) {
534
((OverrideNativeWindowHandle) peer).overrideWindowHandle(handle);
535
}
536
if (closeWindow != null) {
537
closeWindow.run();
538
}
539
}
540
541
542
public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
543
Class<T> abstractRecognizerClass,
544
DragSource ds, Component c, int srcActions,
545
DragGestureListener dgl)
546
{
547
return content == null ? null : content.createDragGestureRecognizer(
548
abstractRecognizerClass, ds, c, srcActions, dgl);
549
}
550
551
public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
552
return content == null ? null : content.createDragSourceContextPeer(dge);
553
}
554
555
public void addDropTarget(DropTarget dt) {
556
if (content == null) return;
557
content.addDropTarget(dt);
558
}
559
560
public void removeDropTarget(DropTarget dt) {
561
if (content == null) return;
562
content.removeDropTarget(dt);
563
}
564
}
565
566