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 "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 
     37 DisplayBase::DisplayBase (EventState& platform)
     38 	: m_eventState	(platform)
     39 {
     40 }
     41 
     42 DisplayBase::~DisplayBase (void)
     43 {
     44 }
     45 
     46 WindowBase::WindowBase ()
     47 	: m_visible	(false)
     48 {
     49 }
     50 
     51 WindowBase::~WindowBase (void)
     52 {
     53 }
     54 
     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 
     65 XlibDisplay::~XlibDisplay (void)
     66 {
     67 	XCloseDisplay(m_display);
     68 }
     69 
     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 
     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 
     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 
    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 
    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 
    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 
    212 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 
    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 
    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 
    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