/*------------------------------------------------------------------------- * drawElements Quality Program Tester Core * ---------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief X11 utilities. *//*--------------------------------------------------------------------*/ #include "tcuLnxX11.hpp" #include "gluRenderConfig.hpp" #include "deMemory.h" #include namespace tcu { namespace lnx { namespace x11 { DisplayBase::DisplayBase (EventState& platform) : m_eventState (platform) { } DisplayBase::~DisplayBase (void) { } WindowBase::WindowBase () : m_visible (false) { } WindowBase::~WindowBase (void) { } XlibDisplay::DisplayState XlibDisplay::s_displayState = XlibDisplay::DISPLAY_STATE_UNKNOWN; bool XlibDisplay::hasDisplay (const char* name) { if (s_displayState == DISPLAY_STATE_UNKNOWN) { XInitThreads(); Display *display = XOpenDisplay((char*)name); if (display) { s_displayState = DISPLAY_STATE_AVAILABLE; XCloseDisplay(display); } else s_displayState = DISPLAY_STATE_UNAVAILABLE; } return s_displayState == DISPLAY_STATE_AVAILABLE ? true : false; } XlibDisplay::XlibDisplay (EventState& eventState, const char* name) : DisplayBase (eventState) { // From man:XinitThreads(3): // // The XInitThreads function initializes Xlib support for concurrent // threads. This function must be the first Xlib function // a multi-threaded program calls, and it must complete before any other // Xlib call is made. DE_CHECK_RUNTIME_ERR(XInitThreads() != 0); m_display = XOpenDisplay((char*)name); // Won't modify argument string. if (!m_display) throw ResourceError("Failed to open display", name, __FILE__, __LINE__); m_deleteAtom = XInternAtom(m_display, "WM_DELETE_WINDOW", False); } XlibDisplay::~XlibDisplay (void) { XCloseDisplay(m_display); } void XlibDisplay::processEvent (XEvent& event) { switch (event.type) { case ClientMessage: if ((unsigned)event.xclient.data.l[0] == m_deleteAtom) m_eventState.setQuitFlag(true); break; // note: ConfigureNotify for window is handled in setDimensions() default: break; } } void XlibDisplay::processEvents (void) { XEvent event; while (XPending(m_display)) { XNextEvent(m_display, &event); processEvent(event); } } bool XlibDisplay::getVisualInfo (VisualID visualID, XVisualInfo& dst) { XVisualInfo query; query.visualid = visualID; int numVisuals = 0; XVisualInfo* response = XGetVisualInfo(m_display, VisualIDMask, &query, &numVisuals); bool succ = false; if (response != DE_NULL) { if (numVisuals > 0) // should be 1, but you never know... { dst = response[0]; succ = true; } XFree(response); } return succ; } ::Visual* XlibDisplay::getVisual (VisualID visualID) { XVisualInfo info; if (getVisualInfo(visualID, info)) return info.visual; return DE_NULL; } XlibWindow::XlibWindow (XlibDisplay& display, int width, int height, ::Visual* visual) : WindowBase () , m_display (display) , m_colormap (None) , m_window (None) { XSetWindowAttributes swa; ::Display* const dpy = m_display.getXDisplay(); ::Window root = DefaultRootWindow(dpy); unsigned long mask = CWBorderPixel | CWEventMask; // If redirect is enabled, window size can't be guaranteed and it is up to // the window manager to decide whether to honor sizing requests. However, // overriding that causes window to appear as an overlay, which causes // other issues, so this is disabled by default. const bool overrideRedirect = false; int depth = CopyFromParent; if (overrideRedirect) { mask |= CWOverrideRedirect; swa.override_redirect = true; } if (visual == DE_NULL) visual = CopyFromParent; else { XVisualInfo info = XVisualInfo(); bool succ = display.getVisualInfo(XVisualIDFromVisual(visual), info); TCU_CHECK_INTERNAL(succ); root = RootWindow(dpy, info.screen); m_colormap = XCreateColormap(dpy, root, visual, AllocNone); swa.colormap = m_colormap; mask |= CWColormap; depth = info.depth; } swa.border_pixel = 0; swa.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask; if (width == glu::RenderConfig::DONT_CARE) width = DEFAULT_WINDOW_WIDTH; if (height == glu::RenderConfig::DONT_CARE) height = DEFAULT_WINDOW_HEIGHT; m_window = XCreateWindow(dpy, root, 0, 0, width, height, 0, depth, InputOutput, visual, mask, &swa); TCU_CHECK(m_window); /* Prevent the window from stealing input, since our windows are * non-interactive. */ XWMHints *hints = XAllocWMHints(); hints->flags |= InputHint; hints->input = False; XSetWMHints(dpy, m_window, hints); XFree(hints); Atom deleteAtom = m_display.getDeleteAtom(); XSetWMProtocols(dpy, m_window, &deleteAtom, 1); XSync(dpy,false); } void XlibWindow::setVisibility (bool visible) { ::Display* dpy = m_display.getXDisplay(); int eventType = None; XEvent event; if (visible == m_visible) return; if (visible) { XMapWindow(dpy, m_window); eventType = MapNotify; } else { XUnmapWindow(dpy, m_window); eventType = UnmapNotify; } // We are only interested about exposure/structure notify events, not user input XSelectInput(dpy, m_window, ExposureMask | StructureNotifyMask); do { XWindowEvent(dpy, m_window, ExposureMask | StructureNotifyMask, &event); } while (event.type != eventType); m_visible = visible; } void XlibWindow::getDimensions (int* width, int* height) const { int x, y; ::Window root; unsigned width_, height_, borderWidth, depth; XGetGeometry(m_display.getXDisplay(), m_window, &root, &x, &y, &width_, &height_, &borderWidth, &depth); if (width != DE_NULL) *width = static_cast(width_); if (height != DE_NULL) *height = static_cast(height_); } void XlibWindow::setDimensions (int width, int height) { const unsigned int mask = CWWidth | CWHeight; XWindowChanges changes; ::Display* dpy = m_display.getXDisplay(); XEvent myevent; changes.width = width; changes.height = height; XConfigureWindow(dpy, m_window, mask, &changes); XFlush(dpy); for(;;) { XNextEvent(dpy, &myevent); if (myevent.type == ConfigureNotify) { XConfigureEvent e = myevent.xconfigure; if (e.width == width && e.height == height) break; } else m_display.processEvent(myevent); } } void XlibWindow::processEvents (void) { // A bit of a hack, since we don't really handle all the events. m_display.processEvents(); } XlibWindow::~XlibWindow (void) { XDestroyWindow(m_display.getXDisplay(), m_window); if (m_colormap != None) XFreeColormap(m_display.getXDisplay(), m_colormap); } } // x11 } // lnx } // tcu