1 /* 2 * Copyright (c) 2010, 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 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.prism.impl.PrismSettings; 32 33 import java.io.File; 34 import java.nio.ByteBuffer; 35 import java.nio.IntBuffer; 36 import java.security.AccessController; 37 import java.security.PrivilegedAction; 38 39 final class WinApplication extends Application implements InvokeLaterDispatcher.InvokeLaterSubmitter { 40 static float overrideUIScale; 41 42 private static boolean getBoolean(String propname, boolean defval, String description) { 43 String str = System.getProperty(propname); 44 if (str == null) { 45 str = System.getenv(propname); 46 } 47 if (str == null) { 48 return defval; 49 } 50 Boolean ret = Boolean.parseBoolean(str); 51 if (PrismSettings.verbose) { 52 System.out.println((ret ? "" : "not ")+description); 53 } 54 return ret; 55 } 56 57 private static float getFloat(String propname, float defval, String description) { 58 String str = System.getProperty(propname); 59 if (str == null) { 60 str = System.getenv(propname); 61 } 62 if (str == null) { 63 return defval; 64 } 65 str = str.trim(); 66 float val; 67 if (str.endsWith("%")) { 68 val = Integer.parseInt(str.substring(0, str.length()-1)) / 100.0f; 69 } else if (str.endsWith("DPI") || str.endsWith("dpi")) { 70 val = Integer.parseInt(str.substring(0, str.length()-3)) / 96.0f; 71 } else { 72 val = Float.parseFloat(str); 73 } 74 if (PrismSettings.verbose) { 75 System.out.println(description+val); 76 } 77 return val; 78 } 79 80 private static native void initIDs(float overrideUIScale); 81 static { 82 // This loading of msvcr120.dll and msvcp120.dll (VS2013) is required when run with Java 8 83 // since it was build with VS2010 and doesn't include msvcr120.dll in its JRE. 84 // Note: See README-builds.html on MSVC requirement: VS2013 is required. 85 AccessController.doPrivileged(new PrivilegedAction<Void>() { 86 public Void run() { 87 verbose = Boolean.getBoolean("javafx.verbose"); 88 if (PrismSettings.allowHiDPIScaling) { 89 overrideUIScale = getFloat("glass.win.uiScale", -1.0f, "Forcing UI scaling factor: "); 90 // We only parse these if verbose, to inform the user... 91 if (PrismSettings.verbose) { 92 getFloat("glass.win.renderScale", -1.0f, 93 "(No longer supported) Rendering scaling factor: "); 94 getFloat("glass.win.minHiDPI", 1.5f, 95 "(No longer supported) UI scaling threshold: "); 96 getBoolean("glass.win.forceIntegerRenderScale", true, 97 "(No longer supported) force integer rendering scale"); 98 } 99 } else { 100 overrideUIScale = 1.0f; 101 } 102 try { 103 NativeLibLoader.loadLibrary("msvcr120"); 104 } catch (Throwable t) { 105 if (verbose) { 106 System.err.println("Error: failed to load msvcr120.dll : " + t); 107 } 108 } 109 try { 110 NativeLibLoader.loadLibrary("msvcp120"); 111 } catch (Throwable t) { 112 if (verbose) { 113 System.err.println("Error: failed to load msvcp120.dll : " + t); 114 } 115 } 116 Application.loadNativeLibrary(); 117 return null; 118 } 119 }); 120 initIDs(overrideUIScale); 121 } 122 123 private final InvokeLaterDispatcher invokeLaterDispatcher; 124 WinApplication() { 125 // Embedded in SWT, with shared event thread 126 boolean isEventThread = AccessController 127 .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("javafx.embed.isEventThread")); 128 if (!isEventThread) { 129 invokeLaterDispatcher = new InvokeLaterDispatcher(this); 130 invokeLaterDispatcher.start(); 131 } else { 132 invokeLaterDispatcher = null; 133 } 134 } 135 136 private static boolean verbose; 137 138 // returng toolkit window HWND 139 private native long _init(int awarenessRequested); 140 private native void _setClassLoader(ClassLoader classLoader); 141 private native void _runLoop(Runnable launchable); 142 private native void _terminateLoop(); 143 144 private static final int Process_DPI_Unaware = 0; 145 private static final int Process_System_DPI_Aware = 1; 146 private static final int Process_Per_Monitor_DPI_Aware = 2; 147 148 private static int getDesiredAwarenesslevel() { 149 if (!PrismSettings.allowHiDPIScaling) { 150 return Process_DPI_Unaware; 151 } 152 String awareRequested = AccessController 153 .doPrivileged((PrivilegedAction<String>) () -> 154 System.getProperty("javafx.glass.winDPIawareness")); 155 if (awareRequested != null) { 156 awareRequested = awareRequested.toLowerCase(); 157 if (awareRequested.equals("aware")) { 158 return Process_System_DPI_Aware; 159 } else if (awareRequested.equals("permonitor")) { 160 return Process_Per_Monitor_DPI_Aware; 161 } else { 162 if (!awareRequested.equals("unaware")) { 163 System.err.println("unrecognized DPI awareness request, defaulting to unaware: "+awareRequested); 164 } 165 return Process_DPI_Unaware; 166 } 167 } 168 return Process_Per_Monitor_DPI_Aware; 169 } 170 171 @Override 172 protected void runLoop(final Runnable launchable) { 173 boolean isEventThread = AccessController 174 .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("javafx.embed.isEventThread")); 175 int awareness = getDesiredAwarenesslevel(); 176 177 ClassLoader classLoader = WinApplication.class.getClassLoader(); 178 _setClassLoader(classLoader); 179 180 if (isEventThread) { 181 _init(awareness); 182 setEventThread(Thread.currentThread()); 183 launchable.run(); 184 return; 185 } 186 final Thread toolkitThread = 187 AccessController.doPrivileged((PrivilegedAction<Thread>) () -> new Thread(() -> { 188 _init(awareness); 189 _runLoop(launchable); 190 }, "WindowsNativeRunloopThread")); 191 setEventThread(toolkitThread); 192 toolkitThread.start(); 193 } 194 195 @Override protected void finishTerminating() { 196 final Thread toolkitThread = getEventThread(); 197 if (toolkitThread != null) { 198 _terminateLoop(); 199 setEventThread(null); 200 } 201 super.finishTerminating(); 202 } 203 204 @Override public boolean shouldUpdateWindow() { 205 return true; 206 } 207 208 native private Object _enterNestedEventLoopImpl(); 209 native private void _leaveNestedEventLoopImpl(Object retValue); 210 211 @Override protected Object _enterNestedEventLoop() { 212 if (invokeLaterDispatcher != null) { 213 invokeLaterDispatcher.notifyEnteringNestedEventLoop(); 214 } 215 try { 216 return _enterNestedEventLoopImpl(); 217 } finally { 218 if (invokeLaterDispatcher != null) { 219 invokeLaterDispatcher.notifyLeftNestedEventLoop(); 220 } 221 } 222 } 223 224 @Override protected void _leaveNestedEventLoop(Object retValue) { 225 if (invokeLaterDispatcher != null) { 226 invokeLaterDispatcher.notifyLeavingNestedEventLoop(); 227 } 228 _leaveNestedEventLoopImpl(retValue); 229 } 230 231 // FACTORY METHODS 232 233 @Override public Window createWindow(Window owner, Screen screen, int styleMask) { 234 return new WinWindow(owner, screen, styleMask); 235 } 236 237 @Override public Window createWindow(long parent) { 238 return new WinChildWindow(parent); 239 } 240 241 @Override public View createView() { 242 return new WinView(); 243 } 244 245 @Override public Cursor createCursor(int type) { 246 return new WinCursor(type); 247 } 248 249 @Override public Cursor createCursor(int x, int y, Pixels pixels) { 250 return new WinCursor(x, y, pixels); 251 } 252 253 @Override protected void staticCursor_setVisible(boolean visible) { 254 WinCursor.setVisible_impl(visible); 255 } 256 257 @Override protected Size staticCursor_getBestSize(int width, int height) { 258 return WinCursor.getBestSize_impl(width, height); 259 } 260 261 @Override public Pixels createPixels(int width, int height, ByteBuffer data) { 262 return new WinPixels(width, height, data); 263 } 264 265 @Override public Pixels createPixels(int width, int height, IntBuffer data) { 266 return new WinPixels(width, height, data); 267 } 268 269 @Override 270 public Pixels createPixels(int width, int height, IntBuffer data, float scalex, float scaley) { 271 return new WinPixels(width, height, data, scalex, scaley); 272 } 273 274 @Override protected int staticPixels_getNativeFormat() { 275 return WinPixels.getNativeFormat_impl(); 276 } 277 278 @Override public Robot createRobot() { 279 return new WinRobot(); 280 } 281 282 @Override protected double staticScreen_getVideoRefreshPeriod() { 283 return 0.0; // indicate millisecond resolution 284 } 285 286 @Override native protected Screen[] staticScreen_getScreens(); 287 288 @Override public Timer createTimer(Runnable runnable) { 289 return new WinTimer(runnable); 290 } 291 292 @Override protected int staticTimer_getMinPeriod() { 293 return WinTimer.getMinPeriod_impl(); 294 } 295 296 @Override protected int staticTimer_getMaxPeriod() { 297 return WinTimer.getMaxPeriod_impl(); 298 } 299 300 @Override public Accessible createAccessible() { 301 return new WinAccessible(); 302 } 303 304 @Override protected FileChooserResult staticCommonDialogs_showFileChooser(Window owner, String folder, String filename, String title, int type, 305 boolean multipleMode, ExtensionFilter[] extensionFilters, int defaultFilterIndex) { 306 if (invokeLaterDispatcher != null) { 307 invokeLaterDispatcher.notifyEnteringNestedEventLoop(); 308 } 309 return WinCommonDialogs.showFileChooser_impl(owner, folder, filename, title, type, multipleMode, extensionFilters, defaultFilterIndex); 310 } 311 312 @Override protected File staticCommonDialogs_showFolderChooser(Window owner, String folder, String title) { 313 if (invokeLaterDispatcher != null) { 314 invokeLaterDispatcher.notifyEnteringNestedEventLoop(); 315 } 316 return WinCommonDialogs.showFolderChooser_impl(owner, folder, title); 317 } 318 319 @Override protected long staticView_getMultiClickTime() { 320 return WinView.getMultiClickTime_impl(); 321 } 322 323 @Override protected int staticView_getMultiClickMaxX() { 324 return WinView.getMultiClickMaxX_impl(); 325 } 326 327 @Override protected int staticView_getMultiClickMaxY() { 328 return WinView.getMultiClickMaxY_impl(); 329 } 330 331 @Override native protected void _invokeAndWait(Runnable runnable); 332 333 native private void _submitForLaterInvocation(Runnable r); 334 // InvokeLaterDispatcher.InvokeLaterSubmitter 335 @Override public void submitForLaterInvocation(Runnable r) { 336 _submitForLaterInvocation(r); 337 } 338 339 @Override protected void _invokeLater(Runnable runnable) { 340 if (invokeLaterDispatcher != null) { 341 invokeLaterDispatcher.invokeLater(runnable); 342 } else { 343 submitForLaterInvocation(runnable); 344 } 345 } 346 347 private native String _getHighContrastTheme(); 348 @Override public String getHighContrastTheme() { 349 checkEventThread(); 350 return _getHighContrastTheme(); 351 } 352 353 @Override 354 protected boolean _supportsInputMethods() { 355 return true; 356 } 357 358 @Override 359 protected boolean _supportsTransparentWindows() { 360 return true; 361 } 362 363 @Override native protected boolean _supportsUnifiedWindows(); 364 365 public String getDataDirectory() { 366 checkEventThread(); 367 String baseDirectory = AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getenv("APPDATA")); 368 if (baseDirectory == null || baseDirectory.length() == 0) { 369 return super.getDataDirectory(); 370 } 371 return baseDirectory + File.separator + name + File.separator; 372 } 373 374 @Override 375 protected native int _getKeyCodeForChar(char c); 376 }