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