12 #define DEF_WIN_WIDTH 1280
13 #define DEF_WIN_HEIGHT 800
15 static Window create_xwindow(void);
16 static int init_gl(void);
17 static void destroy_gl(void);
18 static int proc_xevent(XEvent *ev);
22 static Window win, root;
23 static GLXContext ctx;
24 static XVisualInfo *visinf;
25 static Atom xa_wm_proto, xa_wm_delwin;
27 static volatile int quit;
30 static struct timeval tv, tv0;
32 int main(int argc, char **argv)
38 if((endp = getenv("XSCREENSAVER_WINDOW"))) {
39 printf("XSCREENSAVER_WINDOW: %s\n", endp);
42 if(!(dpy = XOpenDisplay(0))) {
43 fprintf(stderr, "failed to open connection to the X server\n");
46 scr = DefaultScreen(dpy);
47 root = RootWindow(dpy, scr);
49 xa_wm_proto = XInternAtom(dpy, "WM_PROTOCOLS", False);
50 xa_wm_delwin = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
52 for(i=0; i<argc; i++) {
53 printf("argv[%d]: %s\n", i, argv[i]);
56 for(i=1; i<argc; i++) {
57 if(strcmp(argv[i], "-root") == 0) {
58 argv[i] = argv[--argc];
59 if(!(win = VirtualRootWindowOfScreen(ScreenOfDisplay(dpy, scr)))) {
60 fprintf(stderr, "failed to find root window!\n");
66 } else if(strcmp(argv[i], "-window-id") == 0) {
67 if((wid = strtol(argv[i+1], &endp, 0)) > 0 && endp != argv[i+1]) {
68 printf("using window: %x\n", wid);
70 memmove(argv + i, argv + i + 2, (argc - i - 2) * sizeof *argv);
74 fprintf(stderr, "invalid option: -window-id must be followed by a valid window id\n");
81 if(app_parse_args(argc, argv) == -1) {
86 if(!win && !(win = create_xwindow())) {
93 if(app_init() == -1) {
99 gettimeofday(&tv0, 0);
102 while(XPending(dpy)) {
104 XNextEvent(dpy, &ev);
105 if(proc_xevent(&ev) == -1 || quit) {
110 gettimeofday(&tv, 0);
111 msec = (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000;
115 glXSwapBuffers(dpy, win);
116 assert(glGetError() == GL_NO_ERROR);
130 void app_fullscreen(void)
134 void app_windowed(void)
138 static XVisualInfo *choose_visual(void)
141 GLX_RGBA, GLX_DOUBLEBUFFER,
146 GLX_SAMPLE_BUFFERS, 1,
150 int *sample_buffers = glxattr + 10;
151 int *num_samples = glxattr + 13;
155 res = glXChooseVisual(dpy, scr, glxattr);
157 if(*num_samples <= 1) {
158 *sample_buffers = None;
160 } while(!res && *num_samples > 0);
165 static XVisualInfo *match_visual(Window win)
168 XVisualInfo vitmp, *vi;
169 XWindowAttributes wattr;
170 unsigned int mask = VisualScreenMask | VisualDepthMask | VisualClassMask;
172 XGetWindowAttributes(dpy, win, &wattr);
174 vitmp.visualid = XVisualIDFromVisual(wattr.visual);
175 vi = XGetVisualInfo(dpy, VisualIDMask, &vitmp, &numvi);
177 vi = XGetVisualInfo(dpy, mask, &vitmp, &numvi);
179 printf("found %d matching visuals\n", numvi);
180 for(i=0; i<numvi; i++) {
183 glXGetConfig(dpy, vi + i, GLX_SAMPLES, &nsamp);
185 printf("%x (msaa: %d)\n", (unsigned int)vi[i].visualid, nsamp);
190 static Window create_xwindow(void)
192 XSetWindowAttributes xattr;
193 long xattr_mask, evmask;
195 if(!(visinf = choose_visual())) {
196 fprintf(stderr, "failed to find appropriate visual\n");
200 xattr.colormap = XCreateColormap(dpy, root, visinf->visual, AllocNone);
201 xattr.background_pixel = BlackPixel(dpy, scr);
202 xattr_mask = CWColormap | CWBackPixel;
204 if(!(win = XCreateWindow(dpy, root, 0, 0, DEF_WIN_WIDTH, DEF_WIN_HEIGHT, 0,
205 visinf->depth, InputOutput, visinf->visual, xattr_mask, &xattr))) {
206 fprintf(stderr, "failed to create X window\n");
212 evmask = ExposureMask | StructureNotifyMask | KeyPressMask;
213 XSelectInput(dpy, win, evmask);
215 Xutf8SetWMProperties(dpy, win, "census", "census", 0, 0, 0, 0, 0);
216 XSetWMProtocols(dpy, win, &xa_wm_delwin, 1);
218 XMapRaised(dpy, win);
222 static int init_gl(void)
224 XWindowAttributes wattr;
225 int rbits, gbits, bbits, zbits, sbits, nsamp;
229 XGetWindowAttributes(dpy, win, &wattr);
231 if(!visinf && !(visinf = choose_visual())) {
232 fprintf(stderr, "failed to find appropriate visual\n");
236 if(!(ctx = glXCreateContext(dpy, visinf, 0, 1))) {
237 fprintf(stderr, "failed to create OpenGL context\n");
240 XDestroyWindow(dpy, win);
245 glXGetConfig(dpy, visinf, GLX_RED_SIZE, &rbits);
246 glXGetConfig(dpy, visinf, GLX_GREEN_SIZE, &gbits);
247 glXGetConfig(dpy, visinf, GLX_BLUE_SIZE, &bbits);
248 glXGetConfig(dpy, visinf, GLX_DEPTH_SIZE, &zbits);
249 glXGetConfig(dpy, visinf, GLX_STENCIL_SIZE, &sbits);
250 glXGetConfig(dpy, visinf, GLX_SAMPLES, &nsamp);
252 printf("created GLX visual %d bpp (%d%d%d), %dz, %ds, %d samp/pix\n",
253 visinf->depth, rbits, gbits, bbits, zbits, sbits, nsamp);
255 printf("glXMakeCurrent(%p, %x, %p)\n", (void*)dpy, (unsigned int)win, (void*)ctx);
256 glXMakeCurrent(dpy, win, ctx);
257 app_reshape(wattr.width, wattr.height);
258 win_width = wattr.width;
259 win_height = wattr.height;
263 static void destroy_gl(void)
269 glXMakeCurrent(dpy, 0, 0);
270 glXDestroyContext(dpy, ctx);
272 if(win && win != root) {
273 XDestroyWindow(dpy, win);
277 static int proc_xevent(XEvent *ev)
290 case ConfigureNotify:
291 if(ev->xconfigure.width != win_width || ev->xconfigure.height != win_height) {
292 int w = ev->xconfigure.width;
293 int h = ev->xconfigure.height;
302 if((sym = XLookupKeysym(&ev->xkey, 0))) {
303 if(sym == XK_Escape) {
306 app_keyboard(sym, ev->type == KeyPress);
311 if(ev->xclient.message_type == xa_wm_proto) {
312 if(ev->xclient.data.l[0] == xa_wm_delwin) {