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