1 /* xscreensaver, Copyright (c) 2006 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 /* used by the OpenGL screen savers
25 extern GLXContext *init_GL (ModeInfo *);
26 extern void glXSwapBuffers (Display *, Window);
27 extern void glXMakeCurrent (Display *, Window, GLXContext);
28 extern void clear_gl_error (void);
29 extern void check_gl_error (const char *type);
32 @implementation XScreenSaverGLView
37 aglDestroyContext (agl_ctx);
44 [super stopAnimation];
46 // Without this, the GL frame stays on screen when switching tabs
47 // in System Preferences.
50 aglSetCurrentContext (NULL);
51 aglDestroyContext (agl_ctx);
57 // #### maybe this could/should just be on 'lockFocus' instead?
58 - (void) prepareContext
61 if (!aglSetCurrentContext (agl_ctx)) {
62 check_gl_error ("aglSetCurrentContext");
67 - (void) resizeContext
72 /* Constrain the AGL context to the rectangle of this view
73 (not of our parent window).
76 NSRect rect = [[[self window] contentView] convertRect:[self frame]
78 aglrect[0] = rect.origin.x;
79 aglrect[1] = rect.origin.y;
80 aglrect[2] = rect.size.width;
81 aglrect[3] = rect.size.height;
82 aglEnable (agl_ctx, AGL_BUFFER_RECT);
83 aglSetInteger (agl_ctx, AGL_BUFFER_RECT, aglrect);
84 aglUpdateContext (agl_ctx);
88 - (void)drawRect:(NSRect)rect
91 [super drawRect:rect];
95 - (AGLContext) aglContext
100 - (void) setAglContext: (AGLContext) ctx
103 if (! aglDestroyContext (agl_ctx)) {
104 check_gl_error("aglDestroyContext");
108 [self resizeContext];
113 /* Utility functions...
117 /* Called by OpenGL savers using the XLockmore API.
120 init_GL (ModeInfo *mi)
122 Window win = mi->window;
123 XScreenSaverGLView *view = (XScreenSaverGLView *) jwxyz_window_view (win);
125 GLint agl_attrs[] = {
130 AGLPixelFormat aglpixf = aglChoosePixelFormat (NULL, 0, agl_attrs);
131 AGLContext ctx = aglCreateContext (aglpixf, NULL);
132 aglDestroyPixelFormat (aglpixf);
134 check_gl_error("aglCreateContext");
138 if (! aglSetDrawable (ctx, GetWindowPort ([[view window] windowRef]))) {
139 check_gl_error("aglSetDrawable");
143 if (! aglSetCurrentContext (ctx)) {
144 check_gl_error("aglSetCurrentContext");
148 [view setAglContext:ctx];
150 // Sync refreshes to the vertical blanking interval
152 aglSetInteger (ctx, AGL_SWAP_INTERVAL, &r);
154 // Caller expects a pointer to an opaque struct... which it dereferences.
155 // Don't ask me, it's historical...
156 static int blort = -1;
157 return (void *) &blort;
161 /* Copy the back buffer to the front buffer.
164 glXSwapBuffers (Display *dpy, Window window)
166 XScreenSaverGLView *view = (XScreenSaverGLView *) jwxyz_window_view (window);
167 AGLContext ctx = [view aglContext];
168 if (ctx) aglSwapBuffers (ctx);
174 glXMakeCurrent (Display *dpy, Window window, GLXContext context)
179 /* clear away any lingering error codes */
181 clear_gl_error (void)
183 while (glGetError() != GL_NO_ERROR)
185 while (aglGetError() != AGL_NO_ERROR)
190 check_agl_error (const char *type)
195 switch ((i = aglGetError())) {
196 case AGL_NO_ERROR: return;
197 case AGL_BAD_ATTRIBUTE: e = "bad attribute"; break;
198 case AGL_BAD_PROPERTY: e = "bad propery"; break;
199 case AGL_BAD_PIXELFMT: e = "bad pixelfmt"; break;
200 case AGL_BAD_RENDINFO: e = "bad rendinfo"; break;
201 case AGL_BAD_CONTEXT: e = "bad context"; break;
202 case AGL_BAD_DRAWABLE: e = "bad drawable"; break;
203 case AGL_BAD_GDEV: e = "bad gdev"; break;
204 case AGL_BAD_STATE: e = "bad state"; break;
205 case AGL_BAD_VALUE: e = "bad value"; break;
206 case AGL_BAD_MATCH: e = "bad match"; break;
207 case AGL_BAD_ENUM: e = "bad enum"; break;
208 case AGL_BAD_OFFSCREEN: e = "bad offscreen"; break;
209 case AGL_BAD_FULLSCREEN: e = "bad fullscreen";break;
210 case AGL_BAD_WINDOW: e = "bad window"; break;
211 case AGL_BAD_POINTER: e = "bad pointer"; break;
212 case AGL_BAD_MODULE: e = "bad module"; break;
213 case AGL_BAD_ALLOC: e = "bad alloc"; break;
214 case AGL_BAD_CONNECTION: e = "bad connection";break;
216 e = buf; sprintf (buf, "unknown AGL error %d", (int) i); break;
218 NSLog (@"%s AGL error: %s\n", type, e);
223 /* report a GL error. */
225 check_gl_error (const char *type)
227 check_agl_error (type);
232 switch ((i = glGetError())) {
233 case GL_NO_ERROR: return;
234 case GL_INVALID_ENUM: e = "invalid enum"; break;
235 case GL_INVALID_VALUE: e = "invalid value"; break;
236 case GL_INVALID_OPERATION: e = "invalid operation"; break;
237 case GL_STACK_OVERFLOW: e = "stack overflow"; break;
238 case GL_STACK_UNDERFLOW: e = "stack underflow"; break;
239 case GL_OUT_OF_MEMORY: e = "out of memory"; break;
240 #ifdef GL_TABLE_TOO_LARGE_EXT
241 case GL_TABLE_TOO_LARGE_EXT: e = "table too large"; break;
243 #ifdef GL_TEXTURE_TOO_LARGE_EXT
244 case GL_TEXTURE_TOO_LARGE_EXT: e = "texture too large"; break;
247 e = buf; sprintf (buf, "unknown GL error %d", (int) i); break;
249 NSLog (@"%s GL error: %s\n", type, e);