ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-2.07.tar.gz
[xscreensaver] / hacks / glx / xlock-gl.c
1 /* xlock-gc.c --- xscreensaver compatibility layer for xlockmore GL modules.
2  * xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@netscape.com>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  *
12  * This file, along with xlockmore.h, make it possible to compile an xlockmore
13  * GL module into a standalone program, and thus use it with xscreensaver.
14  * By Jamie Zawinski <jwz@netscape.com> on 31-May-97.
15  */
16
17 #include <stdio.h>
18 #include "screenhack.h"
19 #include "xlockmoreI.h"
20
21 #include <GL/gl.h>
22 #include <GL/glx.h>
23
24 /* Gag -- we use this to turn X errors from glXCreateContext() into
25    something that will actually make sense to the user.
26  */
27 static XErrorHandler orig_ehandler = 0;
28 static Bool got_error = 0;
29
30 static int
31 BadValue_ehandler (Display *dpy, XErrorEvent *error)
32 {
33   if (error->error_code == BadValue)
34     {
35       got_error = True;
36       return 0;
37     }
38   else
39     return orig_ehandler (dpy, error);
40 }
41
42
43 GLXContext
44 init_GL(ModeInfo * mi)
45 {
46   Display *dpy = mi->dpy;
47   Window window = mi->window;
48   Screen *screen = mi->xgwa.screen;
49   Visual *visual = mi->xgwa.visual;
50   GLXContext glx_context = 0;
51   XVisualInfo vi_in, *vi_out;
52   int out_count;
53
54   vi_in.screen = screen_number (screen);
55   vi_in.visualid = XVisualIDFromVisual (visual);
56   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
57                            &vi_in, &out_count);
58   if (! vi_out) abort ();
59
60   {
61     XSync (dpy, False);
62     orig_ehandler = XSetErrorHandler (BadValue_ehandler);
63     glx_context = glXCreateContext (dpy, vi_out, 0, GL_TRUE);
64     XSync (dpy, False);
65     XSetErrorHandler (orig_ehandler);
66     if (got_error)
67       glx_context = 0;
68   }
69
70   XFree((char *) vi_out);
71
72   if (!glx_context)
73     {
74       fprintf(stderr, "%s: couldn't create GL context for visual 0x%x.\n",
75               progname, (unsigned int) XVisualIDFromVisual (visual));
76       exit(1);
77     }
78
79   glXMakeCurrent (dpy, window, glx_context);
80
81   {
82     GLboolean rgba_mode = 0;
83     glGetBooleanv(GL_RGBA_MODE, &rgba_mode);
84     if (!rgba_mode)
85       {
86         glIndexi (WhitePixelOfScreen (screen));
87         glClearIndex (BlackPixelOfScreen (screen));
88       }
89   }
90
91   return (glx_context);
92 }
93
94
95 Visual *
96 get_gl_visual (Screen *screen, char *name, char *class)
97 {
98   char *string = get_string_resource (name, class);
99   XVisualInfo *vi = 0;
100   Bool done_once = False;
101
102  AGAIN:
103   if (!string || !*string ||
104       !strcmp (string, "best") ||
105       !strcmp (string, "color") ||
106       !strcmp (string, "default"))
107     {
108       Display *dpy = DisplayOfScreen (screen);
109       int screen_num = screen_number (screen);
110       int attrs[20];
111       int i = 0;
112       Bool dbuf_p = !get_boolean_resource ("noBuffer", "NoBuffer");
113
114       done_once = True;
115
116       attrs[i++] = GLX_RGBA;
117       attrs[i++] = GLX_RED_SIZE;   attrs[i++] = 1;
118       attrs[i++] = GLX_GREEN_SIZE; attrs[i++] = 1;
119       attrs[i++] = GLX_BLUE_SIZE;  attrs[i++] = 1;
120       attrs[i++] = GLX_DEPTH_SIZE; attrs[i++] = 1;
121       if (dbuf_p)
122         attrs[i++] = GLX_DOUBLEBUFFER;
123       attrs[i++] = 0;
124
125       vi = glXChooseVisual (dpy, screen_num, attrs);
126       if (vi) goto DONE;
127
128       /* Try without double-buffering. */
129       attrs[i - 1] = 0;
130       vi = glXChooseVisual (dpy, screen_num, attrs);
131       if (vi) goto DONE;
132
133       /* Try mono. */
134       i = 0;
135       if (dbuf_p)
136         attrs[i++] = GLX_DOUBLEBUFFER;
137       attrs[i++] = 0;
138       vi = glXChooseVisual (dpy, screen_num, attrs);
139       if (vi) goto DONE;
140
141       /* Try mono without double-buffering. */
142       attrs[0] = 0;
143       vi = glXChooseVisual (dpy, screen_num, attrs);
144     }
145
146  DONE:
147   {
148     Visual *v;
149     if (vi)
150       {
151         v = vi->visual;
152         XFree (vi);
153       }
154     else
155       {
156         v = get_visual (screen, string, False, True);
157         if (!v)
158           {
159             if (done_once)
160               v = DefaultVisualOfScreen (screen);
161             else
162               {
163                 free (string);
164                 string = 0;
165                 goto AGAIN;
166               }
167           }
168       }
169
170     free (string);
171     return v;
172   }
173 }