http://ftp.aanet.ru/pub/Linux/X11/apps/xscreensaver-2.31.tar.gz
[xscreensaver] / hacks / glx / xlock-gl.c
1 /* xlock-gc.c --- xscreensaver compatibility layer for xlockmore GL modules.
2  * xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski <jwz@jwz.org>
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@jwz.org> 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   /* GLXContext is already a pointer type.
92      Why this function returns a pointer to a pointer, I have no idea...
93    */
94   {
95     GLXContext *ptr = (GLXContext *) malloc(sizeof(GLXContext));
96     *ptr = glx_context;
97     return ptr;
98   }
99 }
100
101
102 Visual *
103 get_gl_visual (Screen *screen, char *name, char *class)
104 {
105   char *string = get_string_resource (name, class);
106   XVisualInfo *vi = 0;
107   Bool done_once = False;
108
109  AGAIN:
110   if (!string || !*string ||
111       !strcmp (string, "best") ||
112       !strcmp (string, "color") ||
113       !strcmp (string, "default"))
114     {
115       Display *dpy = DisplayOfScreen (screen);
116       int screen_num = screen_number (screen);
117       int attrs[20];
118       int i = 0;
119       Bool dbuf_p = !get_boolean_resource ("noBuffer", "NoBuffer");
120
121       done_once = True;
122
123       attrs[i++] = GLX_RGBA;
124       attrs[i++] = GLX_RED_SIZE;   attrs[i++] = 1;
125       attrs[i++] = GLX_GREEN_SIZE; attrs[i++] = 1;
126       attrs[i++] = GLX_BLUE_SIZE;  attrs[i++] = 1;
127       attrs[i++] = GLX_DEPTH_SIZE; attrs[i++] = 1;
128       if (dbuf_p)
129         attrs[i++] = GLX_DOUBLEBUFFER;
130       attrs[i++] = 0;
131
132       vi = glXChooseVisual (dpy, screen_num, attrs);
133       if (vi) goto DONE;
134
135       /* Try without double-buffering. */
136       attrs[i - 1] = 0;
137       vi = glXChooseVisual (dpy, screen_num, attrs);
138       if (vi) goto DONE;
139
140       /* Try mono. */
141       i = 0;
142       if (dbuf_p)
143         attrs[i++] = GLX_DOUBLEBUFFER;
144       attrs[i++] = 0;
145       vi = glXChooseVisual (dpy, screen_num, attrs);
146       if (vi) goto DONE;
147
148       /* Try mono without double-buffering. */
149       attrs[0] = 0;
150       vi = glXChooseVisual (dpy, screen_num, attrs);
151     }
152
153  DONE:
154   {
155     Visual *v;
156     if (vi)
157       {
158         v = vi->visual;
159         XFree (vi);
160       }
161     else
162       {
163         v = get_visual (screen, string, False, True);
164         if (!v)
165           {
166             if (done_once)
167               v = DefaultVisualOfScreen (screen);
168             else
169               {
170                 free (string);
171                 string = 0;
172                 goto AGAIN;
173               }
174           }
175       }
176
177     free (string);
178     return v;
179   }
180 }