1 /* 2 * Copyright (c) 2011, 2015, 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.misc.ManagedLocalsThread; 39 import sun.print.*; 40 import sun.awt.util.ThreadGroupUtils; 41 42 import static sun.lwawt.LWWindowPeer.PeerType; 43 44 public abstract class LWToolkit extends SunToolkit implements Runnable { 45 46 private static final int STATE_NONE = 0; 47 private static final int STATE_INIT = 1; 48 private static final int STATE_MESSAGELOOP = 2; 49 private static final int STATE_SHUTDOWN = 3; 50 private static final int STATE_CLEANUP = 4; 51 private static final int STATE_DONE = 5; 52 53 private int runState = STATE_NONE; 54 55 private Clipboard clipboard; 56 private MouseInfoPeer mouseInfoPeer; 57 58 /** 59 * Dynamic Layout Resize client code setting. 60 */ 61 private volatile boolean dynamicLayoutSetting = true; 62 63 protected LWToolkit() { 64 } 65 66 /* 67 * This method is called by subclasses to start this toolkit 68 * by launching the message loop. 69 * 70 * This method waits for the toolkit to be completely initialized 71 * and returns before the message pump is started. 72 */ 73 protected final void init() { 74 AWTAutoShutdown.notifyToolkitThreadBusy(); 75 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 76 Runnable shutdownRunnable = () -> { 77 shutdown(); 78 waitForRunState(STATE_CLEANUP); 79 }; 80 Thread shutdown = new ManagedLocalsThread( 81 ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); 82 shutdown.setContextClassLoader(null); 83 Runtime.getRuntime().addShutdownHook(shutdown); 84 String name = "AWT-LW"; 85 Thread toolkitThread = new ManagedLocalsThread( 86 ThreadGroupUtils.getRootThreadGroup(), this, name); 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 KeyboardFocusManagerPeer getKeyboardFocusManagerPeer() { 375 return LWKeyboardFocusManagerPeer.getInstance(); 376 } 377 378 @Override 379 public final synchronized MouseInfoPeer getMouseInfoPeer() { 380 if (mouseInfoPeer == null) { 381 mouseInfoPeer = createMouseInfoPeerImpl(); 382 } 383 return mouseInfoPeer; 384 } 385 386 protected final MouseInfoPeer createMouseInfoPeerImpl() { 387 return new LWMouseInfoPeer(); 388 } 389 390 protected abstract PlatformWindow getPlatformWindowUnderMouse(); 391 392 @Override 393 public final PrintJob getPrintJob(Frame frame, String doctitle, 394 Properties props) { 395 return getPrintJob(frame, doctitle, null, null); 396 } 397 398 @Override 399 public final PrintJob getPrintJob(Frame frame, String doctitle, 400 JobAttributes jobAttributes, 401 PageAttributes pageAttributes) { 402 if (GraphicsEnvironment.isHeadless()) { 403 throw new IllegalArgumentException(); 404 } 405 406 PrintJob2D printJob = new PrintJob2D(frame, doctitle, jobAttributes, pageAttributes); 407 408 if (!printJob.printDialog()) { 409 printJob = null; 410 } 411 412 return printJob; 413 } 414 415 @Override 416 public final Clipboard getSystemClipboard() { 417 SecurityManager security = System.getSecurityManager(); 418 if (security != null) { 419 security.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION); 420 } 421 422 synchronized (this) { 423 if (clipboard == null) { 424 clipboard = createPlatformClipboard(); 425 } 426 } 427 return clipboard; 428 } 429 430 protected abstract SecurityWarningWindow createSecurityWarning( 431 Window ownerWindow, LWWindowPeer ownerPeer); 432 433 // ---- DELEGATES ---- // 434 435 public abstract Clipboard createPlatformClipboard(); 436 437 /* 438 * Creates a delegate for the given peer type (window, frame, dialog, etc.) 439 */ 440 protected abstract PlatformWindow createPlatformWindow(PeerType peerType); 441 442 protected abstract PlatformComponent createPlatformComponent(); 443 444 protected abstract PlatformComponent createLwPlatformComponent(); 445 446 protected abstract FileDialogPeer createFileDialogPeer(FileDialog target); 447 448 protected abstract PlatformDropTarget createDropTarget(DropTarget dropTarget, 449 Component component, 450 LWComponentPeer<?, ?> peer); 451 452 // ---- UTILITY METHODS ---- // 453 454 /* 455 * Expose non-public targetToPeer() method. 456 */ 457 public static final Object targetToPeer(Object target) { 458 return SunToolkit.targetToPeer(target); 459 } 460 461 /* 462 * Expose non-public targetDisposedPeer() method. 463 */ 464 public static final void targetDisposedPeer(Object target, Object peer) { 465 SunToolkit.targetDisposedPeer(target, peer); 466 } 467 468 /* 469 * Returns the current cursor manager. 470 */ 471 public abstract LWCursorManager getCursorManager(); 472 473 public static void postEvent(AWTEvent event) { 474 postEvent(targetToAppContext(event.getSource()), event); 475 } 476 477 @Override 478 public final void grab(final Window w) { 479 final Object peer = AWTAccessor.getComponentAccessor().getPeer(w); 480 if (peer != null) { 481 ((LWWindowPeer) peer).grab(); 482 } 483 } 484 485 @Override 486 public final void ungrab(final Window w) { 487 final Object peer = AWTAccessor.getComponentAccessor().getPeer(w); 488 if (peer != null) { 489 ((LWWindowPeer) peer).ungrab(false); 490 } 491 } 492 493 @Override 494 protected final Object lazilyLoadDesktopProperty(final String name) { 495 if (name.equals("awt.dynamicLayoutSupported")) { 496 return isDynamicLayoutSupported(); 497 } 498 return super.lazilyLoadDesktopProperty(name); 499 } 500 501 @Override 502 public final void setDynamicLayout(final boolean dynamic) { 503 dynamicLayoutSetting = dynamic; 504 } 505 506 @Override 507 protected final boolean isDynamicLayoutSet() { 508 return dynamicLayoutSetting; 509 } 510 511 @Override 512 public final boolean isDynamicLayoutActive() { 513 // "Live resizing" is active by default and user's data is ignored. 514 return isDynamicLayoutSupported(); 515 } 516 517 /** 518 * Returns true if dynamic layout of Containers on resize is supported by 519 * the underlying operating system and/or window manager. 520 */ 521 protected final boolean isDynamicLayoutSupported() { 522 // "Live resizing" is supported by default. 523 return true; 524 } 525 }