Home | History | Annotate | Download | only in X11
      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 
     41 EventState::EventState (void)
     42 	: m_quit(false)
     43 {
     44 }
     45 
     46 EventState::~EventState (void)
     47 {
     48 }
     49 
     50 void EventState::setQuitFlag (bool quit)
     51 {
     52 	de::ScopedLock lock(m_mutex);
     53 	m_quit = quit;
     54 }
     55 
     56 bool EventState::getQuitFlag (void)
     57 {
     58 	de::ScopedLock lock(m_mutex);
     59 	return m_quit;
     60 }
     61 
     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 
     74 Display::~Display (void)
     75 {
     76 	XCloseDisplay(m_display);
     77 }
     78 
     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 
     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 
    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 
    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 
    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 
    209 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 
    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 
    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 
    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