eqemu
diff src/main.cc @ 0:01fb0dee8a92
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 15 Jul 2014 04:46:10 +0300 |
parents | |
children | 374d91dd2996 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/main.cc Tue Jul 15 04:46:10 2014 +0300 1.3 @@ -0,0 +1,287 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <assert.h> 1.7 +#include <errno.h> 1.8 +#include <unistd.h> 1.9 +#include <sys/select.h> 1.10 +#include <GL/glew.h> 1.11 +#include <X11/Xlib.h> 1.12 +#include <GL/glx.h> 1.13 + 1.14 +static bool init(); 1.15 +static void cleanup(); 1.16 +static void display(); 1.17 +static void keyb(int key, bool pressed); 1.18 +static void mouse(int bn, bool pressed, int x, int y); 1.19 +static void motion(int x, int y); 1.20 + 1.21 +static Window create_window(const char *title, int xsz, int ysz); 1.22 +static void process_events(); 1.23 +static int translate_keysym(KeySym sym); 1.24 + 1.25 +static Display *dpy; 1.26 +static Window win; 1.27 +static GLXContext ctx; 1.28 +static Atom xa_wm_prot, xa_wm_del_win; 1.29 + 1.30 +static int win_width, win_height; 1.31 + 1.32 +static bool redisplay_pending; 1.33 +static bool win_mapped; 1.34 + 1.35 +int main() 1.36 +{ 1.37 + if(!init()) { 1.38 + fprintf(stderr, "X11/OpenGL initialization failed\n"); 1.39 + return 1; 1.40 + } 1.41 + atexit(cleanup); 1.42 + 1.43 + int xfd = ConnectionNumber(dpy); 1.44 + 1.45 + for(;;) { 1.46 + fd_set rd; 1.47 + FD_ZERO(&rd); 1.48 + 1.49 + FD_SET(xfd, &rd); 1.50 + 1.51 + while(select(xfd + 1, &rd, 0, 0, 0) == -1 && errno == EINTR); 1.52 + 1.53 + if(FD_ISSET(xfd, &rd)) { 1.54 + process_events(); 1.55 + } 1.56 + 1.57 + if(redisplay_pending) { 1.58 + display(); 1.59 + redisplay_pending = false; 1.60 + } 1.61 + } 1.62 + return 0; 1.63 +} 1.64 + 1.65 +static bool init() 1.66 +{ 1.67 + if(!(dpy = XOpenDisplay(0))) { 1.68 + fprintf(stderr, "failed to connect to the X server!\n"); 1.69 + return false; 1.70 + } 1.71 + 1.72 + if(!(win = create_window("dummy equeue device", 800, 600))) { 1.73 + return false; 1.74 + } 1.75 + 1.76 + return true; 1.77 +} 1.78 + 1.79 +static void cleanup() 1.80 +{ 1.81 + if(!dpy) return; 1.82 + 1.83 + if(win) { 1.84 + XDestroyWindow(dpy, win); 1.85 + } 1.86 + XCloseDisplay(dpy); 1.87 +} 1.88 + 1.89 +static void display() 1.90 +{ 1.91 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1.92 + 1.93 + glMatrixMode(GL_MODELVIEW); 1.94 + glLoadIdentity(); 1.95 + 1.96 + glXSwapBuffers(dpy, win); 1.97 + assert(glGetError() == GL_NO_ERROR); 1.98 +} 1.99 + 1.100 +static void reshape(int x, int y) 1.101 +{ 1.102 + glViewport(0, 0, x, y); 1.103 + 1.104 + glMatrixMode(GL_PROJECTION); 1.105 + glLoadIdentity(); 1.106 + gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0); 1.107 +} 1.108 + 1.109 +static void keyb(int key, bool pressed) 1.110 +{ 1.111 + if(pressed) { 1.112 + switch(key) { 1.113 + case 27: 1.114 + exit(0); 1.115 + } 1.116 + } 1.117 +} 1.118 + 1.119 +static void mouse(int bn, bool pressed, int x, int y) 1.120 +{ 1.121 +} 1.122 + 1.123 +static void motion(int x, int y) 1.124 +{ 1.125 +} 1.126 + 1.127 +static Window create_window(const char *title, int xsz, int ysz) 1.128 +{ 1.129 + int scr = DefaultScreen(dpy); 1.130 + Window root = RootWindow(dpy, scr); 1.131 + 1.132 + int glxattr[] = { 1.133 + GLX_RGBA, 1.134 + GLX_RED_SIZE, 8, 1.135 + GLX_GREEN_SIZE, 8, 1.136 + GLX_BLUE_SIZE, 8, 1.137 + GLX_DEPTH_SIZE, 24, 1.138 + GLX_DOUBLEBUFFER, 1.139 +#if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample) 1.140 + GLX_SAMPLE_BUFFERS_ARB, 1, 1.141 + GLX_SAMPLES_ARB, 1, 1.142 +#endif 1.143 + None 1.144 + }; 1.145 + 1.146 + XVisualInfo *vis = glXChooseVisual(dpy, scr, glxattr); 1.147 + if(!vis) { 1.148 + fprintf(stderr, "failed to find a suitable visual\n"); 1.149 + return 0; 1.150 + } 1.151 + 1.152 + if(!(ctx = glXCreateContext(dpy, vis, 0, True))) { 1.153 + fprintf(stderr, "failed to create OpenGL context\n"); 1.154 + XFree(vis); 1.155 + return -1; 1.156 + } 1.157 + 1.158 + XSetWindowAttributes xattr; 1.159 + xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr); 1.160 + xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone); 1.161 + unsigned int xattr_mask = CWColormap | CWBackPixel | CWBorderPixel; 1.162 + 1.163 + Window win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput, 1.164 + vis->visual, xattr_mask, &xattr); 1.165 + if(!win) { 1.166 + fprintf(stderr, "failed to create window\n"); 1.167 + glXDestroyContext(dpy, ctx); 1.168 + XFree(vis); 1.169 + return -1; 1.170 + } 1.171 + XFree(vis); 1.172 + 1.173 + unsigned int evmask = StructureNotifyMask | VisibilityChangeMask | ExposureMask | 1.174 + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | 1.175 + ButtonMotionMask | PointerMotionMask; 1.176 + XSelectInput(dpy, win, evmask); 1.177 + 1.178 + xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False); 1.179 + xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 1.180 + XSetWMProtocols(dpy, win, &xa_wm_del_win, 1); 1.181 + 1.182 + XClassHint hint; 1.183 + hint.res_name = hint.res_class = (char*)"equeue_win"; 1.184 + XSetClassHint(dpy, win, &hint); 1.185 + 1.186 + XTextProperty wm_name; 1.187 + XStringListToTextProperty((char**)&title, 1, &wm_name); 1.188 + XSetWMName(dpy, win, &wm_name); 1.189 + XSetWMIconName(dpy, win, &wm_name); 1.190 + XFree(wm_name.value); 1.191 + 1.192 + XMapWindow(dpy, win); 1.193 + glXMakeCurrent(dpy, win, ctx); 1.194 + 1.195 + return win; 1.196 +} 1.197 + 1.198 +static void process_events() 1.199 +{ 1.200 + XEvent ev; 1.201 + 1.202 + while(XPending(dpy)) { 1.203 + XNextEvent(dpy, &ev); 1.204 + switch(ev.type) { 1.205 + case MapNotify: 1.206 + win_mapped = true; 1.207 + break; 1.208 + 1.209 + case UnmapNotify: 1.210 + win_mapped = false; 1.211 + break; 1.212 + 1.213 + case Expose: 1.214 + if(win_mapped && ev.xexpose.count == 0) { 1.215 + redisplay_pending = 1; 1.216 + } 1.217 + break; 1.218 + 1.219 + case MotionNotify: 1.220 + motion(ev.xmotion.x, ev.xmotion.y); 1.221 + break; 1.222 + 1.223 + case ButtonPress: 1.224 + mouse(ev.xbutton.button - 1, true, ev.xbutton.x, ev.xbutton.y); 1.225 + break; 1.226 + 1.227 + case ButtonRelease: 1.228 + mouse(ev.xbutton.button - 1, false, ev.xbutton.x, ev.xbutton.y); 1.229 + break; 1.230 + 1.231 + case KeyPress: 1.232 + { 1.233 + KeySym sym = XLookupKeysym(&ev.xkey, 0); 1.234 + keyb(translate_keysym(sym), true); 1.235 + } 1.236 + break; 1.237 + 1.238 + case KeyRelease: 1.239 + { 1.240 + KeySym sym = XLookupKeysym(&ev.xkey, 0); 1.241 + keyb(translate_keysym(sym), false); 1.242 + } 1.243 + break; 1.244 + 1.245 + case ConfigureNotify: 1.246 + { 1.247 + int xsz = ev.xconfigure.width; 1.248 + int ysz = ev.xconfigure.height; 1.249 + 1.250 + if(xsz != win_width || ysz != win_height) { 1.251 + win_width = xsz; 1.252 + win_height = ysz; 1.253 + reshape(xsz, ysz); 1.254 + } 1.255 + } 1.256 + break; 1.257 + 1.258 + case ClientMessage: 1.259 + if(ev.xclient.message_type == xa_wm_prot) { 1.260 + if((Atom)ev.xclient.data.l[0] == xa_wm_del_win) { 1.261 + exit(0); 1.262 + } 1.263 + } 1.264 + break; 1.265 + 1.266 + default: 1.267 + break; 1.268 + } 1.269 + 1.270 + } 1.271 +} 1.272 + 1.273 +static int translate_keysym(KeySym sym) 1.274 +{ 1.275 + switch(sym) { 1.276 + case XK_BackSpace: 1.277 + return '\b'; 1.278 + case XK_Tab: 1.279 + return '\t'; 1.280 + case XK_Linefeed: 1.281 + return '\r'; 1.282 + case XK_Return: 1.283 + return '\n'; 1.284 + case XK_Escape: 1.285 + return 27; 1.286 + default: 1.287 + break; 1.288 + } 1.289 + return (int)sym; 1.290 +}