X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fmain_x11.c;fp=src%2Fmain_x11.c;h=fe87caafc716a60d8f56df971c81ea0d81bc49d0;hb=16b8c35b3b3df5d47bbec1ffc79ddfa711a74ed1;hp=0000000000000000000000000000000000000000;hpb=98882f6f19a4e239e56d6eb5db453c97b64338fe;p=censuslogo diff --git a/src/main_x11.c b/src/main_x11.c new file mode 100644 index 0000000..fe87caa --- /dev/null +++ b/src/main_x11.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "app.h" +#include "vroot.h" + +#define DEF_WIN_WIDTH 1280 +#define DEF_WIN_HEIGHT 800 + +static Window create_xwindow(void); +static int init_gl(void); +static void destroy_gl(void); +static int proc_xevent(XEvent *ev); + +static Display *dpy; +static int scr; +static Window win, root; +static GLXContext ctx; +static XVisualInfo *visinf; +static Atom xa_wm_proto, xa_wm_delwin; + +static volatile int quit; +static int mapped; + +static struct timeval tv, tv0; + +int main(int argc, char **argv) +{ + int i; + unsigned int wid; + char *endp; + + if((endp = getenv("XSCREENSAVER_WINDOW"))) { + printf("XSCREENSAVER_WINDOW: %s\n", endp); + } + + if(!(dpy = XOpenDisplay(0))) { + fprintf(stderr, "failed to open connection to the X server\n"); + return 1; + } + scr = DefaultScreen(dpy); + root = RootWindow(dpy, scr); + + xa_wm_proto = XInternAtom(dpy, "WM_PROTOCOLS", False); + xa_wm_delwin = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + + for(i=0; i 0 && endp != argv[i+1]) { + printf("using window: %x\n", wid); + win = (Window)wid; + memmove(argv + i, argv + i + 2, (argc - i - 2) * sizeof *argv); + argc -= 2; + i--; + } else { + fprintf(stderr, "invalid option: -window-id must be followed by a valid window id\n"); + XCloseDisplay(dpy); + return 1; + } + } + } + + if(app_parse_args(argc, argv) == -1) { + XCloseDisplay(dpy); + return 1; + } + + if(!win && !(win = create_xwindow())) { + XCloseDisplay(dpy); + return 1; + } + if(init_gl() == -1) { + return 1; + } + if(app_init() == -1) { + destroy_gl(); + XCloseDisplay(dpy); + return 1; + } + + gettimeofday(&tv0, 0); + + while(!quit) { + while(XPending(dpy)) { + XEvent ev; + XNextEvent(dpy, &ev); + if(proc_xevent(&ev) == -1 || quit) { + goto done; + } + } + + gettimeofday(&tv, 0); + msec = (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000; + + app_display(); + + glXSwapBuffers(dpy, win); + assert(glGetError() == GL_NO_ERROR); + } + +done: + destroy_gl(); + XCloseDisplay(dpy); + return 0; +} + +void app_quit(void) +{ + exit(0); +} + +void app_fullscreen(void) +{ +} + +void app_windowed(void) +{ +} + +static XVisualInfo *choose_visual(void) +{ + int glxattr[] = { + GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 1, + GLX_SAMPLE_BUFFERS, 1, + GLX_SAMPLES, 8, + None + }; + int *sample_buffers = glxattr + 10; + int *num_samples = glxattr + 13; + XVisualInfo *res; + + do { + res = glXChooseVisual(dpy, scr, glxattr); + *num_samples >>= 1; + if(*num_samples <= 1) { + *sample_buffers = None; + } + } while(!res && *num_samples > 0); + + return res; +} + +static XVisualInfo *match_visual(Window win) +{ + int numvi, i; + XVisualInfo vitmp, *vi; + XWindowAttributes wattr; + unsigned int mask = VisualScreenMask | VisualDepthMask | VisualClassMask; + + XGetWindowAttributes(dpy, win, &wattr); + + vitmp.visualid = XVisualIDFromVisual(wattr.visual); + vi = XGetVisualInfo(dpy, VisualIDMask, &vitmp, &numvi); + vitmp = *vi; + vi = XGetVisualInfo(dpy, mask, &vitmp, &numvi); + + printf("found %d matching visuals\n", numvi); + for(i=0; ivisual, AllocNone); + xattr.background_pixel = BlackPixel(dpy, scr); + xattr_mask = CWColormap | CWBackPixel; + + if(!(win = XCreateWindow(dpy, root, 0, 0, DEF_WIN_WIDTH, DEF_WIN_HEIGHT, 0, + visinf->depth, InputOutput, visinf->visual, xattr_mask, &xattr))) { + fprintf(stderr, "failed to create X window\n"); + XFree(visinf); + visinf = 0; + return 0; + } + + evmask = ExposureMask | StructureNotifyMask | KeyPressMask; + XSelectInput(dpy, win, evmask); + + Xutf8SetWMProperties(dpy, win, "census", "census", 0, 0, 0, 0, 0); + XSetWMProtocols(dpy, win, &xa_wm_delwin, 1); + + XMapRaised(dpy, win); + return win; +} + +static int init_gl(void) +{ + XWindowAttributes wattr; + int rbits, gbits, bbits, zbits, sbits, nsamp; + + if(!win) return -1; + + XGetWindowAttributes(dpy, win, &wattr); + + if(!visinf && !(visinf = choose_visual())) { + fprintf(stderr, "failed to find appropriate visual\n"); + return -1; + } + + if(!(ctx = glXCreateContext(dpy, visinf, 0, 1))) { + fprintf(stderr, "failed to create OpenGL context\n"); + XFree(visinf); + if(win != root) { + XDestroyWindow(dpy, win); + } + return -1; + } + + glXGetConfig(dpy, visinf, GLX_RED_SIZE, &rbits); + glXGetConfig(dpy, visinf, GLX_GREEN_SIZE, &gbits); + glXGetConfig(dpy, visinf, GLX_BLUE_SIZE, &bbits); + glXGetConfig(dpy, visinf, GLX_DEPTH_SIZE, &zbits); + glXGetConfig(dpy, visinf, GLX_STENCIL_SIZE, &sbits); + glXGetConfig(dpy, visinf, GLX_SAMPLES, &nsamp); + + printf("created GLX visual %d bpp (%d%d%d), %dz, %ds, %d samp/pix\n", + visinf->depth, rbits, gbits, bbits, zbits, sbits, nsamp); + + printf("glXMakeCurrent(%p, %x, %p)\n", (void*)dpy, (unsigned int)win, (void*)ctx); + glXMakeCurrent(dpy, win, ctx); + app_reshape(wattr.width, wattr.height); + win_width = wattr.width; + win_height = wattr.height; + return 0; +} + +static void destroy_gl(void) +{ + if(visinf) { + XFree(visinf); + } + if(ctx) { + glXMakeCurrent(dpy, 0, 0); + glXDestroyContext(dpy, ctx); + } + if(win && win != root) { + XDestroyWindow(dpy, win); + } +} + +static int proc_xevent(XEvent *ev) +{ + KeySym sym; + + switch(ev->type) { + case MapNotify: + mapped = 1; + break; + + case UnmapNotify: + mapped = 0; + break; + + case ConfigureNotify: + if(ev->xconfigure.width != win_width || ev->xconfigure.height != win_height) { + int w = ev->xconfigure.width; + int h = ev->xconfigure.height; + app_reshape(w, h); + win_width = w; + win_height = h; + } + break; + + case KeyPress: + case KeyRelease: + if((sym = XLookupKeysym(&ev->xkey, 0))) { + if(sym == XK_Escape) { + sym = 27; + } + app_keyboard(sym, ev->type == KeyPress); + } + break; + + case ClientMessage: + if(ev->xclient.message_type == xa_wm_proto) { + if(ev->xclient.data.l[0] == xa_wm_delwin) { + app_quit(); + } + } + break; + + default: + break; + } + + return 0; +}