1 /*
2 * Copyright (c) 1996, 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.awt.windows;
27
28 import java.awt.*;
29 import java.awt.im.InputMethodHighlight;
30 import java.awt.im.spi.InputMethodDescriptor;
31 import java.awt.image.*;
32 import java.awt.peer.*;
33 import java.awt.event.KeyEvent;
34 import java.awt.datatransfer.Clipboard;
35 import java.awt.TrayIcon;
36 import java.beans.PropertyChangeListener;
37 import java.security.AccessController;
38 import java.security.PrivilegedAction;
39
40 import sun.awt.AWTAccessor;
41 import sun.awt.AppContext;
42 import sun.awt.AWTAutoShutdown;
43 import sun.awt.AWTPermissions;
44 import sun.awt.AppContext;
45 import sun.awt.LightweightFrame;
46 import sun.awt.SunToolkit;
47 import sun.awt.util.ThreadGroupUtils;
48 import sun.awt.Win32GraphicsDevice;
49 import sun.awt.Win32GraphicsEnvironment;
50 import sun.awt.datatransfer.DataTransferer;
51 import sun.java2d.d3d.D3DRenderQueue;
52 import sun.java2d.opengl.OGLRenderQueue;
53
54 import sun.misc.ManagedLocalsThread;
55 import sun.print.PrintJob2D;
56
57 import java.awt.dnd.DragSource;
58 import java.awt.dnd.DragGestureListener;
59 import java.awt.dnd.DragGestureEvent;
60 import java.awt.dnd.DragGestureRecognizer;
61 import java.awt.dnd.MouseDragGestureRecognizer;
62 import java.awt.dnd.InvalidDnDOperationException;
63 import java.awt.dnd.peer.DragSourceContextPeer;
64
65 import java.util.Hashtable;
66 import java.util.Locale;
67 import java.util.Map;
68 import java.util.Properties;
69
70 import sun.font.FontManager;
71 import sun.font.FontManagerFactory;
72 import sun.font.SunFontManager;
73 import sun.misc.PerformanceLogger;
74 import sun.util.logging.PlatformLogger;
75
76 public final class WToolkit extends SunToolkit implements Runnable {
77
78 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.windows.WToolkit");
79
80 // Desktop property which specifies whether XP visual styles are in effect
81 public static final String XPSTYLE_THEME_ACTIVE = "win.xpstyle.themeActive";
82
83 static GraphicsConfiguration config;
84
85 // System clipboard.
86 WClipboard clipboard;
87
88 // cache of font peers
89 private Hashtable<String,FontPeer> cacheFontPeer;
90
91 // Windows properties
92 private WDesktopProperties wprops;
93
94 // Dynamic Layout Resize client code setting
95 protected boolean dynamicLayoutSetting = false;
96
97 //Is it allowed to generate events assigned to extra mouse buttons.
98 //Set to true by default.
99 private static boolean areExtraMouseButtonsEnabled = true;
100
101 /**
102 * Initialize JNI field and method IDs
103 */
104 private static native void initIDs();
105 private static boolean loaded = false;
106 public static void loadLibraries() {
107 if (!loaded) {
108 java.security.AccessController.doPrivileged(
109 new java.security.PrivilegedAction<Void>() {
110 @Override
111 public Void run() {
112 System.loadLibrary("awt");
113 return null;
114 }
115 });
116 loaded = true;
117 }
118 }
119
120 private static native String getWindowsVersion();
121
122 static {
123 loadLibraries();
124 initIDs();
125
126 // Print out which version of Windows is running
127 if (log.isLoggable(PlatformLogger.Level.FINE)) {
128 log.fine("Win version: " + getWindowsVersion());
129 }
130
131 AccessController.doPrivileged(
132 new PrivilegedAction <Void> ()
133 {
134 @Override
135 public Void run() {
136 String browserProp = System.getProperty("browser");
137 if (browserProp != null && browserProp.equals("sun.plugin")) {
138 disableCustomPalette();
139 }
140 return null;
141 }
142 });
143 }
144
145 private static native void disableCustomPalette();
146
147 /*
148 * Reset the static GraphicsConfiguration to the default. Called on
149 * startup and when display settings have changed.
150 */
151 public static void resetGC() {
152 if (GraphicsEnvironment.isHeadless()) {
153 config = null;
154 } else {
155 config = (GraphicsEnvironment
156 .getLocalGraphicsEnvironment()
157 .getDefaultScreenDevice()
158 .getDefaultConfiguration());
159 }
160 }
161
162 /*
163 * NOTE: The following embedded*() methods are non-public API intended
164 * for internal use only. The methods are unsupported and could go
165 * away in future releases.
166 *
167 * New hook functions for using the AWT as an embedded service. These
168 * functions replace the global C function AwtInit() which was previously
169 * exported by awt.dll.
170 *
171 * When used as an embedded service, the AWT does NOT have its own
172 * message pump. It instead relies on the parent application to provide
173 * this functionality. embeddedInit() assumes that the thread on which it
174 * is called is the message pumping thread. Violating this assumption
175 * will lead to undefined behavior.
176 *
177 * embeddedInit must be called before the WToolkit() constructor.
178 * embeddedDispose should be called before the applicaton terminates the
179 * Java VM. It is currently unsafe to reinitialize the toolkit again
180 * after it has been disposed. Instead, awt.dll must be reloaded and the
181 * class loader which loaded WToolkit must be finalized before it is
182 * safe to reuse AWT. Dynamic reusability may be added to the toolkit in
183 * the future.
184 */
185
186 /**
187 * Initializes the Toolkit for use in an embedded environment.
188 *
189 * @return true if the initialization succeeded; false if it failed.
190 * The function will fail if the Toolkit was already initialized.
191 * @since 1.3
192 */
193 public static native boolean embeddedInit();
194
195 /**
196 * Disposes the Toolkit in an embedded environment. This method should
197 * not be called on exit unless the Toolkit was constructed with
198 * embeddedInit.
199 *
200 * @return true if the disposal succeeded; false if it failed. The
201 * function will fail if the calling thread is not the same
202 * thread which called embeddedInit(), or if the Toolkit was
203 * already disposed.
204 * @since 1.3
205 */
206 public static native boolean embeddedDispose();
207
208 /**
209 * To be called after processing the event queue by users of the above
210 * embeddedInit() function. The reason for this additional call is that
211 * there are some operations performed during idle time in the AwtToolkit
212 * event loop which should also be performed during idle time in any
213 * other native event loop. Failure to do so could result in
214 * deadlocks.
215 *
216 * This method was added at the last minute of the jdk1.4 release
217 * to work around a specific customer problem. As with the above
218 * embedded*() class, this method is non-public and should not be
219 * used by external applications.
220 *
221 * See bug #4526587 for more information.
222 */
223 public native void embeddedEventLoopIdleProcessing();
224
225 static class ToolkitDisposer implements sun.java2d.DisposerRecord {
226 @Override
227 public void dispose() {
228 WToolkit.postDispose();
229 }
230 }
231
232 private final Object anchor = new Object();
233
234 private static native void postDispose();
235
236 private static native boolean startToolkitThread(Runnable thread, ThreadGroup rootThreadGroup);
237
238 public WToolkit() {
239 // Startup toolkit threads
240 if (PerformanceLogger.loggingEnabled()) {
241 PerformanceLogger.setTime("WToolkit construction");
242 }
243
244 sun.java2d.Disposer.addRecord(anchor, new ToolkitDisposer());
245
246 /*
247 * Fix for 4701990.
248 * AWTAutoShutdown state must be changed before the toolkit thread
249 * starts to avoid race condition.
250 */
251 AWTAutoShutdown.notifyToolkitThreadBusy();
252
253 // Find a root TG and attach toolkit thread to it
254 ThreadGroup rootTG = AccessController.doPrivileged(
255 (PrivilegedAction<ThreadGroup>) ThreadGroupUtils::getRootThreadGroup);
256 if (!startToolkitThread(this, rootTG)) {
257 String name = "AWT-Windows";
258 Thread toolkitThread = new ManagedLocalsThread(rootTG, this, name);
259 toolkitThread.setDaemon(true);
260 toolkitThread.start();
261 }
262
263 try {
264 synchronized(this) {
265 while(!inited) {
266 wait();
267 }
268 }
269 } catch (InterruptedException x) {
270 // swallow the exception
271 }
272
273 // Enabled "live resizing" by default. It remains controlled
274 // by the native system though.
275 setDynamicLayout(true);
276
277 areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));
278 //set system property if not yet assigned
279 System.setProperty("sun.awt.enableExtraMouseButtons", ""+areExtraMouseButtonsEnabled);
280 setExtraMouseButtonsEnabledNative(areExtraMouseButtonsEnabled);
281 }
282
283 private void registerShutdownHook() {
284 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
285 Thread shutdown = new ManagedLocalsThread(
286 ThreadGroupUtils.getRootThreadGroup(), this::shutdown);
287 shutdown.setContextClassLoader(null);
288 Runtime.getRuntime().addShutdownHook(shutdown);
289 return null;
290 });
291 }
292
293 @Override
294 public void run() {
295 AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
296 Thread.currentThread().setContextClassLoader(null);
297 Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 1);
298 return null;
299 });
300
301 boolean startPump = init();
302
303 if (startPump) {
304 registerShutdownHook();
305 }
306
307 synchronized(this) {
308 inited = true;
309 notifyAll();
310 }
311
312 if (startPump) {
313 eventLoop(); // will Dispose Toolkit when shutdown hook executes
314 }
315 }
316
317 /*
318 * eventLoop() begins the native message pump which retrieves and processes
319 * native events.
320 *
321 * When shutdown() is called by the ShutdownHook added in run(), a
322 * WM_QUIT message is posted to the Toolkit thread indicating that
323 * eventLoop() should Dispose the toolkit and exit.
324 */
325 private native boolean init();
326 private boolean inited = false;
327
328 private native void eventLoop();
329 private native void shutdown();
330
331 /*
332 * Instead of blocking the "AWT-Windows" thread uselessly on a semaphore,
333 * use these functions. startSecondaryEventLoop() corresponds to wait()
334 * and quitSecondaryEventLoop() corresponds to notify.
335 *
336 * These functions simulate blocking while allowing the AWT to continue
337 * processing native events, eliminating a potential deadlock situation
338 * with SendMessage.
339 *
340 * WARNING: startSecondaryEventLoop must only be called from the "AWT-
341 * Windows" thread.
342 */
343 static native void startSecondaryEventLoop();
344 static native void quitSecondaryEventLoop();
345
346 /*
347 * Create peer objects.
348 */
349
350 @Override
351 public ButtonPeer createButton(Button target) {
352 ButtonPeer peer = new WButtonPeer(target);
353 targetCreatedPeer(target, peer);
354 return peer;
355 }
356
357 @Override
358 public TextFieldPeer createTextField(TextField target) {
359 TextFieldPeer peer = new WTextFieldPeer(target);
360 targetCreatedPeer(target, peer);
361 return peer;
362 }
363
364 @Override
365 public LabelPeer createLabel(Label target) {
366 LabelPeer peer = new WLabelPeer(target);
367 targetCreatedPeer(target, peer);
368 return peer;
369 }
370
371 @Override
372 public ListPeer createList(List target) {
373 ListPeer peer = new WListPeer(target);
374 targetCreatedPeer(target, peer);
375 return peer;
376 }
377
378 @Override
379 public CheckboxPeer createCheckbox(Checkbox target) {
380 CheckboxPeer peer = new WCheckboxPeer(target);
381 targetCreatedPeer(target, peer);
382 return peer;
383 }
384
385 @Override
386 public ScrollbarPeer createScrollbar(Scrollbar target) {
387 ScrollbarPeer peer = new WScrollbarPeer(target);
388 targetCreatedPeer(target, peer);
389 return peer;
390 }
391
392 @Override
393 public ScrollPanePeer createScrollPane(ScrollPane target) {
394 ScrollPanePeer peer = new WScrollPanePeer(target);
395 targetCreatedPeer(target, peer);
396 return peer;
397 }
398
399 @Override
400 public TextAreaPeer createTextArea(TextArea target) {
401 TextAreaPeer peer = new WTextAreaPeer(target);
402 targetCreatedPeer(target, peer);
403 return peer;
404 }
405
406 @Override
407 public ChoicePeer createChoice(Choice target) {
408 ChoicePeer peer = new WChoicePeer(target);
409 targetCreatedPeer(target, peer);
410 return peer;
411 }
412
413 @Override
414 public FramePeer createFrame(Frame target) {
415 FramePeer peer = new WFramePeer(target);
416 targetCreatedPeer(target, peer);
417 return peer;
418 }
419
420 @Override
421 public FramePeer createLightweightFrame(LightweightFrame target) {
422 FramePeer peer = new WLightweightFramePeer(target);
423 targetCreatedPeer(target, peer);
424 return peer;
425 }
426
427 @Override
428 public CanvasPeer createCanvas(Canvas target) {
429 CanvasPeer peer = new WCanvasPeer(target);
430 targetCreatedPeer(target, peer);
431 return peer;
432 }
433
434 @Override
435 public void disableBackgroundErase(Canvas canvas) {
436 WCanvasPeer peer = AWTAccessor.getComponentAccessor().getPeer(canvas);
437 if (peer == null) {
438 throw new IllegalStateException("Canvas must have a valid peer");
439 }
440 peer.disableBackgroundErase();
441 }
442
443 @Override
444 public PanelPeer createPanel(Panel target) {
445 PanelPeer peer = new WPanelPeer(target);
446 targetCreatedPeer(target, peer);
447 return peer;
448 }
449
450 @Override
451 public WindowPeer createWindow(Window target) {
452 WindowPeer peer = new WWindowPeer(target);
453 targetCreatedPeer(target, peer);
454 return peer;
455 }
456
457 @Override
458 public DialogPeer createDialog(Dialog target) {
459 DialogPeer peer = new WDialogPeer(target);
460 targetCreatedPeer(target, peer);
461 return peer;
462 }
463
464 @Override
465 public FileDialogPeer createFileDialog(FileDialog target) {
466 FileDialogPeer peer = new WFileDialogPeer(target);
467 targetCreatedPeer(target, peer);
468 return peer;
469 }
470
471 @Override
472 public MenuBarPeer createMenuBar(MenuBar target) {
473 MenuBarPeer peer = new WMenuBarPeer(target);
474 targetCreatedPeer(target, peer);
475 return peer;
476 }
477
478 @Override
479 public MenuPeer createMenu(Menu target) {
480 MenuPeer peer = new WMenuPeer(target);
481 targetCreatedPeer(target, peer);
482 return peer;
483 }
484
485 @Override
486 public PopupMenuPeer createPopupMenu(PopupMenu target) {
487 PopupMenuPeer peer = new WPopupMenuPeer(target);
488 targetCreatedPeer(target, peer);
489 return peer;
490 }
491
492 @Override
493 public MenuItemPeer createMenuItem(MenuItem target) {
494 MenuItemPeer peer = new WMenuItemPeer(target);
495 targetCreatedPeer(target, peer);
496 return peer;
497 }
498
499 @Override
500 public CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) {
501 CheckboxMenuItemPeer peer = new WCheckboxMenuItemPeer(target);
502 targetCreatedPeer(target, peer);
503 return peer;
504 }
505
506 @Override
507 public RobotPeer createRobot(Robot target, GraphicsDevice screen) {
508 // (target is unused for now)
509 // Robot's don't need to go in the peer map since
510 // they're not Component's
511 return new WRobotPeer(screen);
512 }
513
514 public WEmbeddedFramePeer createEmbeddedFrame(WEmbeddedFrame target) {
515 WEmbeddedFramePeer peer = new WEmbeddedFramePeer(target);
516 targetCreatedPeer(target, peer);
517 return peer;
518 }
519
520 WPrintDialogPeer createWPrintDialog(WPrintDialog target) {
521 WPrintDialogPeer peer = new WPrintDialogPeer(target);
522 targetCreatedPeer(target, peer);
523 return peer;
524 }
525
526 WPageDialogPeer createWPageDialog(WPageDialog target) {
527 WPageDialogPeer peer = new WPageDialogPeer(target);
528 targetCreatedPeer(target, peer);
529 return peer;
530 }
531
532 @Override
533 public TrayIconPeer createTrayIcon(TrayIcon target) {
534 WTrayIconPeer peer = new WTrayIconPeer(target);
535 targetCreatedPeer(target, peer);
536 return peer;
537 }
538
539 @Override
540 public SystemTrayPeer createSystemTray(SystemTray target) {
541 return new WSystemTrayPeer(target);
542 }
543
544 @Override
545 public boolean isTraySupported() {
546 return true;
547 }
548
549 @Override
550 public DataTransferer getDataTransferer() {
551 return WDataTransferer.getInstanceImpl();
552 }
553
554 @Override
555 public KeyboardFocusManagerPeer getKeyboardFocusManagerPeer()
556 throws HeadlessException
557 {
558 return WKeyboardFocusManagerPeer.getInstance();
559 }
560
561 private native void setDynamicLayoutNative(boolean b);
562
563 @Override
564 public void setDynamicLayout(boolean b) {
565 if (b == dynamicLayoutSetting) {
566 return;
567 }
568
569 dynamicLayoutSetting = b;
570 setDynamicLayoutNative(b);
571 }
572
573 @Override
574 protected boolean isDynamicLayoutSet() {
575 return dynamicLayoutSetting;
576 }
577
578 /*
579 * Called from lazilyLoadDynamicLayoutSupportedProperty because
580 * Windows doesn't always send WM_SETTINGCHANGE when it should.
581 */
582 private native boolean isDynamicLayoutSupportedNative();
583
584 @Override
585 public boolean isDynamicLayoutActive() {
586 return (isDynamicLayoutSet() && isDynamicLayoutSupported());
587 }
588
589 /**
590 * Returns <code>true</code> if this frame state is supported.
591 */
592 @Override
593 public boolean isFrameStateSupported(int state) {
594 switch (state) {
595 case Frame.NORMAL:
596 case Frame.ICONIFIED:
597 case Frame.MAXIMIZED_BOTH:
598 return true;
599 default:
600 return false;
601 }
602 }
603
604 static native ColorModel makeColorModel();
605 static ColorModel screenmodel;
606
607 static ColorModel getStaticColorModel() {
608 if (GraphicsEnvironment.isHeadless()) {
609 throw new IllegalArgumentException();
610 }
611 if (config == null) {
612 resetGC();
613 }
614 return config.getColorModel();
615 }
616
617 @Override
618 public ColorModel getColorModel() {
619 return getStaticColorModel();
620 }
621
622 @Override
623 public Insets getScreenInsets(GraphicsConfiguration gc)
624 {
625 return getScreenInsets(((Win32GraphicsDevice) gc.getDevice()).getScreen());
626 }
627
628 @Override
629 public int getScreenResolution() {
630 Win32GraphicsEnvironment ge = (Win32GraphicsEnvironment)
631 GraphicsEnvironment.getLocalGraphicsEnvironment();
632 return ge.getXResolution();
633 }
634 @Override
635 protected native int getScreenWidth();
636 @Override
637 protected native int getScreenHeight();
638 private native Insets getScreenInsets(int screen);
639
640
641 @Override
642 public FontMetrics getFontMetrics(Font font) {
643 // This is an unsupported hack, but left in for a customer.
644 // Do not remove.
645 FontManager fm = FontManagerFactory.getInstance();
646 if (fm instanceof SunFontManager
647 && ((SunFontManager) fm).usePlatformFontMetrics()) {
648 return WFontMetrics.getFontMetrics(font);
649 }
650 return super.getFontMetrics(font);
651 }
652
653 @Override
654 public FontPeer getFontPeer(String name, int style) {
655 FontPeer retval = null;
656 String lcName = name.toLowerCase();
657 if (null != cacheFontPeer) {
658 retval = cacheFontPeer.get(lcName + style);
659 if (null != retval) {
660 return retval;
661 }
662 }
663 retval = new WFontPeer(name, style);
664 if (retval != null) {
665 if (null == cacheFontPeer) {
666 cacheFontPeer = new Hashtable<>(5, 0.9f);
667 }
668 if (null != cacheFontPeer) {
669 cacheFontPeer.put(lcName + style, retval);
670 }
671 }
672 return retval;
673 }
674
675 private native void nativeSync();
676
677 @Override
678 public void sync() {
679 // flush the GDI/DD buffers
680 nativeSync();
681 // now flush the OGL pipeline (this is a no-op if OGL is not enabled)
682 OGLRenderQueue.sync();
683 // now flush the D3D pipeline (this is a no-op if D3D is not enabled)
684 D3DRenderQueue.sync();
685 }
686
687 @Override
688 public PrintJob getPrintJob(Frame frame, String doctitle,
689 Properties props) {
690 return getPrintJob(frame, doctitle, null, null);
691 }
692
693 @Override
694 public PrintJob getPrintJob(Frame frame, String doctitle,
695 JobAttributes jobAttributes,
696 PageAttributes pageAttributes)
697 {
698 if (frame == null) {
699 throw new NullPointerException("frame must not be null");
700 }
701
702 PrintJob2D printJob = new PrintJob2D(frame, doctitle,
703 jobAttributes, pageAttributes);
704
705 if (printJob.printDialog() == false) {
706 printJob = null;
707 }
708
709 return printJob;
710 }
711
712 @Override
713 public native void beep();
714
715 @Override
716 public boolean getLockingKeyState(int key) {
717 if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK ||
718 key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) {
719 throw new IllegalArgumentException("invalid key for Toolkit.getLockingKeyState");
720 }
721 return getLockingKeyStateNative(key);
722 }
723
724 private native boolean getLockingKeyStateNative(int key);
725
726 @Override
727 public void setLockingKeyState(int key, boolean on) {
728 if (! (key == KeyEvent.VK_CAPS_LOCK || key == KeyEvent.VK_NUM_LOCK ||
729 key == KeyEvent.VK_SCROLL_LOCK || key == KeyEvent.VK_KANA_LOCK)) {
730 throw new IllegalArgumentException("invalid key for Toolkit.setLockingKeyState");
731 }
732 setLockingKeyStateNative(key, on);
733 }
734
735 private native void setLockingKeyStateNative(int key, boolean on);
736
737 @Override
738 public Clipboard getSystemClipboard() {
739 SecurityManager security = System.getSecurityManager();
740 if (security != null) {
741 security.checkPermission(AWTPermissions.ACCESS_CLIPBOARD_PERMISSION);
742 }
743 synchronized (this) {
744 if (clipboard == null) {
745 clipboard = new WClipboard();
746 }
747 }
748 return clipboard;
749 }
750
751 @Override
752 protected native void loadSystemColors(int[] systemColors);
753
754 public static Object targetToPeer(Object target) {
755 return SunToolkit.targetToPeer(target);
756 }
757
758 public static void targetDisposedPeer(Object target, Object peer) {
759 SunToolkit.targetDisposedPeer(target, peer);
760 }
761
762 /**
763 * Returns a new input method adapter descriptor for native input methods.
764 */
765 @Override
766 public InputMethodDescriptor getInputMethodAdapterDescriptor() {
767 return new WInputMethodDescriptor();
768 }
769
770 /**
771 * Returns a style map for the input method highlight.
772 */
773 @Override
774 public Map<java.awt.font.TextAttribute,?> mapInputMethodHighlight(
775 InputMethodHighlight highlight)
776 {
777 return WInputMethod.mapInputMethodHighlight(highlight);
778 }
779
780 /**
781 * Returns whether enableInputMethods should be set to true for peered
782 * TextComponent instances on this platform.
783 */
784 @Override
785 public boolean enableInputMethodsForTextComponent() {
786 return true;
787 }
788
789 /**
790 * Returns the default keyboard locale of the underlying operating system
791 */
792 @Override
793 public Locale getDefaultKeyboardLocale() {
794 Locale locale = WInputMethod.getNativeLocale();
795
796 if (locale == null) {
797 return super.getDefaultKeyboardLocale();
798 } else {
799 return locale;
800 }
801 }
802
803 /**
804 * Returns a new custom cursor.
805 */
806 @Override
807 public Cursor createCustomCursor(Image cursor, Point hotSpot, String name)
808 throws IndexOutOfBoundsException {
809 return new WCustomCursor(cursor, hotSpot, name);
810 }
811
812 /**
813 * Returns the supported cursor size (Win32 only has one).
814 */
815 @Override
816 public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) {
817 return new Dimension(WCustomCursor.getCursorWidth(),
818 WCustomCursor.getCursorHeight());
819 }
820
821 @Override
822 public native int getMaximumCursorColors();
823
824 static void paletteChanged() {
825 ((Win32GraphicsEnvironment)GraphicsEnvironment
826 .getLocalGraphicsEnvironment())
827 .paletteChanged();
828 }
829
830 /*
831 * Called from Toolkit native code when a WM_DISPLAYCHANGE occurs.
832 * Have Win32GraphicsEnvironment execute the display change code on the
833 * Event thread.
834 */
835 public static void displayChanged() {
836 EventQueue.invokeLater(new Runnable() {
837 @Override
838 public void run() {
839 ((Win32GraphicsEnvironment)GraphicsEnvironment
840 .getLocalGraphicsEnvironment())
841 .displayChanged();
842 }
843 });
844 }
845
846 /**
847 * create the peer for a DragSourceContext
848 */
849
850 @Override
851 public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
852 final LightweightFrame f = SunToolkit.getLightweightFrame(dge.getComponent());
853 if (f != null) {
854 return f.createDragSourceContextPeer(dge);
855 }
856
857 return WDragSourceContextPeer.createDragSourceContextPeer(dge);
858 }
859
860 @Override
861 @SuppressWarnings("unchecked")
862 public <T extends DragGestureRecognizer> T
863 createDragGestureRecognizer(Class<T> abstractRecognizerClass,
864 DragSource ds, Component c, int srcActions,
865 DragGestureListener dgl)
866 {
867 final LightweightFrame f = SunToolkit.getLightweightFrame(c);
868 if (f != null) {
869 return f.createDragGestureRecognizer(abstractRecognizerClass, ds, c, srcActions, dgl);
870 }
871
872 if (MouseDragGestureRecognizer.class.equals(abstractRecognizerClass))
873 return (T)new WMouseDragGestureRecognizer(ds, c, srcActions, dgl);
874 else
875 return null;
876 }
877
878 /**
879 *
880 */
881
882 private static final String prefix = "DnD.Cursor.";
883 private static final String postfix = ".32x32";
884 private static final String awtPrefix = "awt.";
885 private static final String dndPrefix = "DnD.";
886
887 @Override
888 protected Object lazilyLoadDesktopProperty(String name) {
889 if (name.startsWith(prefix)) {
890 String cursorName = name.substring(prefix.length(), name.length()) + postfix;
891
892 try {
893 return Cursor.getSystemCustomCursor(cursorName);
894 } catch (AWTException awte) {
895 throw new RuntimeException("cannot load system cursor: " + cursorName, awte);
896 }
897 }
898
899 if (name.equals("awt.dynamicLayoutSupported")) {
900 return Boolean.valueOf(isDynamicLayoutSupported());
901 }
902
903 if (WDesktopProperties.isWindowsProperty(name) ||
904 name.startsWith(awtPrefix) || name.startsWith(dndPrefix))
905 {
906 synchronized(this) {
907 lazilyInitWProps();
908 return desktopProperties.get(name);
909 }
910 }
911
912 return super.lazilyLoadDesktopProperty(name);
913 }
914
915 private synchronized void lazilyInitWProps() {
916 if (wprops == null) {
917 wprops = new WDesktopProperties(this);
918 updateProperties(wprops.getProperties());
919 }
920 }
921
922 /*
923 * Called from lazilyLoadDesktopProperty because Windows doesn't
924 * always send WM_SETTINGCHANGE when it should.
925 */
926 private synchronized boolean isDynamicLayoutSupported() {
927 boolean nativeDynamic = isDynamicLayoutSupportedNative();
928 lazilyInitWProps();
929 Boolean prop = (Boolean) desktopProperties.get("awt.dynamicLayoutSupported");
930
931 if (log.isLoggable(PlatformLogger.Level.FINER)) {
932 log.finer("In WTK.isDynamicLayoutSupported()" +
933 " nativeDynamic == " + nativeDynamic +
934 " wprops.dynamic == " + prop);
935 }
936
937 if ((prop == null) || (nativeDynamic != prop.booleanValue())) {
938 // We missed the WM_SETTINGCHANGE, so we pretend
939 // we just got one - fire the propertyChange, etc.
940 windowsSettingChange();
941 return nativeDynamic;
942 }
943
944 return prop.booleanValue();
945 }
946
947 /*
948 * Called from native toolkit code when WM_SETTINGCHANGE message received
949 * Also called from lazilyLoadDynamicLayoutSupportedProperty because
950 * Windows doesn't always send WM_SETTINGCHANGE when it should.
951 */
952 private void windowsSettingChange() {
953 // JDK-8039383: Have to update the value of XPSTYLE_THEME_ACTIVE property
954 // as soon as possible to prevent NPE and other errors because theme data
955 // has become unavailable.
956 final Map<String, Object> props = getWProps();
957 if (props == null) {
958 // props has not been initialized, so we have nothing to update
959 return;
960 }
961
962 updateXPStyleEnabled(props.get(XPSTYLE_THEME_ACTIVE));
963
964 if (AppContext.getAppContext() == null) {
965 // We cannot post the update to any EventQueue. Listeners will
966 // be called on EDTs by DesktopPropertyChangeSupport
967 updateProperties(props);
968 } else {
969 // Cannot update on Toolkit thread.
970 // DesktopPropertyChangeSupport will call listeners on Toolkit
971 // thread if it has AppContext (standalone mode)
972 EventQueue.invokeLater(() -> updateProperties(props));
973 }
974 }
975
976 private synchronized void updateProperties(final Map<String, Object> props) {
977 if (null == props) {
978 return;
979 }
980
981 updateXPStyleEnabled(props.get(XPSTYLE_THEME_ACTIVE));
982
983 for (String propName : props.keySet()) {
984 Object val = props.get(propName);
985 if (log.isLoggable(PlatformLogger.Level.FINER)) {
986 log.finer("changed " + propName + " to " + val);
987 }
988 setDesktopProperty(propName, val);
989 }
990 }
991
992 private synchronized Map<String, Object> getWProps() {
993 return (wprops != null) ? wprops.getProperties() : null;
994 }
995
996 private void updateXPStyleEnabled(final Object dskProp) {
997 ThemeReader.xpStyleEnabled = Boolean.TRUE.equals(dskProp);
998 }
999
1000 @Override
1001 public synchronized void addPropertyChangeListener(String name, PropertyChangeListener pcl) {
1002 if (name == null) {
1003 // See JavaDoc for the Toolkit.addPropertyChangeListener() method
1004 return;
1005 }
1006 if ( WDesktopProperties.isWindowsProperty(name)
1007 || name.startsWith(awtPrefix)
1008 || name.startsWith(dndPrefix))
1009 {
1010 // someone is interested in Windows-specific desktop properties
1011 // we should initialize wprops
1012 lazilyInitWProps();
1013 }
1014 super.addPropertyChangeListener(name, pcl);
1015 }
1016
1017 /*
1018 * initialize only static props here and do not try to initialize props which depends on wprops,
1019 * this should be done in lazilyLoadDesktopProperty() only.
1020 */
1021 @Override
1022 protected synchronized void initializeDesktopProperties() {
1023 desktopProperties.put("DnD.Autoscroll.initialDelay",
1024 Integer.valueOf(50));
1025 desktopProperties.put("DnD.Autoscroll.interval",
1026 Integer.valueOf(50));
1027 desktopProperties.put("DnD.isDragImageSupported",
1028 Boolean.TRUE);
1029 desktopProperties.put("Shell.shellFolderManager",
1030 "sun.awt.shell.Win32ShellFolderManager2");
1031 }
1032
1033 /*
1034 * This returns the value for the desktop property "awt.font.desktophints"
1035 * This requires that the Windows properties have already been gathered.
1036 */
1037 @Override
1038 protected synchronized RenderingHints getDesktopAAHints() {
1039 if (wprops == null) {
1040 return null;
1041 } else {
1042 return wprops.getDesktopAAHints();
1043 }
1044 }
1045
1046 @Override
1047 public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) {
1048 return (modalityType == null) ||
1049 (modalityType == Dialog.ModalityType.MODELESS) ||
1050 (modalityType == Dialog.ModalityType.DOCUMENT_MODAL) ||
1051 (modalityType == Dialog.ModalityType.APPLICATION_MODAL) ||
1052 (modalityType == Dialog.ModalityType.TOOLKIT_MODAL);
1053 }
1054
1055 @Override
1056 public boolean isModalExclusionTypeSupported(Dialog.ModalExclusionType exclusionType) {
1057 return (exclusionType == null) ||
1058 (exclusionType == Dialog.ModalExclusionType.NO_EXCLUDE) ||
1059 (exclusionType == Dialog.ModalExclusionType.APPLICATION_EXCLUDE) ||
1060 (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
1061 }
1062
1063 public static WToolkit getWToolkit() {
1064 WToolkit toolkit = (WToolkit)Toolkit.getDefaultToolkit();
1065 return toolkit;
1066 }
1067
1068 /**
1069 * There are two reasons why we don't use buffer per window when
1070 * Vista's DWM (aka Aero) is enabled:
1071 * - since with DWM all windows are already double-buffered, the application
1072 * doesn't get expose events so we don't get to use our true back-buffer,
1073 * wasting memory and performance (this is valid for both d3d and gdi
1074 * pipelines)
1075 * - in some cases with buffer per window enabled it is possible for the
1076 * paint manager to redirect rendering to the screen for some operations
1077 * (like copyArea), and since bpw uses its own BufferStrategy the
1078 * d3d onscreen rendering support is disabled and rendering goes through
1079 * GDI. This doesn't work well with Vista's DWM since one
1080 * can not perform GDI and D3D operations on the same surface
1081 * (see 6630702 for more info)
1082 *
1083 * Note: even though DWM composition state can change during the lifetime
1084 * of the application it is a rare event, and it is more often that it
1085 * is temporarily disabled (because of some app) than it is getting
1086 * permanently enabled so we can live with this approach without the
1087 * complexity of dwm state listeners and such. This can be revisited if
1088 * proved otherwise.
1089 */
1090 @Override
1091 public boolean useBufferPerWindow() {
1092 return !Win32GraphicsEnvironment.isDWMCompositionEnabled();
1093 }
1094
1095 @Override
1096 public void grab(Window w) {
1097 final Object peer = AWTAccessor.getComponentAccessor().getPeer(w);
1098 if (peer != null) {
1099 ((WWindowPeer) peer).grab();
1100 }
1101 }
1102
1103 @Override
1104 public void ungrab(Window w) {
1105 final Object peer = AWTAccessor.getComponentAccessor().getPeer(w);
1106 if (peer != null) {
1107 ((WWindowPeer) peer).ungrab();
1108 }
1109 }
1110
1111 @Override
1112 public native boolean syncNativeQueue(final long timeout);
1113 @Override
1114 public boolean isDesktopSupported() {
1115 return true;
1116 }
1117
1118 @Override
1119 public DesktopPeer createDesktopPeer(Desktop target) {
1120 return new WDesktopPeer();
1121 }
1122
1123 private static native void setExtraMouseButtonsEnabledNative(boolean enable);
1124
1125 @Override
1126 public boolean areExtraMouseButtonsEnabled() throws HeadlessException {
1127 return areExtraMouseButtonsEnabled;
1128 }
1129
1130 private synchronized native int getNumberOfButtonsImpl();
1131
1132 @Override
1133 public int getNumberOfButtons(){
1134 if (numberOfButtons == 0) {
1135 numberOfButtons = getNumberOfButtonsImpl();
1136 }
1137 return (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons;
1138 }
1139
1140 @Override
1141 public boolean isWindowOpacitySupported() {
1142 // supported in Win2K and later
1143 return true;
1144 }
1145
1146 @Override
1147 public boolean isWindowShapingSupported() {
1148 return true;
1149 }
1150
1151 @Override
1152 public boolean isWindowTranslucencySupported() {
1153 // supported in Win2K and later
1154 return true;
1155 }
1156
1157 @Override
1158 public boolean isTranslucencyCapable(GraphicsConfiguration gc) {
1159 //XXX: worth checking if 8-bit? Anyway, it doesn't hurt.
1160 return true;
1161 }
1162
1163 // On MS Windows one must use the peer.updateWindow() to implement
1164 // non-opaque windows.
1165 @Override
1166 public boolean needUpdateWindow() {
1167 return true;
1168 }
1169 }
--- EOF ---