1 /*
2 * Copyright (c) 2011, 2014, 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.*;
29 import java.awt.List;
30 import java.awt.datatransfer.*;
31 import java.awt.image.*;
32 import java.awt.peer.*;
33 import java.security.*;
34 import java.util.*;
35
36 import sun.awt.*;
37 import sun.print.*;
38 import sun.awt.util.ThreadGroupUtils;
39
40 import static sun.lwawt.LWWindowPeer.PeerType;
41
42 public abstract class LWToolkit extends SunToolkit implements Runnable {
43
44 private final static int STATE_NONE = 0;
45 private final static int STATE_INIT = 1;
46 private final static int STATE_MESSAGELOOP = 2;
47 private final static int STATE_SHUTDOWN = 3;
48 private final static int STATE_CLEANUP = 4;
49 private final static int STATE_DONE = 5;
50
51 private int runState = STATE_NONE;
52
53 private Clipboard clipboard;
54 private MouseInfoPeer mouseInfoPeer;
55
56 /**
57 * Dynamic Layout Resize client code setting.
58 */
59 private volatile boolean dynamicLayoutSetting = true;
60
61 protected LWToolkit() {
62 }
63
64 /*
65 * This method is called by subclasses to start this toolkit
66 * by launching the message loop.
67 *
68 * This method waits for the toolkit to be completely initialized
69 * and returns before the message pump is started.
70 */
71 protected final void init() {
72 AWTAutoShutdown.notifyToolkitThreadBusy();
73
74 ThreadGroup rootTG = AccessController.doPrivileged(
75 (PrivilegedAction<ThreadGroup>) ThreadGroupUtils::getRootThreadGroup);
76
77 Runtime.getRuntime().addShutdownHook(
78 new Thread(rootTG, () -> {
79 shutdown();
80 waitForRunState(STATE_CLEANUP);
81 })
82 );
83
84 Thread toolkitThread = new Thread(rootTG, this, "AWT-LW");
85 toolkitThread.setDaemon(true);
86 toolkitThread.setPriority(Thread.NORM_PRIORITY + 1);
87 toolkitThread.start();
88
89 waitForRunState(STATE_MESSAGELOOP);
90 }
91
92 /*
93 * Implemented in subclasses to initialize platform-dependent
94 * part of the toolkit (open X display connection, create
95 * toolkit HWND, etc.)
96 *
97 * This method is called on the toolkit thread.
98 */
99 protected abstract void platformInit();
100
101 /*
102 * Sends a request to stop the message pump.
103 */
104 public final void shutdown() {
105 setRunState(STATE_SHUTDOWN);
106 platformShutdown();
107 }
108
109 /*
110 * Implemented in subclasses to release all the platform-
111 * dependent resources. Called after the message loop is
112 * terminated.
113 *
114 * Could be called (always called?) on a non-toolkit thread.
115 */
116 protected abstract void platformShutdown();
117
118 /*
119 * Implemented in subclasses to release all the platform
120 * resources before the application is terminated.
121 *
122 * This method is called on the toolkit thread.
123 */
124 protected abstract void platformCleanup();
125
126 private synchronized int getRunState() {
127 return runState;
128 }
129
130 private synchronized void setRunState(int state) {
131 runState = state;
132 notifyAll();
133 }
134
135 public final boolean isTerminating() {
136 return getRunState() >= STATE_SHUTDOWN;
137 }
138
139 private void waitForRunState(int state) {
140 while (getRunState() < state) {
141 try {
142 synchronized (this) {
143 wait();
144 }
145 } catch (InterruptedException z) {
146 // TODO: log
147 break;
148 }
149 }
150 }
151
152 @Override
153 public final void run() {
154 setRunState(STATE_INIT);
155 platformInit();
156 AWTAutoShutdown.notifyToolkitThreadFree();
157 setRunState(STATE_MESSAGELOOP);
158 while (getRunState() < STATE_SHUTDOWN) {
159 try {
160 platformRunMessage();
161 if (Thread.currentThread().isInterrupted()) {
162 if (AppContext.getAppContext().isDisposed()) {
163 break;
164 }
165 }
166 } catch (ThreadDeath td) {
167 //XXX: if there isn't native code on the stack, the VM just
168 //kills the thread right away. Do we expect to catch it
169 //nevertheless?
170 break;
171 } catch (Throwable t) {
172 // TODO: log
173 System.err.println("Exception on the toolkit thread");
174 t.printStackTrace(System.err);
175 }
176 }
177 //XXX: if that's a secondary loop, jump back to the STATE_MESSAGELOOP
178 setRunState(STATE_CLEANUP);
179 AWTAutoShutdown.notifyToolkitThreadFree();
180 platformCleanup();
181 setRunState(STATE_DONE);
182 }
183
184 /*
185 * Process the next message(s) from the native event queue.
186 *
187 * Initially, all the LWToolkit implementations were supposed
188 * to have the similar message loop sequence: check if any events
189 * available, peek events, wait. However, the later analysis shown
190 * that X11 and Windows implementations are really different, so
191 * let the subclasses do whatever they require.
192 */
193 protected abstract void platformRunMessage();
194
195 public static LWToolkit getLWToolkit() {
196 return (LWToolkit)Toolkit.getDefaultToolkit();
197 }
198
199 // ---- TOPLEVEL PEERS ---- //
200
201 /*
202 * Note that LWWindowPeer implements WindowPeer, FramePeer
203 * and DialogPeer interfaces.
204 */
205 protected LWWindowPeer createDelegatedPeer(Window target,
206 PlatformComponent platformComponent,
207 PlatformWindow platformWindow,
208 PeerType peerType) {
209 LWWindowPeer peer = new LWWindowPeer(target, platformComponent, platformWindow, peerType);
210 targetCreatedPeer(target, peer);
211 peer.initialize();
212 return peer;
213 }
214
215 @Override
216 public final FramePeer createLightweightFrame(LightweightFrame target) {
217 PlatformComponent platformComponent = createLwPlatformComponent();
218 PlatformWindow platformWindow = createPlatformWindow(PeerType.LW_FRAME);
219 LWLightweightFramePeer peer = new LWLightweightFramePeer(target,
220 platformComponent,
221 platformWindow);
222 targetCreatedPeer(target, peer);
223 peer.initialize();
224 return peer;
225 }
226
227 @Override
228 public final WindowPeer createWindow(Window target) {
229 PlatformComponent platformComponent = createPlatformComponent();
230 PlatformWindow platformWindow = createPlatformWindow(PeerType.SIMPLEWINDOW);
231 return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.SIMPLEWINDOW);
232 }
233
234 @Override
235 public final FramePeer createFrame(Frame target) {
236 PlatformComponent platformComponent = createPlatformComponent();
237 PlatformWindow platformWindow = createPlatformWindow(PeerType.FRAME);
238 return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.FRAME);
239 }
240
241 @Override
242 public DialogPeer createDialog(Dialog target) {
243 PlatformComponent platformComponent = createPlatformComponent();
244 PlatformWindow platformWindow = createPlatformWindow(PeerType.DIALOG);
245 return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.DIALOG);
246 }
247
248 @Override
249 public final FileDialogPeer createFileDialog(FileDialog target) {
250 FileDialogPeer peer = createFileDialogPeer(target);
251 targetCreatedPeer(target, peer);
252 return peer;
253 }
254
255 // ---- LIGHTWEIGHT COMPONENT PEERS ---- //
256
257 @Override
258 public final ButtonPeer createButton(Button target) {
259 PlatformComponent platformComponent = createPlatformComponent();
260 LWButtonPeer peer = new LWButtonPeer(target, platformComponent);
261 targetCreatedPeer(target, peer);
262 peer.initialize();
263 return peer;
264 }
265
266 @Override
267 public final CheckboxPeer createCheckbox(Checkbox target) {
268 PlatformComponent platformComponent = createPlatformComponent();
269 LWCheckboxPeer peer = new LWCheckboxPeer(target, platformComponent);
270 targetCreatedPeer(target, peer);
271 peer.initialize();
272 return peer;
273 }
274
275 @Override
276 public final ChoicePeer createChoice(Choice target) {
277 PlatformComponent platformComponent = createPlatformComponent();
278 LWChoicePeer peer = new LWChoicePeer(target, platformComponent);
279 targetCreatedPeer(target, peer);
280 peer.initialize();
281 return peer;
282 }
283
284 @Override
285 public final LabelPeer createLabel(Label target) {
286 PlatformComponent platformComponent = createPlatformComponent();
287 LWLabelPeer peer = new LWLabelPeer(target, platformComponent);
288 targetCreatedPeer(target, peer);
289 peer.initialize();
290 return peer;
291 }
292
293 @Override
294 public final CanvasPeer createCanvas(Canvas target) {
295 PlatformComponent platformComponent = createPlatformComponent();
296 LWCanvasPeer<?, ?> peer = new LWCanvasPeer<>(target, platformComponent);
297 targetCreatedPeer(target, peer);
298 peer.initialize();
299 return peer;
300 }
301
302 @Override
303 public final ListPeer createList(List target) {
304 PlatformComponent platformComponent = createPlatformComponent();
305 LWListPeer peer = new LWListPeer(target, platformComponent);
306 targetCreatedPeer(target, peer);
307 peer.initialize();
308 return peer;
309 }
310
311 @Override
312 public final PanelPeer createPanel(Panel target) {
313 PlatformComponent platformComponent = createPlatformComponent();
314 LWPanelPeer peer = new LWPanelPeer(target, platformComponent);
315 targetCreatedPeer(target, peer);
316 peer.initialize();
317 return peer;
318 }
319
320 @Override
321 public final ScrollPanePeer createScrollPane(ScrollPane target) {
322 PlatformComponent platformComponent = createPlatformComponent();
323 LWScrollPanePeer peer = new LWScrollPanePeer(target, platformComponent);
324 targetCreatedPeer(target, peer);
325 peer.initialize();
326 return peer;
327 }
328
329 @Override
330 public final ScrollbarPeer createScrollbar(Scrollbar target) {
331 PlatformComponent platformComponent = createPlatformComponent();
332 LWScrollBarPeer peer = new LWScrollBarPeer(target, platformComponent);
333 targetCreatedPeer(target, peer);
334 peer.initialize();
335 return peer;
336 }
337
338 @Override
339 public final TextAreaPeer createTextArea(TextArea target) {
340 PlatformComponent platformComponent = createPlatformComponent();
341 LWTextAreaPeer peer = new LWTextAreaPeer(target, platformComponent);
342 targetCreatedPeer(target, peer);
343 peer.initialize();
344 return peer;
345 }
346
347 @Override
348 public final TextFieldPeer createTextField(TextField target) {
349 PlatformComponent platformComponent = createPlatformComponent();
350 LWTextFieldPeer peer = new LWTextFieldPeer(target, platformComponent);
351 targetCreatedPeer(target, peer);
352 peer.initialize();
353 return peer;
354 }
355
356 // ---- NON-COMPONENT PEERS ---- //
357
358 @Override
359 public final ColorModel getColorModel() throws HeadlessException {
360 return GraphicsEnvironment.getLocalGraphicsEnvironment()
361 .getDefaultScreenDevice()
362 .getDefaultConfiguration().getColorModel();
363 }
364
365 @Override
366 public final boolean isDesktopSupported() {
367 return true;
368 }
369
370 @Override
371 public final KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() {
372 return LWKeyboardFocusManagerPeer.getInstance();
373 }
374
375 @Override
376 public final synchronized MouseInfoPeer getMouseInfoPeer() {
377 if (mouseInfoPeer == null) {
378 mouseInfoPeer = createMouseInfoPeerImpl();
379 }
380 return mouseInfoPeer;
381 }
382
383 protected final MouseInfoPeer createMouseInfoPeerImpl() {
384 return new LWMouseInfoPeer();
385 }
386
387 @Override
388 public final PrintJob getPrintJob(Frame frame, String doctitle,
389 Properties props) {
390 return getPrintJob(frame, doctitle, null, null);
391 }
392
393 @Override
394 public final PrintJob getPrintJob(Frame frame, String doctitle,
395 JobAttributes jobAttributes,
396 PageAttributes pageAttributes) {
397 if (GraphicsEnvironment.isHeadless()) {
398 throw new IllegalArgumentException();
399 }
400
401 PrintJob2D printJob = new PrintJob2D(frame, doctitle, jobAttributes, pageAttributes);
402
403 if (!printJob.printDialog()) {
404 printJob = null;
405 }
406
407 return printJob;
408 }
409
410 @Override
411 public final Clipboard getSystemClipboard() {
412 SecurityManager security = System.getSecurityManager();
413 if (security != null) {
414 security.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION);
415 }
416
417 synchronized (this) {
418 if (clipboard == null) {
419 clipboard = createPlatformClipboard();
420 }
421 }
422 return clipboard;
423 }
424
425 protected abstract SecurityWarningWindow createSecurityWarning(
426 Window ownerWindow, LWWindowPeer ownerPeer);
427
428 // ---- DELEGATES ---- //
429
430 public abstract Clipboard createPlatformClipboard();
431
432 /*
433 * Creates a delegate for the given peer type (window, frame, dialog, etc.)
434 */
435 protected abstract PlatformWindow createPlatformWindow(PeerType peerType);
436
437 protected abstract PlatformComponent createPlatformComponent();
438
439 protected abstract PlatformComponent createLwPlatformComponent();
440
441 protected abstract FileDialogPeer createFileDialogPeer(FileDialog target);
442
443 // ---- UTILITY METHODS ---- //
444
445 /*
446 * Expose non-public targetToPeer() method.
447 */
448 public final static Object targetToPeer(Object target) {
449 return SunToolkit.targetToPeer(target);
450 }
451
452 /*
453 * Expose non-public targetDisposedPeer() method.
454 */
455 public final static void targetDisposedPeer(Object target, Object peer) {
456 SunToolkit.targetDisposedPeer(target, peer);
457 }
458
459 /*
460 * Returns the current cursor manager.
461 */
462 public abstract LWCursorManager getCursorManager();
463
464 public static void postEvent(AWTEvent event) {
465 postEvent(targetToAppContext(event.getSource()), event);
466 }
467
468 @Override
469 public final void grab(final Window w) {
470 final Object peer = AWTAccessor.getComponentAccessor().getPeer(w);
471 if (peer != null) {
472 ((LWWindowPeer) peer).grab();
473 }
474 }
475
476 @Override
477 public final void ungrab(final Window w) {
478 final Object peer = AWTAccessor.getComponentAccessor().getPeer(w);
479 if (peer != null) {
480 ((LWWindowPeer) peer).ungrab(false);
481 }
482 }
483
484 @Override
485 protected final Object lazilyLoadDesktopProperty(final String name) {
486 if (name.equals("awt.dynamicLayoutSupported")) {
487 return isDynamicLayoutSupported();
488 }
489 return super.lazilyLoadDesktopProperty(name);
490 }
491
492 @Override
493 public final void setDynamicLayout(final boolean dynamic) {
494 dynamicLayoutSetting = dynamic;
495 }
496
497 @Override
498 protected final boolean isDynamicLayoutSet() {
499 return dynamicLayoutSetting;
500 }
501
502 @Override
503 public final boolean isDynamicLayoutActive() {
504 // "Live resizing" is active by default and user's data is ignored.
505 return isDynamicLayoutSupported();
506 }
507
508 /**
509 * Returns true if dynamic layout of Containers on resize is supported by
510 * the underlying operating system and/or window manager.
511 */
512 protected final boolean isDynamicLayoutSupported() {
513 // "Live resizing" is supported by default.
514 return true;
515 }
516 }
--- EOF ---