Unix: Rename X11Display to X11Window and make it work again with Spectre/Window/Window
This commit is contained in:
parent
96f6725428
commit
45d3bff620
9 changed files with 60 additions and 62 deletions
|
|
@ -1,421 +0,0 @@
|
|||
|
||||
#include <cstring>
|
||||
#include <Spectre/System/Log.h>
|
||||
#include <Spectre/Graphics/Image.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include "XRandR.h"
|
||||
#include "X11WindowEventHandler.h"
|
||||
#include "Xlib.h"
|
||||
#include "wm_hints.h"
|
||||
#include "GLXContext.h"
|
||||
#include "X11Display.h"
|
||||
|
||||
// Sometimes not defined in headers.
|
||||
#ifndef _NET_WM_STATE_TOGGLE
|
||||
#define _NET_WM_STATE_TOGGLE 2
|
||||
#endif
|
||||
|
||||
namespace sp {
|
||||
|
||||
namespace _priv {
|
||||
|
||||
// Pointer to the display that has focus (or NULL if none have).
|
||||
X11Display* focused_display = NULL;
|
||||
}
|
||||
|
||||
X11Display* X11Display::getFocused()
|
||||
{
|
||||
return _priv::focused_display;
|
||||
}
|
||||
|
||||
X11Display::
|
||||
X11Display() :
|
||||
m_screen (0),
|
||||
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;
|
||||
::Display* disp = Xlib::getDisplay();
|
||||
|
||||
m_screen = DefaultScreen(disp);
|
||||
root_win = XRootWindow(disp, m_screen);
|
||||
visual = DefaultVisual(disp, m_screen);
|
||||
|
||||
attr.border_pixel = BlackPixel(disp, m_screen);
|
||||
attr.background_pixel = WhitePixel(disp, m_screen);
|
||||
//attr.override_redirect = True;
|
||||
attr.colormap = ::XCreateColormap(disp, root_win, visual, AllocNone);
|
||||
// We want InputFocus,Keyboard,Mouse,Resize,Exposure (repaint) events.
|
||||
attr.event_mask = FocusChangeMask
|
||||
| KeyPressMask | KeyReleaseMask
|
||||
| ButtonPressMask | ButtonReleaseMask | PointerMotionMask
|
||||
| StructureNotifyMask | ExposureMask;
|
||||
|
||||
m_win = ::XCreateWindow(disp, root_win,
|
||||
0, 0, /* Position */
|
||||
m_size.x, m_size.y, 0 /* Border width */, DefaultDepth(disp, m_screen),
|
||||
InputOutput, visual,
|
||||
CWBackPixel | CWColormap | CWBorderPixel | CWEventMask, &attr);
|
||||
|
||||
// Register event handler
|
||||
X11WindowEventHandler::registerHandler(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 = Xlib::getAtom("WM_DELETE_WINDOW");
|
||||
XSetWMProtocols(disp, m_win, &protocols, 1);
|
||||
|
||||
setVisible(true);
|
||||
|
||||
setSize(description.mode.width, description.mode.height);
|
||||
|
||||
setDecoration(description.decoration);
|
||||
|
||||
// Clear and take focus
|
||||
XClearWindow(disp, m_win);
|
||||
XMapRaised(disp, m_win);
|
||||
|
||||
Log::info("X11: Created display");
|
||||
|
||||
createHiddenCursor();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void X11Display::destroy()
|
||||
{
|
||||
if (m_win) {
|
||||
::Display* disp = Xlib::getDisplay();
|
||||
X11WindowEventHandler::unregisterHandler(disp, m_win);
|
||||
::XDestroyWindow(disp, m_win);
|
||||
}
|
||||
}
|
||||
|
||||
bool X11Display::isValid()
|
||||
{
|
||||
return m_win;
|
||||
}
|
||||
|
||||
void* X11Display::getHandle() const
|
||||
{
|
||||
return (void*) m_win;
|
||||
}
|
||||
|
||||
void X11Display::setSize(unsigned int width, unsigned int height)
|
||||
{
|
||||
Log::info("X11: Set size %dx%d", width, height);
|
||||
|
||||
// X11 does not like if width or height is zero.
|
||||
if (width == 0) {
|
||||
width = 1;
|
||||
}
|
||||
|
||||
if (height == 0) {
|
||||
height = 1;
|
||||
}
|
||||
|
||||
m_size = Vector2u(width, height);
|
||||
::XResizeWindow(Xlib::getDisplay(), m_win, m_size.x, m_size.y);
|
||||
}
|
||||
|
||||
Vector2u X11Display::getSize() const
|
||||
{
|
||||
int x, y;
|
||||
unsigned int w, h, bw, d;
|
||||
::Display* disp = Xlib::getDisplay();
|
||||
::Window ancestor = m_win;
|
||||
::Window root = DefaultRootWindow(disp);
|
||||
|
||||
while (Xlib::getParentWindow(ancestor) != root) {
|
||||
// Next window up (parent window).
|
||||
ancestor = Xlib::getParentWindow(ancestor);
|
||||
}
|
||||
|
||||
::XGetGeometry(disp, ancestor, &root, &x, &y, &w, &h, &bw, &d);
|
||||
|
||||
return Vector2u(w, h);
|
||||
}
|
||||
|
||||
void X11Display::setPosition(unsigned int x, unsigned int y)
|
||||
{
|
||||
::XMoveWindow(Xlib::getDisplay(), m_win, x, y);
|
||||
}
|
||||
|
||||
Vector2u X11Display::getPosition() const
|
||||
{
|
||||
int x, y;
|
||||
unsigned int w, h, bw, d;
|
||||
::Display* disp = Xlib::getDisplay();
|
||||
::Window ancestor = m_win;
|
||||
::Window root = DefaultRootWindow(disp);
|
||||
|
||||
while (Xlib::getParentWindow(ancestor) != root) {
|
||||
// Next window up (parent window).
|
||||
ancestor = Xlib::getParentWindow(ancestor);
|
||||
}
|
||||
|
||||
::XGetGeometry(disp, ancestor, &root, &x, &y, &w, &h, &bw, &d);
|
||||
|
||||
return Vector2u(x, y);
|
||||
}
|
||||
|
||||
void X11Display::setVisible(bool visible)
|
||||
{
|
||||
if (visible) {
|
||||
::XMapWindow(Xlib::getDisplay(), m_win);
|
||||
} else {
|
||||
::XUnmapWindow(Xlib::getDisplay(), m_win);
|
||||
}
|
||||
}
|
||||
|
||||
void X11Display::setDecoration(unsigned decoration)
|
||||
{
|
||||
Atom WMHintsAtom = Xlib::getAtom("_MOTIF_WM_HINTS", false);
|
||||
|
||||
Log::info("X11: Decoration");
|
||||
|
||||
if (WMHintsAtom) {
|
||||
WMHints hints;
|
||||
std::memset(&hints, 0, sizeof(hints));
|
||||
hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
|
||||
hints.decorations = 0;
|
||||
hints.functions = 0;
|
||||
|
||||
if (decoration & DisplayDecorate::Menu) {
|
||||
Log::info("X11: Decoration Menu");
|
||||
hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU;
|
||||
hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE;
|
||||
}
|
||||
|
||||
if (decoration & DisplayDecorate::Resize) {
|
||||
Log::info("X11: Decoration Resize");
|
||||
hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH;
|
||||
hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE;
|
||||
}
|
||||
|
||||
if (decoration & DisplayDecorate::Close) {
|
||||
Log::info("X11: Decoration Close");
|
||||
hints.decorations |= 0;
|
||||
hints.functions |= MWM_FUNC_CLOSE;
|
||||
}
|
||||
|
||||
|
||||
::XChangeProperty(Xlib::getDisplay(), m_win, WMHintsAtom, WMHintsAtom,
|
||||
32, PropModeReplace, (const unsigned char*)&hints, WMHINTS_NUM_ELEMENTS);
|
||||
}
|
||||
}
|
||||
|
||||
void X11Display::minimize()
|
||||
{
|
||||
::XIconifyWindow(Xlib::getDisplay(), m_win, m_screen);
|
||||
}
|
||||
|
||||
void X11Display::maximize()
|
||||
{
|
||||
::XClientMessageEvent ev = {};
|
||||
::Display* disp = Xlib::getDisplay();
|
||||
|
||||
ev.type = ClientMessage;
|
||||
ev.window = m_win;
|
||||
ev.message_type = Xlib::getAtom("_NET_WM_STATE");
|
||||
ev.format = 32;
|
||||
ev.data.l[0] = _NET_WM_STATE_TOGGLE;
|
||||
ev.data.l[1] = Xlib::getAtom("_NET_WM_STATE_MAXIMIZED_HORZ");
|
||||
ev.data.l[2] = Xlib::getAtom("_NET_WM_STATE_MAXIMIZED_VERT");
|
||||
ev.data.l[3] = 1;
|
||||
|
||||
::XSendEvent(disp, DefaultRootWindow(disp), False,
|
||||
SubstructureNotifyMask, (XEvent*) &ev);
|
||||
}
|
||||
|
||||
void X11Display::enterFullscreen(DisplayMode mode)
|
||||
{
|
||||
if (!XRandR::FindMode(Xlib::getDisplay(), mode.width, mode.height, mode.bpp, &m_fullscreen_mode.size, &m_fullscreen_mode.rate)) {
|
||||
Log::warn("X11: Failed to find a mode");
|
||||
return;
|
||||
}
|
||||
|
||||
toggleFullscreen(true);
|
||||
}
|
||||
|
||||
void X11Display::toggleFullscreen(bool enable)
|
||||
{
|
||||
::Display* disp = Xlib::getDisplay();
|
||||
::Window root;
|
||||
::XRRScreenConfiguration *conf;
|
||||
XRandR::VideoMode *mode = &m_desktop_mode;
|
||||
|
||||
root = RootWindow(disp, 0);
|
||||
conf = XRRGetScreenInfo(disp, root);
|
||||
|
||||
if (enable) {
|
||||
if (m_desktop_mode.rate < 1) {
|
||||
Rotation r;
|
||||
m_desktop_mode.rate = XRRConfigCurrentRate(conf);
|
||||
m_desktop_mode.size = XRRConfigCurrentConfiguration(conf, &r);
|
||||
}
|
||||
|
||||
mode = &m_fullscreen_mode;
|
||||
}
|
||||
|
||||
wm_fullscreen(enable);
|
||||
XRRSetScreenConfigAndRate(disp, conf, root, mode->size, RR_Rotate_0, mode->rate, CurrentTime);
|
||||
}
|
||||
|
||||
void X11Display::exitFullscreen()
|
||||
{
|
||||
if (m_fullscreen_mode.rate > 0) {
|
||||
toggleFullscreen(false);
|
||||
m_fullscreen_mode.rate = 0;
|
||||
m_fullscreen_mode.size = 0;
|
||||
m_desktop_mode.rate = 0;
|
||||
m_desktop_mode.size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
||||
#define _NET_WM_STATE_ADD 1 /* add/set property */
|
||||
|
||||
void X11Display::wm_fullscreen(bool enabled) {
|
||||
|
||||
::Display* disp = sp::Xlib::getDisplay();
|
||||
|
||||
XEvent xev;
|
||||
Atom wm_state = sp::Xlib::getAtom("_NET_WM_STATE", False);
|
||||
Atom wm_fs = sp::Xlib::getAtom("_NET_WM_STATE_FULLSCREEN", False);
|
||||
|
||||
memset(&xev, 0, sizeof(xev));
|
||||
xev.type = ClientMessage;
|
||||
xev.xclient.window = m_win;
|
||||
xev.xclient.message_type = wm_state;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
|
||||
xev.xclient.data.l[1] = wm_fs;
|
||||
xev.xclient.data.l[2] = 0;
|
||||
|
||||
::XSendEvent(disp, ::XDefaultRootWindow(disp), False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
&xev);
|
||||
}
|
||||
|
||||
|
||||
void X11Display::setCaption(const std::string& caption)
|
||||
{
|
||||
::XStoreName(Xlib::getDisplay(), m_win, caption.c_str());
|
||||
}
|
||||
|
||||
void X11Display::setIcon(unsigned int width, unsigned int height, const uint8_t *pixels)
|
||||
{
|
||||
::Display* disp = Xlib::getDisplay();
|
||||
::Atom net_wm_icon = Xlib::getAtom("_NET_WM_ICON", False);
|
||||
::Atom cardinal = Xlib::getAtom("CARDINAL", False);
|
||||
std::vector<uint64_t> buffer(2 + width * height);
|
||||
uint64_t *ptr = &buffer[0];
|
||||
|
||||
*ptr++ = width;
|
||||
*ptr++ = height;
|
||||
|
||||
// TODO: Conversion between different 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(disp, m_win,
|
||||
net_wm_icon, cardinal, 32,
|
||||
PropModeReplace,
|
||||
reinterpret_cast<const unsigned char*>(&buffer[0]),
|
||||
2 + width * height);
|
||||
|
||||
XFlush(disp);
|
||||
}
|
||||
|
||||
void X11Display::createHiddenCursor()
|
||||
{
|
||||
::Display* disp = Xlib::getDisplay();
|
||||
XColor c;
|
||||
Pixmap pix = ::XCreatePixmap(disp, m_win, 1, 1, 1);
|
||||
GC gc = ::XCreateGC(disp, pix, 0, NULL);
|
||||
|
||||
// Draw transparent pixel.
|
||||
::XDrawPoint(disp, pix, gc, 0, 0);
|
||||
|
||||
c.red = c.green = c.blue = 0;
|
||||
c.flags = DoRed | DoGreen | DoBlue;
|
||||
m_cur_hidden = XCreatePixmapCursor(disp, pix, pix, &c, &c, 0, 0);
|
||||
|
||||
// Free GC and pixmap.
|
||||
::XFreePixmap(disp, pix);
|
||||
::XFreeGC(disp, gc);
|
||||
}
|
||||
|
||||
void X11Display::showCursor(bool value)
|
||||
{
|
||||
XDefineCursor(Xlib::getDisplay(), m_win, value ? m_cur_last : m_cur_hidden);
|
||||
}
|
||||
|
||||
void X11Display::grabCursor(bool value)
|
||||
{
|
||||
if (value) {
|
||||
int result = ::XGrabPointer(Xlib::getDisplay(), m_win, True, None,
|
||||
GrabModeAsync, GrabModeAsync, m_win, None, CurrentTime);
|
||||
|
||||
if (result != GrabSuccess) {
|
||||
Log::info("X11: Cursor Grab failed");
|
||||
}
|
||||
} else {
|
||||
::XUngrabPointer(Xlib::getDisplay(), CurrentTime);
|
||||
}
|
||||
}
|
||||
|
||||
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 %dx%d", m_size.x, m_size.y);
|
||||
onReshape(size.x, size.y);
|
||||
}
|
||||
break;
|
||||
case MotionNotify :
|
||||
// Generates to much events to log :)
|
||||
break;
|
||||
case FocusIn:
|
||||
Log::debug("X11: FocusIn");
|
||||
_priv::focused_display = this;
|
||||
|
||||
if (m_fullscreen_mode.rate > 0) {
|
||||
toggleFullscreen(true);
|
||||
}
|
||||
|
||||
break;
|
||||
case FocusOut:
|
||||
Log::debug("X11: FocusOut");
|
||||
_priv::focused_display = NULL;
|
||||
if (m_fullscreen_mode.rate > 0) {
|
||||
toggleFullscreen(false);
|
||||
minimize();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
Loading…
Add table
Add a link
Reference in a new issue