1 /* xscreensaver, Copyright (c) 2006, 2007 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 CGLContextObj cctx = CGLGetCurrentContext();
160 # define kCGLCEMPEngine 313 // #### new in MacOS 10.4.8 + XCode 2.4
161 CGLError err = CGLEnable (cctx, kCGLCEMPEngine);
162 if (err != kCGLNoError) {
163 NSLog (@"enabling multi-threaded OpenGL failed: %d", err);
167 // Caller expects a pointer to an opaque struct... which it dereferences.
168 // Don't ask me, it's historical...
169 static int blort = -1;
170 return (void *) &blort;
174 /* Copy the back buffer to the front buffer.
177 glXSwapBuffers (Display *dpy, Window window)
179 XScreenSaverGLView *view = (XScreenSaverGLView *) jwxyz_window_view (window);
180 AGLContext ctx = [view aglContext];
181 if (ctx) aglSwapBuffers (ctx);
187 glXMakeCurrent (Display *dpy, Window window, GLXContext context)
192 /* clear away any lingering error codes */
194 clear_gl_error (void)
196 while (glGetError() != GL_NO_ERROR)
198 while (aglGetError() != AGL_NO_ERROR)
203 check_agl_error (const char *type)
208 switch ((i = aglGetError())) {
209 case AGL_NO_ERROR: return;
210 case AGL_BAD_ATTRIBUTE: e = "bad attribute"; break;
211 case AGL_BAD_PROPERTY: e = "bad propery"; break;
212 case AGL_BAD_PIXELFMT: e = "bad pixelfmt"; break;
213 case AGL_BAD_RENDINFO: e = "bad rendinfo"; break;
214 case AGL_BAD_CONTEXT: e = "bad context"; break;
215 case AGL_BAD_DRAWABLE: e = "bad drawable"; break;
216 case AGL_BAD_GDEV: e = "bad gdev"; break;
217 case AGL_BAD_STATE: e = "bad state"; break;
218 case AGL_BAD_VALUE: e = "bad value"; break;
219 case AGL_BAD_MATCH: e = "bad match"; break;
220 case AGL_BAD_ENUM: e = "bad enum"; break;
221 case AGL_BAD_OFFSCREEN: e = "bad offscreen"; break;
222 case AGL_BAD_FULLSCREEN: e = "bad fullscreen";break;
223 case AGL_BAD_WINDOW: e = "bad window"; break;
224 case AGL_BAD_POINTER: e = "bad pointer"; break;
225 case AGL_BAD_MODULE: e = "bad module"; break;
226 case AGL_BAD_ALLOC: e = "bad alloc"; break;
227 case AGL_BAD_CONNECTION: e = "bad connection";break;
229 e = buf; sprintf (buf, "unknown AGL error %d", (int) i); break;
231 NSLog (@"%s AGL error: %s", type, e);
236 /* report a GL error. */
238 check_gl_error (const char *type)
240 check_agl_error (type);
245 switch ((i = glGetError())) {
246 case GL_NO_ERROR: return;
247 case GL_INVALID_ENUM: e = "invalid enum"; break;
248 case GL_INVALID_VALUE: e = "invalid value"; break;
249 case GL_INVALID_OPERATION: e = "invalid operation"; break;
250 case GL_STACK_OVERFLOW: e = "stack overflow"; break;
251 case GL_STACK_UNDERFLOW: e = "stack underflow"; break;
252 case GL_OUT_OF_MEMORY: e = "out of memory"; break;
253 #ifdef GL_TABLE_TOO_LARGE_EXT
254 case GL_TABLE_TOO_LARGE_EXT: e = "table too large"; break;
256 #ifdef GL_TEXTURE_TOO_LARGE_EXT
257 case GL_TEXTURE_TOO_LARGE_EXT: e = "texture too large"; break;
260 e = buf; sprintf (buf, "unknown GL error %d", (int) i); break;
262 NSLog (@"%s GL error: %s", type, e);