nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: static bool init(); nuclear@0: static void cleanup(); nuclear@0: static void display(); nuclear@0: static void keyb(int key, bool pressed); nuclear@0: static void mouse(int bn, bool pressed, int x, int y); nuclear@0: static void motion(int x, int y); nuclear@0: nuclear@0: static Window create_window(const char *title, int xsz, int ysz); nuclear@0: static void process_events(); nuclear@0: static int translate_keysym(KeySym sym); nuclear@0: nuclear@0: static Display *dpy; nuclear@0: static Window win; nuclear@0: static GLXContext ctx; nuclear@0: static Atom xa_wm_prot, xa_wm_del_win; nuclear@0: nuclear@0: static int win_width, win_height; nuclear@0: nuclear@0: static bool redisplay_pending; nuclear@0: static bool win_mapped; nuclear@0: nuclear@0: int main() nuclear@0: { nuclear@0: if(!init()) { nuclear@0: fprintf(stderr, "X11/OpenGL initialization failed\n"); nuclear@0: return 1; nuclear@0: } nuclear@0: atexit(cleanup); nuclear@0: nuclear@0: int xfd = ConnectionNumber(dpy); nuclear@0: nuclear@0: for(;;) { nuclear@0: fd_set rd; nuclear@0: FD_ZERO(&rd); nuclear@0: nuclear@0: FD_SET(xfd, &rd); nuclear@0: nuclear@0: while(select(xfd + 1, &rd, 0, 0, 0) == -1 && errno == EINTR); nuclear@0: nuclear@0: if(FD_ISSET(xfd, &rd)) { nuclear@0: process_events(); nuclear@0: } nuclear@0: nuclear@0: if(redisplay_pending) { nuclear@0: display(); nuclear@0: redisplay_pending = false; nuclear@0: } nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static bool init() nuclear@0: { nuclear@0: if(!(dpy = XOpenDisplay(0))) { nuclear@0: fprintf(stderr, "failed to connect to the X server!\n"); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: if(!(win = create_window("dummy equeue device", 800, 600))) { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: static void cleanup() nuclear@0: { nuclear@0: if(!dpy) return; nuclear@0: nuclear@0: if(win) { nuclear@0: XDestroyWindow(dpy, win); nuclear@0: } nuclear@0: XCloseDisplay(dpy); nuclear@0: } nuclear@0: nuclear@0: static void display() nuclear@0: { nuclear@0: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glLoadIdentity(); nuclear@0: nuclear@0: glXSwapBuffers(dpy, win); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: } nuclear@0: nuclear@0: static void reshape(int x, int y) nuclear@0: { nuclear@0: glViewport(0, 0, x, y); nuclear@0: nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glLoadIdentity(); nuclear@0: gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0); nuclear@0: } nuclear@0: nuclear@0: static void keyb(int key, bool pressed) nuclear@0: { nuclear@0: if(pressed) { nuclear@0: switch(key) { nuclear@0: case 27: nuclear@0: exit(0); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static void mouse(int bn, bool pressed, int x, int y) nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: static void motion(int x, int y) nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: static Window create_window(const char *title, int xsz, int ysz) nuclear@0: { nuclear@0: int scr = DefaultScreen(dpy); nuclear@0: Window root = RootWindow(dpy, scr); nuclear@0: nuclear@0: int glxattr[] = { nuclear@0: GLX_RGBA, nuclear@0: GLX_RED_SIZE, 8, nuclear@0: GLX_GREEN_SIZE, 8, nuclear@0: GLX_BLUE_SIZE, 8, nuclear@0: GLX_DEPTH_SIZE, 24, nuclear@0: GLX_DOUBLEBUFFER, nuclear@0: #if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample) nuclear@0: GLX_SAMPLE_BUFFERS_ARB, 1, nuclear@0: GLX_SAMPLES_ARB, 1, nuclear@0: #endif nuclear@0: None nuclear@0: }; nuclear@0: nuclear@0: XVisualInfo *vis = glXChooseVisual(dpy, scr, glxattr); nuclear@0: if(!vis) { nuclear@0: fprintf(stderr, "failed to find a suitable visual\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: if(!(ctx = glXCreateContext(dpy, vis, 0, True))) { nuclear@0: fprintf(stderr, "failed to create OpenGL context\n"); nuclear@0: XFree(vis); nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: XSetWindowAttributes xattr; nuclear@0: xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr); nuclear@0: xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone); nuclear@0: unsigned int xattr_mask = CWColormap | CWBackPixel | CWBorderPixel; nuclear@0: nuclear@0: Window win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput, nuclear@0: vis->visual, xattr_mask, &xattr); nuclear@0: if(!win) { nuclear@0: fprintf(stderr, "failed to create window\n"); nuclear@0: glXDestroyContext(dpy, ctx); nuclear@0: XFree(vis); nuclear@0: return -1; nuclear@0: } nuclear@0: XFree(vis); nuclear@0: nuclear@0: unsigned int evmask = StructureNotifyMask | VisibilityChangeMask | ExposureMask | nuclear@0: KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | nuclear@0: ButtonMotionMask | PointerMotionMask; nuclear@0: XSelectInput(dpy, win, evmask); nuclear@0: nuclear@0: xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False); nuclear@0: xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False); nuclear@0: XSetWMProtocols(dpy, win, &xa_wm_del_win, 1); nuclear@0: nuclear@0: XClassHint hint; nuclear@0: hint.res_name = hint.res_class = (char*)"equeue_win"; nuclear@0: XSetClassHint(dpy, win, &hint); nuclear@0: nuclear@0: XTextProperty wm_name; nuclear@0: XStringListToTextProperty((char**)&title, 1, &wm_name); nuclear@0: XSetWMName(dpy, win, &wm_name); nuclear@0: XSetWMIconName(dpy, win, &wm_name); nuclear@0: XFree(wm_name.value); nuclear@0: nuclear@0: XMapWindow(dpy, win); nuclear@0: glXMakeCurrent(dpy, win, ctx); nuclear@0: nuclear@0: return win; nuclear@0: } nuclear@0: nuclear@0: static void process_events() nuclear@0: { nuclear@0: XEvent ev; nuclear@0: nuclear@0: while(XPending(dpy)) { nuclear@0: XNextEvent(dpy, &ev); nuclear@0: switch(ev.type) { nuclear@0: case MapNotify: nuclear@0: win_mapped = true; nuclear@0: break; nuclear@0: nuclear@0: case UnmapNotify: nuclear@0: win_mapped = false; nuclear@0: break; nuclear@0: nuclear@0: case Expose: nuclear@0: if(win_mapped && ev.xexpose.count == 0) { nuclear@0: redisplay_pending = 1; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case MotionNotify: nuclear@0: motion(ev.xmotion.x, ev.xmotion.y); nuclear@0: break; nuclear@0: nuclear@0: case ButtonPress: nuclear@0: mouse(ev.xbutton.button - 1, true, ev.xbutton.x, ev.xbutton.y); nuclear@0: break; nuclear@0: nuclear@0: case ButtonRelease: nuclear@0: mouse(ev.xbutton.button - 1, false, ev.xbutton.x, ev.xbutton.y); nuclear@0: break; nuclear@0: nuclear@0: case KeyPress: nuclear@0: { nuclear@0: KeySym sym = XLookupKeysym(&ev.xkey, 0); nuclear@0: keyb(translate_keysym(sym), true); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case KeyRelease: nuclear@0: { nuclear@0: KeySym sym = XLookupKeysym(&ev.xkey, 0); nuclear@0: keyb(translate_keysym(sym), false); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case ConfigureNotify: nuclear@0: { nuclear@0: int xsz = ev.xconfigure.width; nuclear@0: int ysz = ev.xconfigure.height; nuclear@0: nuclear@0: if(xsz != win_width || ysz != win_height) { nuclear@0: win_width = xsz; nuclear@0: win_height = ysz; nuclear@0: reshape(xsz, ysz); nuclear@0: } nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case ClientMessage: nuclear@0: if(ev.xclient.message_type == xa_wm_prot) { nuclear@0: if((Atom)ev.xclient.data.l[0] == xa_wm_del_win) { nuclear@0: exit(0); nuclear@0: } nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static int translate_keysym(KeySym sym) nuclear@0: { nuclear@0: switch(sym) { nuclear@0: case XK_BackSpace: nuclear@0: return '\b'; nuclear@0: case XK_Tab: nuclear@0: return '\t'; nuclear@0: case XK_Linefeed: nuclear@0: return '\r'; nuclear@0: case XK_Return: nuclear@0: return '\n'; nuclear@0: case XK_Escape: nuclear@0: return 27; nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: return (int)sym; nuclear@0: }