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