• 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 	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