1 /*
   2  * Copyright (c) 2010, 2013, 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 package com.sun.glass.ui.win;
  26 
  27 import com.sun.glass.ui.*;
  28 import com.sun.glass.ui.CommonDialogs.ExtensionFilter;
  29 import com.sun.glass.ui.CommonDialogs.FileChooserResult;
  30 import com.sun.glass.utils.NativeLibLoader;
  31 import com.sun.javafx.application.PlatformImpl;
  32 import com.sun.javafx.tk.Toolkit;
  33 
  34 import java.io.File;
  35 import java.nio.ByteBuffer;
  36 import java.nio.IntBuffer;
  37 import java.security.AccessController;
  38 import java.security.PrivilegedAction;
  39 import java.util.List;
  40 
  41 import javafx.scene.accessibility.Accessible;
  42 
  43 final class WinApplication extends Application implements InvokeLaterDispatcher.InvokeLaterSubmitter {
  44 
  45     private static native void initIDs();
  46     static {
  47         // This loading of msvcr100.dll (VS2010) is required when run with Java 6
  48         // since it was build with VS2003 and doesn't include msvcr100.dll in it's JRE.
  49         // Note: See README-builds.html on MSVC requirement: VS2010 is required.
  50         AccessController.doPrivileged(new PrivilegedAction<Void>() {
  51             public Void run() {
  52                 verbose = Boolean.getBoolean("javafx.verbose");
  53                 try {
  54                     NativeLibLoader.loadLibrary("msvcr100");
  55                 } catch (Throwable t) {
  56                     if (verbose) {
  57                         System.err.println("Error: failed to load msvcr100.dll : " + t);
  58                     }
  59                 }
  60                 Application.loadNativeLibrary();
  61                 return null;
  62             }
  63         });
  64         initIDs();
  65     }
  66 
  67     private final InvokeLaterDispatcher invokeLaterDispatcher;
  68     WinApplication() {
  69         boolean isEventThread = AccessController
  70                 .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("javafx.embed.isEventThread"));
  71         if (!isEventThread) {
  72             invokeLaterDispatcher = new InvokeLaterDispatcher(this);
  73             invokeLaterDispatcher.start();
  74         } else {
  75             invokeLaterDispatcher = null;
  76         }
  77     }
  78 
  79     private static boolean verbose;
  80 
  81     // returng toolkit window HWND
  82     private native long _init();
  83     private native void _setClassLoader(ClassLoader classLoader);
  84     private native void _runLoop(Runnable launchable);
  85     private native void _terminateLoop();
  86 
  87     @Override
  88     protected void runLoop(final Runnable launchable) {
  89         boolean isEventThread = AccessController
  90             .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("javafx.embed.isEventThread"));
  91 
  92         ClassLoader classLoader = WinApplication.class.getClassLoader();
  93         _setClassLoader(classLoader);
  94 
  95         if (isEventThread) {
  96             _init();
  97             setEventThread(Thread.currentThread());
  98             launchable.run();
  99             return;
 100         }
 101         final Thread toolkitThread =
 102             AccessController.doPrivileged((PrivilegedAction<Thread>) () -> new Thread(() -> {
 103                 _init();
 104                 _runLoop(launchable);
 105             }, "WindowsNativeRunloopThread"));
 106         setEventThread(toolkitThread);
 107         toolkitThread.start();
 108     }
 109 
 110     @Override protected void finishTerminating() {
 111         final Thread toolkitThread = getEventThread();
 112         if (toolkitThread != null) {
 113             _terminateLoop();
 114             setEventThread(null);
 115         }
 116         super.finishTerminating();
 117     }
 118 
 119     @Override public boolean shouldUpdateWindow() {
 120         return true;
 121     }
 122 
 123     native private Object _enterNestedEventLoopImpl();
 124     native private void _leaveNestedEventLoopImpl(Object retValue);
 125 
 126     @Override protected Object _enterNestedEventLoop() {
 127         if (invokeLaterDispatcher != null) {
 128             invokeLaterDispatcher.notifyEnteringNestedEventLoop();
 129         }
 130         try {
 131             return _enterNestedEventLoopImpl();
 132         } finally {
 133             if (invokeLaterDispatcher != null) {
 134                 invokeLaterDispatcher.notifyLeftNestedEventLoop();
 135             }
 136         }
 137     }
 138 
 139     @Override protected void _leaveNestedEventLoop(Object retValue) {
 140         if (invokeLaterDispatcher != null) {
 141             invokeLaterDispatcher.notifyLeavingNestedEventLoop();
 142         }
 143         _leaveNestedEventLoopImpl(retValue);
 144     }
 145 
 146     // FACTORY METHODS
 147 
 148     @Override public Window createWindow(Window owner, Screen screen, int styleMask) {
 149         return new WinWindow(owner, screen, styleMask);
 150     }
 151 
 152     @Override public Window createWindow(long parent) {
 153         return new WinChildWindow(parent);
 154     }
 155 
 156     @Override public View createView() {
 157         return new WinView();
 158     }
 159 
 160     @Override public Cursor createCursor(int type) {
 161         return new WinCursor(type);
 162     }
 163 
 164     @Override public Cursor createCursor(int x, int y, Pixels pixels) {
 165         return new WinCursor(x, y, pixels);
 166     }
 167 
 168     @Override protected void staticCursor_setVisible(boolean visible) {
 169         WinCursor.setVisible_impl(visible);
 170     }
 171 
 172     @Override protected Size staticCursor_getBestSize(int width, int height) {
 173         return WinCursor.getBestSize_impl(width, height);
 174     }
 175 
 176     @Override public Pixels createPixels(int width, int height, ByteBuffer data) {
 177         return new WinPixels(width, height, data);
 178     }
 179 
 180     @Override public Pixels createPixels(int width, int height, IntBuffer data) {
 181         return new WinPixels(width, height, data);
 182     }
 183 
 184     @Override
 185     public Pixels createPixels(int width, int height, IntBuffer data, float scale) {
 186         return new WinPixels(width, height, data, scale);
 187     }
 188 
 189     @Override protected int staticPixels_getNativeFormat() {
 190         return WinPixels.getNativeFormat_impl();
 191     }
 192 
 193     @Override public Robot createRobot() {
 194         return new WinRobot();
 195     }
 196 
 197     @Override protected double staticScreen_getVideoRefreshPeriod() {
 198         return 0.0;     // indicate millisecond resolution
 199     }
 200 
 201     @Override native protected Screen[] staticScreen_getScreens();
 202     
 203     @Override public Timer createTimer(Runnable runnable) {
 204         return new WinTimer(runnable);
 205     }
 206 
 207     @Override protected int staticTimer_getMinPeriod() {
 208         return WinTimer.getMinPeriod_impl();
 209     }
 210 
 211     @Override protected int staticTimer_getMaxPeriod() {
 212         return WinTimer.getMaxPeriod_impl();
 213     }
 214 
 215     @Override public PlatformAccessible createAccessible(Accessible accessible) {
 216         return WinAccessible.createAccessible(accessible);
 217     }
 218 
 219     @Override protected FileChooserResult staticCommonDialogs_showFileChooser(Window owner, String folder, String filename, String title, int type,
 220                                              boolean multipleMode, ExtensionFilter[] extensionFilters, int defaultFilterIndex) {
 221         if (invokeLaterDispatcher != null) {
 222             invokeLaterDispatcher.notifyEnteringNestedEventLoop();
 223         }
 224         return WinCommonDialogs.showFileChooser_impl(owner, folder, filename, title, type, multipleMode, extensionFilters, defaultFilterIndex);
 225     }
 226 
 227     @Override protected File staticCommonDialogs_showFolderChooser(Window owner, String folder, String title) {
 228         if (invokeLaterDispatcher != null) {
 229             invokeLaterDispatcher.notifyEnteringNestedEventLoop();
 230         }
 231         return WinCommonDialogs.showFolderChooser_impl(owner, folder, title);
 232     }
 233 
 234     @Override protected long staticView_getMultiClickTime() {
 235         return WinView.getMultiClickTime_impl();
 236     }
 237 
 238     @Override protected int staticView_getMultiClickMaxX() {
 239         return WinView.getMultiClickMaxX_impl();
 240     }
 241 
 242     @Override protected int staticView_getMultiClickMaxY() {
 243         return WinView.getMultiClickMaxY_impl();
 244     }
 245     
 246     @Override native protected void _invokeAndWait(Runnable runnable);
 247 
 248     native private void _submitForLaterInvocation(Runnable r);
 249     // InvokeLaterDispatcher.InvokeLaterSubmitter
 250     @Override public void submitForLaterInvocation(Runnable r) {
 251         _submitForLaterInvocation(r);
 252     }
 253 
 254     @Override protected void _invokeLater(Runnable runnable) {
 255         if (invokeLaterDispatcher != null) {
 256             invokeLaterDispatcher.invokeLater(runnable);
 257         } else {
 258             submitForLaterInvocation(runnable);
 259         }
 260     }
 261 
 262     protected boolean notifyThemeChanged(String themeName) {
 263         return PlatformImpl.setAccessibilityTheme(themeName);
 264     }
 265 
 266     private native String _getHighContrastTheme();
 267     @Override public String getHighContrastTheme() {
 268         return _getHighContrastTheme();
 269     }
 270  
 271     @Override
 272     protected boolean _supportsInputMethods() {
 273         return true;
 274     }
 275 
 276     @Override
 277     protected boolean _supportsTransparentWindows() {
 278         return true;
 279     }
 280 
 281     @Override native protected boolean _supportsUnifiedWindows();
 282     
 283     public String getDataDirectory() {
 284         checkEventThread();
 285         String baseDirectory = AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getenv("APPDATA"));
 286         if (baseDirectory == null || baseDirectory.length() == 0) {
 287             return super.getDataDirectory();
 288         }
 289         return baseDirectory + File.separator + name + File.separator;
 290     }
 291 }