diff --git a/src/java/org/lwjgl/opengl/MacOSXCanvasPeerInfo.java b/src/java/org/lwjgl/opengl/MacOSXCanvasPeerInfo.java index d43e1d0d..801fe97c 100644 --- a/src/java/org/lwjgl/opengl/MacOSXCanvasPeerInfo.java +++ b/src/java/org/lwjgl/opengl/MacOSXCanvasPeerInfo.java @@ -32,6 +32,11 @@ package org.lwjgl.opengl; import java.awt.Canvas; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.Insets; +import java.awt.Container; +import java.awt.Component; import java.nio.ByteBuffer; import org.lwjgl.LWJGLException; @@ -62,11 +67,85 @@ abstract class MacOSXCanvasPeerInfo extends MacOSXPeerInfo { forceCALayer = false; } - window_handle = nInitHandle(awt_surface.lockAndGetHandle(component), getHandle(), window_handle, forceCALayer); + Insets insets = getInsets(component); + + int top = insets != null ? insets.top : 0; + int left = insets != null ? insets.left : 0; + + window_handle = nInitHandle(awt_surface.lockAndGetHandle(component), getHandle(), window_handle, forceCALayer, component.getX()-left, component.getY()-top); + + if (javaVersion.startsWith("1.7")) { + // fix for CALayer position not covering Canvas due to a Java 7 bug + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7172187 + addComponentListener(component); + } } - private static native ByteBuffer nInitHandle(ByteBuffer surface_buffer, ByteBuffer peer_info_handle, ByteBuffer window_handle, boolean forceCALayer) throws LWJGLException; + + private void addComponentListener(final Canvas component) { + + ComponentListener[] components = component.getComponentListeners(); + + // avoid adding duplicate listners by checking if one has already been added + for (int i = 0; i < components.length; i++) { + ComponentListener c = components[i]; + if (c.toString() == "CanvasPeerInfoListener") { + return; // already contains the listner below return without adding + } + } + + ComponentListener comp = new ComponentListener() { + public void componentHidden(ComponentEvent e) { + + } + public void componentMoved(ComponentEvent e) { + Insets insets = getInsets(component); + + int top = insets != null ? insets.top : 0; + int left = insets != null ? insets.left : 0; + + nSetLayerPosition(getHandle(), component.getX()-left, component.getY()-top); + } + + public void componentResized(ComponentEvent e) { + Insets insets = getInsets(component); + + int top = insets != null ? insets.top : 0; + int left = insets != null ? insets.left : 0; + + nSetLayerPosition(getHandle(), component.getX()-left, component.getY()-top); + } + + public void componentShown(ComponentEvent e) { + + } + + public String toString() { + return "CanvasPeerInfoListener"; + } + }; + + component.addComponentListener(comp); + } + + private static native ByteBuffer nInitHandle(ByteBuffer surface_buffer, ByteBuffer peer_info_handle, ByteBuffer window_handle, boolean forceCALayer, int x, int y) throws LWJGLException; + + private static native void nSetLayerPosition(ByteBuffer peer_info_handle, int x, int y); + protected void doUnlock() throws LWJGLException { awt_surface.unlock(); } + + private Insets getInsets(Canvas component) { + Component parent = component.getParent(); + + while (parent != null) { + if (parent instanceof Container) { + return ((Container)parent).getInsets(); + } + parent = parent.getParent(); + } + + return null; + } } diff --git a/src/native/macosx/org_lwjgl_opengl_MacOSXCanvasPeerInfo.m b/src/native/macosx/org_lwjgl_opengl_MacOSXCanvasPeerInfo.m index 61c12cae..84a054a3 100644 --- a/src/native/macosx/org_lwjgl_opengl_MacOSXCanvasPeerInfo.m +++ b/src/native/macosx/org_lwjgl_opengl_MacOSXCanvasPeerInfo.m @@ -47,7 +47,7 @@ #include "common_tools.h" JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nInitHandle -(JNIEnv *env, jclass clazz, jobject lock_buffer_handle, jobject peer_info_handle, jobject window_handle, jboolean forceCALayer) { +(JNIEnv *env, jclass clazz, jobject lock_buffer_handle, jobject peer_info_handle, jobject window_handle, jboolean forceCALayer, jint x, jint y) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; MacOSXPeerInfo *peer_info = (MacOSXPeerInfo *)(*env)->GetDirectBufferAddress(env, peer_info_handle); @@ -78,6 +78,9 @@ JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nInitHandle peer_info->glLayer->canvasBounds = (JAWT_Rectangle)surface->dsi->bounds; peer_info->window_info = (MacOSXWindowInfo *)(*env)->GetDirectBufferAddress(env, window_handle); peer_info->glLayer->window_info = peer_info->window_info; + + // ensure the CALayer size is correct, needed for Java 7+ + peer_info->glLayer.frame = CGRectMake(x, y, peer_info->glLayer->canvasBounds.width, peer_info->glLayer->canvasBounds.height); [peer_info->glLayer performSelectorOnMainThread:@selector(createWindow:) withObject:peer_info->pixel_format waitUntilDone:YES]; @@ -99,6 +102,17 @@ JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nInitHandle return NULL; } +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nSetLayerPosition +(JNIEnv *env, jclass clazz, jobject peer_info_handle, jint x, jint y) { + MacOSXPeerInfo *peer_info = (MacOSXPeerInfo *)(*env)->GetDirectBufferAddress(env, peer_info_handle); + + if (peer_info->glLayer != nil) { + NSPoint point = NSMakePoint(x, y); + NSValue *value = [NSValue valueWithPoint:point]; + [peer_info->glLayer performSelectorOnMainThread:@selector(updatePosition:) withObject:value waitUntilDone:NO]; + } +} + @implementation GLLayer - (void) attachLayer { @@ -113,8 +127,10 @@ JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nInitHandle if (surfaceLayers.layer != self) { surfaceLayers.layer = self; - // ensure the CALayer size is correct, needed for Java 7+ - self.frame = CGRectMake(0, 0, [self getWidth], [self getHeight]); + // flip CALayer y position, needed for Java 7 workaround + self.frame = CGRectMake(self.frame.origin.x, + self.superlayer.bounds.size.height - self.frame.origin.y - self.frame.size.height, + self.frame.size.width, self.frame.size.height); } } @@ -135,9 +151,9 @@ JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nInitHandle [self removeFromSuperlayer]; } -- (void)setNeedsLayout { - // make sure the CALayer remains in bottom corner during resize - self.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height); +- (void)updatePosition:(NSValue*)value { + NSPoint point = [value pointValue]; + self.position = CGPointMake(point.x, self.superlayer.bounds.size.height - point.y - self.bounds.size.height); } - (int) getWidth {