1 /* xscreensaver, Copyright (c) 2006-2008 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 /* This is a subclass of Apple's ScreenSaverView that knows how to run
13 xscreensaver programs without X11 via the dark magic of the "jwxyz"
14 library. In xscreensaver terminology, this is the replacement for
15 the "screenhack.c" module.
18 #import "XScreenSaverGLView.h"
19 #import "XScreenSaverConfigSheet.h"
20 #import "screenhackI.h"
21 #import "xlockmoreI.h"
23 #import <OpenGL/OpenGL.h>
25 /* used by the OpenGL screen savers
27 extern GLXContext *init_GL (ModeInfo *);
28 extern void glXSwapBuffers (Display *, Window);
29 extern void glXMakeCurrent (Display *, Window, GLXContext);
30 extern void clear_gl_error (void);
31 extern void check_gl_error (const char *type);
34 @implementation XScreenSaverGLView
39 aglDestroyContext (agl_ctx);
46 [super stopAnimation];
48 // Without this, the GL frame stays on screen when switching tabs
49 // in System Preferences.
52 aglSetCurrentContext (NULL);
53 aglDestroyContext (agl_ctx);
59 // #### maybe this could/should just be on 'lockFocus' instead?
60 - (void) prepareContext
63 if (!aglSetCurrentContext (agl_ctx)) {
64 check_gl_error ("aglSetCurrentContext");
69 - (void) resizeContext
74 /* Constrain the AGL context to the rectangle of this view
75 (not of our parent window).
78 NSRect rect = [[[self window] contentView] convertRect:[self frame]
80 aglrect[0] = rect.origin.x;
81 aglrect[1] = rect.origin.y;
82 aglrect[2] = rect.size.width;
83 aglrect[3] = rect.size.height;
84 aglEnable (agl_ctx, AGL_BUFFER_RECT);
85 aglSetInteger (agl_ctx, AGL_BUFFER_RECT, aglrect);
86 aglUpdateContext (agl_ctx);
90 - (void)drawRect:(NSRect)rect
93 [super drawRect:rect];
97 - (AGLContext) aglContext
102 - (void) setAglContext: (AGLContext) ctx
105 if (! aglDestroyContext (agl_ctx)) {
106 check_gl_error("aglDestroyContext");
110 [self resizeContext];
115 /* Utility functions...
119 /* Called by OpenGL savers using the XLockmore API.
122 init_GL (ModeInfo *mi)
124 Window win = mi->window;
125 XScreenSaverGLView *view = (XScreenSaverGLView *) jwxyz_window_view (win);
127 GLint agl_attrs[] = {
132 AGLPixelFormat aglpixf = aglChoosePixelFormat (NULL, 0, agl_attrs);
133 AGLContext ctx = aglCreateContext (aglpixf, NULL);
134 aglDestroyPixelFormat (aglpixf);
136 check_gl_error("aglCreateContext");
140 if (! aglSetDrawable (ctx, GetWindowPort ([[view window] windowRef]))) {
141 check_gl_error("aglSetDrawable");
145 if (! aglSetCurrentContext (ctx)) {
146 check_gl_error("aglSetCurrentContext");
150 [view setAglContext:ctx];
152 // Sync refreshes to the vertical blanking interval
154 aglSetInteger (ctx, AGL_SWAP_INTERVAL, &r);
156 // Enable multi-threading, if possible. This runs most OpenGL commands
157 // and GPU management on a second CPU.
159 # ifndef kCGLCEMPEngine
160 # define kCGLCEMPEngine 313 // Added in MacOS 10.4.8 + XCode 2.4.
162 CGLContextObj cctx = CGLGetCurrentContext();
163 CGLError err = CGLEnable (cctx, kCGLCEMPEngine);
164 if (err != kCGLNoError) {
165 NSLog (@"enabling multi-threaded OpenGL failed: %d", err);
169 // Caller expects a pointer to an opaque struct... which it dereferences.
170 // Don't ask me, it's historical...
171 static int blort = -1;
172 return (void *) &blort;
176 /* Copy the back buffer to the front buffer.
179 glXSwapBuffers (Display *dpy, Window window)
181 XScreenSaverGLView *view = (XScreenSaverGLView *) jwxyz_window_view (window);
182 AGLContext ctx = [view aglContext];
183 if (ctx) aglSwapBuffers (ctx);
189 glXMakeCurrent (Display *dpy, Window window, GLXContext context)
194 /* clear away any lingering error codes */
196 clear_gl_error (void)
198 while (glGetError() != GL_NO_ERROR)
200 while (aglGetError() != AGL_NO_ERROR)
205 check_agl_error (const char *type)
210 switch ((i = aglGetError())) {
211 case AGL_NO_ERROR: return;
212 case AGL_BAD_ATTRIBUTE: e = "bad attribute"; break;
213 case AGL_BAD_PROPERTY: e = "bad propery"; break;
214 case AGL_BAD_PIXELFMT: e = "bad pixelfmt"; break;
215 case AGL_BAD_RENDINFO: e = "bad rendinfo"; break;
216 case AGL_BAD_CONTEXT: e = "bad context"; break;
217 case AGL_BAD_DRAWABLE: e = "bad drawable"; break;
218 case AGL_BAD_GDEV: e = "bad gdev"; break;
219 case AGL_BAD_STATE: e = "bad state"; break;
220 case AGL_BAD_VALUE: e = "bad value"; break;
221 case AGL_BAD_MATCH: e = "bad match"; break;
222 case AGL_BAD_ENUM: e = "bad enum"; break;
223 case AGL_BAD_OFFSCREEN: e = "bad offscreen"; break;
224 case AGL_BAD_FULLSCREEN: e = "bad fullscreen";break;
225 case AGL_BAD_WINDOW: e = "bad window"; break;
226 case AGL_BAD_POINTER: e = "bad pointer"; break;
227 case AGL_BAD_MODULE: e = "bad module"; break;
228 case AGL_BAD_ALLOC: e = "bad alloc"; break;
229 case AGL_BAD_CONNECTION: e = "bad connection";break;
231 e = buf; sprintf (buf, "unknown AGL error %d", (int) i); break;
233 NSLog (@"%s AGL error: %s", type, e);
238 /* report a GL error. */
240 check_gl_error (const char *type)
242 check_agl_error (type);
247 switch ((i = glGetError())) {
248 case GL_NO_ERROR: return;
249 case GL_INVALID_ENUM: e = "invalid enum"; break;
250 case GL_INVALID_VALUE: e = "invalid value"; break;
251 case GL_INVALID_OPERATION: e = "invalid operation"; break;
252 case GL_STACK_OVERFLOW: e = "stack overflow"; break;
253 case GL_STACK_UNDERFLOW: e = "stack underflow"; break;
254 case GL_OUT_OF_MEMORY: e = "out of memory"; break;
255 #ifdef GL_TABLE_TOO_LARGE_EXT
256 case GL_TABLE_TOO_LARGE_EXT: e = "table too large"; break;
258 #ifdef GL_TEXTURE_TOO_LARGE_EXT
259 case GL_TEXTURE_TOO_LARGE_EXT: e = "texture too large"; break;
262 e = buf; sprintf (buf, "unknown GL error %d", (int) i); break;
264 NSLog (@"%s GL error: %s", type, e);