Merge vk-gkl-cts/vulkan-cts-1.1.2 into vk-gl-cts/vulkan-cts-1.1.3
[platform/upstream/VK-GL-CTS.git] / framework / platform / lnx / X11 / tcuLnxX11.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 "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
37 DisplayBase::DisplayBase (EventState& platform)
38         : m_eventState  (platform)
39 {
40 }
41
42 DisplayBase::~DisplayBase (void)
43 {
44 }
45
46 WindowBase::WindowBase ()
47         : m_visible     (false)
48 {
49 }
50
51 WindowBase::~WindowBase (void)
52 {
53 }
54
55 XlibDisplay::DisplayState XlibDisplay::s_displayState = XlibDisplay::DISPLAY_STATE_UNKNOWN;
56
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
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
90 XlibDisplay::~XlibDisplay (void)
91 {
92         XCloseDisplay(m_display);
93 }
94
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
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
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
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
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
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
250 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
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
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
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