Hi!

Recently I was using NSOpenGLView and fixed a couple of bugs in gnustep-back 0.12.0 ( I believe newer versions have the same issues):

- XGGLPixelFormat handling was confusing glx parameters, since glx 1.3 has some different parameters than earlier versions of glx - XGGLContext did not create the rendering context, the x window, and the glx window with the same Visual - XGGLContext did not create a colormap for the x window (which has to use the same Visual too)

The attached files fix this issues. I tried to follow the gnustep coding style but I am not sure if I succeeded :)

Please let me know if there are any change requests.
I am not subscribed to the list, so please CC me.

Thanks

TOM
/* 	-*-ObjC-*- */
/* XGOpenGL - openGL management using glX

   Copyright (C) 2002 Free Software Foundation, Inc.

   Author: Frederic De Jaeger
   Date: Nov 2002

   This file is part of the GNUstep GUI Library.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this library; see the file COPYING.LIB.
   If not, write to the Free Software Foundation,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ 

#ifndef _GNUstep_H_XGOpenGL
#define _GNUstep_H_XGOpenGL

#include <AppKit/NSOpenGL.h>

#define id _gs_avoid_id_collision
#define BOOL XWINDOWSBOOL
#include <GL/glx.h>
#undef id
#undef BOOL

@class NSView;
@class XGXSubWindow;
@class XGGLPixelFormat;

@interface XGGLContext : NSOpenGLContext
{
  GLXContext        glx_context;
  GLXWindow         glx_drawable;
  XGXSubWindow     *xSubWindow;
  XGGLPixelFormat  *pixelFormat;
}

- (GLXContext)glxcontext;

@end

@interface XGGLPixelFormat : NSOpenGLPixelFormat
{
  @public
    union
      {
        GLXFBConfig  *fbconfig;
        XVisualInfo  *visualinfo;
      } configurations;

      int configurationCount;
}
@end

static inline int
GSglxMinorVersion(Display *dpy)
{
  int major, minor;
  Bool result; 
  result = glXQueryVersion (dpy, &major, &minor);

  if (result == False)
  {
    return -1;
  }

  return minor;
}

#endif
/* -*- 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 Library 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
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */


#include "config.h"
#ifdef HAVE_GLX
#include <Foundation/NSDebug.h>
#include <Foundation/NSException.h>
#include <GNUstepGUI/GSDisplayServer.h>
#include <AppKit/NSView.h>
#include <AppKit/NSWindow.h>
#include "x11/XGServerWindow.h"
#include "x11/XGOpenGL.h"

#include <X11/Xlib.h>

//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;

  [super init];

  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: [[view 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);

  XSetWindowAttributes window_attributes;
  window_attributes.border_pixel = 255;
  window_attributes.colormap = XCreateColormap( win_info->display, win_info->ident,
                                    xVisualInfo->visual, AllocNone );
  window_attributes.event_mask = StructureNotifyMask;

  int mask = CWBorderPixel | CWColormap | CWEventMask;

//   winid = XCreateWindow(win_info->display, DefaultRootWindow(win_info->display),
// 			x, y, width, height, 0, 
// 			CopyFromParent, InputOutput, CopyFromParent, 0, NULL);

  xwindowid = XCreateWindow(win_info->display, win_info->ident,
			x, y, width, height, 0, 
			CopyFromParent, 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)
    {
      glXMakeContextCurrent(dpy, None, None, NULL);
    }
  else
    {
      glXMakeCurrent(dpy, None, NULL);
    }

  currentGLContext = nil;
}

+ (NSOpenGLContext *)currentContext
{
  return currentGLContext;
}

- (void) _detach
{
  if (xSubWindow)
    {
      MAKE_DISPLAY(dpy);

      if (currentGLContext == self)
	    {
	      [XGGLContext clearCurrentContext];
	    }
      //      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
{
  GLXContext other;
  MAKE_DISPLAY(dpy);

  if (context == nil ||  ![context isKindOfClass: [XGGLContext class]])
    [NSException raise: NSInvalidArgumentException
		 format: @"%@ is an invalid context", context];

  other = ((XGGLContext *)context)->glx_context;

  glXCopyContext(dpy, other, glx_context, mask);
}

- (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);
}


- (void)getValues:(long *)vals 
     forParameter:(NSOpenGLContextParameter)param
{
  //  TODO
  [self notImplemented: _cmd];
}


- (id)initWithFormat: (NSOpenGLPixelFormat *)_format 
	    shareContext: (NSOpenGLContext *)share
{
  [super init];

  glx_context = None;
  
  if (_format && [_format isKindOfClass: [XGGLPixelFormat class]])
    {
      MAKE_DISPLAY(dpy);
      ASSIGN(pixelFormat, (XGGLPixelFormat *)_format);
      //FIXME: allow index mode and sharing

      if (GSglxMinorVersion (dpy) >= 3)
        {
	      glx_context = glXCreateNewContext(dpy, pixelFormat->configurations.fbconfig[0], 
					                        GLX_RGBA_TYPE, [ (XGGLContext *)share glxcontext ], YES);
        }
      else
        {
	      glx_context = glXCreateContext(dpy, pixelFormat->configurations.visualinfo, [ (XGGLContext *)share glxcontext ], GL_TRUE);
        }

      return self;
    }
  else
    {
      NSDebugMLLog(@"GLX", @"invalid format %@", _format);
      RELEASE(self);

      return nil;
    }
}


- (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");
      glXMakeContextCurrent(dpy, glx_drawable, glx_drawable, glx_context);
      NSDebugMLLog(@"GLX", @"after glXMakeContextCurrent");
    }
  else
    {
      NSDebugMLLog(@"GLX", @"before glXMakeCurrent");
      glXMakeCurrent(dpy, glx_drawable, glx_context);
      NSDebugMLLog(@"GLX", @"after glXMakeCurrent");
    }

//   NSAssert(glx_context != None,   NSInternalInconsistencyException);

//   glXMakeCurrent(dpy, xsubwin->winid, glx_context);

  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
{
  XGXSubWindow *win;
  MAKE_DISPLAY(dpy);

  if (!view)
    [NSException raise: NSInvalidArgumentException
		 format: @"setView called with a nil value"];

  NSAssert(pixelFormat, NSInternalInconsistencyException);

  XVisualInfo * xvinfo;

  if (GSglxMinorVersion (dpy) >= 3)
    {
      xvinfo = glXGetVisualFromFBConfig(dpy,pixelFormat->configurations.fbconfig[0]);
    }
  else
    {
      xvinfo = pixelFormat->configurations.visualinfo;
    }


  win = [XGXSubWindow subwindowOnView:view visualinfo:xvinfo ];
  ASSIGN(xSubWindow, win);

  glx_drawable = glXCreateWindow( dpy, pixelFormat->configurations.fbconfig[0], win->xwindowid, NULL );

  //glx_drawable = xSubWindow->xwindowid;

//FIXME
//The following line should be the good one.  But it crashes my X server...

//   glx_drawable = glXCreateWindow(dpy, *format->conf_tab, xsubwin->winid,
// 				 NULL);
  NSDebugMLLog(@"GLX", @"glx_window : %u", glx_drawable);
}


- (void)update
{
  [xSubWindow update];
}


- (NSView *)view
{
  if (xSubWindow)
    {
      return xSubWindow->attached;
    }
  else
    {
      return nil;
    }
}

@end
#endif
/* -*- 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 Library 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
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */

#include "config.h"
#ifdef HAVE_GLX
#include <Foundation/NSDebug.h>
#include <Foundation/NSException.h>
#include <Foundation/NSData.h>
#include <GNUstepGUI/GSDisplayServer.h>
#include "x11/XGServer.h"
#include "x11/XGOpenGL.h"

#include <X11/Xlib.h>

#define MAKE_DISPLAY(dpy) Display *dpy;\
  dpy = [(XGServer *)GSCurrentServer() xDisplay];\
  NSAssert(dpy != NULL, NSInternalInconsistencyException)


@implementation XGGLPixelFormat

/* FIXME:
     we assume that the ABI of NSOpenGLPixelFormatAttribute matches the ABI 
     of glX. Apparently, this is true for the most useful attributes.
*/

- (void) getValues: (GLint *)vals 
      forAttribute: (NSOpenGLPixelFormatAttribute)attrib 
  forVirtualScreen: (GLint)screen
{
  MAKE_DISPLAY(dpy);

  NSAssert(((GSglxMinorVersion (dpy) >= 3) ? (void *)configurations.fbconfig : (void *)configurations.visualinfo) != NULL
	        && configurationCount > 0,
            NSInternalInconsistencyException);

  if (GSglxMinorVersion (dpy) >= 3)
    {
      glXGetFBConfigAttrib(dpy, configurations.fbconfig[0], attrib, vals);
    }
  else
    {
      glXGetConfig(dpy, configurations.visualinfo, attrib, vals);
    }
}

- (id)initWithAttributes:(NSOpenGLPixelFormatAttribute *)attribs
{
  int v1, v2;
  int AccumSize;
  NSOpenGLPixelFormatAttribute *ptr = attribs;
  NSMutableData *data = [NSMutableData data];
  MAKE_DISPLAY(dpy);

#define append(a, b) do {v1 = a;v2 = b;[data appendBytes: &v1 length: sizeof(v1)];\
  [data appendBytes: &v2 length: sizeof(v2)];} while (0)

#define append1(a) do {v1 = a;[data appendBytes: &v1 length: sizeof(v1)];} while (0)

  if (GSglxMinorVersion (dpy) < 3)
    {
        append1 (GLX_RGBA);
    }
  else
    {
        append(GLX_RENDER_TYPE, GLX_RGBA_BIT);
        append(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT|GLX_PIXMAP_BIT);
      //  append(GLX_X_RENDERABLE,YES);
      //append(GLX_X_VISUAL_TYPE,GLX_TRUE_COLOR);
    }

  while (*ptr)
    {
      switch(*ptr)
	{
	// it means all the same on GLX - there is no diffrent here
	case NSOpenGLPFASingleRenderer:
	case NSOpenGLPFAAllRenderers:
	case NSOpenGLPFAAccelerated:
      if ( GSglxMinorVersion (dpy) < 3 )
	  append(GLX_USE_GL,YES);
	  break;
	case  NSOpenGLPFADoubleBuffer:
	  append(GLX_DOUBLEBUFFER, YES);
	  break;
	case NSOpenGLPFAStereo:
	  append(GLX_STEREO, YES);
	  break;
	case NSOpenGLPFAAuxBuffers:
	  ptr++;
	  append(GLX_AUX_BUFFERS, *ptr);
	  break;
	case NSOpenGLPFAColorSize:
	  ptr++;
	  append(GLX_RED_SIZE, *ptr);
	  append(GLX_GREEN_SIZE, *ptr);
	  append(GLX_BLUE_SIZE, *ptr);
	  break;
	case NSOpenGLPFAAlphaSize:
	  ptr++;
	  append(GLX_ALPHA_SIZE, *ptr);
	  break;
	case NSOpenGLPFADepthSize:
	  ptr++;
	  append(GLX_DEPTH_SIZE, *ptr);
	  break;
	case NSOpenGLPFAStencilSize:
	  ptr++;
	  append(GLX_STENCIL_SIZE, *ptr);
	  break;
	case NSOpenGLPFAAccumSize:
	  ptr++;
	  //has to been tested - I did it in that way....
	  //FIXME?  I don't understand...
	  //append(GLX_ACCUM_RED_SIZE, *ptr/3);
	  //append(GLX_ACCUM_GREEN_SIZE, *ptr/3);
	  //append(GLX_ACCUM_BLUE_SIZE, *ptr/3);
	AccumSize=*ptr;  
	switch (AccumSize)
		{
		case 8:
		 	append(GLX_ACCUM_RED_SIZE, 3);
		 	append(GLX_ACCUM_GREEN_SIZE, 3);
		 	append(GLX_ACCUM_BLUE_SIZE, 2);
		 	append(GLX_ACCUM_ALPHA_SIZE, 0);
		 	break;
		case 15:
		case 16:
		 	append(GLX_ACCUM_RED_SIZE, 5);
		 	append(GLX_ACCUM_GREEN_SIZE, 5);
		 	append(GLX_ACCUM_BLUE_SIZE, 5);
		 	append(GLX_ACCUM_ALPHA_SIZE, 0);
			break;
		case 24:
			append(GLX_ACCUM_RED_SIZE, 8);
			append(GLX_ACCUM_GREEN_SIZE, 8);
			append(GLX_ACCUM_BLUE_SIZE, 8);
			append(GLX_ACCUM_ALPHA_SIZE, 0);
			break;
		case 32:
			append(GLX_ACCUM_RED_SIZE, 8);
			append(GLX_ACCUM_GREEN_SIZE, 8);
			append(GLX_ACCUM_BLUE_SIZE, 8);
			append(GLX_ACCUM_ALPHA_SIZE, 8);
			break;
		}
		break;
	//can not be handle by X11
	case NSOpenGLPFAMinimumPolicy:
	  break;
	// can not be handle by X11
	case NSOpenGLPFAMaximumPolicy:
	  break;

	  //FIXME all of this stuff...
	case NSOpenGLPFAOffScreen:
	case NSOpenGLPFAFullScreen:
	case NSOpenGLPFASampleBuffers:
	case NSOpenGLPFASamples:
	case NSOpenGLPFAAuxDepthStencil:
	case NSOpenGLPFARendererID:
	case NSOpenGLPFANoRecovery:
	case NSOpenGLPFAClosestPolicy:
	case NSOpenGLPFARobust:
	case NSOpenGLPFABackingStore:
	case NSOpenGLPFAMPSafe:
	case NSOpenGLPFAWindow:
	case NSOpenGLPFAMultiScreen:
	case NSOpenGLPFACompliant:
	case NSOpenGLPFAScreenMask:
	case NSOpenGLPFAVirtualScreenCount:
	  break;
	}
      ptr ++;
    }

  append1(None);

  //FIXME, what screen number ?
  if (GSglxMinorVersion (dpy) >= 3)
    {
      configurations.fbconfig = glXChooseFBConfig(dpy, DefaultScreen(dpy), [data mutableBytes], &configurationCount);
    }
  else
    {
      configurations.visualinfo = glXChooseVisual(dpy, DefaultScreen(dpy), [data mutableBytes]);
    }
  
  if (((GSglxMinorVersion (dpy) >= 3) ? (void *)configurations.fbconfig : (void *)configurations.visualinfo) == NULL)
    {
      NSDebugMLLog(@"GLX", @"no pixel format found matching what is required");
      RELEASE(self);

      return nil;
    }
  else
    {
      NSDebugMLLog(@"GLX", @"We found %d pixel formats", configurationCount);
      
      return self;
    }
}

- (void) dealloc
{
  //FIXME 	
  //are we sure that X Connection is still up here ?
  MAKE_DISPLAY(dpy);

  if (GSglxMinorVersion (dpy) >= 3)
    {
      XFree (configurations.fbconfig);
    }
  else
    {
      XFree (configurations.visualinfo);
    }

  NSDebugMLLog(@"GLX", @"deallocation");
  [super dealloc];
}

- (int)numberOfVirtualScreens
{
  //  [self notImplemented: _cmd];
  //FIXME
  //This looks like a reasonable value to return...
  return 1;
}

@end
#endif
_______________________________________________
Gnustep-dev mailing list
Gnustep-dev@gnu.org
http://lists.gnu.org/mailman/listinfo/gnustep-dev

Reply via email to