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