#include // Prevents conflict with X.h defining "None" #include #include #include "X11WindowEventHandler.h" #include "X11SharedDisplay.h" #include "GLXContext.h" #include "X11Display.h" namespace sp { X11Display:: X11Display() : m_screen (0), m_disp (NULL), m_size (200,200), m_cur_last (0), m_cur_hidden (0) { } bool X11Display::create(DisplayDescription description) { XSetWindowAttributes attr; XVisualInfo* vi; Atom protocols; Visual* visual; Window root_win; m_disp = XGetDisplay(); if (m_disp == NULL) { Log::warn("X11: Could not open display"); return false; } m_screen = DefaultScreen(m_disp); root_win = XRootWindow(m_disp, m_screen); visual = DefaultVisual(m_disp, m_screen); attr.border_pixel = BlackPixel(m_disp, m_screen); attr.background_pixel = WhitePixel(m_disp, m_screen); //attr.override_redirect = True; attr.colormap = ::XCreateColormap(m_disp, root_win, visual, AllocNone); // We want Keyboard,Mouse,Resize,Exposure (repaint) events. attr.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | ExposureMask; m_win = XCreateWindow(m_disp, root_win, 0, 0, m_size.x, m_size.y, 0, DefaultDepth(m_disp, m_screen), InputOutput, visual, CWBackPixel | CWColormap | CWBorderPixel | CWEventMask, &attr); // Register event handler X11WindowEventHandler::registerHandler(m_disp, m_win, this); // X11 does not handle pressing the X button on a window. // that is the job of the window manager. // Here we can request the WM to send us a delete event so we can handle it ourself. protocols = getAtom("WM_DELETE_WINDOW"); XSetWMProtocols(m_disp, m_win, &protocols, 1); XMapWindow(m_disp, m_win); setSize(description.mode.width, description.mode.height); // Clear and take focus XClearWindow(m_disp, m_win); XMapRaised(m_disp, m_win); Log::info("X11: Created display"); createHiddenCursor(); return true; } void X11Display::destroy() { if (m_disp) { if (m_win) { X11WindowEventHandler::unregisterHandler(m_disp, m_win); ::XDestroyWindow(m_disp, m_win); } XReleaseDisplay(m_disp); m_disp = NULL; } } bool X11Display::isValid() { return m_disp && m_win; } void* X11Display::getHandle() const { return (void*) m_win; } void X11Display::setSize(unsigned int width, unsigned int height) { m_size = Vector2u(width, height); ::XResizeWindow(m_disp, m_win, m_size.x, m_size.y); } Vector2u X11Display::getSize() const { return m_size; } void X11Display::setPosition(unsigned int x, unsigned int y) { ::XMoveWindow(m_disp, m_win, x, y); } void X11Display::setCaption(const std::string& caption) { ::XStoreName(m_disp, m_win, caption.c_str()); } // TODO: Move this up to the non-platform layer. void X11Display::setIcon(const std::string& icon) { Image img; if (img.loadFromFile(icon)) { setIcon(img.getWidth(), img.getHeight(), img.getPixels()); } } void X11Display::setIcon(unsigned int width, unsigned int height, const uint8_t *pixels) { ::Atom net_wm_icon = getAtom("_NET_WM_ICON", False); ::Atom cardinal = getAtom("CARDINAL", False); std::vector buffer(2 + width * height); uint64_t *ptr = &buffer[0]; *ptr++ = width; *ptr++ = height; // TODO: Conversion between differnet formats should be defined as functions in Graphics/PixelFormat.h for (std::size_t i = 0; i < width * height; i++) { *ptr++ = (pixels[i * 4 + 2] << 0) | (pixels[i * 4 + 1] << 8) | (pixels[i * 4 + 0] << 16) | (pixels[i * 4 + 3] << 24); } ::XChangeProperty(m_disp, m_win, net_wm_icon, cardinal, 32, PropModeReplace, reinterpret_cast(&buffer[0]), 2 + width * height); XFlush(m_disp); } void X11Display::createHiddenCursor() { XColor c; Pixmap pix = ::XCreatePixmap(m_disp, m_win, 1, 1, 1); GC gc = ::XCreateGC(m_disp, pix, 0, NULL); // Draw transparent pixel. ::XDrawPoint(m_disp, pix, gc, 0, 0); c.red = c.green = c.blue = 0; c.flags = DoRed | DoGreen | DoBlue; m_cur_hidden = XCreatePixmapCursor(m_disp, pix, pix, &c, &c, 0, 0); // Free GC and pixmap. ::XFreePixmap(m_disp, pix); ::XFreeGC(m_disp, gc); } void X11Display::showCursor(bool value) { XDefineCursor(m_disp, m_win, value ? m_cur_last : m_cur_hidden); } void X11Display::processEvent(const ::XEvent& event) { Vector2u size; switch(event.xany.type) { case ConfigureNotify: size.x = event.xconfigure.width; size.y = event.xconfigure.height; if (m_size != size) { m_size = size; Log::info("X11: Resize event"); onReshape(size.x, size.y); } break; } } } // namespace sp