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
EventState(void)35 EventState::EventState (void)
36 : m_quit(false)
37 {
38 }
39
~EventState(void)40 EventState::~EventState (void)
41 {
42 }
43
setQuitFlag(bool quit)44 void EventState::setQuitFlag (bool quit)
45 {
46 de::ScopedLock lock(m_mutex);
47 m_quit = quit;
48 }
49
getQuitFlag(void)50 bool EventState::getQuitFlag (void)
51 {
52 de::ScopedLock lock(m_mutex);
53 return m_quit;
54 }
55
DisplayBase(EventState & platform)56 DisplayBase::DisplayBase (EventState& platform)
57 : m_eventState (platform)
58 {
59 }
60
~DisplayBase(void)61 DisplayBase::~DisplayBase (void)
62 {
63 }
64
WindowBase()65 WindowBase::WindowBase ()
66 : m_visible (false)
67 {
68 }
69
~WindowBase(void)70 WindowBase::~WindowBase (void)
71 {
72 }
73
XlibDisplay(EventState & eventState,const char * name)74 XlibDisplay::XlibDisplay (EventState& eventState, const char* name)
75 : DisplayBase (eventState)
76 {
77 m_display = XOpenDisplay((char*)name); // Won't modify argument string.
78 if (!m_display)
79 throw ResourceError("Failed to open display", name, __FILE__, __LINE__);
80
81 m_deleteAtom = XInternAtom(m_display, "WM_DELETE_WINDOW", False);
82 }
83
~XlibDisplay(void)84 XlibDisplay::~XlibDisplay (void)
85 {
86 XCloseDisplay(m_display);
87 }
88
processEvent(XEvent & event)89 void XlibDisplay::processEvent (XEvent& event)
90 {
91 switch (event.type)
92 {
93 case ClientMessage:
94 if ((unsigned)event.xclient.data.l[0] == m_deleteAtom)
95 m_eventState.setQuitFlag(true);
96 break;
97 // note: ConfigureNotify for window is handled in setDimensions()
98 default:
99 break;
100 }
101 }
102
processEvents(void)103 void XlibDisplay::processEvents (void)
104 {
105 XEvent event;
106
107 while (XPending(m_display))
108 {
109 XNextEvent(m_display, &event);
110 processEvent(event);
111 }
112 }
113
getVisualInfo(VisualID visualID,XVisualInfo & dst)114 bool XlibDisplay::getVisualInfo (VisualID visualID, XVisualInfo& dst)
115 {
116 XVisualInfo query;
117 query.visualid = visualID;
118 int numVisuals = 0;
119 XVisualInfo* response = XGetVisualInfo(m_display, VisualIDMask, &query, &numVisuals);
120 bool succ = false;
121
122 if (response != DE_NULL)
123 {
124 if (numVisuals > 0) // should be 1, but you never know...
125 {
126 dst = response[0];
127 succ = true;
128 }
129 XFree(response);
130 }
131
132 return succ;
133 }
134
getVisual(VisualID visualID)135 ::Visual* XlibDisplay::getVisual (VisualID visualID)
136 {
137 XVisualInfo info;
138
139 if (getVisualInfo(visualID, info))
140 return info.visual;
141
142 return DE_NULL;
143 }
144
XlibWindow(XlibDisplay & display,int width,int height,::Visual * visual)145 XlibWindow::XlibWindow (XlibDisplay& display, int width, int height, ::Visual* visual)
146 : WindowBase ()
147 , m_display (display)
148 , m_colormap (None)
149 , m_window (None)
150 {
151 XSetWindowAttributes swa;
152 ::Display* const dpy = m_display.getXDisplay();
153 ::Window root = DefaultRootWindow(dpy);
154 unsigned long mask = CWBorderPixel | CWEventMask;
155
156 // If redirect is enabled, window size can't be guaranteed and it is up to
157 // the window manager to decide whether to honor sizing requests. However,
158 // overriding that causes window to appear as an overlay, which causes
159 // other issues, so this is disabled by default.
160 const bool overrideRedirect = false;
161
162 if (overrideRedirect)
163 {
164 mask |= CWOverrideRedirect;
165 swa.override_redirect = true;
166 }
167
168 if (visual == DE_NULL)
169 visual = CopyFromParent;
170 else
171 {
172 XVisualInfo info = XVisualInfo();
173 bool succ = display.getVisualInfo(XVisualIDFromVisual(visual), info);
174
175 TCU_CHECK_INTERNAL(succ);
176
177 root = RootWindow(dpy, info.screen);
178 m_colormap = XCreateColormap(dpy, root, visual, AllocNone);
179 swa.colormap = m_colormap;
180 mask |= CWColormap;
181 }
182
183 swa.border_pixel = 0;
184 swa.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask;
185
186 if (width == glu::RenderConfig::DONT_CARE)
187 width = DEFAULT_WINDOW_WIDTH;
188 if (height == glu::RenderConfig::DONT_CARE)
189 height = DEFAULT_WINDOW_HEIGHT;
190
191 m_window = XCreateWindow(dpy, root, 0, 0, width, height, 0,
192 CopyFromParent, InputOutput, visual, mask, &swa);
193 TCU_CHECK(m_window);
194
195 Atom deleteAtom = m_display.getDeleteAtom();
196 XSetWMProtocols(dpy, m_window, &deleteAtom, 1);
197 XSync(dpy,false);
198 }
199
setVisibility(bool visible)200 void XlibWindow::setVisibility (bool visible)
201 {
202 ::Display* dpy = m_display.getXDisplay();
203 int eventType = None;
204 XEvent event;
205
206 if (visible == m_visible)
207 return;
208
209 if (visible)
210 {
211 XMapWindow(dpy, m_window);
212 eventType = MapNotify;
213 }
214 else
215 {
216 XUnmapWindow(dpy, m_window);
217 eventType = UnmapNotify;
218 }
219
220 // We are only interested about exposure/structure notify events, not user input
221 XSelectInput(dpy, m_window, ExposureMask | StructureNotifyMask);
222
223 do
224 {
225 XWindowEvent(dpy, m_window, ExposureMask | StructureNotifyMask, &event);
226 } while (event.type != eventType);
227
228 m_visible = visible;
229 }
230
getDimensions(int * width,int * height) const231 void XlibWindow::getDimensions (int* width, int* height) const
232 {
233 int x, y;
234 ::Window root;
235 unsigned width_, height_, borderWidth, depth;
236
237 XGetGeometry(m_display.getXDisplay(), m_window, &root, &x, &y, &width_, &height_, &borderWidth, &depth);
238 if (width != DE_NULL)
239 *width = static_cast<int>(width_);
240 if (height != DE_NULL)
241 *height = static_cast<int>(height_);
242 }
243
setDimensions(int width,int height)244 void XlibWindow::setDimensions (int width, int height)
245 {
246 const unsigned int mask = CWWidth | CWHeight;
247 XWindowChanges changes;
248 ::Display* dpy = m_display.getXDisplay();
249 XEvent myevent;
250 changes.width = width;
251 changes.height = height;
252 XConfigureWindow(dpy, m_window, mask, &changes);
253 XFlush(dpy);
254
255 for(;;)
256 {
257 XNextEvent(dpy, &myevent);
258 if (myevent.type == ConfigureNotify) {
259 XConfigureEvent e = myevent.xconfigure;
260 if (e.width == width && e.height == height)
261 break;
262 }
263 else
264 m_display.processEvent(myevent);
265 }
266 }
267
processEvents(void)268 void XlibWindow::processEvents (void)
269 {
270 // A bit of a hack, since we don't really handle all the events.
271 m_display.processEvents();
272 }
273
~XlibWindow(void)274 XlibWindow::~XlibWindow (void)
275 {
276 XDestroyWindow(m_display.getXDisplay(), m_window);
277 if (m_colormap != None)
278 XFreeColormap(m_display.getXDisplay(), m_colormap);
279 }
280
281 } // x11
282 } // tcu
283