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