]> git.cworth.org Git - apitrace/blob - glws_glx.cpp
Simplify glws class hierarchy.
[apitrace] / glws_glx.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 #include <stdlib.h>
27 #include <iostream>
28
29 #include "glws.hpp"
30
31 #include <X11/Xlib.h>
32 #include <GL/gl.h>
33 #include <GL/glx.h>
34
35
36 namespace glws {
37
38
39 static Display *display = NULL;
40 static int screen = 0;
41
42
43 class GlxVisual : public Visual
44 {
45 public:
46     XVisualInfo *visinfo;
47
48     GlxVisual(XVisualInfo *vi) :
49         visinfo(vi)
50     {}
51
52     ~GlxVisual() {
53         XFree(visinfo);
54     }
55 };
56
57
58 static void describeEvent(const XEvent &event) {
59     if (0) {
60         switch (event.type) {
61         case ConfigureNotify:
62             std::cerr << "ConfigureNotify";
63             break;
64         case Expose:
65             std::cerr << "Expose";
66             break;
67         case KeyPress:
68             std::cerr << "KeyPress";
69             break;
70         case MapNotify:
71             std::cerr << "MapNotify";
72             break;
73         case ReparentNotify:
74             std::cerr << "ReparentNotify";
75             break;
76         default:
77             std::cerr << "Event " << event.type;
78         }
79         std::cerr << " " << event.xany.window << "\n";
80     }
81 }
82
83 static void waitForEvent(Window window, int type) {
84     XFlush(display);
85     XEvent event;
86     do {
87         XNextEvent(display, &event);
88         describeEvent(event);
89     } while (event.type != type ||
90              event.xany.window != window);
91 }
92
93
94 class GlxDrawable : public Drawable
95 {
96 public:
97     Window window;
98
99     GlxDrawable(const Visual *vis, int w, int h) :
100         Drawable(vis, w, h)
101     {
102         XVisualInfo *visinfo = dynamic_cast<const GlxVisual *>(visual)->visinfo;
103
104         Window root = RootWindow(display, screen);
105
106         /* window attributes */
107         XSetWindowAttributes attr;
108         attr.background_pixel = 0;
109         attr.border_pixel = 0;
110         attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
111         attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
112
113         unsigned long mask;
114         mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
115
116         int x = 0, y = 0;
117
118         window = XCreateWindow(
119             display, root,
120             x, y, width, height,
121             0,
122             visinfo->depth,
123             InputOutput,
124             visinfo->visual,
125             mask,
126             &attr);
127
128         XSizeHints sizehints;
129         sizehints.x = x;
130         sizehints.y = y;
131         sizehints.width  = width;
132         sizehints.height = height;
133         sizehints.flags = USSize | USPosition;
134         XSetNormalHints(display, window, &sizehints);
135
136         const char *name = "glretrace";
137         XSetStandardProperties(
138             display, window, name, name,
139             None, (char **)NULL, 0, &sizehints);
140
141         glXWaitX();
142     }
143
144     ~GlxDrawable() {
145         XDestroyWindow(display, window);
146     }
147
148     void
149     resize(int w, int h) {
150         glXWaitGL();
151
152         // We need to ensure that pending events are processed here, and XSync
153         // with discard = True guarantees that, but it appears the limited
154         // event processing we do so far is sufficient
155         //XSync(display, True);
156
157         Drawable::resize(w, h);
158
159         XResizeWindow(display, window, w, h);
160
161         // Tell the window manager to respect the requested size
162         XSizeHints *size_hints;
163         size_hints = XAllocSizeHints();
164         size_hints->max_width  = size_hints->min_width  = w;
165         size_hints->max_height = size_hints->min_height = h;
166         size_hints->flags = PMinSize | PMaxSize;
167         XSetWMNormalHints(display, window, size_hints);
168         XFree(size_hints);
169
170         waitForEvent(window, ConfigureNotify);
171
172         glXWaitX();
173     }
174
175     void show(void) {
176         if (!visible) {
177             XMapWindow(display, window);
178
179             waitForEvent(window, Expose);
180
181             Drawable::show();
182         }
183     }
184
185     void swapBuffers(void) {
186         glXSwapBuffers(display, window);
187     }
188 };
189
190
191 class GlxContext : public Context
192 {
193 public:
194     GLXContext context;
195
196     GlxContext(const Visual *vis, GLXContext ctx) :
197         Context(vis),
198         context(ctx)
199     {}
200
201     ~GlxContext() {
202         glXDestroyContext(display, context);
203     }
204 };
205
206 void
207 init(void) {
208     if (!display) {
209         display = XOpenDisplay(NULL);
210         if (!display) {
211             std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
212             exit(1);
213         }
214         screen = DefaultScreen(display);
215     }
216 }
217
218 void
219 cleanup(void) {
220     if (display) {
221         XCloseDisplay(display);
222         display = NULL;
223     }
224 }
225
226 Visual *
227 createVisual(bool doubleBuffer) {
228     int single_attribs[] = {
229         GLX_RGBA,
230         GLX_RED_SIZE, 1,
231         GLX_GREEN_SIZE, 1,
232         GLX_BLUE_SIZE, 1,
233         GLX_ALPHA_SIZE, 1,
234         GLX_DEPTH_SIZE, 1,
235         GLX_STENCIL_SIZE, 1,
236         None
237     };
238
239     int double_attribs[] = {
240         GLX_RGBA,
241         GLX_RED_SIZE, 1,
242         GLX_GREEN_SIZE, 1,
243         GLX_BLUE_SIZE, 1,
244         GLX_ALPHA_SIZE, 1,
245         GLX_DOUBLEBUFFER,
246         GLX_DEPTH_SIZE, 1,
247         GLX_STENCIL_SIZE, 1,
248         None
249     };
250
251     XVisualInfo *visinfo;
252
253     visinfo = glXChooseVisual(display, screen, doubleBuffer ? double_attribs : single_attribs);
254
255     return new GlxVisual(visinfo);
256 }
257
258 Drawable *
259 createDrawable(const Visual *visual, int width, int height)
260 {
261     return new GlxDrawable(visual, width, height);
262 }
263
264 Context *
265 createContext(const Visual *visual, Context *shareContext)
266 {
267     XVisualInfo *visinfo = dynamic_cast<const GlxVisual *>(visual)->visinfo;
268     GLXContext share_context = NULL;
269     GLXContext context;
270
271     if (shareContext) {
272         share_context = dynamic_cast<GlxContext*>(shareContext)->context;
273     }
274
275     context = glXCreateContext(display, visinfo,
276                                share_context, True);
277     return new GlxContext(visual, context);
278 }
279
280 bool
281 makeCurrent(Drawable *drawable, Context *context)
282 {
283     if (!drawable || !context) {
284         return glXMakeCurrent(display, None, NULL);
285     } else {
286         GlxDrawable *glxDrawable = dynamic_cast<GlxDrawable *>(drawable);
287         GlxContext *glxContext = dynamic_cast<GlxContext *>(context);
288
289         return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
290     }
291 }
292
293 bool
294 processEvents(void) {
295     XFlush(display);
296     while (XPending(display) > 0) {
297         XEvent event;
298         XNextEvent(display, &event);
299         describeEvent(event);
300     }
301     return true;
302 }
303
304
305 } /* namespace glws */