doorbell
diff spycam/src/main.cc @ 0:a5755687dd75
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 08 Mar 2016 03:26:01 +0200 |
parents | |
children | daade2a35e69 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/spycam/src/main.cc Tue Mar 08 03:26:01 2016 +0200 1.3 @@ -0,0 +1,236 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <unistd.h> 1.7 +#include <sys/select.h> 1.8 +#include <X11/Xlib.h> 1.9 +#include <X11/Xatom.h> 1.10 +#include <GLES2/gl2.h> 1.11 +#include <EGL/egl.h> 1.12 +#include "spycam.h" 1.13 + 1.14 +static void cleanup(); 1.15 +static bool create_glwin(int xsz, int ysz); 1.16 +static bool handle_event(XEvent *ev); 1.17 +static void set_window_title(const char *title); 1.18 + 1.19 +static int win_width, win_height; 1.20 +static bool quit, redraw_pending; 1.21 +static Display *dpy; 1.22 +static Window win; 1.23 +static EGLDisplay egl_dpy; 1.24 +static EGLContext egl_ctx; 1.25 +static EGLSurface egl_win; 1.26 +static Atom xa_wm_proto, xa_del_window; 1.27 + 1.28 +int main(int argc, char **argv) 1.29 +{ 1.30 + if(!(dpy = XOpenDisplay(0))) { 1.31 + fprintf(stderr, "failed to connect to the X server.\n"); 1.32 + return 1; 1.33 + } 1.34 + xa_wm_proto = XInternAtom(dpy, "WM_PROTOCOLS", False); 1.35 + xa_del_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 1.36 + 1.37 + egl_dpy = eglGetDisplay(dpy); 1.38 + int egl_ver_major, egl_ver_minor; 1.39 + if(!eglInitialize(egl_dpy, &egl_ver_major, &egl_ver_minor)) { 1.40 + fprintf(stderr, "failed to initialize EGL\n"); 1.41 + return 1; 1.42 + } 1.43 + printf("initialized EGL %d.%d\n", egl_ver_major, egl_ver_minor); 1.44 + 1.45 + if(!create_glwin(800, 600)) { 1.46 + cleanup(); 1.47 + return 1; 1.48 + } 1.49 + 1.50 + if(!app_init()) { 1.51 + cleanup(); 1.52 + return 1; 1.53 + } 1.54 + 1.55 + for(;;) { 1.56 + while(XPending(dpy) || !redraw_pending) { 1.57 + XEvent ev; 1.58 + XNextEvent(dpy, &ev); 1.59 + if(!handle_event(&ev) || quit) { 1.60 + goto break_main_loop; 1.61 + } 1.62 + } 1.63 + 1.64 + if(redraw_pending) { 1.65 + app_draw(); 1.66 + eglSwapBuffers(egl_dpy, egl_win); 1.67 + } 1.68 + } 1.69 +break_main_loop: 1.70 + 1.71 + cleanup(); 1.72 + return 0; 1.73 +} 1.74 + 1.75 +void app_quit() 1.76 +{ 1.77 + quit = true; 1.78 +} 1.79 + 1.80 +void app_redisplay() 1.81 +{ 1.82 + redraw_pending = true; 1.83 +} 1.84 + 1.85 +static void cleanup() 1.86 +{ 1.87 + if(egl_dpy) { 1.88 + eglMakeCurrent(egl_dpy, 0, 0, 0); 1.89 + if(egl_win) 1.90 + eglDestroySurface(egl_dpy, egl_win); 1.91 + if(egl_ctx) 1.92 + eglDestroyContext(egl_dpy, egl_ctx); 1.93 + eglTerminate(egl_dpy); 1.94 + } 1.95 + if(dpy) { 1.96 + if(win) 1.97 + XDestroyWindow(dpy, win); 1.98 + XCloseDisplay(dpy); 1.99 + } 1.100 +} 1.101 + 1.102 +static bool create_glwin(int xsz, int ysz) 1.103 +{ 1.104 + static const int egl_attr[] = { 1.105 + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 1.106 + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 1.107 + EGL_RED_SIZE, 5, 1.108 + EGL_GREEN_SIZE, 5, 1.109 + EGL_BLUE_SIZE, 5, 1.110 + EGL_DEPTH_SIZE, 16, 1.111 + EGL_NONE 1.112 + }; 1.113 + 1.114 + int scr = DefaultScreen(dpy); 1.115 + Window root_win = RootWindow(dpy, scr); 1.116 + 1.117 + EGLConfig cfg; 1.118 + int num_cfg; 1.119 + if(!eglChooseConfig(egl_dpy, egl_attr, &cfg, 1, &num_cfg)) { 1.120 + fprintf(stderr, "failed to find matching EGL visual\n"); 1.121 + return false; 1.122 + } 1.123 + int rsize, gsize, bsize, zsize, ssize, vis_id; 1.124 + eglGetConfigAttrib(egl_dpy, cfg, EGL_RED_SIZE, &rsize); 1.125 + eglGetConfigAttrib(egl_dpy, cfg, EGL_GREEN_SIZE, &gsize); 1.126 + eglGetConfigAttrib(egl_dpy, cfg, EGL_BLUE_SIZE, &bsize); 1.127 + eglGetConfigAttrib(egl_dpy, cfg, EGL_DEPTH_SIZE, &zsize); 1.128 + eglGetConfigAttrib(egl_dpy, cfg, EGL_STENCIL_SIZE, &ssize); 1.129 + eglGetConfigAttrib(egl_dpy, cfg, EGL_NATIVE_VISUAL_ID, &vis_id); 1.130 + printf("got visual %d: %d bpp (%d%d%d), %d zbuffer, %d stencil\n", vis_id, rsize + gsize + bsize, 1.131 + rsize, gsize, bsize, zsize, ssize); 1.132 + 1.133 + int num_vis; 1.134 + XVisualInfo *vis_info, vis_template; 1.135 + vis_template.visualid = vis_id; 1.136 + if(!(vis_info = XGetVisualInfo(dpy, VisualIDMask, &vis_template, &num_vis))) { 1.137 + fprintf(stderr, "visual id %d is invalid (?!)\n", vis_id); 1.138 + return false; 1.139 + } 1.140 + 1.141 + XSetWindowAttributes xattr; 1.142 + xattr.border_pixel = xattr.backing_pixel = BlackPixel(dpy, scr); 1.143 + xattr.colormap = XCreateColormap(dpy, root_win, vis_info->visual, AllocNone); 1.144 + unsigned int xattr_mask = CWColormap | CWBorderPixel | CWBackPixel; 1.145 + 1.146 + win = XCreateWindow(dpy, root_win, 0, 0, xsz, ysz, 0, vis_info->depth, InputOutput, 1.147 + vis_info->visual, xattr_mask, &xattr); 1.148 + if(!win) { 1.149 + fprintf(stderr, "failed to create window\n"); 1.150 + XFree(vis_info); 1.151 + return false; 1.152 + } 1.153 + XFree(vis_info); 1.154 + XSelectInput(dpy, win, ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask); 1.155 + 1.156 + XSetWMProtocols(dpy, win, &xa_del_window, 1); 1.157 + set_window_title("spycam"); 1.158 + 1.159 + eglBindAPI(EGL_OPENGL_ES_API); 1.160 + 1.161 + if(!(egl_win = eglCreateWindowSurface(egl_dpy, cfg, win, 0))) { 1.162 + fprintf(stderr, "failed to create EGL window\n"); 1.163 + XDestroyWindow(dpy, win); 1.164 + return false; 1.165 + } 1.166 + 1.167 + static const int ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 1.168 + if(!(egl_ctx = eglCreateContext(egl_dpy, cfg, EGL_NO_CONTEXT, ctxattr))) { 1.169 + fprintf(stderr, "failed to create EGL context\n"); 1.170 + eglDestroySurface(egl_dpy, egl_win); 1.171 + XDestroyWindow(dpy, win); 1.172 + return false; 1.173 + } 1.174 + eglMakeCurrent(egl_dpy, egl_win, egl_win, egl_ctx); 1.175 + 1.176 + XMapWindow(dpy, win); 1.177 + 1.178 + eglQuerySurface(dpy, egl_win, EGL_WIDTH, &win_width); 1.179 + eglQuerySurface(dpy, egl_win, EGL_HEIGHT, &win_height); 1.180 + app_reshape(win_width, win_height); 1.181 + 1.182 + return true; 1.183 +} 1.184 + 1.185 +static bool handle_event(XEvent *ev) 1.186 +{ 1.187 + static bool mapped; 1.188 + 1.189 + switch(ev->type) { 1.190 + case Expose: 1.191 + if(mapped) { 1.192 + redraw_pending = true; 1.193 + } 1.194 + break; 1.195 + 1.196 + case MapNotify: 1.197 + mapped = true; 1.198 + redraw_pending = true; 1.199 + break; 1.200 + 1.201 + case UnmapNotify: 1.202 + mapped = false; 1.203 + redraw_pending = false; 1.204 + break; 1.205 + 1.206 + case ConfigureNotify: 1.207 + if(win_width != (int)ev->xconfigure.width || win_height != (int)ev->xconfigure.height) { 1.208 + win_width = ev->xconfigure.width; 1.209 + win_height = ev->xconfigure.height; 1.210 + app_reshape(win_width, win_height); 1.211 + } 1.212 + break; 1.213 + 1.214 + case KeyPress: 1.215 + case KeyRelease: 1.216 + app_keyboard(XLookupKeysym(&ev->xkey, 0) & 0xff, ev->type == KeyPress); 1.217 + break; 1.218 + 1.219 + case ClientMessage: 1.220 + if(ev->xclient.message_type == xa_wm_proto && 1.221 + (Atom)ev->xclient.data.l[0] == xa_del_window) { 1.222 + return false; 1.223 + } 1.224 + break; 1.225 + 1.226 + default: 1.227 + break; 1.228 + } 1.229 + return true; 1.230 +} 1.231 + 1.232 +static void set_window_title(const char *title) 1.233 +{ 1.234 + XTextProperty text_prop; 1.235 + XStringListToTextProperty((char**)&title, 1, &text_prop); 1.236 + XSetWMName(dpy, win, &text_prop); 1.237 + XSetWMIconName(dpy, win, &text_prop); 1.238 + XFree(text_prop.value); 1.239 +}