jogamp.newt.driver.windows.WindowDriver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jogl-all-android Show documentation
Show all versions of jogl-all-android Show documentation
Java™ Binding for the OpenGL® API (Android)
The newest version!
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
* ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
* DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
*/
package jogamp.newt.driver.windows;
import java.nio.ByteBuffer;
import jogamp.nativewindow.windows.GDI;
import jogamp.nativewindow.windows.GDIUtil;
import jogamp.newt.PointerIconImpl;
import jogamp.newt.WindowImpl;
import com.jogamp.nativewindow.AbstractGraphicsConfiguration;
import com.jogamp.nativewindow.GraphicsConfigurationFactory;
import com.jogamp.nativewindow.NativeWindowException;
import com.jogamp.nativewindow.VisualIDHolder;
import com.jogamp.nativewindow.util.InsetsImmutable;
import com.jogamp.nativewindow.util.Point;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.VersionNumber;
import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseEvent.PointerType;
public class WindowDriver extends WindowImpl {
static {
DisplayDriver.initSingleton();
}
private long hmon;
private long hdc;
private long hdc_old;
private long windowHandleClose;
public WindowDriver() {
}
@Override
protected int lockSurfaceImpl() {
if (0 != hdc) {
throw new InternalError("surface not released");
}
final long hWnd = getWindowHandle();
hdc = GDI.GetDC(hWnd);
// return ( 0 == hdc ) ? LOCK_SURFACE_NOT_READY : ( hdc_old != hdc ) ? LOCK_SURFACE_CHANGED : LOCK_SUCCESS ;
if( 0 == hdc ) {
return LOCK_SURFACE_NOT_READY;
}
hmon = MonitorFromWindow0(hWnd);
// Let's not trigger on HDC change, GLDrawableImpl.'s destroy/create is a nop here anyways.
// FIXME: Validate against EGL surface creation: ANGLE uses HWND -> fine!
return LOCK_SUCCESS;
/**
if( hdc_old == hdc ) {
return LOCK_SUCCESS;
}
if(DEBUG_IMPLEMENTATION) {
System.err.println("WindowsWindow: surface change "+toHexString(hdc_old)+" -> "+toHexString(hdc));
// Thread.dumpStack();
}
return LOCK_SURFACE_CHANGED; */
}
@Override
protected void unlockSurfaceImpl() {
if (0 != hdc) {
GDI.ReleaseDC(getWindowHandle(), hdc);
hdc_old = hdc;
hdc=0;
}
}
@Override
public final long getSurfaceHandle() {
return hdc;
}
@Override
public boolean hasDeviceChanged() {
if(0!=getWindowHandle()) {
final long _hmon = MonitorFromWindow0(getWindowHandle());
if (hmon != _hmon) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("Info: Window Device Changed "+Thread.currentThread().getName()+
", HMON "+toHexString(hmon)+" -> "+toHexString(_hmon));
// Thread.dumpStack();
}
hmon = _hmon;
return true;
}
}
return false;
}
@Override
protected void createNativeImpl() {
final ScreenDriver screen = (ScreenDriver) getScreen();
final DisplayDriver display = (DisplayDriver) screen.getDisplay();
final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice(), capsRequested).chooseGraphicsConfiguration(
capsRequested, capsRequested, capabilitiesChooser, screen.getGraphicsScreen(), VisualIDHolder.VID_UNDEFINED);
if (null == cfg) {
throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this);
}
setGraphicsConfiguration(cfg);
final VersionNumber winVer = Platform.getOSVersionNumber();
int flags = getReconfigureMask(0, true) & STATE_MASK_CREATENATIVE;
int maxCount = 0;
if( 0 != ( STATE_MASK_MAXIMIZED_HORZ & flags ) ) {
flags |= CHANGE_MASK_MAXIMIZED_HORZ;
maxCount++;
}
if( 0 != ( STATE_MASK_MAXIMIZED_VERT & flags ) ) {
flags |= CHANGE_MASK_MAXIMIZED_VERT;
maxCount++;
}
final long _windowHandle = CreateWindow0(DisplayDriver.getHInstance(), display.getWindowClassName(), display.getWindowClassName(),
winVer.getMajor(), winVer.getMinor(),
getParentWindowHandle(),
getX(), getY(), getWidth(), getHeight(), flags);
if ( 0 == _windowHandle ) {
throw new NativeWindowException("Error creating window");
}
if( !cfg.getChosenCapabilities().isBackgroundOpaque() ) {
GDIUtil.DwmSetupTranslucency(_windowHandle, true);
}
InitWindow0(_windowHandle, flags);
setWindowHandle(_windowHandle);
windowHandleClose = _windowHandle;
if( 0 == ( STATE_MASK_CHILDWIN & flags ) && 1 == maxCount ) {
reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), flags);
}
if(DEBUG_IMPLEMENTATION) {
final Exception e = new Exception("Info: Window new window handle "+Thread.currentThread().getName()+
" (Parent HWND "+toHexString(getParentWindowHandle())+
") : HWND "+toHexString(_windowHandle)+", "+Thread.currentThread());
e.printStackTrace();
}
}
@Override
protected void closeNativeImpl() {
if( 0 != windowHandleClose ) {
if ( 0 != hdc ) {
try {
GDI.ReleaseDC(windowHandleClose, hdc);
} catch (final Throwable t) {
if(DEBUG_IMPLEMENTATION) {
final Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t);
e.printStackTrace();
}
}
}
try {
GDI.DestroyWindow(windowHandleClose);
} catch (final Throwable t) {
if(DEBUG_IMPLEMENTATION) {
final Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t);
e.printStackTrace();
}
}
}
windowHandleClose = 0;
hdc = 0;
hdc_old = 0;
}
@Override
protected final int getSupportedReconfigMaskImpl() {
return minimumReconfigStateMask |
STATE_MASK_CHILDWIN |
STATE_MASK_UNDECORATED |
STATE_MASK_ALWAYSONTOP |
STATE_MASK_ALWAYSONBOTTOM |
// STATE_MASK_STICKY |
STATE_MASK_RESIZABLE |
STATE_MASK_MAXIMIZED_VERT |
STATE_MASK_MAXIMIZED_HORZ |
STATE_MASK_POINTERVISIBLE |
STATE_MASK_POINTERCONFINED;
}
@Override
protected boolean reconfigureWindowImpl(int x, int y, int width, int height, final int flags) {
if(DEBUG_IMPLEMENTATION) {
System.err.println("WindowsWindow reconfig.0: "+x+"/"+y+" "+width+"x"+height+
", "+getReconfigStateMaskString(flags));
}
final InsetsImmutable insets = getInsets();
if( 0 == ( STATE_MASK_CHILDWIN & flags ) &&
0 != ( ( CHANGE_MASK_MAXIMIZED_HORZ | CHANGE_MASK_MAXIMIZED_VERT ) & flags ) ) {
final int[] posSize = { x, y, width, height };
if( ( 0 != ( STATE_MASK_MAXIMIZED_HORZ & flags ) ) == ( 0 != ( STATE_MASK_MAXIMIZED_VERT & flags ) ) ) {
resetMaximizedManual(posSize); // reset before native maximize/reset
} else {
reconfigMaximizedManual(flags, posSize, insets);
}
x = posSize[0];
y = posSize[1];
width = posSize[2];
height = posSize[3];
}
final boolean changeDecoration = 0 != ( CHANGE_MASK_DECORATION & flags);
final boolean isTranslucent = !getChosenCapabilities().isBackgroundOpaque();
if( changeDecoration && isTranslucent ) {
GDIUtil.DwmSetupTranslucency(getWindowHandle(), false);
}
reconfigureWindow0( getParentWindowHandle(), getWindowHandle(), x, y, width, height, flags);
if( changeDecoration && isTranslucent ) {
GDIUtil.DwmSetupTranslucency(getWindowHandle(), true);
}
if( 0 != ( CHANGE_MASK_VISIBILITY & flags) ) {
visibleChanged(false, 0 != ( STATE_MASK_VISIBLE & flags));
}
if(DEBUG_IMPLEMENTATION) {
System.err.println("WindowsWindow reconfig.X: "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()+", "+getStateMaskString());
}
return true;
}
@Override
protected void requestFocusImpl(final boolean force) {
requestFocus0(getWindowHandle(), force);
}
@Override
protected void setTitleImpl(final String title) {
setTitle0(getWindowHandle(), title);
}
@Override
protected void setPointerIconImpl(final PointerIconImpl pi) {
setPointerIcon0(getWindowHandle(), null != pi ? pi.validatedHandle() : 0);
}
@Override
protected boolean setPointerVisibleImpl(final boolean pointerVisible) {
final boolean[] res = new boolean[] { false };
this.runOnEDTIfAvail(true, new Runnable() {
@Override
public void run() {
res[0] = setPointerVisible0(getWindowHandle(), pointerVisible);
}
});
return res[0];
}
@Override
protected boolean confinePointerImpl(final boolean confine) {
final Boolean[] res = new Boolean[] { Boolean.FALSE };
this.runOnEDTIfAvail(true, new Runnable() {
@Override
public void run() {
final Point p0 = convertToPixelUnits( getLocationOnScreenImpl(0, 0) );
res[0] = Boolean.valueOf(confinePointer0(getWindowHandle(), confine,
p0.getX(), p0.getY(),
p0.getX()+getSurfaceWidth(), p0.getY()+getSurfaceHeight()));
}
});
return res[0].booleanValue();
}
@Override
protected void warpPointerImpl(final int x, final int y) {
this.runOnEDTIfAvail(true, new Runnable() {
@Override
public void run() {
final Point sPos = convertToPixelUnits( getLocationOnScreenImpl(x, y) );
warpPointer0(getWindowHandle(), sPos.getX(), sPos.getY());
}
});
return;
}
@Override
protected Point getLocationOnScreenImpl(final int x, final int y) {
return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y);
}
//
// PointerEvent Handling
//
/**
* Send multiple-pointer {@link MouseEvent.PointerType#TouchScreen} event to be directly consumed
*
* Assumes non normal pointer names and rotation/scroll will be determined by a gesture handler.
*
*
* See {@link #doPointerEvent(boolean, boolean, PointerType[], short, int, int, boolean, int[], int[], int[], float[], float, float[], float)}
* for details.
*
*/
public final void sendTouchScreenEvent(final short eventType, final int modifiers,
final int pActionIdx, final int[] pNames,
final int[] pX, final int[] pY, final float[] pPressure, final float maxPressure) {
final int pCount = pNames.length;
final MouseEvent.PointerType[] pTypes = new MouseEvent.PointerType[pCount];
for(int i=pCount-1; i>=0; i--) { pTypes[i] = PointerType.TouchScreen; }
doPointerEvent(false /*enqueue*/, false /*wait*/,
pTypes, eventType, modifiers, pActionIdx, false /*normalPNames*/, pNames,
pX, pY, pPressure, maxPressure, new float[] { 0f, 0f, 0f} /*rotationXYZ*/, 1f/*rotationScale*/);
}
//
// KeyEvent Handling
//
private short repeatedKey = KeyEvent.VK_UNDEFINED;
private final boolean handlePressTypedAutoRepeat(final boolean isModifierKey, int modifiers, final short keyCode, final short keySym, final char keyChar) {
if( setKeyPressed(keyCode, true) ) {
// AR: Key was already pressed: Either [enter | within] AR mode
final boolean withinAR = repeatedKey == keyCode;
repeatedKey = keyCode;
if( !isModifierKey ) {
// AR: Key was already pressed: Either [enter | within] AR mode
modifiers |= InputEvent.AUTOREPEAT_MASK;
if( withinAR ) {
// AR: Within AR mode
super.sendKeyEvent(KeyEvent.EVENT_KEY_PRESSED, modifiers, keyCode, keySym, keyChar);
} // else { AR: Enter AR mode - skip already send PRESSED ; or ALT }
super.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, keySym, keyChar);
}
return true;
}
return false;
}
@Override
public final void sendKeyEvent(final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar) {
final boolean isModifierKey = KeyEvent.isModifierKey(keySym);
// System.err.println("*** sendKeyEvent: event "+KeyEvent.getEventTypeString(eventType)+", keyCode "+toHexString(keyCode)+", keyChar <"+keyChar+">, mods "+toHexString(modifiers)+
// ", isKeyCodeTracked "+isKeyCodeTracked(keyCode)+", was: pressed "+isKeyPressed(keyCode)+", printableKey "+KeyEvent.isPrintableKey(keyCode, false)+" [modifierKey "+isModifierKey+"] - "+System.currentTimeMillis());
// Reorder: WINDOWS delivery order is PRESSED (t0), TYPED (t0) and RELEASED (t1) -> NEWT order: PRESSED (t0) and RELEASED (t1)
// Auto-Repeat: WINDOWS delivers only PRESSED (t0) and TYPED (t0).
switch(eventType) {
case KeyEvent.EVENT_KEY_RELEASED:
if( isKeyCodeTracked(keyCode) ) {
if( repeatedKey == keyCode && !isModifierKey ) {
// AR out - send out missing PRESSED
super.sendKeyEvent(KeyEvent.EVENT_KEY_PRESSED, modifiers | InputEvent.AUTOREPEAT_MASK, keyCode, keySym, keyChar);
}
setKeyPressed(keyCode, false);
repeatedKey = KeyEvent.VK_UNDEFINED;
}
super.sendKeyEvent(KeyEvent.EVENT_KEY_RELEASED, modifiers, keyCode, keySym, keyChar);
break;
case KeyEvent.EVENT_KEY_PRESSED:
if( !handlePressTypedAutoRepeat(isModifierKey, modifiers, keyCode, keySym, keyChar) ) {
super.sendKeyEvent(KeyEvent.EVENT_KEY_PRESSED, modifiers, keyCode, keySym, keyChar);
}
break;
}
}
@Override
public final void enqueueKeyEvent(final boolean wait, final short eventType, final int modifiers, final short keyCode, final short keySym, final char keyChar) {
throw new InternalError("XXX: Adapt Java Code to Native Code Changes");
}
//----------------------------------------------------------------------
// Internals only
//
protected static native long getNewtWndProc0();
protected static native boolean initIDs0(long hInstance);
private native long CreateWindow0(long hInstance, String wndClassName, String wndName, int winMajor, int winMinor,
long parentWindowHandle, int x, int y, int width, int height, int flags);
private native void InitWindow0(long windowHandle, int flags);
private native long MonitorFromWindow0(long windowHandle);
private native void reconfigureWindow0(long parentWindowHandle, long windowHandle,
int x, int y, int width, int height, int flags);
private static native void setTitle0(long windowHandle, String title);
private native void requestFocus0(long windowHandle, boolean force);
private static native boolean setPointerVisible0(long windowHandle, boolean visible);
private static native boolean confinePointer0(long windowHandle, boolean grab, int l, int t, int r, int b);
private static native void warpPointer0(long windowHandle, int x, int y);
private static native ByteBuffer newDirectByteBuffer(long addr, long capacity);
private static native void setPointerIcon0(long windowHandle, long iconHandle);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy