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 enum
36 {
37 	DEFAULT_WINDOW_WIDTH	= 400,
38 	DEFAULT_WINDOW_HEIGHT	= 300
39 };
40 
EventState(void)41 EventState::EventState (void)
42 	: m_quit(false)
43 {
44 }
45 
~EventState(void)46 EventState::~EventState (void)
47 {
48 }
49 
setQuitFlag(bool quit)50 void EventState::setQuitFlag (bool quit)
51 {
52 	de::ScopedLock lock(m_mutex);
53 	m_quit = quit;
54 }
55 
getQuitFlag(void)56 bool EventState::getQuitFlag (void)
57 {
58 	de::ScopedLock lock(m_mutex);
59 	return m_quit;
60 }
61 
Display(EventState & eventState,const char * name)62 Display::Display (EventState& eventState, const char* name)
63 	: m_eventState	(eventState)
64 	, m_display		(DE_NULL)
65 	, m_deleteAtom	(DE_NULL)
66 {
67 	m_display = XOpenDisplay((char*)name); // Won't modify argument string.
68 	if (!m_display)
69 		throw ResourceError("Failed to open display", name, __FILE__, __LINE__);
70 
71 	m_deleteAtom	= XInternAtom(m_display, "WM_DELETE_WINDOW", False);
72 }
73 
~Display(void)74 Display::~Display (void)
75 {
76 	XCloseDisplay(m_display);
77 }
78 
processEvents(void)79 void Display::processEvents (void)
80 {
81 	XEvent	event;
82 
83 	while (XPending(m_display))
84 	{
85 		XNextEvent(m_display, &event);
86 
87 		// \todo [2010-10-27 pyry] Handle ConfigureNotify?
88 		if (event.type == ClientMessage && (unsigned)event.xclient.data.l[0] == m_deleteAtom)
89 			m_eventState.setQuitFlag(true);
90 	}
91 }
92 
getVisualInfo(VisualID visualID,XVisualInfo & dst)93 bool Display::getVisualInfo (VisualID visualID, XVisualInfo& dst)
94 {
95 	XVisualInfo		query;
96 	query.visualid = visualID;
97 	int				numVisuals	= 0;
98 	XVisualInfo*	response	= XGetVisualInfo(m_display, VisualIDMask, &query, &numVisuals);
99 	bool			succ		= false;
100 
101 	if (response != DE_NULL)
102 	{
103 		if (numVisuals > 0) // should be 1, but you never know...
104 		{
105 			dst = response[0];
106 			succ = true;
107 		}
108 		XFree(response);
109 	}
110 
111 	return succ;
112 }
113 
getVisual(VisualID visualID)114 ::Visual* Display::getVisual (VisualID visualID)
115 {
116 	XVisualInfo		info;
117 
118 	if (getVisualInfo(visualID, info))
119 		return info.visual;
120 
121 	return DE_NULL;
122 }
123 
Window(Display & display,int width,int height,::Visual * visual)124 Window::Window (Display& display, int width, int height, ::Visual* visual)
125 	: m_display		(display)
126 	, m_colormap	(None)
127 	, m_window		(None)
128 	, m_visible		(false)
129 {
130 	XSetWindowAttributes	swa;
131 	::Display* const		dpy					= m_display.getXDisplay();
132 	::Window				root				= DefaultRootWindow(dpy);
133 	unsigned long			mask				= CWBorderPixel | CWEventMask;
134 
135 	// If redirect is enabled, window size can't be guaranteed and it is up to
136 	// the window manager to decide whether to honor sizing requests. However,
137 	// overriding that causes window to appear as an overlay, which causes
138 	// other issues, so this is disabled by default.
139 	const bool				overrideRedirect	= false;
140 
141 	if (overrideRedirect)
142 	{
143 		mask |= CWOverrideRedirect;
144 		swa.override_redirect = true;
145 	}
146 
147 	if (visual == DE_NULL)
148 		visual = CopyFromParent;
149 	else
150 	{
151 		XVisualInfo	info	= XVisualInfo();
152 		bool		succ	= display.getVisualInfo(XVisualIDFromVisual(visual), info);
153 
154 		TCU_CHECK_INTERNAL(succ);
155 
156 		root				= RootWindow(dpy, info.screen);
157 		m_colormap			= XCreateColormap(dpy, root, visual, AllocNone);
158 		swa.colormap		= m_colormap;
159 		mask |= CWColormap;
160 	}
161 
162 	swa.border_pixel	= 0;
163 	swa.event_mask		= ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask;
164 
165 	if (width == glu::RenderConfig::DONT_CARE)
166 		width = DEFAULT_WINDOW_WIDTH;
167 	if (height == glu::RenderConfig::DONT_CARE)
168 		height = DEFAULT_WINDOW_HEIGHT;
169 
170 	m_window = XCreateWindow(dpy, root, 0, 0, width, height, 0,
171 							 CopyFromParent, InputOutput, visual, mask, &swa);
172 	TCU_CHECK(m_window);
173 
174 	Atom deleteAtom = m_display.getDeleteAtom();
175 	XSetWMProtocols(dpy, m_window, &deleteAtom, 1);
176 }
177 
setVisibility(bool visible)178 void Window::setVisibility (bool visible)
179 {
180 	::Display*	dpy			= m_display.getXDisplay();
181 	int			eventType	= None;
182 	XEvent		event;
183 
184 	if (visible == m_visible)
185 		return;
186 
187 	if (visible)
188 	{
189 		XMapWindow(dpy, m_window);
190 		eventType = MapNotify;
191 	}
192 	else
193 	{
194 		XUnmapWindow(dpy, m_window);
195 		eventType = UnmapNotify;
196 	}
197 
198 	// We are only interested about exposure/structure notify events, not user input
199 	XSelectInput(dpy, m_window, ExposureMask | StructureNotifyMask);
200 
201 	do
202 	{
203 		XNextEvent(dpy, &event);
204 	} while (event.type != eventType);
205 
206 	m_visible = visible;
207 }
208 
getDimensions(int * width,int * height) const209 void Window::getDimensions (int* width, int* height) const
210 {
211 	int x, y;
212 	::Window root;
213 	unsigned width_, height_, borderWidth, depth;
214 
215 	XGetGeometry(m_display.getXDisplay(), m_window, &root, &x, &y, &width_, &height_, &borderWidth, &depth);
216 	if (width != DE_NULL)
217 		*width = static_cast<int>(width_);
218 	if (height != DE_NULL)
219 		*height = static_cast<int>(height_);
220 }
221 
setDimensions(int width,int height)222 void Window::setDimensions (int width, int height)
223 {
224 	const unsigned int	mask = CWWidth | CWHeight;
225 	XWindowChanges		changes;
226 	changes.width		= width;
227 	changes.height		= height;
228 
229 	XConfigureWindow(m_display.getXDisplay(), m_window, mask, &changes);
230 }
231 
processEvents(void)232 void Window::processEvents (void)
233 {
234 	// A bit of a hack, since we don't really handle all the events.
235 	m_display.processEvents();
236 }
237 
~Window(void)238 Window::~Window (void)
239 {
240 	XDestroyWindow(m_display.getXDisplay(), m_window);
241 	if (m_colormap != None)
242 		XFreeColormap(m_display.getXDisplay(), m_colormap);
243 }
244 
245 } // x11
246 } // tcu
247