Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/swing/JLightweightFrame.java
38829 views
1
/*
2
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.swing;
27
28
import java.awt.BorderLayout;
29
import java.awt.Color;
30
import java.awt.Component;
31
import java.awt.Container;
32
import java.awt.Dimension;
33
import java.awt.EventQueue;
34
import java.awt.Graphics;
35
import java.awt.Graphics2D;
36
import java.awt.MouseInfo;
37
import java.awt.Point;
38
import java.awt.Rectangle;
39
import java.awt.Window;
40
import java.awt.dnd.DragGestureEvent;
41
import java.awt.dnd.DragGestureListener;
42
import java.awt.dnd.DragGestureRecognizer;
43
import java.awt.dnd.DragSource;
44
import java.awt.dnd.DropTarget;
45
import java.awt.dnd.InvalidDnDOperationException;
46
import java.awt.dnd.peer.DragSourceContextPeer;
47
import java.awt.event.ContainerEvent;
48
import java.awt.event.ContainerListener;
49
import java.awt.image.BufferedImage;
50
import java.awt.image.DataBufferInt;
51
import java.beans.PropertyChangeEvent;
52
import java.beans.PropertyChangeListener;
53
import java.security.AccessController;
54
import javax.swing.JComponent;
55
56
import javax.swing.JLayeredPane;
57
import javax.swing.JPanel;
58
import javax.swing.JRootPane;
59
import javax.swing.LayoutFocusTraversalPolicy;
60
import javax.swing.RepaintManager;
61
import javax.swing.RootPaneContainer;
62
import javax.swing.SwingUtilities;
63
64
import sun.awt.AWTAccessor;
65
import sun.awt.DisplayChangedListener;
66
import sun.awt.LightweightFrame;
67
import sun.awt.OverrideNativeWindowHandle;
68
import sun.security.action.GetPropertyAction;
69
import sun.swing.SwingUtilities2.RepaintListener;
70
71
/**
72
* The frame serves as a lightweight container which paints its content
73
* to an offscreen image and provides access to the image's data via the
74
* {@link LightweightContent} interface. Note, that it may not be shown
75
* as a standalone toplevel frame. Its purpose is to provide functionality
76
* for lightweight embedding.
77
*
78
* @author Artem Ananiev
79
* @author Anton Tarasov
80
*/
81
public final class JLightweightFrame extends LightweightFrame implements RootPaneContainer {
82
83
private final JRootPane rootPane = new JRootPane();
84
85
private LightweightContent content;
86
87
private Component component;
88
private JPanel contentPane;
89
90
private BufferedImage bbImage;
91
92
private volatile int scaleFactor = 1;
93
94
/**
95
* {@code copyBufferEnabled}, true by default, defines the following strategy.
96
* A duplicating (copy) buffer is created for the original pixel buffer.
97
* The copy buffer is synchronized with the original buffer every time the
98
* latter changes. {@code JLightweightFrame} passes the copy buffer array
99
* to the {@link LightweightContent#imageBufferReset} method. The code spot
100
* which synchronizes two buffers becomes the only critical section guarded
101
* by the lock (managed with the {@link LightweightContent#paintLock()},
102
* {@link LightweightContent#paintUnlock()} methods).
103
*/
104
private static boolean copyBufferEnabled;
105
private int[] copyBuffer;
106
107
private PropertyChangeListener layoutSizeListener;
108
private RepaintListener repaintListener;
109
110
static {
111
SwingAccessor.setJLightweightFrameAccessor(new SwingAccessor.JLightweightFrameAccessor() {
112
@Override
113
public void updateCursor(JLightweightFrame frame) {
114
frame.updateClientCursor();
115
}
116
});
117
copyBufferEnabled = "true".equals(AccessController.
118
doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true")));
119
}
120
121
/**
122
* Constructs a new, initially invisible {@code JLightweightFrame}
123
* instance.
124
*/
125
public JLightweightFrame() {
126
super();
127
copyBufferEnabled = "true".equals(AccessController.
128
doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true")));
129
130
add(rootPane, BorderLayout.CENTER);
131
setFocusTraversalPolicy(new LayoutFocusTraversalPolicy());
132
if (getGraphicsConfiguration().isTranslucencyCapable()) {
133
setBackground(new Color(0, 0, 0, 0));
134
}
135
136
layoutSizeListener = new PropertyChangeListener() {
137
@Override
138
public void propertyChange(PropertyChangeEvent e) {
139
Dimension d = (Dimension)e.getNewValue();
140
141
if ("preferredSize".equals(e.getPropertyName())) {
142
content.preferredSizeChanged(d.width, d.height);
143
144
} else if ("maximumSize".equals(e.getPropertyName())) {
145
content.maximumSizeChanged(d.width, d.height);
146
147
} else if ("minimumSize".equals(e.getPropertyName())) {
148
content.minimumSizeChanged(d.width, d.height);
149
}
150
}
151
};
152
153
repaintListener = (JComponent c, int x, int y, int w, int h) -> {
154
Window jlf = SwingUtilities.getWindowAncestor(c);
155
if (jlf != JLightweightFrame.this) {
156
return;
157
}
158
Point p = SwingUtilities.convertPoint(c, x, y, jlf);
159
Rectangle r = new Rectangle(p.x, p.y, w, h).intersection(
160
new Rectangle(0, 0, bbImage.getWidth() / scaleFactor,
161
bbImage.getHeight() / scaleFactor));
162
163
if (!r.isEmpty()) {
164
notifyImageUpdated(r.x, r.y, r.width, r.height);
165
}
166
};
167
168
SwingAccessor.getRepaintManagerAccessor().addRepaintListener(
169
RepaintManager.currentManager(this), repaintListener);
170
}
171
172
@Override
173
public void dispose() {
174
SwingAccessor.getRepaintManagerAccessor().removeRepaintListener(
175
RepaintManager.currentManager(this), repaintListener);
176
super.dispose();
177
}
178
179
/**
180
* Sets the {@link LightweightContent} instance for this frame.
181
* The {@code JComponent} object returned by the
182
* {@link LightweightContent#getComponent()} method is immediately
183
* added to the frame's content pane.
184
*
185
* @param content the {@link LightweightContent} instance
186
*/
187
public void setContent(final LightweightContent content) {
188
if (content == null) {
189
System.err.println("JLightweightFrame.setContent: content may not be null!");
190
return;
191
}
192
this.content = content;
193
this.component = content.getComponent();
194
195
Dimension d = this.component.getPreferredSize();
196
content.preferredSizeChanged(d.width, d.height);
197
198
d = this.component.getMaximumSize();
199
content.maximumSizeChanged(d.width, d.height);
200
201
d = this.component.getMinimumSize();
202
content.minimumSizeChanged(d.width, d.height);
203
204
initInterior();
205
}
206
207
@Override
208
public Graphics getGraphics() {
209
if (bbImage == null) return null;
210
211
Graphics2D g = bbImage.createGraphics();
212
g.setBackground(getBackground());
213
g.setColor(getForeground());
214
g.setFont(getFont());
215
g.scale(scaleFactor, scaleFactor);
216
return g;
217
}
218
219
/**
220
* {@inheritDoc}
221
*
222
* @see LightweightContent#focusGrabbed()
223
*/
224
@Override
225
public void grabFocus() {
226
if (content != null) content.focusGrabbed();
227
}
228
229
/**
230
* {@inheritDoc}
231
*
232
* @see LightweightContent#focusUngrabbed()
233
*/
234
@Override
235
public void ungrabFocus() {
236
if (content != null) content.focusUngrabbed();
237
}
238
239
@Override
240
public int getScaleFactor() {
241
return scaleFactor;
242
}
243
244
@Override
245
public void notifyDisplayChanged(final int scaleFactor) {
246
if (scaleFactor != this.scaleFactor) {
247
if (!copyBufferEnabled) content.paintLock();
248
try {
249
if (bbImage != null) {
250
resizeBuffer(getWidth(), getHeight(), scaleFactor);
251
}
252
} finally {
253
if (!copyBufferEnabled) content.paintUnlock();
254
}
255
this.scaleFactor = scaleFactor;
256
}
257
if (getPeer() instanceof DisplayChangedListener) {
258
((DisplayChangedListener)getPeer()).displayChanged();
259
}
260
repaint();
261
}
262
263
@Override
264
public void addNotify() {
265
super.addNotify();
266
if (getPeer() instanceof DisplayChangedListener) {
267
((DisplayChangedListener)getPeer()).displayChanged();
268
}
269
}
270
271
private void syncCopyBuffer(boolean reset, int x, int y, int w, int h, int scale) {
272
content.paintLock();
273
try {
274
int[] srcBuffer = ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData();
275
if (reset) {
276
copyBuffer = new int[srcBuffer.length];
277
}
278
int linestride = bbImage.getWidth();
279
280
x *= scale;
281
y *= scale;
282
w *= scale;
283
h *= scale;
284
285
for (int i=0; i<h; i++) {
286
int from = (y + i) * linestride + x;
287
System.arraycopy(srcBuffer, from, copyBuffer, from, w);
288
}
289
} finally {
290
content.paintUnlock();
291
}
292
}
293
294
private void notifyImageUpdated(int x, int y, int width, int height) {
295
if (copyBufferEnabled) {
296
syncCopyBuffer(false, x, y, width, height, scaleFactor);
297
}
298
content.imageUpdated(x, y, width, height);
299
}
300
301
private void initInterior() {
302
contentPane = new JPanel() {
303
@Override
304
public void paint(Graphics g) {
305
if (!copyBufferEnabled) {
306
content.paintLock();
307
}
308
try {
309
super.paint(g);
310
311
final Rectangle clip = g.getClipBounds() != null ?
312
g.getClipBounds() :
313
new Rectangle(0, 0, contentPane.getWidth(), contentPane.getHeight());
314
315
clip.x = Math.max(0, clip.x);
316
clip.y = Math.max(0, clip.y);
317
clip.width = Math.min(contentPane.getWidth(), clip.width);
318
clip.height = Math.min(contentPane.getHeight(), clip.height);
319
320
EventQueue.invokeLater(new Runnable() {
321
@Override
322
public void run() {
323
Rectangle c = contentPane.getBounds().intersection(clip);
324
notifyImageUpdated(c.x, c.y, c.width, c.height);
325
}
326
});
327
} finally {
328
if (!copyBufferEnabled) {
329
content.paintUnlock();
330
}
331
}
332
}
333
@Override
334
protected boolean isPaintingOrigin() {
335
return true;
336
}
337
};
338
contentPane.setLayout(new BorderLayout());
339
contentPane.add(component);
340
if ("true".equals(AccessController.
341
doPrivileged(new GetPropertyAction("swing.jlf.contentPaneTransparent", "false"))))
342
{
343
contentPane.setOpaque(false);
344
}
345
setContentPane(contentPane);
346
347
contentPane.addContainerListener(new ContainerListener() {
348
@Override
349
public void componentAdded(ContainerEvent e) {
350
Component c = JLightweightFrame.this.component;
351
if (e.getChild() == c) {
352
c.addPropertyChangeListener("preferredSize", layoutSizeListener);
353
c.addPropertyChangeListener("maximumSize", layoutSizeListener);
354
c.addPropertyChangeListener("minimumSize", layoutSizeListener);
355
}
356
}
357
@Override
358
public void componentRemoved(ContainerEvent e) {
359
Component c = JLightweightFrame.this.component;
360
if (e.getChild() == c) {
361
c.removePropertyChangeListener(layoutSizeListener);
362
}
363
}
364
});
365
}
366
367
@SuppressWarnings("deprecation")
368
@Override public void reshape(int x, int y, int width, int height) {
369
super.reshape(x, y, width, height);
370
371
if (width == 0 || height == 0) {
372
return;
373
}
374
if (!copyBufferEnabled) {
375
content.paintLock();
376
}
377
try {
378
boolean createBB = (bbImage == null);
379
int newW = width;
380
int newH = height;
381
if (bbImage != null) {
382
int imgWidth = bbImage.getWidth() / scaleFactor;
383
int imgHeight = bbImage.getHeight() / scaleFactor;
384
if (width != imgWidth || height != imgHeight) {
385
createBB = true;
386
if (bbImage != null) {
387
int oldW = imgWidth;
388
int oldH = imgHeight;
389
if ((oldW >= newW) && (oldH >= newH)) {
390
createBB = false;
391
} else {
392
if (oldW >= newW) {
393
newW = oldW;
394
} else {
395
newW = Math.max((int)(oldW * 1.2), width);
396
}
397
if (oldH >= newH) {
398
newH = oldH;
399
} else {
400
newH = Math.max((int)(oldH * 1.2), height);
401
}
402
}
403
}
404
}
405
}
406
if (createBB) {
407
resizeBuffer(newW, newH, scaleFactor);
408
return;
409
}
410
content.imageReshaped(0, 0, width, height);
411
412
} finally {
413
if (!copyBufferEnabled) {
414
content.paintUnlock();
415
}
416
}
417
}
418
419
private void resizeBuffer(int width, int height, int newScaleFactor) {
420
bbImage = new BufferedImage(width*newScaleFactor,height*newScaleFactor,
421
BufferedImage.TYPE_INT_ARGB_PRE);
422
int[] pixels= ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData();
423
if (copyBufferEnabled) {
424
syncCopyBuffer(true, 0, 0, width, height, newScaleFactor);
425
pixels = copyBuffer;
426
}
427
content.imageBufferReset(pixels, 0, 0, width, height,
428
width * newScaleFactor, newScaleFactor);
429
}
430
431
@Override
432
public JRootPane getRootPane() {
433
return rootPane;
434
}
435
436
@Override
437
public void setContentPane(Container contentPane) {
438
getRootPane().setContentPane(contentPane);
439
}
440
441
@Override
442
public Container getContentPane() {
443
return getRootPane().getContentPane();
444
}
445
446
@Override
447
public void setLayeredPane(JLayeredPane layeredPane) {
448
getRootPane().setLayeredPane(layeredPane);
449
}
450
451
@Override
452
public JLayeredPane getLayeredPane() {
453
return getRootPane().getLayeredPane();
454
}
455
456
@Override
457
public void setGlassPane(Component glassPane) {
458
getRootPane().setGlassPane(glassPane);
459
}
460
461
@Override
462
public Component getGlassPane() {
463
return getRootPane().getGlassPane();
464
}
465
466
467
/*
468
* Notifies client toolkit that it should change a cursor.
469
*
470
* Called from the peer via SwingAccessor, because the
471
* Component.updateCursorImmediately method is final
472
* and could not be overridden.
473
*/
474
private void updateClientCursor() {
475
Point p = MouseInfo.getPointerInfo().getLocation();
476
SwingUtilities.convertPointFromScreen(p, this);
477
Component target = SwingUtilities.getDeepestComponentAt(this, p.x, p.y);
478
if (target != null) {
479
content.setCursor(target.getCursor());
480
}
481
}
482
483
//Called by reflection by SwingNode
484
public void overrideNativeWindowHandle(long handle, Runnable closeWindow) {
485
final Object peer = AWTAccessor.getComponentAccessor().getPeer(this);
486
if (peer instanceof OverrideNativeWindowHandle) {
487
((OverrideNativeWindowHandle) peer).overrideWindowHandle(handle);
488
}
489
if (closeWindow != null) {
490
closeWindow.run();
491
}
492
}
493
494
public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
495
Class<T> abstractRecognizerClass,
496
DragSource ds, Component c, int srcActions,
497
DragGestureListener dgl)
498
{
499
return content == null ? null : content.createDragGestureRecognizer(
500
abstractRecognizerClass, ds, c, srcActions, dgl);
501
}
502
503
public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
504
return content == null ? null : content.createDragSourceContextPeer(dge);
505
}
506
507
public void addDropTarget(DropTarget dt) {
508
if (content == null) return;
509
content.addDropTarget(dt);
510
}
511
512
public void removeDropTarget(DropTarget dt) {
513
if (content == null) return;
514
content.removeDropTarget(dt);
515
}
516
}
517
518