/* -*- mode:ObjC -*- XGGLContext - backend implementation of NSOpenGLContext Copyright (C) 1998,2002 Free Software Foundation, Inc. Written by: Frederic De Jaeger Date: Nov 2002 This file is part of the GNU Objective C User Interface Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. If not, see or write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #ifdef HAVE_GLX #include #include #include #include #include #include "x11/XGServerWindow.h" #include "x11/XGOpenGL.h" #include //FIXME //should I store the display ? #define MAKE_DISPLAY(dpy) Display *dpy;\ dpy = [(XGServer *)GSCurrentServer() xDisplay];\ NSAssert(dpy != NULL, NSInternalInconsistencyException) @interface XGXSubWindow : NSObject { @public Window xwindowid; NSView *attached; } + subwindowOnView:(NSView *)view visualinfo:(XVisualInfo *)xVisualInfo; - (void) update; @end @implementation XGXSubWindow //We assume that the current context is the same and is an XGServer - initWithView: (NSView *)view visualinfo: (XVisualInfo *)xVisualInfo { NSRect rect; gswindow_device_t *win_info; XGServer *server; NSWindow *window; int x, y, width, height; int mask; XSetWindowAttributes window_attributes; self = [super init]; if (!self) return nil; window = [view window]; NSAssert(window, @"request of an X window attachment on a view that is not on a NSWindow"); if ([view isRotatedOrScaledFromBase]) { [NSException raise: NSInvalidArgumentException format: @"Cannot attach an Xwindow to a view that is rotated or scaled"]; } server = (XGServer *)GSServerForWindow(window); NSAssert(server != nil, NSInternalInconsistencyException); NSAssert([server isKindOfClass: [XGServer class]], NSInternalInconsistencyException); win_info = [XGServer _windowWithTag: [window windowNumber]]; NSAssert(win_info, NSInternalInconsistencyException); if ([server handlesWindowDecorations] == YES) { /* The window manager handles window decorations, so the * the parent X window is equal to the content view and * we must therefore use content view coordinates. */ rect = [view convertRect: [view bounds] toView: [window contentView]]; } else { /* The GUI library handles window decorations, so the * the parent X window is equal to the NSWindow frame * and we can use window base coordinates. */ rect = [view convertRect: [view bounds] toView: nil]; } x = NSMinX(rect); y = NSHeight(win_info->xframe) - NSMaxY(rect); width = NSWidth(rect); height = NSHeight(rect); window_attributes.border_pixel = 255; window_attributes.background_pixel = 0; window_attributes.colormap = XCreateColormap(win_info->display, win_info->ident, xVisualInfo->visual, AllocNone); window_attributes.event_mask = StructureNotifyMask | VisibilityChangeMask | ExposureMask; mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; xwindowid = XCreateWindow(win_info->display, win_info->ident, x, y, width, height, 0, xVisualInfo->depth, InputOutput, xVisualInfo->visual, mask, &window_attributes); XMapWindow(win_info->display, xwindowid); attached = view; return self; } - (void) map { MAKE_DISPLAY(dpy); XMapWindow(dpy, xwindowid); } - (void) detach { //FIXME //I assume that the current server is correct. MAKE_DISPLAY(dpy); attached = nil; XDestroyWindow(dpy, xwindowid); } - (void) update { NSRect rect; gswindow_device_t *win_info; GSDisplayServer *server; NSWindow *win; int x, y, width, height; NSAssert(attached, NSInternalInconsistencyException); win = [attached window]; NSAssert1(win, @"%@'s window is nil now!", attached); NSAssert1(![attached isRotatedOrScaledFromBase], @"%@ is rotated or scaled, now!", attached); server = GSServerForWindow(win); NSAssert(server != nil, NSInternalInconsistencyException); NSAssert([server isKindOfClass: [XGServer class]], NSInternalInconsistencyException); //FIXME //we should check that the window hasn't changed, maybe. win_info = [XGServer _windowWithTag: [win windowNumber]]; NSAssert(win_info, NSInternalInconsistencyException); if ([server handlesWindowDecorations] == YES) { /* The window manager handles window decorations, so the * the parent X window is equal to the content view and * we must therefore use content view coordinates. */ rect = [attached convertRect: [attached bounds] toView: [[attached window] contentView]]; } else { /* The GUI library handles window decorations, so the * the parent X window is equal to the NSWindow frame * and we can use window base coordinates. */ rect = [attached convertRect: [attached bounds] toView: nil]; } x = NSMinX(rect); y = NSHeight(win_info->xframe) - NSMaxY(rect); width = NSWidth(rect); height = NSHeight(rect); XMoveResizeWindow(win_info->display, xwindowid,x, y, width, height); } - (void) dealloc { NSDebugMLLog(@"GLX", @"deallocating"); [self detach]; [super dealloc]; } + subwindowOnView:(NSView *)view visualinfo:(XVisualInfo *)xVisualInfo { XGXSubWindow *win = [[self alloc] initWithView: view visualinfo: xVisualInfo]; return AUTORELEASE(win); } @end //FIXME: //should be on per thread basis. static XGGLContext *currentGLContext; @implementation XGGLContext + (void)clearCurrentContext { MAKE_DISPLAY(dpy); if (GSglxMinorVersion(dpy) >= 3) { if ( !glXMakeContextCurrent(dpy, None, None, NULL) ) NSDebugMLLog( @"GLX", @"Can not clear current GL context - Errror %u", glGetError() ); } else { if ( !glXMakeCurrent(dpy, None, NULL) ) NSDebugMLLog( @"GLX", @"Can not clear current GL context - Errror %u", glGetError() ); } currentGLContext = nil; } + (NSOpenGLContext *)currentContext { return currentGLContext; } - (void) _detach { if (xSubWindow) { MAKE_DISPLAY(dpy); if (currentGLContext == self) { [XGGLContext clearCurrentContext]; } // FIXME: // glXDestroyWindow(dpy, glx_drawable); glx_drawable = None; DESTROY(xSubWindow); } } - (GLXContext)glxcontext { return glx_context; } - (void)clearDrawable { [self _detach]; } - (void)copyAttributesFromContext:(NSOpenGLContext *)context withMask:(unsigned long)mask { GLint error; MAKE_DISPLAY(dpy); if (context == nil || ![context isKindOfClass: [XGGLContext class]]) [NSException raise: NSInvalidArgumentException format: @"%@ is an invalid context", context]; glXCopyContext(dpy, ((XGGLContext *)context)->glx_context, glx_context, mask); error = glGetError(); if ( error != GL_NO_ERROR ) NSDebugMLLog( @"GLX", @"Can not copy GL context %@ from context %@ - Errror %u", self, context, error ); } - (void)createTexture:(unsigned long)target fromView:(NSView*)view internalFormat:(unsigned long)format { [self notImplemented: _cmd]; } - (int)currentVirtualScreen { [self notImplemented: _cmd]; return 0; } - (void)flushBuffer { MAKE_DISPLAY(dpy); glXSwapBuffers(dpy, glx_drawable); #if 0 // FIXME Not with Mesa Xlib sofware driver ! // TODO Use EXT_framebuffer_blit if available if ( _doubleBuffer ) { if ( _backingStore ) { GLint rBuf,dBuf; GLint viewport[4]; GLfloat raster_pos[4]; /* save viewport */ glGetIntegerv(GL_VIEWPORT, viewport); /* save old raster position */ glGetFloatv(GL_CURRENT_RASTER_POSITION, raster_pos); /* set raster position */ glRasterPos4f(0.0, 0.0, 0.0, 1.0); /* save target/source buffers */ glGetIntegerv( GL_READ_BUFFER, &rBuf ); glGetIntegerv( GL_DRAW_BUFFER, &wBuf ); /* set projection matrix */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity() ; gluOrtho2D(0, viewport[2], 0, viewport[3]); /* set modelview matrix */ glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); //FIXME copy depth, stencil? glReadBuffer (GL_FRONT_LEFT); glDrawBuffer (GL_BACK_LEFT); glCopyPixels(0, 0, viewport[2], viewport[3], GL_COLOR); if ( _stereo ) { glReadBuffer (GL_FRONT_RIGHT); glDrawBuffer (GL_BACK_RIGHT); glCopyPixels(0, 0, viewport[2], viewport[3], GL_COLOR); } /* restore target/source buffers */ glReadBuffer (rBuf); glDrawBuffer (dBuf); /* restore old raster position */ glRasterPos4fv(raster_pos); /* restore old matrices */ glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); /* restore viewport */ glViewport(viewport[0],viewport[1],viewport[2],viewport[3]); } } #endif } - (void)getValues:(long *)vals forParameter:(NSOpenGLContextParameter)param { // TODO [self notImplemented: _cmd]; } - (id)initWithFormat: (NSOpenGLPixelFormat *)_format shareContext: (NSOpenGLContext *)share { self = [super init]; if (!self) return nil; glx_context = None; if (!_format || ![_format isKindOfClass: [XGGLPixelFormat class]]) { NSDebugMLLog(@"GLX", @"invalid format %@", _format); RELEASE(self); return nil; } ASSIGN(pixelFormat, (XGGLPixelFormat *)_format); //FIXME: allow index mode and sharing glx_context = [pixelFormat createGLXContext: (XGGLContext *)share]; return self; } - (void) dealloc { NSDebugMLLog(@"GLX", @"deallocating"); [self _detach]; RELEASE(pixelFormat); if (glx_context != None) { MAKE_DISPLAY(dpy); glXDestroyContext(dpy, glx_context); } [super dealloc]; } - (void) makeCurrentContext { MAKE_DISPLAY(dpy); if (xSubWindow == nil) [NSException raise: NSGenericException format: @"GL Context is not bind, cannot be made current"]; NSAssert(glx_context != None && glx_drawable != None, NSInternalInconsistencyException); if (GSglxMinorVersion(dpy) >= 3) { //NSDebugMLLog(@"GLX", @"before glXMakeContextCurrent"); if ( !glXMakeContextCurrent(dpy, glx_drawable, glx_drawable, glx_context) ) NSDebugMLLog( @"GLX", @"Can not make GL context %@ current - Errror %u", self, glGetError() ); //NSDebugMLLog(@"GLX", @"after glXMakeContextCurrent"); } else { //NSDebugMLLog(@"GLX", @"before glXMakeCurrent"); if ( !glXMakeCurrent(dpy, glx_drawable, glx_context) ) NSDebugMLLog( @"GLX", @"Can not make GL context %@ current - Errror %u", self, glGetError() ); //NSDebugMLLog(@"GLX", @"after glXMakeCurrent"); } currentGLContext = self; } - (void)setCurrentVirtualScreen:(int)screen { [self notImplemented: _cmd]; } - (void)setFullScreen { [self notImplemented: _cmd]; } - (void)setOffScreen:(void *)baseaddr width:(long)width height:(long)height rowbytes:(long)rowbytes { [self notImplemented: _cmd]; } - (void)setValues:(const long *)vals forParameter:(NSOpenGLContextParameter)param { [self notImplemented: _cmd]; } - (void)setView:(NSView *)view { NSView *current_view; if (!view) [NSException raise: NSInvalidArgumentException format: @"setView called with a nil value"]; NSAssert(pixelFormat, NSInternalInconsistencyException); current_view = [self view]; if ( current_view != nil ) { [current_view _setIgnoresBacking: saved_ignores_backing]; } ASSIGN(xSubWindow, [XGXSubWindow subwindowOnView: view visualinfo: [pixelFormat xvinfo]]); glx_drawable = [pixelFormat drawableForWindow: xSubWindow->xwindowid]; saved_ignores_backing = [view _ignoresBacking]; [view _setIgnoresBacking: YES]; NSDebugMLLog(@"GLX", @"glx_window : %u", glx_drawable); } - (void)update { [xSubWindow update]; } - (NSView *)view { if (xSubWindow) { return xSubWindow->attached; } else { return nil; } } @end #endif