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