1 /* 2 * Copyright (c) 2010, 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 package com.sun.glass.ui.gtk; 26 27 import com.sun.glass.ui.Application; 28 import com.sun.glass.ui.CommonDialogs.ExtensionFilter; 29 import com.sun.glass.ui.CommonDialogs.FileChooserResult; 30 import com.sun.glass.ui.Cursor; 31 import com.sun.glass.ui.InvokeLaterDispatcher; 32 import com.sun.glass.ui.Pixels; 33 import com.sun.glass.ui.Robot; 34 import com.sun.glass.ui.Screen; 35 import com.sun.glass.ui.Size; 36 import com.sun.glass.ui.Timer; 37 import com.sun.glass.ui.View; 38 import com.sun.glass.ui.Window; 39 40 import java.io.File; 41 import java.nio.ByteBuffer; 42 import java.nio.IntBuffer; 43 import java.security.AccessController; 44 import java.security.PrivilegedAction; 45 import java.util.Map; 46 import java.util.concurrent.CountDownLatch; 47 48 final class GtkApplication extends Application implements InvokeLaterDispatcher.InvokeLaterSubmitter { 49 50 static { 51 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 52 Application.loadNativeLibrary(); 53 return null; 54 }); 55 } 56 57 public static int screen = -1; 58 public static long display = 0; 59 public static long visualID = 0; 60 61 private final InvokeLaterDispatcher invokeLaterDispatcher; 62 63 GtkApplication() { 64 // Check whether the Display is valid and throw an exception if not. 65 // We use UnsupportedOperationException rather than HeadlessException 66 // so as not to introduce a dependency on AWT. 67 if (!isDisplayValid()) { 68 throw new UnsupportedOperationException("Unable to open DISPLAY"); 69 } 70 71 // Embedded in SWT, with shared event thread 72 boolean isEventThread = AccessController 73 .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("javafx.embed.isEventThread")); 74 if (!isEventThread) { 75 invokeLaterDispatcher = new InvokeLaterDispatcher(this); 76 invokeLaterDispatcher.start(); 77 } else { 78 invokeLaterDispatcher = null; 79 } 80 } 81 82 private static boolean isDisplayValid() { 83 return _isDisplayValid(); 84 } 85 86 private void initDisplay() { 87 Map ds = getDeviceDetails(); 88 if (ds != null) { 89 Object value; 90 value = ds.get("XDisplay"); 91 if (value != null) { 92 display = (Long)value; 93 } 94 value = ds.get("XVisualID"); 95 if (value != null) { 96 visualID = (Long)value; 97 } 98 value = ds.get("XScreenID"); 99 if (value != null) { 100 screen = (Integer)value; 101 } 102 } 103 } 104 105 private void init() { 106 initDisplay(); 107 long eventProc = 0; 108 Map map = getDeviceDetails(); 109 if (map != null) { 110 Long result = (Long) map.get("javafx.embed.eventProc"); 111 eventProc = result == null ? 0 : result; 112 } 113 114 final boolean disableGrab = AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("sun.awt.disablegrab") || 115 Boolean.getBoolean("glass.disableGrab")); 116 117 _init(eventProc, disableGrab); 118 } 119 120 @Override 121 protected void runLoop(final Runnable launchable) { 122 // Embedded in SWT, with shared event thread 123 final boolean isEventThread = AccessController 124 .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("javafx.embed.isEventThread")); 125 126 if (isEventThread) { 127 init(); 128 setEventThread(Thread.currentThread()); 129 launchable.run(); 130 return; 131 } 132 133 final boolean noErrorTrap = AccessController 134 .doPrivileged((PrivilegedAction<Boolean>) () -> Boolean.getBoolean("glass.noErrorTrap")); 135 136 final Thread toolkitThread = 137 AccessController.doPrivileged((PrivilegedAction<Thread>) () -> new Thread(() -> { 138 init(); 139 _runLoop(launchable, noErrorTrap); 140 }, "GtkNativeMainLoopThread")); 141 setEventThread(toolkitThread); 142 toolkitThread.start(); 143 } 144 145 @Override 146 protected void finishTerminating() { 147 final Thread toolkitThread = getEventThread(); 148 if (toolkitThread != null) { 149 _terminateLoop(); 150 setEventThread(null); 151 } 152 super.finishTerminating(); 153 } 154 155 @Override public boolean shouldUpdateWindow() { 156 return true; 157 } 158 159 private static native boolean _isDisplayValid(); 160 161 private native void _terminateLoop(); 162 163 private native void _init(long eventProc, boolean disableGrab); 164 165 private native void _runLoop(Runnable launchable, boolean noErrorTrap); 166 167 @Override 168 protected void _invokeAndWait(final Runnable runnable) { 169 if (invokeLaterDispatcher != null) { 170 invokeLaterDispatcher.invokeAndWait(runnable); 171 } else { 172 final CountDownLatch latch = new CountDownLatch(1); 173 submitForLaterInvocation(() -> { 174 if (runnable != null) runnable.run(); 175 latch.countDown(); 176 }); 177 try { 178 latch.await(); 179 } catch (InterruptedException e) { 180 //FAIL SILENTLY 181 } 182 } 183 } 184 185 private native void _submitForLaterInvocation(Runnable r); 186 // InvokeLaterDispatcher.InvokeLaterSubmitter 187 @Override public void submitForLaterInvocation(Runnable r) { 188 _submitForLaterInvocation(r); 189 } 190 191 @Override protected void _invokeLater(Runnable runnable) { 192 if (invokeLaterDispatcher != null) { 193 invokeLaterDispatcher.invokeLater(runnable); 194 } else { 195 submitForLaterInvocation(runnable); 196 } 197 } 198 199 private Object eventLoopExitEnterPassValue; 200 201 private native void enterNestedEventLoopImpl(); 202 203 private native void leaveNestedEventLoopImpl(); 204 205 @Override 206 protected Object _enterNestedEventLoop() { 207 if (invokeLaterDispatcher != null) { 208 invokeLaterDispatcher.notifyEnteringNestedEventLoop(); 209 } 210 try { 211 enterNestedEventLoopImpl(); 212 final Object retValue = eventLoopExitEnterPassValue; 213 eventLoopExitEnterPassValue = null; 214 return retValue; 215 } finally { 216 if (invokeLaterDispatcher != null) { 217 invokeLaterDispatcher.notifyLeftNestedEventLoop(); 218 } 219 } 220 } 221 222 @Override 223 protected void _leaveNestedEventLoop(Object retValue) { 224 if (invokeLaterDispatcher != null) { 225 invokeLaterDispatcher.notifyLeavingNestedEventLoop(); 226 } 227 eventLoopExitEnterPassValue = retValue; 228 leaveNestedEventLoopImpl(); 229 } 230 231 @Override 232 public Window createWindow(Window owner, Screen screen, int styleMask) { 233 return new GtkWindow(owner, screen, styleMask); 234 } 235 236 @Override 237 public Window createWindow(long parent) { 238 return new GtkChildWindow(parent); 239 } 240 241 @Override 242 public View createView() { 243 return new GtkView(); 244 } 245 246 @Override 247 public Cursor createCursor(int type) { 248 return new GtkCursor(type); 249 } 250 251 @Override 252 public Cursor createCursor(int x, int y, Pixels pixels) { 253 return new GtkCursor(x, y, pixels); 254 } 255 256 @Override 257 protected void staticCursor_setVisible(boolean visible) { 258 } 259 260 @Override 261 protected Size staticCursor_getBestSize(int width, int height) { 262 return GtkCursor._getBestSize(width, height); 263 } 264 265 @Override 266 public Pixels createPixels(int width, int height, ByteBuffer data) { 267 return new GtkPixels(width, height, data); 268 } 269 270 @Override 271 public Pixels createPixels(int width, int height, IntBuffer data) { 272 return new GtkPixels(width, height, data); 273 } 274 275 @Override 276 public Pixels createPixels(int width, int height, IntBuffer data, float scale) { 277 return new GtkPixels(width, height, data, scale); 278 } 279 280 @Override 281 protected int staticPixels_getNativeFormat() { 282 return Pixels.Format.BYTE_BGRA_PRE; // TODO 283 } 284 285 @Override 286 public Robot createRobot() { 287 return new GtkRobot(); 288 } 289 290 @Override 291 public Timer createTimer(Runnable runnable) { 292 return new GtkTimer(runnable); 293 } 294 295 @Override 296 protected native int staticTimer_getMinPeriod(); 297 298 @Override 299 protected native int staticTimer_getMaxPeriod(); 300 301 @Override protected double staticScreen_getVideoRefreshPeriod() { 302 return 0.0; // indicate millisecond resolution 303 } 304 305 @Override native protected Screen[] staticScreen_getScreens(); 306 307 @Override 308 protected FileChooserResult staticCommonDialogs_showFileChooser( 309 Window owner, String folder, String filename, String title, 310 int type, boolean multipleMode, ExtensionFilter[] extensionFilters, int defaultFilterIndex) { 311 312 return GtkCommonDialogs.showFileChooser(owner, folder, filename, title, 313 type, multipleMode, extensionFilters, defaultFilterIndex); 314 } 315 316 @Override 317 protected File staticCommonDialogs_showFolderChooser(Window owner, String folder, String title) { 318 return GtkCommonDialogs.showFolderChooser(owner, folder, title); 319 } 320 321 @Override 322 protected native long staticView_getMultiClickTime(); 323 324 @Override 325 protected native int staticView_getMultiClickMaxX(); 326 327 @Override 328 protected native int staticView_getMultiClickMaxY(); 329 330 @Override 331 protected boolean _supportsInputMethods() { 332 return true; 333 } 334 335 @Override 336 protected native boolean _supportsTransparentWindows(); 337 338 @Override protected boolean _supportsUnifiedWindows() { 339 return false; 340 } 341 342 @Override 343 protected native int _getKeyCodeForChar(char c); 344 345 }