Merge Vulkan CTS 1.0.2.2 into goog/oc-dev
[platform/upstream/VK-GL-CTS.git] / framework / platform / X11 / tcuX11.cpp
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 EventState::EventState (void)
36         : m_quit(false)
37 {
38 }
39
40 EventState::~EventState (void)
41 {
42 }
43
44 void EventState::setQuitFlag (bool quit)
45 {
46         de::ScopedLock lock(m_mutex);
47         m_quit = quit;
48 }
49
50 bool EventState::getQuitFlag (void)
51 {
52         de::ScopedLock lock(m_mutex);
53         return m_quit;
54 }
55
56 DisplayBase::DisplayBase (EventState& platform)
57         : m_eventState  (platform)
58 {
59 }
60
61 DisplayBase::~DisplayBase (void)
62 {
63 }
64
65 WindowBase::WindowBase ()
66         : m_visible     (false)
67 {
68 }
69
70 WindowBase::~WindowBase (void)
71 {
72 }
73
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
84 XlibDisplay::~XlibDisplay (void)
85 {
86         XCloseDisplay(m_display);
87 }
88
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
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
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
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
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
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
231 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
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
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
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