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.macosx;
27
28 import java.awt.*;
29 import java.awt.datatransfer.Clipboard;
30 import java.awt.dnd.*;
31 import java.awt.dnd.peer.DragSourceContextPeer;
32 import java.awt.event.InputEvent;
33 import java.awt.event.InvocationEvent;
34 import java.awt.event.KeyEvent;
35 import java.awt.font.TextAttribute;
36 import java.awt.im.InputMethodHighlight;
37 import java.awt.im.spi.InputMethodDescriptor;
38 import java.awt.peer.*;
39 import java.lang.reflect.*;
40 import java.net.URL;
41 import java.security.*;
42 import java.util.*;
43 import java.util.concurrent.Callable;
44 import java.net.MalformedURLException;
45
46 import sun.awt.*;
47 import sun.awt.datatransfer.DataTransferer;
48 import sun.awt.util.ThreadGroupUtils;
49 import sun.java2d.opengl.OGLRenderQueue;
50 import sun.lwawt.*;
51 import sun.lwawt.LWWindowPeer.PeerType;
52 import sun.security.action.GetBooleanAction;
53
54 import sun.util.CoreResourceBundleControl;
55
56 @SuppressWarnings("serial") // JDK implementation class
57 final class NamedCursor extends Cursor {
58 NamedCursor(String name) {
59 super(name);
60 }
61 }
62
63 /**
64 * Mac OS X Cocoa-based AWT Toolkit.
65 */
66 public final class LWCToolkit extends LWToolkit {
67 // While it is possible to enumerate all mouse devices
68 // and query them for the number of buttons, the code
69 // that does it is rather complex. Instead, we opt for
70 // the easy way and just support up to 5 mouse buttons,
71 // like Windows.
72 private static final int BUTTONS = 5;
73
74 private static native void initIDs();
75 private static native void initAppkit(ThreadGroup appKitThreadGroup, boolean headless);
76 private static CInputMethodDescriptor sInputMethodDescriptor;
77
78 static {
79 System.err.flush();
80
81 ResourceBundle platformResources = java.security.AccessController.doPrivileged(
82 new java.security.PrivilegedAction<ResourceBundle>() {
83 @Override
84 public ResourceBundle run() {
85 ResourceBundle platformResources = null;
86 try {
87 platformResources =
88 ResourceBundle.getBundle("sun.awt.resources.awtosx",
89 CoreResourceBundleControl.getRBControlInstance());
90 } catch (MissingResourceException e) {
91 // No resource file; defaults will be used.
92 }
93
94 System.loadLibrary("awt");
95 System.loadLibrary("fontmanager");
96
97 return platformResources;
98 }
99 });
100
101 AWTAccessor.getToolkitAccessor().setPlatformResources(platformResources);
102
103 if (!GraphicsEnvironment.isHeadless()) {
104 initIDs();
105 }
106 inAWT = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
107 @Override
108 public Boolean run() {
109 return !Boolean.parseBoolean(System.getProperty("javafx.embed.singleThread", "false"));
110 }
111 });
112 }
113
114 /*
115 * If true we operate in normal mode and nested runloop is executed in JavaRunLoopMode
116 * If false we operate in singleThreaded FX/AWT interop mode and nested loop uses NSDefaultRunLoopMode
117 */
118 private static final boolean inAWT;
119
120 public LWCToolkit() {
121 areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));
122 //set system property if not yet assigned
123 System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled);
124 initAppkit(ThreadGroupUtils.getRootThreadGroup(), GraphicsEnvironment.isHeadless());
125 }
126
127 /*
128 * System colors with default initial values, overwritten by toolkit if system values differ and are available.
129 */
130 private final static int NUM_APPLE_COLORS = 3;
131 public final static int KEYBOARD_FOCUS_COLOR = 0;
132 public final static int INACTIVE_SELECTION_BACKGROUND_COLOR = 1;
133 public final static int INACTIVE_SELECTION_FOREGROUND_COLOR = 2;
134 private static int[] appleColors = {
135 0xFF808080, // keyboardFocusColor = Color.gray;
136 0xFFC0C0C0, // secondarySelectedControlColor
137 0xFF303030, // controlDarkShadowColor
138 };
139
140 private native void loadNativeColors(final int[] systemColors, final int[] appleColors);
141
142 @Override
143 protected void loadSystemColors(final int[] systemColors) {
144 if (systemColors == null) return;
145 loadNativeColors(systemColors, appleColors);
146 }
147
148 @SuppressWarnings("serial") // JDK implementation class
149 private static class AppleSpecificColor extends Color {
150 private final int index;
151 AppleSpecificColor(int index) {
152 super(appleColors[index]);
153 this.index = index;
154 }
155
156 @Override
157 public int getRGB() {
158 return appleColors[index];
159 }
160 }
161
162 /**
163 * Returns Apple specific colors that we may expose going forward.
164 */
165 public static Color getAppleColor(int color) {
166 return new AppleSpecificColor(color);
167 }
168
169 // This is only called from native code.
170 static void systemColorsChanged() {
171 EventQueue.invokeLater(() -> {
172 AccessController.doPrivileged( (PrivilegedAction<Object>) () -> {
173 AWTAccessor.getSystemColorAccessor().updateSystemColors();
174 return null;
175 });
176 });
177 }
178
179 public static LWCToolkit getLWCToolkit() {
180 return (LWCToolkit)Toolkit.getDefaultToolkit();
181 }
182
183 @Override
184 protected PlatformWindow createPlatformWindow(PeerType peerType) {
185 if (peerType == PeerType.EMBEDDED_FRAME) {
186 return new CPlatformEmbeddedFrame();
187 } else if (peerType == PeerType.VIEW_EMBEDDED_FRAME) {
188 return new CViewPlatformEmbeddedFrame();
189 } else if (peerType == PeerType.LW_FRAME) {
190 return new CPlatformLWWindow();
191 } else {
192 assert (peerType == PeerType.SIMPLEWINDOW
193 || peerType == PeerType.DIALOG
194 || peerType == PeerType.FRAME);
195 return new CPlatformWindow();
196 }
197 }
198
199 LWWindowPeer createEmbeddedFrame(CEmbeddedFrame target) {
200 PlatformComponent platformComponent = createPlatformComponent();
201 PlatformWindow platformWindow = createPlatformWindow(PeerType.EMBEDDED_FRAME);
202 return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.EMBEDDED_FRAME);
203 }
204
205 LWWindowPeer createEmbeddedFrame(CViewEmbeddedFrame target) {
206 PlatformComponent platformComponent = createPlatformComponent();
207 PlatformWindow platformWindow = createPlatformWindow(PeerType.VIEW_EMBEDDED_FRAME);
208 return createDelegatedPeer(target, platformComponent, platformWindow, PeerType.VIEW_EMBEDDED_FRAME);
209 }
210
211 private CPrinterDialogPeer createCPrinterDialog(CPrinterDialog target) {
212 PlatformComponent platformComponent = createPlatformComponent();
213 PlatformWindow platformWindow = createPlatformWindow(PeerType.DIALOG);
214 CPrinterDialogPeer peer = new CPrinterDialogPeer(target, platformComponent, platformWindow);
215 targetCreatedPeer(target, peer);
216 return peer;
217 }
218
219 @Override
220 public DialogPeer createDialog(Dialog target) {
221 if (target instanceof CPrinterDialog) {
222 return createCPrinterDialog((CPrinterDialog)target);
223 }
224 return super.createDialog(target);
225 }
226
227 @Override
228 protected SecurityWarningWindow createSecurityWarning(Window ownerWindow,
229 LWWindowPeer ownerPeer) {
230 return new CWarningWindow(ownerWindow, ownerPeer);
231 }
232
233 @Override
234 protected PlatformComponent createPlatformComponent() {
235 return new CPlatformComponent();
236 }
237
238 @Override
239 protected PlatformComponent createLwPlatformComponent() {
240 return new CPlatformLWComponent();
241 }
242
243 @Override
244 protected FileDialogPeer createFileDialogPeer(FileDialog target) {
245 return new CFileDialog(target);
246 }
247
248 @Override
249 public MenuPeer createMenu(Menu target) {
250 MenuPeer peer = new CMenu(target);
251 targetCreatedPeer(target, peer);
252 return peer;
253 }
254
255 @Override
256 public MenuBarPeer createMenuBar(MenuBar target) {
257 MenuBarPeer peer = new CMenuBar(target);
258 targetCreatedPeer(target, peer);
259 return peer;
260 }
261
262 @Override
263 public MenuItemPeer createMenuItem(MenuItem target) {
264 MenuItemPeer peer = new CMenuItem(target);
265 targetCreatedPeer(target, peer);
266 return peer;
267 }
268
269 @Override
270 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) {
271 CheckboxMenuItemPeer peer = new CCheckboxMenuItem(target);
272 targetCreatedPeer(target, peer);
273 return peer;
274 }
275
276 @Override
277 public PopupMenuPeer createPopupMenu(PopupMenu target) {
278 PopupMenuPeer peer = new CPopupMenu(target);
279 targetCreatedPeer(target, peer);
280 return peer;
281 }
282
283 @Override
284 public SystemTrayPeer createSystemTray(SystemTray target) {
285 return new CSystemTray();
286 }
287
288 @Override
289 public TrayIconPeer createTrayIcon(TrayIcon target) {
290 TrayIconPeer peer = new CTrayIcon(target);
291 targetCreatedPeer(target, peer);
292 return peer;
293 }
294
295 @Override
296 protected DesktopPeer createDesktopPeer(Desktop target) {
297 return new CDesktopPeer();
298 }
299
300 @Override
301 public LWCursorManager getCursorManager() {
302 return CCursorManager.getInstance();
303 }
304
305 @Override
306 public Cursor createCustomCursor(final Image cursor, final Point hotSpot,
307 final String name)
308 throws IndexOutOfBoundsException, HeadlessException {
309 return new CCustomCursor(cursor, hotSpot, name);
310 }
311
312 @Override
313 public Dimension getBestCursorSize(final int preferredWidth,
314 final int preferredHeight)
315 throws HeadlessException {
316 return CCustomCursor.getBestCursorSize(preferredWidth, preferredHeight);
317 }
318
319 @Override
320 protected void platformCleanup() {
321 // TODO Auto-generated method stub
322 }
323
324 @Override
325 protected void platformInit() {
326 // TODO Auto-generated method stub
327 }
328
329 @Override
330 protected void platformRunMessage() {
331 // TODO Auto-generated method stub
332 }
333
334 @Override
335 protected void platformShutdown() {
336 // TODO Auto-generated method stub
337 }
338
339 class OSXPlatformFont extends sun.awt.PlatformFont
340 {
341 OSXPlatformFont(String name, int style)
342 {
343 super(name, style);
344 }
345 @Override
346 protected char getMissingGlyphCharacter()
347 {
348 // Follow up for real implementation
349 return (char)0xfff8; // see http://developer.apple.com/fonts/LastResortFont/
350 }
351 }
352 @Override
353 public FontPeer getFontPeer(String name, int style) {
354 return new OSXPlatformFont(name, style);
355 }
356
357 @Override
358 protected int getScreenHeight() {
359 return GraphicsEnvironment.getLocalGraphicsEnvironment()
360 .getDefaultScreenDevice().getDefaultConfiguration().getBounds().height;
361 }
362
363 @Override
364 protected int getScreenWidth() {
365 return GraphicsEnvironment.getLocalGraphicsEnvironment()
366 .getDefaultScreenDevice().getDefaultConfiguration().getBounds().width;
367 }
368
369 @Override
370 protected void initializeDesktopProperties() {
371 super.initializeDesktopProperties();
372 Map <Object, Object> fontHints = new HashMap<>();
373 fontHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
374 fontHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
375 desktopProperties.put(SunToolkit.DESKTOPFONTHINTS, fontHints);
376 desktopProperties.put("awt.mouse.numButtons", BUTTONS);
377
378 // These DnD properties must be set, otherwise Swing ends up spewing NPEs
379 // all over the place. The values came straight off of MToolkit.
380 desktopProperties.put("DnD.Autoscroll.initialDelay", new Integer(50));
381 desktopProperties.put("DnD.Autoscroll.interval", new Integer(50));
382 desktopProperties.put("DnD.Autoscroll.cursorHysteresis", new Integer(5));
383
384 desktopProperties.put("DnD.isDragImageSupported", new Boolean(true));
385
386 // Register DnD cursors
387 desktopProperties.put("DnD.Cursor.CopyDrop", new NamedCursor("DnD.Cursor.CopyDrop"));
388 desktopProperties.put("DnD.Cursor.MoveDrop", new NamedCursor("DnD.Cursor.MoveDrop"));
389 desktopProperties.put("DnD.Cursor.LinkDrop", new NamedCursor("DnD.Cursor.LinkDrop"));
390 desktopProperties.put("DnD.Cursor.CopyNoDrop", new NamedCursor("DnD.Cursor.CopyNoDrop"));
391 desktopProperties.put("DnD.Cursor.MoveNoDrop", new NamedCursor("DnD.Cursor.MoveNoDrop"));
392 desktopProperties.put("DnD.Cursor.LinkNoDrop", new NamedCursor("DnD.Cursor.LinkNoDrop"));
393 }
394
395 @Override
396 protected boolean syncNativeQueue(long timeout) {
397 return nativeSyncQueue(timeout);
398 }
399
400 @Override
401 public native void beep();
402
403 @Override
404 public int getScreenResolution() throws HeadlessException {
405 return (int) ((CGraphicsDevice) GraphicsEnvironment
406 .getLocalGraphicsEnvironment().getDefaultScreenDevice())
407 .getXResolution();
408 }
409
410 @Override
411 public Insets getScreenInsets(final GraphicsConfiguration gc) {
412 return ((CGraphicsConfig) gc).getDevice().getScreenInsets();
413 }
414
415 @Override
416 public void sync() {
417 // flush the OGL pipeline (this is a no-op if OGL is not enabled)
418 OGLRenderQueue.sync();
419 // setNeedsDisplay() selector was sent to the appropriate CALayer so now
420 // we have to flush the native selectors queue.
421 flushNativeSelectors();
422 }
423
424 @Override
425 public RobotPeer createRobot(Robot target, GraphicsDevice screen) {
426 return new CRobot(target, (CGraphicsDevice)screen);
427 }
428
429 private native boolean isCapsLockOn();
430
431 /*
432 * NOTE: Among the keys this method is supposed to check,
433 * only Caps Lock works as a true locking key with OS X.
434 * There is no Scroll Lock key on modern Apple keyboards,
435 * and with a PC keyboard plugged in Scroll Lock is simply
436 * ignored: no LED lights up if you press it.
437 * The key located at the same position on Apple keyboards
438 * as Num Lock on PC keyboards is called Clear, doesn't lock
439 * anything and is used for entirely different purpose.
440 */
441 @Override
442 public boolean getLockingKeyState(int keyCode) throws UnsupportedOperationException {
443 switch (keyCode) {
444 case KeyEvent.VK_NUM_LOCK:
445 case KeyEvent.VK_SCROLL_LOCK:
446 case KeyEvent.VK_KANA_LOCK:
447 throw new UnsupportedOperationException("Toolkit.getLockingKeyState");
448
449 case KeyEvent.VK_CAPS_LOCK:
450 return isCapsLockOn();
451
452 default:
453 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState");
454 }
455 }
456
457 //Is it allowed to generate events assigned to extra mouse buttons.
458 //Set to true by default.
459 private static boolean areExtraMouseButtonsEnabled = true;
460
461 @Override
462 public boolean areExtraMouseButtonsEnabled() throws HeadlessException {
463 return areExtraMouseButtonsEnabled;
464 }
465
466 @Override
467 public int getNumberOfButtons(){
468 return BUTTONS;
469 }
470
471 @Override
472 public boolean isTraySupported() {
473 return true;
474 }
475
476 @Override
477 public DataTransferer getDataTransferer() {
478 return CDataTransferer.getInstanceImpl();
479 }
480
481 @Override
482 public boolean isAlwaysOnTopSupported() {
483 return true;
484 }
485
486 private static final String APPKIT_THREAD_NAME = "AppKit Thread";
487
488 // Intended to be called from the LWCToolkit.m only.
489 private static void installToolkitThreadInJava() {
490 Thread.currentThread().setName(APPKIT_THREAD_NAME);
491 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
492 Thread.currentThread().setContextClassLoader(null);
493 return null;
494 });
495 }
496
497 @Override
498 public boolean isWindowOpacitySupported() {
499 return true;
500 }
501
502 @Override
503 public boolean isFrameStateSupported(int state) throws HeadlessException {
504 switch (state) {
505 case Frame.NORMAL:
506 case Frame.ICONIFIED:
507 case Frame.MAXIMIZED_BOTH:
508 return true;
509 default:
510 return false;
511 }
512 }
513
514 /**
515 * Determines which modifier key is the appropriate accelerator
516 * key for menu shortcuts.
517 * <p>
518 * Menu shortcuts, which are embodied in the
519 * <code>MenuShortcut</code> class, are handled by the
520 * <code>MenuBar</code> class.
521 * <p>
522 * By default, this method returns <code>Event.CTRL_MASK</code>.
523 * Toolkit implementations should override this method if the
524 * <b>Control</b> key isn't the correct key for accelerators.
525 * @return the modifier mask on the <code>Event</code> class
526 * that is used for menu shortcuts on this toolkit.
527 * @see java.awt.MenuBar
528 * @see java.awt.MenuShortcut
529 * @since 1.1
530 */
531 @Override
532 public int getMenuShortcutKeyMask() {
533 return Event.META_MASK;
534 }
535
536 @Override
537 public Image getImage(final String filename) {
538 final Image nsImage = checkForNSImage(filename);
539 if (nsImage != null) {
540 return nsImage;
541 }
542
543 if (imageCached(filename)) {
544 return super.getImage(filename);
545 }
546
547 String filename2x = getScaledImageName(filename);
548 return (imageExists(filename2x))
549 ? getImageWithResolutionVariant(filename, filename2x)
550 : super.getImage(filename);
551 }
552
553 @Override
554 public Image getImage(URL url) {
555
556 if (imageCached(url)) {
557 return super.getImage(url);
558 }
559
560 URL url2x = getScaledImageURL(url);
561 return (imageExists(url2x))
562 ? getImageWithResolutionVariant(url, url2x) : super.getImage(url);
563 }
564
565 private static final String nsImagePrefix = "NSImage://";
566 private Image checkForNSImage(final String imageName) {
567 if (imageName == null) return null;
568 if (!imageName.startsWith(nsImagePrefix)) return null;
569 return CImage.getCreator().createImageFromName(imageName.substring(nsImagePrefix.length()));
570 }
571
572 // Thread-safe Object.equals() called from native
573 public static boolean doEquals(final Object a, final Object b, Component c) {
574 if (a == b) return true;
575
576 final boolean[] ret = new boolean[1];
577
578 try { invokeAndWait(new Runnable() { public void run() { synchronized(ret) {
579 ret[0] = a.equals(b);
580 }}}, c); } catch (Exception e) { e.printStackTrace(); }
581
582 synchronized(ret) { return ret[0]; }
583 }
584
585 public static <T> T invokeAndWait(final Callable<T> callable,
586 Component component) throws Exception {
587 final CallableWrapper<T> wrapper = new CallableWrapper<>(callable);
588 invokeAndWait(wrapper, component);
589 return wrapper.getResult();
590 }
591
592 static final class CallableWrapper<T> implements Runnable {
593 final Callable<T> callable;
594 T object;
595 Exception e;
596
597 CallableWrapper(final Callable<T> callable) {
598 this.callable = callable;
599 }
600
601 @Override
602 public void run() {
603 try {
604 object = callable.call();
605 } catch (final Exception e) {
606 this.e = e;
607 }
608 }
609
610 public T getResult() throws Exception {
611 if (e != null) throw e;
612 return object;
613 }
614 }
615
616 /**
617 * Kicks an event over to the appropriate event queue and waits for it to
618 * finish To avoid deadlocking, we manually run the NSRunLoop while waiting
619 * Any selector invoked using ThreadUtilities performOnMainThread will be
620 * processed in doAWTRunLoop The InvocationEvent will call
621 * LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual
622 * run loop. Does not dispatch native events while in the loop
623 */
624 public static void invokeAndWait(Runnable runnable, Component component)
625 throws InvocationTargetException {
626 Objects.requireNonNull(component, "Null component provided to invokeAndWait");
627
628 long mediator = createAWTRunLoopMediator();
629 InvocationEvent invocationEvent =
630 new InvocationEvent(component,
631 runnable,
632 () -> {
633 if (mediator != 0) {
634 stopAWTRunLoop(mediator);
635 }
636 },
637 true);
638
639 AppContext appContext = SunToolkit.targetToAppContext(component);
640 SunToolkit.postEvent(appContext, invocationEvent);
641 // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
642 SunToolkit.flushPendingEvents(appContext);
643 doAWTRunLoop(mediator, false);
644
645 checkException(invocationEvent);
646 }
647
648 public static void invokeLater(Runnable event, Component component)
649 throws InvocationTargetException {
650 Objects.requireNonNull(component, "Null component provided to invokeLater");
651
652 InvocationEvent invocationEvent = new InvocationEvent(component, event);
653
654 AppContext appContext = SunToolkit.targetToAppContext(component);
655 SunToolkit.postEvent(SunToolkit.targetToAppContext(component), invocationEvent);
656 // 3746956 - flush events from PostEventQueue to prevent them from getting stuck and causing a deadlock
657 SunToolkit.flushPendingEvents(appContext);
658
659 checkException(invocationEvent);
660 }
661
662 /**
663 * Checks if exception occurred while {@code InvocationEvent} was processed and rethrows it as
664 * an {@code InvocationTargetException}
665 *
666 * @param event the event to check for an exception
667 * @throws InvocationTargetException if exception occurred when event was processed
668 */
669 private static void checkException(InvocationEvent event) throws InvocationTargetException {
670 Throwable eventException = event.getException();
671 if (eventException == null) return;
672
673 if (eventException instanceof UndeclaredThrowableException) {
674 eventException = ((UndeclaredThrowableException)eventException).getUndeclaredThrowable();
675 }
676 throw new InvocationTargetException(eventException);
677 }
678
679 /**
680 * Schedules a {@code Runnable} execution on the Appkit thread after a delay
681 * @param r a {@code Runnable} to execute
682 * @param delay a delay in milliseconds
683 */
684 native static void performOnMainThreadAfterDelay(Runnable r, long delay);
685
686 // DnD support
687
688 @Override
689 public DragSourceContextPeer createDragSourceContextPeer(
690 DragGestureEvent dge) throws InvalidDnDOperationException {
691 final LightweightFrame f = SunToolkit.getLightweightFrame(dge.getComponent());
692 if (f != null) {
693 return f.createDragSourceContextPeer(dge);
694 }
695
696 return CDragSourceContextPeer.createDragSourceContextPeer(dge);
697 }
698
699 @Override
700 @SuppressWarnings("unchecked")
701 public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
702 Class<T> abstractRecognizerClass, DragSource ds, Component c,
703 int srcActions, DragGestureListener dgl) {
704 final LightweightFrame f = SunToolkit.getLightweightFrame(c);
705 if (f != null) {
706 return f.createDragGestureRecognizer(abstractRecognizerClass, ds, c, srcActions, dgl);
707 }
708
709 DragGestureRecognizer dgr = null;
710
711 // Create a new mouse drag gesture recognizer if we have a class match:
712 if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass))
713 dgr = new CMouseDragGestureRecognizer(ds, c, srcActions, dgl);
714
715 return (T)dgr;
716 }
717
718 @Override
719 protected PlatformDropTarget createDropTarget(DropTarget dropTarget,
720 Component component,
721 LWComponentPeer<?, ?> peer) {
722 return new CDropTarget(dropTarget, component, peer);
723 }
724
725 // InputMethodSupport Method
726 /**
727 * Returns the default keyboard locale of the underlying operating system
728 */
729 @Override
730 public Locale getDefaultKeyboardLocale() {
731 Locale locale = CInputMethod.getNativeLocale();
732
733 if (locale == null) {
734 return super.getDefaultKeyboardLocale();
735 }
736
737 return locale;
738 }
739
740 @Override
741 public InputMethodDescriptor getInputMethodAdapterDescriptor() {
742 if (sInputMethodDescriptor == null)
743 sInputMethodDescriptor = new CInputMethodDescriptor();
744
745 return sInputMethodDescriptor;
746 }
747
748 /**
749 * Returns a map of visual attributes for thelevel description
750 * of the given input method highlight, or null if no mapping is found.
751 * The style field of the input method highlight is ignored. The map
752 * returned is unmodifiable.
753 * @param highlight input method highlight
754 * @return style attribute map, or null
755 * @since 1.3
756 */
757 @Override
758 public Map<TextAttribute, ?> mapInputMethodHighlight(InputMethodHighlight highlight) {
759 return CInputMethod.mapInputMethodHighlight(highlight);
760 }
761
762 /**
763 * Returns key modifiers used by Swing to set up a focus accelerator key
764 * stroke.
765 */
766 @Override
767 public int getFocusAcceleratorKeyMask() {
768 return InputEvent.CTRL_MASK | InputEvent.ALT_MASK;
769 }
770
771 /**
772 * Tests whether specified key modifiers mask can be used to enter a
773 * printable character.
774 */
775 @Override
776 public boolean isPrintableCharacterModifiersMask(int mods) {
777 return ((mods & (InputEvent.META_MASK | InputEvent.CTRL_MASK)) == 0);
778 }
779
780 /**
781 * Returns whether popup is allowed to be shown above the task bar.
782 */
783 @Override
784 public boolean canPopupOverlapTaskBar() {
785 return false;
786 }
787
788 private static Boolean sunAwtDisableCALayers = null;
789
790 /**
791 * Returns the value of "sun.awt.disableCALayers" property. Default
792 * value is {@code false}.
793 */
794 public static synchronized boolean getSunAwtDisableCALayers() {
795 if (sunAwtDisableCALayers == null) {
796 sunAwtDisableCALayers = AccessController.doPrivileged(
797 new GetBooleanAction("sun.awt.disableCALayers"));
798 }
799 return sunAwtDisableCALayers;
800 }
801
802 /*
803 * Returns true if the application (one of its windows) owns keyboard focus.
804 */
805 native boolean isApplicationActive();
806
807 /**
808 * Returns true if AWT toolkit is embedded, false otherwise.
809 *
810 * @return true if AWT toolkit is embedded, false otherwise
811 */
812 public static native boolean isEmbedded();
813
814 /*
815 * Activates application ignoring other apps.
816 */
817 public native void activateApplicationIgnoringOtherApps();
818
819 /************************
820 * Native methods section
821 ************************/
822
823 static native long createAWTRunLoopMediator();
824 /**
825 * Method to run a nested run-loop. The nested loop is spinned in the javaRunLoop mode, so selectors sent
826 * by [JNFRunLoop performOnMainThreadWaiting] are processed.
827 * @param mediator a native pointer to the mediator object created by createAWTRunLoopMediator
828 * @param processEvents if true - dispatches event while in the nested loop. Used in DnD.
829 * Additional attention is needed when using this feature as we short-circuit normal event
830 * processing which could break Appkit.
831 * (One known example is when the window is resized with the mouse)
832 *
833 * if false - all events come after exit form the nested loop
834 */
835 static void doAWTRunLoop(long mediator, boolean processEvents) {
836 doAWTRunLoopImpl(mediator, processEvents, inAWT);
837 }
838 private static native void doAWTRunLoopImpl(long mediator, boolean processEvents, boolean inAWT);
839 static native void stopAWTRunLoop(long mediator);
840
841 private native boolean nativeSyncQueue(long timeout);
842
843 /**
844 * Just spin a single empty block synchronously.
845 */
846 static native void flushNativeSelectors();
847
848 @Override
849 public Clipboard createPlatformClipboard() {
850 return new CClipboard("System");
851 }
852
853 @Override
854 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
855 return (exclusionType == null) ||
856 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
857 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
858 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
859 }
860
861 @Override
862 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
863 //TODO: FileDialog blocks excluded windows...
864 //TODO: Test: 2 file dialogs, separate AppContexts: a) Dialog 1 blocked, shouldn't be. Frame 4 blocked (shouldn't be).
865 return (modalityType == null) ||
866 (modalityType == Dialog.ModalityType.MODELESS) ||
867 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) ||
868 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) ||
869 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL);
870 }
871
872 @Override
873 public boolean isWindowShapingSupported() {
874 return true;
875 }
876
877 @Override
878 public boolean isWindowTranslucencySupported() {
879 return true;
880 }
881
882 @Override
883 public boolean isTranslucencyCapable(GraphicsConfiguration gc) {
884 return true;
885 }
886
887 @Override
888 public boolean isSwingBackbufferTranslucencySupported() {
889 return true;
890 }
891
892 @Override
893 public boolean enableInputMethodsForTextComponent() {
894 return true;
895 }
896
897 private static URL getScaledImageURL(URL url) {
898 try {
899 String scaledImagePath = getScaledImageName(url.getPath());
900 return scaledImagePath == null ? null : new URL(url.getProtocol(),
901 url.getHost(), url.getPort(), scaledImagePath);
902 } catch (MalformedURLException e) {
903 return null;
904 }
905 }
906
907 private static String getScaledImageName(String path) {
908 if (!isValidPath(path)) {
909 return null;
910 }
911
912 int slash = path.lastIndexOf('/');
913 String name = (slash < 0) ? path : path.substring(slash + 1);
914
915 if (name.contains("@2x")) {
916 return null;
917 }
918
919 int dot = name.lastIndexOf('.');
920 String name2x = (dot < 0) ? name + "@2x"
921 : name.substring(0, dot) + "@2x" + name.substring(dot);
922 return (slash < 0) ? name2x : path.substring(0, slash + 1) + name2x;
923 }
924
925 private static boolean isValidPath(String path) {
926 return path != null &&
927 !path.isEmpty() &&
928 !path.endsWith("/") &&
929 !path.endsWith(".");
930 }
931 }
--- EOF ---