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