From c499f33bcf9c3308db6ba8d381015e345451ee4d Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sun, 6 Apr 2008 20:56:52 +0000 Subject: [PATCH] Added experimental Display.setParent to allow Display to be embedded in an AWT Canvas. Added basic linux implementation and test. --- .../lwjgl/opengl/AWTCanvasImplementation.java | 4 +- src/java/org/lwjgl/opengl/AWTSurfaceLock.java | 10 +- src/java/org/lwjgl/opengl/Display.java | 57 +++++++- .../lwjgl/opengl/DisplayImplementation.java | 3 +- .../opengl/LinuxAWTGLCanvasPeerInfo.java | 6 +- .../opengl/LinuxCanvasImplementation.java | 4 +- src/java/org/lwjgl/opengl/LinuxDisplay.java | 28 +++- .../opengl/MacOSXAWTGLCanvasPeerInfo.java | 6 +- .../opengl/MacOSXCanvasImplementation.java | 4 +- .../lwjgl/opengl/MacOSXCanvasPeerInfo.java | 4 +- src/java/org/lwjgl/opengl/MacOSXDisplay.java | 3 +- .../opengl/WindowsAWTGLCanvasPeerInfo.java | 6 +- .../opengl/WindowsCanvasImplementation.java | 4 +- src/java/org/lwjgl/opengl/WindowsDisplay.java | 3 +- .../test/opengl/awt/DisplayParentTest.java | 122 ++++++++++++++++++ src/native/linux/org_lwjgl_opengl_Display.c | 77 +++++++---- 16 files changed, 282 insertions(+), 59 deletions(-) create mode 100644 src/java/org/lwjgl/test/opengl/awt/DisplayParentTest.java diff --git a/src/java/org/lwjgl/opengl/AWTCanvasImplementation.java b/src/java/org/lwjgl/opengl/AWTCanvasImplementation.java index 8544fa9b..32040873 100644 --- a/src/java/org/lwjgl/opengl/AWTCanvasImplementation.java +++ b/src/java/org/lwjgl/opengl/AWTCanvasImplementation.java @@ -33,7 +33,7 @@ package org.lwjgl.opengl; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; -import java.awt.Component; +import java.awt.Canvas; import org.lwjgl.LWJGLException; @@ -47,7 +47,7 @@ interface AWTCanvasImplementation { /** * Return an opaque handle to the canvas peer information required to create a context from it. */ - PeerInfo createPeerInfo(Component component, PixelFormat pixel_format) throws LWJGLException; + PeerInfo createPeerInfo(Canvas component, PixelFormat pixel_format) throws LWJGLException; /** * Find a proper GraphicsConfiguration from the given GraphicsDevice and PixelFormat. diff --git a/src/java/org/lwjgl/opengl/AWTSurfaceLock.java b/src/java/org/lwjgl/opengl/AWTSurfaceLock.java index a28fdf74..aa13305a 100644 --- a/src/java/org/lwjgl/opengl/AWTSurfaceLock.java +++ b/src/java/org/lwjgl/opengl/AWTSurfaceLock.java @@ -31,7 +31,7 @@ */ package org.lwjgl.opengl; -import java.awt.Component; +import java.awt.Canvas; import java.nio.ByteBuffer; import java.security.AccessController; import java.security.PrivilegedActionException; @@ -60,7 +60,7 @@ final class AWTSurfaceLock { private static native ByteBuffer createHandle(); - public ByteBuffer lockAndGetHandle(Component component) throws LWJGLException { + public ByteBuffer lockAndGetHandle(Canvas component) throws LWJGLException { while (!privilegedLockAndInitHandle(component)) { LWJGLUtil.log("Could not get drawing surface info, retrying..."); try { @@ -73,12 +73,12 @@ final class AWTSurfaceLock { return lock_buffer; } - private boolean privilegedLockAndInitHandle(final Component component) throws LWJGLException { + private boolean privilegedLockAndInitHandle(final Canvas component) throws LWJGLException { // Workaround for Sun JDK bug 4796548 which still exists in java for OS X // We need to elevate privileges because of an AWT bug. Please see // http://192.18.37.44/forums/index.php?topic=10572 for a discussion. // It is only needed on first call, so we avoid it on all subsequent calls - // due to performance. + // due to performance. if (firstLockSucceeded) return lockAndInitHandle(lock_buffer, component); else @@ -96,7 +96,7 @@ final class AWTSurfaceLock { } } - private static native boolean lockAndInitHandle(ByteBuffer lock_buffer, Component component) throws LWJGLException; + private static native boolean lockAndInitHandle(ByteBuffer lock_buffer, Canvas component) throws LWJGLException; protected void unlock() throws LWJGLException { nUnlock(lock_buffer); diff --git a/src/java/org/lwjgl/opengl/Display.java b/src/java/org/lwjgl/opengl/Display.java index 2d348260..843c287a 100644 --- a/src/java/org/lwjgl/opengl/Display.java +++ b/src/java/org/lwjgl/opengl/Display.java @@ -49,6 +49,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; import java.util.HashSet; +import java.awt.Canvas; import org.lwjgl.BufferUtils; import org.lwjgl.LWJGLException; @@ -71,6 +72,9 @@ public final class Display { /** The initial display mode */ private static final DisplayMode initial_mode; + /** The parent, if any */ + private static Canvas parent; + /** The current display mode, if created */ private static DisplayMode current_mode; @@ -244,7 +248,7 @@ public final class Display { } int window_x; int window_y; - if (!fullscreen) { + if (!fullscreen && parent == null) { // if no display location set, center window if (x == -1 && y == -1) { window_x = Math.max(0, (initial_mode.getWidth() - current_mode.getWidth()) / 2); @@ -257,7 +261,10 @@ public final class Display { window_x = 0; window_y = 0; } - display_impl.createWindow(current_mode, fullscreen, window_x, window_y); + Canvas tmp_parent = fullscreen ? null : parent; + if (tmp_parent != null && !tmp_parent.isDisplayable()) // Only a best effort check, since the parent can turn undisplayable hereafter + throw new LWJGLException("Parent.isDisplayable() must be true"); + display_impl.createWindow(current_mode, fullscreen, tmp_parent, window_x, window_y); window_created = true; setTitle(title); @@ -464,6 +471,50 @@ public final class Display { } } + /** + * Return the last parent set with setParent(). + */ + public static Canvas getParent() { + synchronized (GlobalLock.lock) { + return parent; + } + } + + /** + * Set the parent of the Display. If parent is null, the Display will appear as a top level window. + * If parent is not null, the Display is made a child of the parent. A parent's isDisplayable() must be true when + * setParent() is called and remain true until setParent() is called again with + * null or a different parent. This generally means that the parent component must remain added to it's parent container.

+ * It is not advisable to call this method from an AWT thread, since the context will be made current on the thread + * and it is difficult to predict which AWT thread will process any given AWT event.

+ * If the Display is in fullscreen mode, the current parent will be ignored. + * + */ + public static void setParent(Canvas parent) throws LWJGLException { + synchronized (GlobalLock.lock) { + if (Display.parent != parent) { + Display.parent = parent; + if (!isCreated()) + return; + destroyWindow(); + try { + if (fullscreen) { + switchDisplayMode(); + } else { + display_impl.resetDisplayMode(); + } + createWindow(); + makeCurrentAndSetSwapInterval(); + } catch (LWJGLException e) { + destroyContext(); + destroyPeerInfo(); + display_impl.resetDisplayMode(); + throw e; + } + } + } + } + /** * Set the fullscreen mode of the context. If no context has been created through create(), * the mode will apply when create() is called. If fullscreen is true, the context will become @@ -914,7 +965,7 @@ public final class Display { } /** - * Set the window's location. This is a no-op on fullscreen windows. + * Set the window's location. This is a no-op on fullscreen windows or when getParent() != null. * The window is clamped to remain entirely on the screen. If you attempt * to position the window such that it would extend off the screen, the window * is simply placed as close to the edge as possible. diff --git a/src/java/org/lwjgl/opengl/DisplayImplementation.java b/src/java/org/lwjgl/opengl/DisplayImplementation.java index 1d1b2bae..02f2f7e4 100644 --- a/src/java/org/lwjgl/opengl/DisplayImplementation.java +++ b/src/java/org/lwjgl/opengl/DisplayImplementation.java @@ -41,12 +41,13 @@ package org.lwjgl.opengl; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; +import java.awt.Canvas; import org.lwjgl.LWJGLException; interface DisplayImplementation extends InputImplementation { - void createWindow(DisplayMode mode, boolean fullscreen, int x, int y) throws LWJGLException; + void createWindow(DisplayMode mode, boolean fullscreen, Canvas parent, int x, int y) throws LWJGLException; void destroyWindow(); diff --git a/src/java/org/lwjgl/opengl/LinuxAWTGLCanvasPeerInfo.java b/src/java/org/lwjgl/opengl/LinuxAWTGLCanvasPeerInfo.java index d95cc612..289aa14b 100644 --- a/src/java/org/lwjgl/opengl/LinuxAWTGLCanvasPeerInfo.java +++ b/src/java/org/lwjgl/opengl/LinuxAWTGLCanvasPeerInfo.java @@ -35,7 +35,7 @@ import java.nio.ByteBuffer; import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLUtil; -import java.awt.Component; +import java.awt.Canvas; /** * @@ -44,11 +44,11 @@ import java.awt.Component; * $Id$ */ final class LinuxAWTGLCanvasPeerInfo extends LinuxPeerInfo { - private final Component component; + private final Canvas component; private final AWTSurfaceLock awt_surface = new AWTSurfaceLock(); private int screen = -1; - public LinuxAWTGLCanvasPeerInfo(Component component) { + public LinuxAWTGLCanvasPeerInfo(Canvas component) { this.component = component; } diff --git a/src/java/org/lwjgl/opengl/LinuxCanvasImplementation.java b/src/java/org/lwjgl/opengl/LinuxCanvasImplementation.java index 2fbcdbc4..037c481b 100644 --- a/src/java/org/lwjgl/opengl/LinuxCanvasImplementation.java +++ b/src/java/org/lwjgl/opengl/LinuxCanvasImplementation.java @@ -33,7 +33,7 @@ package org.lwjgl.opengl; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; -import java.awt.Component; +import java.awt.Canvas; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedExceptionAction; @@ -76,7 +76,7 @@ final class LinuxCanvasImplementation implements AWTCanvasImplementation { } } - public PeerInfo createPeerInfo(Component component, PixelFormat pixel_format) throws LWJGLException { + public PeerInfo createPeerInfo(Canvas component, PixelFormat pixel_format) throws LWJGLException { return new LinuxAWTGLCanvasPeerInfo(component); } diff --git a/src/java/org/lwjgl/opengl/LinuxDisplay.java b/src/java/org/lwjgl/opengl/LinuxDisplay.java index 3b9e3e30..6ca1ba80 100644 --- a/src/java/org/lwjgl/opengl/LinuxDisplay.java +++ b/src/java/org/lwjgl/opengl/LinuxDisplay.java @@ -42,6 +42,8 @@ import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; +import java.awt.Canvas; + import org.lwjgl.BufferUtils; import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLUtil; @@ -103,6 +105,7 @@ final class LinuxDisplay implements DisplayImplementation { private boolean focused_at_least_once; private long current_cursor; private long blank_cursor; + private Canvas parent; private LinuxKeyboard keyboard; private LinuxMouse mouse; @@ -357,7 +360,7 @@ final class LinuxDisplay implements DisplayImplementation { ungrabKeyboard(); } - public void createWindow(DisplayMode mode, boolean fullscreen, int x, int y) throws LWJGLException { + public void createWindow(DisplayMode mode, boolean fullscreen, Canvas parent, int x, int y) throws LWJGLException { lockAWT(); try { incDisplay(); @@ -365,7 +368,10 @@ final class LinuxDisplay implements DisplayImplementation { ByteBuffer handle = peer_info.lockAndGetHandle(); try { current_window_mode = getWindowMode(fullscreen); - current_window = nCreateWindow(getDisplay(), getDefaultScreen(), handle, mode, current_window_mode, x, y); + boolean undecorated = Display.getPrivilegedBoolean("org.lwjgl.opengl.Window.undecorated") || current_window_mode != WINDOWED; + this.parent = parent; + long parent_window = parent != null ? getHandle(parent) : getRootWindow(getDisplay(), getDefaultScreen()); + current_window = nCreateWindow(getDisplay(), getDefaultScreen(), handle, mode, current_window_mode, x, y, undecorated, parent_window); blank_cursor = createBlankCursor(); current_cursor = None; focused = true; @@ -388,7 +394,19 @@ final class LinuxDisplay implements DisplayImplementation { unlockAWT(); } } - private static native long nCreateWindow(long display, int screen, ByteBuffer peer_info_handle, DisplayMode mode, int window_mode, int x, int y) throws LWJGLException; + private static native long nCreateWindow(long display, int screen, ByteBuffer peer_info_handle, DisplayMode mode, int window_mode, int x, int y, boolean undecorated, long parent_handle) throws LWJGLException; + private static native long getRootWindow(long display, int screen); + + private static long getHandle(Canvas parent) throws LWJGLException { + AWTCanvasImplementation awt_impl = AWTGLCanvas.createImplementation(); + LinuxPeerInfo parent_peer_info = (LinuxPeerInfo)awt_impl.createPeerInfo(parent, null); + ByteBuffer parent_peer_info_handle = parent_peer_info.lockAndGetHandle(); + try { + return parent_peer_info.getDrawable(); + } finally { + parent_peer_info.unlock(); + } + } private void updateInputGrab() { updatePointerGrab(); @@ -602,7 +620,11 @@ final class LinuxDisplay implements DisplayImplementation { return peer_info; } + private native static void setInputFocus(long display, long window); + private void processEvents() { + if (!focused && parent != null && parent.isFocusOwner()) + setInputFocus(getDisplay(), getWindow()); while (LinuxEvent.getPending(getDisplay()) > 0) { event_buffer.nextEvent(getDisplay()); long event_window = event_buffer.getWindow(); diff --git a/src/java/org/lwjgl/opengl/MacOSXAWTGLCanvasPeerInfo.java b/src/java/org/lwjgl/opengl/MacOSXAWTGLCanvasPeerInfo.java index 71d12caf..49159a41 100644 --- a/src/java/org/lwjgl/opengl/MacOSXAWTGLCanvasPeerInfo.java +++ b/src/java/org/lwjgl/opengl/MacOSXAWTGLCanvasPeerInfo.java @@ -33,7 +33,7 @@ package org.lwjgl.opengl; import org.lwjgl.LWJGLException; -import java.awt.Component; +import java.awt.Canvas; /** * @@ -42,9 +42,9 @@ import java.awt.Component; * $Id$ */ final class MacOSXAWTGLCanvasPeerInfo extends MacOSXCanvasPeerInfo { - private final Component component; + private final Canvas component; - public MacOSXAWTGLCanvasPeerInfo(Component component, PixelFormat pixel_format, boolean support_pbuffer) throws LWJGLException { + public MacOSXAWTGLCanvasPeerInfo(Canvas component, PixelFormat pixel_format, boolean support_pbuffer) throws LWJGLException { super(pixel_format, support_pbuffer); this.component = component; } diff --git a/src/java/org/lwjgl/opengl/MacOSXCanvasImplementation.java b/src/java/org/lwjgl/opengl/MacOSXCanvasImplementation.java index 252313e9..266fd96a 100644 --- a/src/java/org/lwjgl/opengl/MacOSXCanvasImplementation.java +++ b/src/java/org/lwjgl/opengl/MacOSXCanvasImplementation.java @@ -33,7 +33,7 @@ package org.lwjgl.opengl; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; -import java.awt.Component; +import java.awt.Canvas; import org.lwjgl.LWJGLException; @@ -44,7 +44,7 @@ import org.lwjgl.LWJGLException; * $Id$ */ final class MacOSXCanvasImplementation implements AWTCanvasImplementation { - public PeerInfo createPeerInfo(Component component, PixelFormat pixel_format) throws LWJGLException { + public PeerInfo createPeerInfo(Canvas component, PixelFormat pixel_format) throws LWJGLException { try { return new MacOSXAWTGLCanvasPeerInfo(component, pixel_format, true); } catch (LWJGLException e) { diff --git a/src/java/org/lwjgl/opengl/MacOSXCanvasPeerInfo.java b/src/java/org/lwjgl/opengl/MacOSXCanvasPeerInfo.java index 34eb89cf..a138115a 100644 --- a/src/java/org/lwjgl/opengl/MacOSXCanvasPeerInfo.java +++ b/src/java/org/lwjgl/opengl/MacOSXCanvasPeerInfo.java @@ -31,7 +31,7 @@ */ package org.lwjgl.opengl; -import java.awt.Component; +import java.awt.Canvas; import java.nio.ByteBuffer; import org.lwjgl.LWJGLException; @@ -49,7 +49,7 @@ abstract class MacOSXCanvasPeerInfo extends MacOSXPeerInfo { super(pixel_format, true, true, support_pbuffer, true); } - protected void initHandle(Component component) throws LWJGLException { + protected void initHandle(Canvas component) throws LWJGLException { nInitHandle(awt_surface.lockAndGetHandle(component), getHandle()); } private static native void nInitHandle(ByteBuffer surface_buffer, ByteBuffer peer_info_handle) throws LWJGLException; diff --git a/src/java/org/lwjgl/opengl/MacOSXDisplay.java b/src/java/org/lwjgl/opengl/MacOSXDisplay.java index 9f71b205..9bac3f6c 100644 --- a/src/java/org/lwjgl/opengl/MacOSXDisplay.java +++ b/src/java/org/lwjgl/opengl/MacOSXDisplay.java @@ -39,6 +39,7 @@ package org.lwjgl.opengl; */ import java.awt.Cursor; +import java.awt.Canvas; import java.awt.Robot; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -73,7 +74,7 @@ final class MacOSXDisplay implements DisplayImplementation { new MacOSXApplicationListener(); } - public void createWindow(DisplayMode mode, boolean fullscreen, int x, int y) throws LWJGLException { + public void createWindow(DisplayMode mode, boolean fullscreen, Canvas parent, int x, int y) throws LWJGLException { hideUI(fullscreen); close_requested = false; try { diff --git a/src/java/org/lwjgl/opengl/WindowsAWTGLCanvasPeerInfo.java b/src/java/org/lwjgl/opengl/WindowsAWTGLCanvasPeerInfo.java index d2d774b2..992b3731 100644 --- a/src/java/org/lwjgl/opengl/WindowsAWTGLCanvasPeerInfo.java +++ b/src/java/org/lwjgl/opengl/WindowsAWTGLCanvasPeerInfo.java @@ -35,7 +35,7 @@ import java.nio.ByteBuffer; import org.lwjgl.LWJGLException; -import java.awt.Component; +import java.awt.Canvas; /** * @@ -44,12 +44,12 @@ import java.awt.Component; * $Id$ */ final class WindowsAWTGLCanvasPeerInfo extends WindowsPeerInfo { - private final Component component; + private final Canvas component; private final AWTSurfaceLock awt_surface = new AWTSurfaceLock(); private final PixelFormat pixel_format; private boolean has_pixel_format= false; - public WindowsAWTGLCanvasPeerInfo(Component component, PixelFormat pixel_format) { + public WindowsAWTGLCanvasPeerInfo(Canvas component, PixelFormat pixel_format) { this.component = component; this.pixel_format = pixel_format; } diff --git a/src/java/org/lwjgl/opengl/WindowsCanvasImplementation.java b/src/java/org/lwjgl/opengl/WindowsCanvasImplementation.java index b997fdfa..235a4d30 100644 --- a/src/java/org/lwjgl/opengl/WindowsCanvasImplementation.java +++ b/src/java/org/lwjgl/opengl/WindowsCanvasImplementation.java @@ -34,7 +34,7 @@ package org.lwjgl.opengl; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.Toolkit; -import java.awt.Component; +import java.awt.Canvas; import java.security.PrivilegedAction; import java.security.AccessController; @@ -70,7 +70,7 @@ final class WindowsCanvasImplementation implements AWTCanvasImplementation { return new WindowsAWTInput(canvas); } - public PeerInfo createPeerInfo(Component component, PixelFormat pixel_format) throws LWJGLException { + public PeerInfo createPeerInfo(Canvas component, PixelFormat pixel_format) throws LWJGLException { return new WindowsAWTGLCanvasPeerInfo(component, pixel_format); } diff --git a/src/java/org/lwjgl/opengl/WindowsDisplay.java b/src/java/org/lwjgl/opengl/WindowsDisplay.java index 964c1f56..cd541b91 100644 --- a/src/java/org/lwjgl/opengl/WindowsDisplay.java +++ b/src/java/org/lwjgl/opengl/WindowsDisplay.java @@ -41,6 +41,7 @@ package org.lwjgl.opengl; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; +import java.awt.Canvas; import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLUtil; @@ -139,7 +140,7 @@ final class WindowsDisplay implements DisplayImplementation { current_display = this; } - public void createWindow(DisplayMode mode, boolean fullscreen, int x, int y) throws LWJGLException { + public void createWindow(DisplayMode mode, boolean fullscreen, Canvas container, int x, int y) throws LWJGLException { close_requested = false; is_dirty = false; isFullscreen = fullscreen; diff --git a/src/java/org/lwjgl/test/opengl/awt/DisplayParentTest.java b/src/java/org/lwjgl/test/opengl/awt/DisplayParentTest.java new file mode 100644 index 00000000..f7909463 --- /dev/null +++ b/src/java/org/lwjgl/test/opengl/awt/DisplayParentTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2002-2005 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions 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 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.lwjgl.test.opengl.awt; + +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Container; +import java.awt.Component; +import java.awt.Canvas; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import org.lwjgl.LWJGLException; +import org.lwjgl.opengl.AWTGLCanvas; +import org.lwjgl.opengl.GL11; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.util.glu.GLU; +import org.lwjgl.opengl.Display; +import org.lwjgl.opengl.DisplayMode; + +/** + *

+ * Tests Display.setParent() + *

+ * @version $Revision$ + * @author $Author$ + * $Id$ + */ +public class DisplayParentTest extends Frame { + public DisplayParentTest() throws LWJGLException { + setTitle("LWJGL Display Parent Test"); + setSize(640, 320); + setLayout(new GridLayout(1, 2)); + final Canvas display_parent = new Canvas(); + display_parent.setFocusable(true); + add(display_parent); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + dispose(); + } + }); + setResizable(true); + setVisible(true); + Display.setParent(display_parent); + Display.create(); + float angle = 0f; + + int current_height = 0; + int current_width = 0; + while (isVisible()) { + angle += 1.0f; + if (getWidth() != current_width || getHeight() != current_height) { + current_width = getWidth(); + current_height = getHeight(); + Display.setDisplayMode(new DisplayMode(getWidth(), getHeight())); + GL11.glViewport(0, 0, current_width, current_height); + } + GL11.glViewport(0, 0, getWidth(), getHeight()); + GL11.glClearColor(0.0f, 1.0f, 0.0f, 1.0f); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glLoadIdentity(); + GLU.gluOrtho2D(0.0f, (float) getWidth(), 0.0f, (float) getHeight()); + GL11.glMatrixMode(GL11.GL_MODELVIEW); + GL11.glPushMatrix(); + GL11.glTranslatef(getWidth() / 2.0f, getHeight() / 2.0f, 0.0f); + GL11.glRotatef(2*angle, 0f, 0f, -1.0f); + GL11.glRectf(-50.0f, -50.0f, 50.0f, 50.0f); + GL11.glPopMatrix(); + Display.update(); + while(Keyboard.next()) { + // closing on ESCAPE + if(Keyboard.getEventKey() == Keyboard.KEY_ESCAPE && Keyboard.getEventKeyState()) { + dispose(); + } + + if(Keyboard.getEventKey() == Keyboard.KEY_SPACE && Keyboard.getEventKeyState()) { + Mouse.setGrabbed(!Mouse.isGrabbed()); + } + } +/* while (Mouse.next()) { +System.out.println(" Mouse.getEventX() = " + Mouse.getEventX() + " | Mouse.getEventY() = " + Mouse.getEventY()); + }*/ + } + System.exit(0); + } + + public static void main(String[] args) throws LWJGLException { + new DisplayParentTest(); + } +} diff --git a/src/native/linux/org_lwjgl_opengl_Display.c b/src/native/linux/org_lwjgl_opengl_Display.c index 9ad0a2b9..0cedfc0d 100644 --- a/src/native/linux/org_lwjgl_opengl_Display.c +++ b/src/native/linux/org_lwjgl_opengl_Display.c @@ -242,18 +242,44 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nReshape(JNIEnv *env, XMoveWindow(disp, window, x, y); } -static Window createWindow(JNIEnv* env, Display *disp, int screen, jint window_mode, X11PeerInfo *peer_info, int x, int y, int width, int height) { - bool undecorated = getBooleanProperty(env, "org.lwjgl.opengl.Window.undecorated"); - Window root_win; +JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_getRootWindow(JNIEnv *env, jclass clazz, jlong display, jint screen) { + Display *disp = (Display *)(intptr_t)display; + return RootWindow(disp, screen); +} + +static void updateWindowHints(JNIEnv *env, Display *disp, Window window) { + XWMHints* win_hints = XAllocWMHints(); + if (win_hints == NULL) { + throwException(env, "XAllocWMHints failed"); + return; + } + + win_hints->flags = InputHint; + win_hints->input = True; + if (current_icon_pixmap != 0) { + win_hints->flags |= IconPixmapHint; + win_hints->icon_pixmap = current_icon_pixmap; + } + if (current_icon_mask_pixmap != 0) { + win_hints->flags |= IconMaskHint; + win_hints->icon_mask = current_icon_mask_pixmap; + } + + XSetWMHints(disp, window, win_hints); + XFree(win_hints); + XFlush(disp); +} + +static Window createWindow(JNIEnv* env, Display *disp, int screen, jint window_mode, X11PeerInfo *peer_info, int x, int y, int width, int height, jboolean undecorated, long parent_handle) { + Window parent = (Window)parent_handle; Window win; XSetWindowAttributes attribs; int attribmask; - root_win = RootWindow(disp, screen); XVisualInfo *vis_info = getVisualInfoFromPeerInfo(env, peer_info); if (vis_info == NULL) return false; - cmap = XCreateColormap(disp, root_win, vis_info->visual, AllocNone); + cmap = XCreateColormap(disp, parent, vis_info->visual, AllocNone); attribs.colormap = cmap; attribs.event_mask = ExposureMask | /*FocusChangeMask | */VisibilityChangeMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask; attribmask = CWColormap | CWEventMask; @@ -261,7 +287,7 @@ static Window createWindow(JNIEnv* env, Display *disp, int screen, jint window_m attribmask |= CWOverrideRedirect; attribs.override_redirect = True; } - win = XCreateWindow(disp, root_win, x, y, width, height, 0, vis_info->depth, InputOutput, vis_info->visual, attribmask, &attribs); + win = XCreateWindow(disp, parent, x, y, width, height, 0, vis_info->depth, InputOutput, vis_info->visual, attribmask, &attribs); current_depth = vis_info->depth; current_visual = vis_info->visual; @@ -271,8 +297,8 @@ static Window createWindow(JNIEnv* env, Display *disp, int screen, jint window_m XFreeColormap(disp, cmap); return false; } - printfDebugJava(env, "Created window"); - if (window_mode != org_lwjgl_opengl_LinuxDisplay_WINDOWED || undecorated) { +// printfDebugJava(env, "Created window"); + if (undecorated) { // Use Motif decoration hint property and hope the window manager respects them setDecorations(disp, win, 0); } @@ -283,9 +309,11 @@ static Window createWindow(JNIEnv* env, Display *disp, int screen, jint window_m size_hints->min_height = height; size_hints->max_height = height; XSetWMNormalHints(disp, win, size_hints); + updateWindowHints(env, disp, win); XFree(size_hints); - Atom delete_atom = XInternAtom(disp, "WM_DELETE_WINDOW", False); - XSetWMProtocols(disp, win, &delete_atom, 1); +#define NUM_ATOMS 1 + Atom protocol_atoms[NUM_ATOMS] = {XInternAtom(disp, "WM_DELETE_WINDOW", False)/*, XInternAtom(disp, "WM_TAKE_FOCUS", False)*/}; + XSetWMProtocols(disp, win, protocol_atoms, NUM_ATOMS); if (window_mode == org_lwjgl_opengl_LinuxDisplay_FULLSCREEN_NETWM) { Atom fullscreen_atom = XInternAtom(disp, "_NET_WM_STATE_FULLSCREEN", False); XChangeProperty(disp, win, XInternAtom(disp, "_NET_WM_STATE", False), @@ -299,7 +327,17 @@ static Window createWindow(JNIEnv* env, Display *disp, int screen, jint window_m return win; } -JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nCreateWindow(JNIEnv *env, jclass clazz, jlong display, jint screen, jobject peer_info_handle, jobject mode, jint window_mode, jint x, jint y) { +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_setInputFocus(JNIEnv *env, jclass clazz, jlong display, jlong window_ptr) { + Display *disp = (Display *)(intptr_t)display; + Window window = (Window)window_ptr; + // Normally, a real time stamp from an event should be passed instead of CurrentTime, but we don't get timestamps + // from awt. Instead we grab the server before and ungrab it after the request + XGrabServer(disp); + XSetInputFocus(disp, window, RevertToParent, CurrentTime); + XUngrabServer(disp); +} + +JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nCreateWindow(JNIEnv *env, jclass clazz, jlong display, jint screen, jobject peer_info_handle, jobject mode, jint window_mode, jint x, jint y, jboolean undecorated, jlong parent_handle) { Display *disp = (Display *)(intptr_t)display; X11PeerInfo *peer_info = (*env)->GetDirectBufferAddress(env, peer_info_handle); GLXFBConfig *fb_config = NULL; @@ -313,7 +351,7 @@ JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nCreateWindow(JNIEnv jfieldID fid_height = (*env)->GetFieldID(env, cls_displayMode, "height", "I"); int width = (*env)->GetIntField(env, mode, fid_width); int height = (*env)->GetIntField(env, mode, fid_height); - Window win = createWindow(env, disp, screen, window_mode, peer_info, x, y, width, height); + Window win = createWindow(env, disp, screen, window_mode, peer_info, x, y, width, height, undecorated, parent_handle); if ((*env)->ExceptionOccurred(env)) { return 0; } @@ -384,7 +422,6 @@ static Pixmap createPixmapFromBuffer(JNIEnv *env, Display *disp, Window window, } static void setIcon(JNIEnv *env, Display *disp, Window window, char *rgb_data, char *mask_data, int icon_size, int width, int height) { - XWMHints* win_hints; freeIconPixmap(disp); current_icon_pixmap = createPixmapFromBuffer(env, disp, window, rgb_data, icon_size, width, height); if ((*env)->ExceptionCheck(env)) @@ -395,19 +432,7 @@ static void setIcon(JNIEnv *env, Display *disp, Window window, char *rgb_data, c return; } - win_hints = XAllocWMHints(); - if (win_hints == NULL) { - throwException(env, "XAllocWMHints failed"); - return; - } - - win_hints->flags = IconPixmapHint | IconMaskHint; - win_hints->icon_pixmap = current_icon_pixmap; - win_hints->icon_mask = current_icon_mask_pixmap; - - XSetWMHints(disp, window, win_hints); - XFree(win_hints); - XFlush(disp); + updateWindowHints(env, disp, window); } JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetWindowIcon