eqemu

view 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 source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <sys/select.h>
7 #include <GL/glew.h>
8 #include <X11/Xlib.h>
9 #include <GL/glx.h>
11 static bool init();
12 static void cleanup();
13 static void display();
14 static void keyb(int key, bool pressed);
15 static void mouse(int bn, bool pressed, int x, int y);
16 static void motion(int x, int y);
18 static Window create_window(const char *title, int xsz, int ysz);
19 static void process_events();
20 static int translate_keysym(KeySym sym);
22 static Display *dpy;
23 static Window win;
24 static GLXContext ctx;
25 static Atom xa_wm_prot, xa_wm_del_win;
27 static int win_width, win_height;
29 static bool redisplay_pending;
30 static bool win_mapped;
32 int main()
33 {
34 if(!init()) {
35 fprintf(stderr, "X11/OpenGL initialization failed\n");
36 return 1;
37 }
38 atexit(cleanup);
40 int xfd = ConnectionNumber(dpy);
42 for(;;) {
43 fd_set rd;
44 FD_ZERO(&rd);
46 FD_SET(xfd, &rd);
48 while(select(xfd + 1, &rd, 0, 0, 0) == -1 && errno == EINTR);
50 if(FD_ISSET(xfd, &rd)) {
51 process_events();
52 }
54 if(redisplay_pending) {
55 display();
56 redisplay_pending = false;
57 }
58 }
59 return 0;
60 }
62 static bool init()
63 {
64 if(!(dpy = XOpenDisplay(0))) {
65 fprintf(stderr, "failed to connect to the X server!\n");
66 return false;
67 }
69 if(!(win = create_window("dummy equeue device", 800, 600))) {
70 return false;
71 }
73 return true;
74 }
76 static void cleanup()
77 {
78 if(!dpy) return;
80 if(win) {
81 XDestroyWindow(dpy, win);
82 }
83 XCloseDisplay(dpy);
84 }
86 static void display()
87 {
88 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
90 glMatrixMode(GL_MODELVIEW);
91 glLoadIdentity();
93 glXSwapBuffers(dpy, win);
94 assert(glGetError() == GL_NO_ERROR);
95 }
97 static void reshape(int x, int y)
98 {
99 glViewport(0, 0, x, y);
101 glMatrixMode(GL_PROJECTION);
102 glLoadIdentity();
103 gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0);
104 }
106 static void keyb(int key, bool pressed)
107 {
108 if(pressed) {
109 switch(key) {
110 case 27:
111 exit(0);
112 }
113 }
114 }
116 static void mouse(int bn, bool pressed, int x, int y)
117 {
118 }
120 static void motion(int x, int y)
121 {
122 }
124 static Window create_window(const char *title, int xsz, int ysz)
125 {
126 int scr = DefaultScreen(dpy);
127 Window root = RootWindow(dpy, scr);
129 int glxattr[] = {
130 GLX_RGBA,
131 GLX_RED_SIZE, 8,
132 GLX_GREEN_SIZE, 8,
133 GLX_BLUE_SIZE, 8,
134 GLX_DEPTH_SIZE, 24,
135 GLX_DOUBLEBUFFER,
136 #if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample)
137 GLX_SAMPLE_BUFFERS_ARB, 1,
138 GLX_SAMPLES_ARB, 1,
139 #endif
140 None
141 };
143 XVisualInfo *vis = glXChooseVisual(dpy, scr, glxattr);
144 if(!vis) {
145 fprintf(stderr, "failed to find a suitable visual\n");
146 return 0;
147 }
149 if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
150 fprintf(stderr, "failed to create OpenGL context\n");
151 XFree(vis);
152 return -1;
153 }
155 XSetWindowAttributes xattr;
156 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
157 xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
158 unsigned int xattr_mask = CWColormap | CWBackPixel | CWBorderPixel;
160 Window win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
161 vis->visual, xattr_mask, &xattr);
162 if(!win) {
163 fprintf(stderr, "failed to create window\n");
164 glXDestroyContext(dpy, ctx);
165 XFree(vis);
166 return -1;
167 }
168 XFree(vis);
170 unsigned int evmask = StructureNotifyMask | VisibilityChangeMask | ExposureMask |
171 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
172 ButtonMotionMask | PointerMotionMask;
173 XSelectInput(dpy, win, evmask);
175 xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
176 xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
177 XSetWMProtocols(dpy, win, &xa_wm_del_win, 1);
179 XClassHint hint;
180 hint.res_name = hint.res_class = (char*)"equeue_win";
181 XSetClassHint(dpy, win, &hint);
183 XTextProperty wm_name;
184 XStringListToTextProperty((char**)&title, 1, &wm_name);
185 XSetWMName(dpy, win, &wm_name);
186 XSetWMIconName(dpy, win, &wm_name);
187 XFree(wm_name.value);
189 XMapWindow(dpy, win);
190 glXMakeCurrent(dpy, win, ctx);
192 return win;
193 }
195 static void process_events()
196 {
197 XEvent ev;
199 while(XPending(dpy)) {
200 XNextEvent(dpy, &ev);
201 switch(ev.type) {
202 case MapNotify:
203 win_mapped = true;
204 break;
206 case UnmapNotify:
207 win_mapped = false;
208 break;
210 case Expose:
211 if(win_mapped && ev.xexpose.count == 0) {
212 redisplay_pending = 1;
213 }
214 break;
216 case MotionNotify:
217 motion(ev.xmotion.x, ev.xmotion.y);
218 break;
220 case ButtonPress:
221 mouse(ev.xbutton.button - 1, true, ev.xbutton.x, ev.xbutton.y);
222 break;
224 case ButtonRelease:
225 mouse(ev.xbutton.button - 1, false, ev.xbutton.x, ev.xbutton.y);
226 break;
228 case KeyPress:
229 {
230 KeySym sym = XLookupKeysym(&ev.xkey, 0);
231 keyb(translate_keysym(sym), true);
232 }
233 break;
235 case KeyRelease:
236 {
237 KeySym sym = XLookupKeysym(&ev.xkey, 0);
238 keyb(translate_keysym(sym), false);
239 }
240 break;
242 case ConfigureNotify:
243 {
244 int xsz = ev.xconfigure.width;
245 int ysz = ev.xconfigure.height;
247 if(xsz != win_width || ysz != win_height) {
248 win_width = xsz;
249 win_height = ysz;
250 reshape(xsz, ysz);
251 }
252 }
253 break;
255 case ClientMessage:
256 if(ev.xclient.message_type == xa_wm_prot) {
257 if((Atom)ev.xclient.data.l[0] == xa_wm_del_win) {
258 exit(0);
259 }
260 }
261 break;
263 default:
264 break;
265 }
267 }
268 }
270 static int translate_keysym(KeySym sym)
271 {
272 switch(sym) {
273 case XK_BackSpace:
274 return '\b';
275 case XK_Tab:
276 return '\t';
277 case XK_Linefeed:
278 return '\r';
279 case XK_Return:
280 return '\n';
281 case XK_Escape:
282 return 27;
283 default:
284 break;
285 }
286 return (int)sym;
287 }