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