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