com.machinepublishers.glass.ui.monocle.MonocleApplication Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jbrowserdriver Show documentation
Show all versions of jbrowserdriver Show documentation
A programmable, embedded web browser driver compatible with the Selenium WebDriver spec -- fast, headless, WebKit-based, 100% pure Java, and no browser dependencies
/*
* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.machinepublishers.glass.ui.monocle;
import java.io.File;
import java.lang.reflect.Constructor;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import com.sun.glass.ui.Application;
import com.sun.glass.ui.CommonDialogs.ExtensionFilter;
import com.sun.glass.ui.CommonDialogs.FileChooserResult;
import com.sun.glass.ui.Cursor;
import com.sun.glass.ui.Pixels;
import com.sun.glass.ui.Robot;
import com.sun.glass.ui.Screen;
import com.sun.glass.ui.Size;
import com.sun.glass.ui.Timer;
import com.sun.glass.ui.View;
import com.sun.glass.ui.Window;
import javafx.scene.control.TextInputDialog;
public final class MonocleApplication extends Application {
private final NativePlatform platform = NativePlatformFactory.getNativePlatform();
private final RunnableProcessor runnableProcessor = platform.getRunnableProcessor();
/** Bit to indicate that a device has touch support */
private static final int DEVICE_TOUCH = 0;
/** Bit to indicate that a device has multitouch support */
private static final int DEVICE_MULTITOUCH = 1;
/** Bit to indicate that a device has relative motion pointer support */
private static final int DEVICE_POINTER = 2;
/** Bit to indicate that a device has arrow keys and a select key */
private static final int DEVICE_5WAY = 3;
/** Bit to indicate that a device has a full PC keyboard */
private static final int DEVICE_PC_KEYBOARD = 4;
/** Largest bit used in device capability bitmasks */
private static final int DEVICE_MAX = 4;
/** A running count of the numbers of devices with each device capability */
private int[] deviceFlags = new int[DEVICE_MAX + 1];
private Thread shutdownHookThread;
private Runnable renderEndNotifier = () -> platform.getScreen().swapBuffers();
MonocleApplication() {
// for (InputDevice device : platform.getInputDeviceRegistry().getInputDevices()) {
// updateDeviceFlags(device, true);
// }
// platform.getInputDeviceRegistry().getInputDevices().addListener(
// (SetChangeListener) change -> {
// if (change.wasAdded()) {
// InputDevice device = change.getElementAdded();
// updateDeviceFlags(device, true);
// } else if (change.wasRemoved()) {
// InputDevice device = change.getElementRemoved();
// updateDeviceFlags(device, false);
// }
// });
}
private void updateDeviceFlags(InputDevice device, boolean added) {
int modifier = added ? 1 : -1;
if (device.isTouch()) {
deviceFlags[DEVICE_TOUCH] += modifier;
}
if (device.isMultiTouch()) {
deviceFlags[DEVICE_MULTITOUCH] += modifier;
}
if (device.isRelative()) {
deviceFlags[DEVICE_POINTER] += modifier;
if (deviceFlags[DEVICE_POINTER] >= 1 && added) {
staticCursor_setVisible(true);
} else if (deviceFlags[DEVICE_POINTER] < 1 && !added) {
staticCursor_setVisible(false);
}
}
if (device.isFullKeyboard()) {
deviceFlags[DEVICE_PC_KEYBOARD] += modifier;
}
if (device.is5Way()) {
deviceFlags[DEVICE_5WAY] += modifier;
}
}
@Override
protected void runLoop(Runnable launchable) {
runnableProcessor.invokeLater(launchable);
long stackSize = AccessController.doPrivileged(
(PrivilegedAction) () -> Long.getLong("monocle.stackSize", 0));
Thread t = new Thread(
new ThreadGroup("Event"),
runnableProcessor,
"Event Thread",
stackSize);
setEventThread(t);
t.start();
shutdownHookThread = new Thread("Monocle shutdown hook") {
@Override
public void run() {
platform.shutdown();
}
};
Runtime.getRuntime().addShutdownHook(shutdownHookThread);
}
@Override
protected void _invokeAndWait(Runnable runnable) {
runnableProcessor.invokeAndWait(runnable);
}
@Override
protected void _invokeLater(Runnable runnable) {
runnableProcessor.invokeLater(runnable);
}
@Override
protected Object _enterNestedEventLoop() {
return runnableProcessor.enterNestedEventLoop();
}
@Override
protected void _leaveNestedEventLoop(Object retValue) {
runnableProcessor.leaveNestedEventLoop(retValue);
}
@Override
public Window createWindow(Window owner, Screen screen, int styleMask) {
return new MonocleWindow(owner, screen, styleMask);
}
@Override
public Window createWindow(long parent) {
return new MonocleWindow(parent);
}
@Override
public View createView() {
return new MonocleView();
}
@Override
public Cursor createCursor(int type) {
return new MonocleCursor(type);
}
@Override
public Cursor createCursor(int x, int y, Pixels pixels) {
return new MonocleCursor(x, y, pixels);
}
@Override
protected void staticCursor_setVisible(boolean visible) {
NativeCursor cursor = NativePlatformFactory.getNativePlatform().getCursor();
cursor.setVisibility(deviceFlags[DEVICE_POINTER] >= 1 ? visible : false);
}
@Override
protected Size staticCursor_getBestSize(int width, int height) {
NativeCursor cursor = NativePlatformFactory.getNativePlatform().getCursor();
return cursor.getBestSize();
}
@Override
public Pixels createPixels(int width, int height, ByteBuffer data) {
return new MonoclePixels(width, height, data);
}
@Override
public Pixels createPixels(int width, int height, IntBuffer data) {
return new MonoclePixels(width, height, data);
}
// @Override
public Pixels createPixels(int width, int height, IntBuffer data,
float scalex, float scaley) {
return new MonoclePixels(width, height, data);//Java 8 and Java 9 constructors conflict--work around: use a constructor they both have
}
// @Override
public Pixels createPixels(int width, int height, IntBuffer data, float scale) {
return new MonoclePixels(width, height, data);//Java 8 and Java 9 constructors conflict--work around: use a constructor they both have
}
@Override
protected int staticPixels_getNativeFormat() {
return platform.getScreen().getNativeFormat();
}
@Override
public Robot createRobot() {
return new MonocleRobot();
}
@Override
protected double staticScreen_getVideoRefreshPeriod() {
return 0.0;
}
@Override
protected Screen[] staticScreen_getScreens() {
Screen screen = null;
try {
NativeScreen ns = platform.getScreen();
final AtomicBoolean java9 = new AtomicBoolean();
Constructor c = AccessController.doPrivileged(
new PrivilegedAction() {
@Override
public Constructor run() {
try {
Constructor c = Screen.class.getDeclaredConstructor(
Long.TYPE,
Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE, Float.TYPE);
c.setAccessible(true);
return c;
} catch (Exception e) {
try {
Constructor c = Screen.class.getDeclaredConstructor(
Long.TYPE,
Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE,
Float.TYPE, Float.TYPE,
Float.TYPE, Float.TYPE);
c.setAccessible(true);
java9.set(true);
return c;
} catch (Exception e2) {
e2.printStackTrace();
return null;
}
}
}
});
if (c != null) {
if (java9.get()) {
screen = (Screen) c.newInstance(1l, // dummy native pointer;
ns.getDepth(),
0, 0, ns.getWidth(), ns.getHeight(),
0, 0, ns.getWidth(), ns.getHeight(),
0, 0, ns.getWidth(), ns.getHeight(),
ns.getDPI(), ns.getDPI(),
ns.getScale(), ns.getScale(),
ns.getScale(), ns.getScale());
// Move the cursor to the middle of the screen
MouseState mouseState = new MouseState();
mouseState.setX(ns.getWidth() / 2);
mouseState.setY(ns.getHeight() / 2);
MouseInput.getInstance().setState(mouseState, false);
} else {
screen = (Screen) c.newInstance(
1l, // dummy native pointer;
ns.getDepth(),
0, 0, ns.getWidth(), ns.getHeight(),
0, 0, ns.getWidth(), ns.getHeight(),
ns.getDPI(), ns.getDPI(),
ns.getScale());
// Move the cursor to the middle of the screen
MouseState mouseState = new MouseState();
mouseState.setX(ns.getWidth() / 2);
mouseState.setY(ns.getHeight() / 2);
MouseInput.getInstance().setState(mouseState, false);
}
}
} catch (Throwable t) {
t.printStackTrace();
}
return new Screen[] { screen };
}
@Override
public Timer createTimer(Runnable runnable) {
return new MonocleTimer(runnable);
}
@Override
protected int staticTimer_getMinPeriod() {
return MonocleTimer.getMinPeriod_impl();
}
@Override
protected int staticTimer_getMaxPeriod() {
return MonocleTimer.getMaxPeriod_impl();
}
public boolean hasWindowManager() {
return false;
}
@Override
protected FileChooserResult staticCommonDialogs_showFileChooser(
Window owner, String folder, String filename, String title,
int type, boolean multipleMode,
ExtensionFilter[] extensionFilters,
int defaultFilterIndex) {
TextInputDialog dialog = new TextInputDialog();
dialog.showAndWait();
File[] files;
String filePaths = dialog.getEditor().getText();
if (filePaths != null && !filePaths.isEmpty()) {
String[] filePathParts = filePaths.split("\t");
files = new File[filePathParts.length];
for (int i = 0; i < filePathParts.length; i++) {
files[i] = new File(filePathParts[i]);
}
} else {
files = new File[0];
}
return new FileChooserResult(Arrays.asList(files), null);
}
@Override
protected File staticCommonDialogs_showFolderChooser(Window owner,
String folder,
String title) {
Thread.dumpStack();
throw new UnsupportedOperationException();
}
@Override
protected long staticView_getMultiClickTime() {
return MonocleView._getMultiClickTime();
}
@Override
protected int staticView_getMultiClickMaxX() {
return MonocleView._getMultiClickMaxX();
}
@Override
protected int staticView_getMultiClickMaxY() {
return MonocleView._getMultiClickMaxY();
}
@Override
protected boolean _supportsTransparentWindows() {
return true;
}
@Override
protected boolean _supportsUnifiedWindows() {
return false;
}
@Override
public boolean hasTwoLevelFocus() {
return deviceFlags[DEVICE_PC_KEYBOARD] == 0 && deviceFlags[DEVICE_5WAY] > 0;
}
@Override
public boolean hasVirtualKeyboard() {
return deviceFlags[DEVICE_PC_KEYBOARD] == 0 && deviceFlags[DEVICE_TOUCH] > 0;
}
@Override
public boolean hasTouch() {
return deviceFlags[DEVICE_TOUCH] > 0;
}
@Override
public boolean hasMultiTouch() {
return deviceFlags[DEVICE_MULTITOUCH] > 0;
}
@Override
public boolean hasPointer() {
return deviceFlags[DEVICE_POINTER] > 0;
}
//@Override
public void notifyRenderingFinished() {
invokeLater(renderEndNotifier);
}
@Override
protected void finishTerminating() {
//if this method is getting called, we don't need the shutdown hook
Runtime.getRuntime().removeShutdownHook(shutdownHookThread);
setEventThread(null);
platform.shutdown();
super.finishTerminating();
}
void enterDnDEventLoop() {
_enterNestedEventLoop();
}
void leaveDndEventLoop() {
_leaveNestedEventLoop(null);
}
//@Override
protected int _getKeyCodeForChar(char c) {
return KeyInput.getInstance().getKeyCodeForChar(c);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy