]> git.cworth.org Git - apitrace/blob - glws_glx.cpp
Tell the window manager to respect the requested window size
[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 "glimports.hpp"
30 #include "glws.hpp"
31
32 #include <X11/Xlib.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         XMapWindow(display, window);
142
143         waitForEvent(window, Expose);
144         glXWaitX();
145     }
146
147     ~GlxDrawable() {
148         XDestroyWindow(display, window);
149     }
150
151     void
152     resize(int w, int h) {
153         glXWaitGL();
154
155         // We need to ensure that pending events are processed here, and XSync
156         // with discard = True guarantees that, but it appears the limited
157         // event processing we do so far is sufficient
158         //XSync(display, True);
159
160         Drawable::resize(w, h);
161
162         XResizeWindow(display, window, w, h);
163
164         // Tell the window manager to respect the requested size
165         XSizeHints *size_hints;
166         size_hints = XAllocSizeHints();
167         size_hints->max_width  = size_hints->min_width  = w;
168         size_hints->max_height = size_hints->min_height = h;
169         size_hints->flags = PMinSize | PMaxSize;
170         XSetWMNormalHints(display, window, size_hints);
171         XFree(size_hints);
172
173         waitForEvent(window, ConfigureNotify);
174
175         glXWaitX();
176     }
177
178     void swapBuffers(void) {
179         glXSwapBuffers(display, window);
180     }
181 };
182
183
184 class GlxContext : public Context
185 {
186 public:
187     GLXContext context;
188
189     GlxContext(const Visual *vis, GLXContext ctx) :
190         Context(vis),
191         context(ctx)
192     {}
193
194     ~GlxContext() {
195         glXDestroyContext(display, context);
196     }
197 };
198
199
200 class GlxWindowSystem : public WindowSystem
201 {
202 public:
203     GlxWindowSystem() {
204         if (!display) {
205             display = XOpenDisplay(NULL);
206             if (!display) {
207                 std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
208                 exit(1);
209             }
210             screen = DefaultScreen(display);
211         }
212     }
213
214     ~GlxWindowSystem() {
215         XCloseDisplay(display);
216     }
217
218     Visual *
219     createVisual(bool doubleBuffer) {
220         int single_attribs[] = {
221             GLX_RGBA,
222             GLX_RED_SIZE, 1,
223             GLX_GREEN_SIZE, 1,
224             GLX_BLUE_SIZE, 1,
225             GLX_ALPHA_SIZE, 1,
226             GLX_DEPTH_SIZE, 1,
227             GLX_STENCIL_SIZE, 1,
228             None
229         };
230
231         int double_attribs[] = {
232             GLX_RGBA,
233             GLX_RED_SIZE, 1,
234             GLX_GREEN_SIZE, 1,
235             GLX_BLUE_SIZE, 1,
236             GLX_ALPHA_SIZE, 1,
237             GLX_DOUBLEBUFFER,
238             GLX_DEPTH_SIZE, 1,
239             GLX_STENCIL_SIZE, 1,
240             None
241         };
242
243         XVisualInfo *visinfo;
244
245         visinfo = glXChooseVisual(display, screen, doubleBuffer ? double_attribs : single_attribs);
246
247         return new GlxVisual(visinfo);
248     }
249
250     Drawable *
251     createDrawable(const Visual *visual, int width, int height)
252     {
253         return new GlxDrawable(visual, width, height);
254     }
255
256     Context *
257     createContext(const Visual *visual, Context *shareContext)
258     {
259         XVisualInfo *visinfo = dynamic_cast<const GlxVisual *>(visual)->visinfo;
260         GLXContext share_context = NULL;
261         GLXContext context;
262
263         if (shareContext) {
264             share_context = dynamic_cast<GlxContext*>(shareContext)->context;
265         }
266
267         context = glXCreateContext(display, visinfo,
268                                    share_context, True);
269         return new GlxContext(visual, context);
270     }
271
272     bool
273     makeCurrent(Drawable *drawable, Context *context)
274     {
275         if (!drawable || !context) {
276             return glXMakeCurrent(display, None, NULL);
277         } else {
278             GlxDrawable *glxDrawable = dynamic_cast<GlxDrawable *>(drawable);
279             GlxContext *glxContext = dynamic_cast<GlxContext *>(context);
280
281             return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
282         }
283     }
284
285     bool
286     processEvents(void) {
287         XFlush(display);
288         while (XPending(display) > 0) {
289             XEvent event;
290             XNextEvent(display, &event);
291             describeEvent(event);
292         }
293         return true;
294     }
295 };
296
297
298 WindowSystem *createNativeWindowSystem(void) {
299     return new GlxWindowSystem();
300 }
301
302
303 } /* namespace glretrace */