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* const dpy = m_display.getXDisplay();
132 ::Window root = DefaultRootWindow(dpy);
133 unsigned long mask = CWBorderPixel | CWEventMask;
134
135 // If redirect is enabled, window size can't be guaranteed and it is up to
136 // the window manager to decide whether to honor sizing requests. However,
137 // overriding that causes window to appear as an overlay, which causes
138 // other issues, so this is disabled by default.
139 const bool overrideRedirect = false;
140
141 if (overrideRedirect)
142 {
143 mask |= CWOverrideRedirect;
144 swa.override_redirect = true;
145 }
146
147 if (visual == DE_NULL)
148 visual = CopyFromParent;
149 else
150 {
151 XVisualInfo info = XVisualInfo();
152 bool succ = display.getVisualInfo(XVisualIDFromVisual(visual), info);
153
154 TCU_CHECK_INTERNAL(succ);
155
156 root = RootWindow(dpy, info.screen);
157 m_colormap = XCreateColormap(dpy, root, visual, AllocNone);
158 swa.colormap = m_colormap;
159 mask |= CWColormap;
160 }
161
162 swa.border_pixel = 0;
163 swa.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask;
164
165 if (width == glu::RenderConfig::DONT_CARE)
166 width = DEFAULT_WINDOW_WIDTH;
167 if (height == glu::RenderConfig::DONT_CARE)
168 height = DEFAULT_WINDOW_HEIGHT;
169
170 m_window = XCreateWindow(dpy, root, 0, 0, width, height, 0,
171 CopyFromParent, InputOutput, visual, mask, &swa);
172 TCU_CHECK(m_window);
173
174 Atom deleteAtom = m_display.getDeleteAtom();
175 XSetWMProtocols(dpy, m_window, &deleteAtom, 1);
176 }
177
setVisibility(bool visible)178 void Window::setVisibility (bool visible)
179 {
180 ::Display* dpy = m_display.getXDisplay();
181 int eventType = None;
182 XEvent event;
183
184 if (visible == m_visible)
185 return;
186
187 if (visible)
188 {
189 XMapWindow(dpy, m_window);
190 eventType = MapNotify;
191 }
192 else
193 {
194 XUnmapWindow(dpy, m_window);
195 eventType = UnmapNotify;
196 }
197
198 // We are only interested about exposure/structure notify events, not user input
199 XSelectInput(dpy, m_window, ExposureMask | StructureNotifyMask);
200
201 do
202 {
203 XNextEvent(dpy, &event);
204 } while (event.type != eventType);
205
206 m_visible = visible;
207 }
208
getDimensions(int * width,int * height) const209 void Window::getDimensions (int* width, int* height) const
210 {
211 int x, y;
212 ::Window root;
213 unsigned width_, height_, borderWidth, depth;
214
215 XGetGeometry(m_display.getXDisplay(), m_window, &root, &x, &y, &width_, &height_, &borderWidth, &depth);
216 if (width != DE_NULL)
217 *width = static_cast<int>(width_);
218 if (height != DE_NULL)
219 *height = static_cast<int>(height_);
220 }
221
setDimensions(int width,int height)222 void Window::setDimensions (int width, int height)
223 {
224 const unsigned int mask = CWWidth | CWHeight;
225 XWindowChanges changes;
226 changes.width = width;
227 changes.height = height;
228
229 XConfigureWindow(m_display.getXDisplay(), m_window, mask, &changes);
230 }
231
processEvents(void)232 void Window::processEvents (void)
233 {
234 // A bit of a hack, since we don't really handle all the events.
235 m_display.processEvents();
236 }
237
~Window(void)238 Window::~Window (void)
239 {
240 XDestroyWindow(m_display.getXDisplay(), m_window);
241 if (m_colormap != None)
242 XFreeColormap(m_display.getXDisplay(), m_colormap);
243 }
244
245 } // x11
246 } // tcu
247