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.misc.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 }