1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief X11 utilities.
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuX11.hpp"
25 #include "gluRenderConfig.hpp"
26 #include "deMemory.h"
27
28 #include <X11/Xutil.h>
29
30 namespace tcu
31 {
32 namespace x11
33 {
34
35 enum
36 {
37 DEFAULT_WINDOW_WIDTH = 400,
38 DEFAULT_WINDOW_HEIGHT = 300
39 };
40
EventState(void)41 EventState::EventState (void)
42 : m_quit(false)
43 {
44 }
45
~EventState(void)46 EventState::~EventState (void)
47 {
48 }
49
setQuitFlag(bool quit)50 void EventState::setQuitFlag (bool quit)
51 {
52 de::ScopedLock lock(m_mutex);
53 m_quit = quit;
54 }
55
getQuitFlag(void)56 bool EventState::getQuitFlag (void)
57 {
58 de::ScopedLock lock(m_mutex);
59 return m_quit;
60 }
61
Display(EventState & eventState,const char * name)62 Display::Display (EventState& eventState, const char* name)
63 : m_eventState (eventState)
64 , m_display (DE_NULL)
65 , m_deleteAtom (DE_NULL)
66 {
67 m_display = XOpenDisplay((char*)name); // Won't modify argument string.
68 if (!m_display)
69 throw ResourceError("Failed to open display", name, __FILE__, __LINE__);
70
71 m_deleteAtom = XInternAtom(m_display, "WM_DELETE_WINDOW", False);
72 }
73
~Display(void)74 Display::~Display (void)
75 {
76 XCloseDisplay(m_display);
77 }
78
processEvents(void)79 void Display::processEvents (void)
80 {
81 XEvent event;
82
83 while (XPending(m_display))
84 {
85 XNextEvent(m_display, &event);
86
87 // \todo [2010-10-27 pyry] Handle ConfigureNotify?
88 if (event.type == ClientMessage && (unsigned)event.xclient.data.l[0] == m_deleteAtom)
89 m_eventState.setQuitFlag(true);
90 }
91 }
92
getVisualInfo(VisualID visualID,XVisualInfo & dst)93 bool Display::getVisualInfo (VisualID visualID, XVisualInfo& dst)
94 {
95 XVisualInfo query;
96 query.visualid = visualID;
97 int numVisuals = 0;
98 XVisualInfo* response = XGetVisualInfo(m_display, VisualIDMask, &query, &numVisuals);
99 bool succ = false;
100
101 if (response != DE_NULL)
102 {
103 if (numVisuals > 0) // should be 1, but you never know...
104 {
105 dst = response[0];
106 succ = true;
107 }
108 XFree(response);
109 }
110
111 return succ;
112 }
113
getVisual(VisualID visualID)114 ::Visual* Display::getVisual (VisualID visualID)
115 {
116 XVisualInfo info;
117
118 if (getVisualInfo(visualID, info))
119 return info.visual;
120
121 return DE_NULL;
122 }
123
Window(Display & display,int width,int height,::Visual * visual)124 Window::Window (Display& display, int width, int height, ::Visual* visual)
125 : m_display (display)
126 , m_colormap (None)
127 , m_window (None)
128 , m_visible (false)
129 {
130 XSetWindowAttributes swa;
131 ::Display* dpy = m_display.getXDisplay();
132 ::Window root = DefaultRootWindow(dpy);
133 unsigned long mask = CWBorderPixel | CWEventMask;
134
135 if (visual == DE_NULL)
136 visual = CopyFromParent;
137 else
138 {
139 XVisualInfo info = XVisualInfo();
140 bool succ = display.getVisualInfo(XVisualIDFromVisual(visual), info);
141
142 TCU_CHECK_INTERNAL(succ);
143
144 root = RootWindow(dpy, info.screen);
145 m_colormap = XCreateColormap(dpy, root, visual, AllocNone);
146 swa.colormap = m_colormap;
147 mask |= CWColormap;
148 }
149
150 swa.border_pixel = 0;
151 swa.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask;
152
153 mask |= CWOverrideRedirect;
154 swa.override_redirect = true;
155
156 if (width == glu::RenderConfig::DONT_CARE)
157 width = DEFAULT_WINDOW_WIDTH;
158 if (height == glu::RenderConfig::DONT_CARE)
159 height = DEFAULT_WINDOW_HEIGHT;
160
161 m_window = XCreateWindow(dpy, root, 0, 0, width, height, 0,
162 CopyFromParent, InputOutput, visual, mask, &swa);
163 TCU_CHECK(m_window);
164
165 Atom deleteAtom = m_display.getDeleteAtom();
166 XSetWMProtocols(dpy, m_window, &deleteAtom, 1);
167
168 }
169
setVisibility(bool visible)170 void Window::setVisibility (bool visible)
171 {
172 ::Display* dpy = m_display.getXDisplay();
173 int eventType = None;
174 XEvent event;
175
176 if (visible == m_visible)
177 return;
178
179 if (visible)
180 {
181 XMapWindow(dpy, m_window);
182 eventType = MapNotify;
183 }
184 else
185 {
186 XUnmapWindow(dpy, m_window);
187 eventType = UnmapNotify;
188 }
189
190 // We are only interested about exposure/structure notify events, not user input
191 XSelectInput(dpy, m_window, ExposureMask | StructureNotifyMask);
192
193 do
194 {
195 XNextEvent(dpy, &event);
196 } while (event.type != eventType);
197
198 m_visible = visible;
199 }
200
getDimensions(int * width,int * height) const201 void Window::getDimensions (int* width, int* height) const
202 {
203 int x, y;
204 ::Window root;
205 unsigned width_, height_, borderWidth, depth;
206
207 XGetGeometry(m_display.getXDisplay(), m_window, &root, &x, &y, &width_, &height_, &borderWidth, &depth);
208 if (width != DE_NULL)
209 *width = static_cast<int>(width_);
210 if (height != DE_NULL)
211 *height = static_cast<int>(height_);
212 }
213
setDimensions(int width,int height)214 void Window::setDimensions (int width, int height)
215 {
216 const unsigned int mask = CWWidth | CWHeight;
217 XWindowChanges changes;
218 changes.width = width;
219 changes.height = height;
220
221 XConfigureWindow(m_display.getXDisplay(), m_window, mask, &changes);
222 }
223
processEvents(void)224 void Window::processEvents (void)
225 {
226 // A bit of a hack, since we don't really handle all the events.
227 m_display.processEvents();
228 }
229
~Window(void)230 Window::~Window (void)
231 {
232 XDestroyWindow(m_display.getXDisplay(), m_window);
233 if (m_colormap != None)
234 XFreeColormap(m_display.getXDisplay(), m_colormap);
235 }
236
237 } // x11
238 } // tcu
239