Fixed Rect/RECT conversion and added a workaround that resets the OpenGL client area when we toggle resizable after window creation.

This commit is contained in:
Ioannis Tsakpinis 2013-12-13 15:33:13 +02:00
parent 1703b62ed5
commit 66c987f9c2
2 changed files with 92 additions and 51 deletions

View File

@ -43,6 +43,8 @@ import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.*; import java.nio.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLException;
@ -196,7 +198,6 @@ final class WindowsDisplay implements DisplayImplementation {
private boolean inAppActivate; private boolean inAppActivate;
private boolean resized; private boolean resized;
private boolean resizable; private boolean resizable;
private boolean maximized;
private int x; private int x;
private int y; private int y;
private int width; private int width;
@ -213,6 +214,8 @@ final class WindowsDisplay implements DisplayImplementation {
private boolean trackingMouse; private boolean trackingMouse;
private boolean mouseInside; private boolean mouseInside;
private List<Runnable> deferredActions = new ArrayList<Runnable>();
static { static {
try { try {
Method windowProc = WindowsDisplay.class.getDeclaredMethod("handleMessage", long.class, int.class, long.class, long.class, long.class); Method windowProc = WindowsDisplay.class.getDeclaredMethod("handleMessage", long.class, int.class, long.class, long.class, long.class);
@ -232,12 +235,14 @@ final class WindowsDisplay implements DisplayImplementation {
isMinimized = false; isMinimized = false;
isFocused = false; isFocused = false;
redoMakeContextCurrent = false; redoMakeContextCurrent = false;
maximized = false;
this.parent = parent; this.parent = parent;
hasParent = parent != null; hasParent = parent != null;
parent_hwnd = parent != null ? getHwnd(parent) : 0; parent_hwnd = parent != null ? getHwnd(parent) : 0;
this.hwnd = nCreateWindow(x, y, mode.getWidth(), mode.getHeight(), Display.isFullscreen() || isUndecorated(), parent != null, parent_hwnd); this.hwnd = nCreateWindow(x, y, mode.getWidth(), mode.getHeight(), Display.isFullscreen() || isUndecorated(), parent != null, parent_hwnd);
this.resizable=false; if ( Display.isResizable() && parent == null ) {
setResizable(true, false);
}
if (hwnd == 0) { if (hwnd == 0) {
throw new LWJGLException("Failed to create window"); throw new LWJGLException("Failed to create window");
} }
@ -261,9 +266,6 @@ final class WindowsDisplay implements DisplayImplementation {
updateWidthAndHeight(); updateWidthAndHeight();
if ( parent == null ) { if ( parent == null ) {
if(Display.isResizable()) {
setResizable(true);
}
setForegroundWindow(getHwnd()); setForegroundWindow(getHwnd());
} else { } else {
parent_focused = new AtomicBoolean(false); parent_focused = new AtomicBoolean(false);
@ -551,6 +553,12 @@ final class WindowsDisplay implements DisplayImplementation {
} }
public void update() { public void update() {
if ( !deferredActions.isEmpty() ) {
for ( Runnable r : deferredActions )
r.run();
deferredActions.clear();
}
nUpdate(); nUpdate();
if ( !isFocused && parent != null && parent_focused.compareAndSet(true, false) ) { if ( !isFocused && parent != null && parent_focused.compareAndSet(true, false) ) {
@ -975,7 +983,6 @@ final class WindowsDisplay implements DisplayImplementation {
switch ((int)wParam) { switch ((int)wParam) {
case SIZE_RESTORED: case SIZE_RESTORED:
case SIZE_MAXIMIZED: case SIZE_MAXIMIZED:
maximized = ((int)wParam) == SIZE_MAXIMIZED;
resized = true; resized = true;
updateWidthAndHeight(); updateWidthAndHeight();
setMinimized(false); setMinimized(false);
@ -1155,31 +1162,59 @@ final class WindowsDisplay implements DisplayImplementation {
} }
public void setResizable(boolean resizable) { public void setResizable(boolean resizable) {
if(this.resizable != resizable) { if ( this.resizable == resizable )
int style = (int)getWindowLongPtr(hwnd, GWL_STYLE); return;
int styleex = (int)getWindowLongPtr(hwnd, GWL_EXSTYLE);
// update frame style setResizable(resizable, true);
if(resizable && !Display.isFullscreen()) { }
setWindowLongPtr(hwnd, GWL_STYLE, style |= (WS_THICKFRAME | WS_MAXIMIZEBOX));
} else {
setWindowLongPtr(hwnd, GWL_STYLE, style &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX));
}
// from the existing client rect, determine the new window rect private void setResizable(boolean resizable, boolean defer) {
// based on the style changes - using AdjustWindowRectEx. this.resized = false;
getClientRect(hwnd, rect_buffer);
rect.copyFromBuffer(rect_buffer);
adjustWindowRectEx(rect_buffer, style, false, styleex);
rect.copyFromBuffer(rect_buffer);
// force a frame update and resize accordingly
setWindowPos(hwnd, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
updateWidthAndHeight();
resized = false;
}
this.resizable = resizable; this.resizable = resizable;
int style = (int)getWindowLongPtr(hwnd, GWL_STYLE);
int styleex = (int)getWindowLongPtr(hwnd, GWL_EXSTYLE);
// update frame style
setWindowLongPtr(
hwnd,
GWL_STYLE,
style = resizable && !Display.isFullscreen()
? (style | (WS_THICKFRAME | WS_MAXIMIZEBOX))
: (style & ~(WS_THICKFRAME | WS_MAXIMIZEBOX))
);
// from the existing client rect, determine the new window rect
// based on the style changes - using AdjustWindowRectEx.
getGlobalClientRect(hwnd, rect);
rect.copyToBuffer(rect_buffer);
adjustWindowRectEx(rect_buffer, style, false, styleex);
rect.copyFromBuffer(rect_buffer);
final int x = rect.left;
final int y = rect.top;
final int cx = rect.right - rect.left;
final int cy = rect.bottom - rect.top;
if ( defer ) {
// SWP_FRAMECHANGED does not play nice with WS_THICKFRAME on/off, the OpenGL client area
// ends up in the wrong position. Reshape the window later, this will reset the client
// area to the correct position.
deferredActions.add(new Runnable() {
public void run() {
setWindowPos(hwnd, 0L, x, y, cx, cy, SWP_NOZORDER);
updateWidthAndHeight();
}
});
// apply the style changes
setWindowPos(hwnd, 0L, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
} else {
// apply the style changes
setWindowPos(hwnd, 0L, x, y, cx, cy, SWP_NOZORDER | SWP_FRAMECHANGED);
}
updateWidthAndHeight();
} }
private native boolean adjustWindowRectEx(IntBuffer rectBuffer, int style, boolean menu, int styleex); private native boolean adjustWindowRectEx(IntBuffer rectBuffer, int style, boolean menu, int styleex);
@ -1191,44 +1226,50 @@ final class WindowsDisplay implements DisplayImplementation {
} }
return false; return false;
} }
public float getPixelScaleFactor() { public float getPixelScaleFactor() {
return 1f; return 1f;
} }
private static final class Rect { private static final class Rect {
public int top;
public int bottom; public int
public int left; left,
public int right; top,
right,
bottom;
public void copyToBuffer(IntBuffer buffer) { public void copyToBuffer(IntBuffer buffer) {
buffer.put(0, top).put(1, bottom).put(2, left).put(3, right); buffer
.put(0, left)
.put(1, top)
.put(2, right)
.put(3, bottom);
} }
public void copyFromBuffer(IntBuffer buffer) { public void copyFromBuffer(IntBuffer buffer) {
top = buffer.get(0); left = buffer.get(0);
bottom = buffer.get(1); top = buffer.get(1);
left = buffer.get(2); right = buffer.get(2);
right = buffer.get(3); bottom = buffer.get(3);
} }
public void offset(int offset_x, int offset_y) { public void offset(int offset_x, int offset_y) {
left += offset_x; left += offset_x;
right += offset_x;
top += offset_y; top += offset_y;
right += offset_x;
bottom += offset_y; bottom += offset_y;
} }
public static void intersect(Rect r1, Rect r2, Rect dst) { public static void intersect(Rect r1, Rect r2, Rect dst) {
dst.top = Math.max(r1.top, r2.top);
dst.bottom = Math.min(r1.bottom, r2.bottom);
dst.left = Math.max(r1.left, r2.left); dst.left = Math.max(r1.left, r2.left);
dst.top = Math.max(r1.top, r2.top);
dst.right = Math.min(r1.right, r2.right); dst.right = Math.min(r1.right, r2.right);
dst.bottom = Math.min(r1.bottom, r2.bottom);
} }
public String toString() { public String toString() {
return "Rect: top = " + top + " bottom = " + bottom + " left = " + left + " right = " + right + ", width: " + (right - left) + ", height: " + (bottom - top); return "Rect: left = " + left + " top = " + top + " right = " + right + " bottom = " + bottom + ", width: " + (right - left) + ", height: " + (bottom - top);
} }
} }
} }

View File

@ -245,10 +245,10 @@ static void copyBufferToRect(JNIEnv *env, jobject buffer_handle, RECT *rect) {
throwFormattedRuntimeException(env, "Buffer size < 4", size); throwFormattedRuntimeException(env, "Buffer size < 4", size);
return; return;
} }
rect->top = buffer[0]; rect->left = buffer[0];
rect->bottom = buffer[1]; rect->top = buffer[1];
rect->left = buffer[2]; rect->right = buffer[2];
rect->right = buffer[3]; rect->bottom = buffer[3];
} }
static void copyRectToBuffer(JNIEnv *env, RECT *rect, jobject buffer_handle) { static void copyRectToBuffer(JNIEnv *env, RECT *rect, jobject buffer_handle) {
@ -258,10 +258,10 @@ static void copyRectToBuffer(JNIEnv *env, RECT *rect, jobject buffer_handle) {
throwFormattedRuntimeException(env, "Buffer size < 4", size); throwFormattedRuntimeException(env, "Buffer size < 4", size);
return; return;
} }
buffer[0] = rect->top; buffer[0] = rect->left;
buffer[1] = rect->bottom; buffer[1] = rect->top;
buffer[2] = rect->left; buffer[2] = rect->right;
buffer[3] = rect->right; buffer[3] = rect->bottom;
} }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_WindowsDisplay_clipCursor(JNIEnv *env, jclass unused, jobject handle_buffer) { JNIEXPORT void JNICALL Java_org_lwjgl_opengl_WindowsDisplay_clipCursor(JNIEnv *env, jclass unused, jobject handle_buffer) {