boo/lib/x11/WindowXlib.cpp

1286 lines
41 KiB
C++
Raw Normal View History

2015-08-18 22:43:30 +00:00
#include "boo/IWindow.hpp"
#include "boo/IGraphicsContext.hpp"
#include "boo/IApplication.hpp"
#include "boo/graphicsdev/GL.hpp"
2015-05-09 05:33:48 +00:00
2015-08-18 19:40:26 +00:00
#include <limits.h>
2015-05-09 05:33:48 +00:00
#include <stdlib.h>
#include <stdio.h>
2015-05-12 09:38:37 +00:00
#include <stdint.h>
2015-05-09 05:33:48 +00:00
#include <string.h>
2015-11-17 04:20:11 +00:00
#include <thread>
#include <mutex>
#include <condition_variable>
2015-05-09 05:33:48 +00:00
#include <GL/glx.h>
2015-05-09 05:33:48 +00:00
#define XK_MISCELLANY
#define XK_XKB_KEYS
#define XK_LATIN1
#include <X11/keysymdef.h>
#include <xkbcommon/xkbcommon.h>
#include <X11/extensions/XInput2.h>
#include <X11/Xatom.h>
2015-11-05 07:30:40 +00:00
#include <LogVisor/LogVisor.hpp>
2015-05-09 05:33:48 +00:00
2015-11-30 00:20:20 +00:00
#include "XlibCommon.hpp"
2015-05-09 05:33:48 +00:00
#define REF_DPMM 3.7824 /* 96 DPI */
#define FS_ATOM "_NET_WM_STATE_FULLSCREEN"
2015-05-06 00:50:57 +00:00
2015-11-05 07:30:40 +00:00
#define MWM_HINTS_FUNCTIONS (1L << 0)
#define MWM_HINTS_DECORATIONS (1L << 1)
#define MWM_DECOR_BORDER (1L<<1)
#define MWM_DECOR_RESIZEH (1L<<2)
#define MWM_DECOR_TITLE (1L<<3)
#define MWM_DECOR_MENU (1L<<4)
#define MWM_DECOR_MINIMIZE (1L<<5)
#define MWM_DECOR_MAXIMIZE (1L<<6)
#define MWM_FUNC_RESIZE (1L<<1)
#define MWM_FUNC_MOVE (1L<<2)
#define MWM_FUNC_MINIMIZE (1L<<3)
#define MWM_FUNC_MAXIMIZE (1L<<4)
#define MWM_FUNC_CLOSE (1L<<5)
2015-11-21 01:12:22 +00:00
#undef None
2015-10-31 19:21:23 +00:00
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
2015-11-17 04:20:11 +00:00
static glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
typedef int (*glXWaitVideoSyncSGIProc)(int divisor, int remainder, unsigned int* count);
static glXWaitVideoSyncSGIProc glXWaitVideoSyncSGI = 0;
2015-10-31 19:21:23 +00:00
static const int ContextAttribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
2015-11-05 04:31:30 +00:00
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
2015-10-31 19:21:23 +00:00
//GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
//GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
2015-11-21 01:12:22 +00:00
0
2015-10-31 19:21:23 +00:00
};
2015-05-06 00:50:57 +00:00
namespace boo
{
static LogVisor::LogModule Log("boo::WindowXCB");
2015-11-06 03:35:17 +00:00
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent);
void _XlibUpdateLastGlxCtx(GLXContext lastGlxCtx);
void GLXExtensionCheck();
void GLXEnableVSync(Display* disp, GLXWindow drawable);
2015-05-09 05:33:48 +00:00
2015-05-13 08:51:18 +00:00
extern int XINPUT_OPCODE;
2015-11-21 01:12:22 +00:00
static uint32_t translateKeysym(KeySym sym, ESpecialKey& specialSym, EModifierKey& modifierSym)
2015-05-09 05:33:48 +00:00
{
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::None;
modifierSym = EModifierKey::None;
2015-05-09 05:33:48 +00:00
if (sym >= XK_F1 && sym <= XK_F12)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey(int(ESpecialKey::F1) + sym - XK_F1);
2015-05-09 05:33:48 +00:00
else if (sym == XK_Escape)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::Esc;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Return)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::Enter;
2015-05-09 05:33:48 +00:00
else if (sym == XK_BackSpace)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::Backspace;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Insert)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::Insert;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Delete)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::Delete;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Home)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::Home;
2015-05-09 05:33:48 +00:00
else if (sym == XK_End)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::End;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Page_Up)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::PgUp;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Page_Down)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::PgDown;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Left)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::Left;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Right)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::Right;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Up)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::Up;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Down)
2015-11-21 01:12:22 +00:00
specialSym = ESpecialKey::Down;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Shift_L || sym == XK_Shift_R)
2015-11-21 01:12:22 +00:00
modifierSym = EModifierKey::Shift;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Control_L || sym == XK_Control_R)
2015-11-21 01:12:22 +00:00
modifierSym = EModifierKey::Ctrl;
2015-05-09 05:33:48 +00:00
else if (sym == XK_Alt_L || sym == XK_Alt_R)
2015-11-21 01:12:22 +00:00
modifierSym = EModifierKey::Alt;
2015-05-09 05:33:48 +00:00
else
return xkb_keysym_to_utf32(sym);
return 0;
}
2015-11-21 01:12:22 +00:00
static EModifierKey translateModifiers(unsigned state)
2015-05-09 05:33:48 +00:00
{
2015-11-21 01:12:22 +00:00
EModifierKey retval = EModifierKey::None;
if (state & ShiftMask)
2015-11-21 01:12:22 +00:00
retval |= EModifierKey::Shift;
if (state & ControlMask)
2015-11-21 01:12:22 +00:00
retval |= EModifierKey::Ctrl;
if (state & Mod1Mask)
2015-11-21 01:12:22 +00:00
retval |= EModifierKey::Alt;
2015-05-09 05:33:48 +00:00
return retval;
}
2015-11-21 01:12:22 +00:00
static EMouseButton translateButton(unsigned detail)
2015-05-09 05:33:48 +00:00
{
2015-11-21 01:12:22 +00:00
switch (detail)
{
case 1:
return EMouseButton::Primary;
case 3:
return EMouseButton::Secondary;
case 2:
return EMouseButton::Middle;
case 8:
return EMouseButton::Aux1;
case 9:
return EMouseButton::Aux2;
default: break;
}
return EMouseButton::None;
2015-05-09 05:33:48 +00:00
}
2015-08-18 19:40:26 +00:00
struct XCBAtoms
2015-05-09 05:33:48 +00:00
{
Atom m_wmProtocols = 0;
Atom m_wmDeleteWindow = 0;
Atom m_netwmState = 0;
Atom m_netwmStateFullscreen = 0;
Atom m_netwmStateAdd = 0;
Atom m_netwmStateRemove = 0;
2015-10-31 19:21:23 +00:00
Atom m_motifWmHints = 0;
XCBAtoms(Display* disp)
{
m_wmProtocols = XInternAtom(disp, "WM_PROTOCOLS", True);
m_wmDeleteWindow = XInternAtom(disp, "WM_DELETE_WINDOW", True);
m_netwmState = XInternAtom(disp, "_NET_WM_STATE", False);
m_netwmStateFullscreen = XInternAtom(disp, "_NET_WM_STATE_FULLSCREEN", False);
m_netwmStateAdd = XInternAtom(disp, "_NET_WM_STATE_ADD", False);
m_netwmStateRemove = XInternAtom(disp, "_NET_WM_STATE_REMOVE", False);
2015-10-31 19:21:23 +00:00
m_motifWmHints = XInternAtom(disp, "_MOTIF_WM_HINTS", True);
2015-05-09 05:33:48 +00:00
}
};
2015-08-18 19:40:26 +00:00
static XCBAtoms* S_ATOMS = NULL;
2015-05-09 05:33:48 +00:00
2015-10-31 19:21:23 +00:00
static void genFrameDefault(Screen* screen, int& xOut, int& yOut, int& wOut, int& hOut)
2015-05-09 05:33:48 +00:00
{
float width = screen->width * 2.0 / 3.0;
float height = screen->height * 2.0 / 3.0;
2015-10-31 19:21:23 +00:00
xOut = (screen->width - width) / 2.0;
yOut = (screen->height - height) / 2.0;
wOut = width;
hOut = height;
2015-05-09 05:33:48 +00:00
}
2015-05-06 00:50:57 +00:00
struct GraphicsContextGLX : IGraphicsContext
2015-08-28 00:10:46 +00:00
{
EGraphicsAPI m_api;
EPixelFormat m_pf;
IWindow* m_parentWindow;
Display* m_xDisp = nullptr;
GLXContext m_lastCtx = 0;
2015-08-28 00:10:46 +00:00
GLXFBConfig m_fbconfig = 0;
int m_visualid = 0;
GLXWindow m_glxWindow = 0;
GLXContext m_glxCtx = 0;
2015-08-28 00:10:46 +00:00
2015-10-30 00:00:56 +00:00
IGraphicsCommandQueue* m_commandQueue = nullptr;
IGraphicsDataFactory* m_dataFactory = nullptr;
2015-11-17 06:41:32 +00:00
GLXContext m_mainCtx = 0;
GLXContext m_loadCtx = 0;
2015-10-30 00:00:56 +00:00
2015-11-17 04:20:11 +00:00
std::thread m_vsyncThread;
bool m_vsyncRunning;
2015-08-28 00:10:46 +00:00
public:
IWindowCallback* m_callback;
GraphicsContextGLX(EGraphicsAPI api, IWindow* parentWindow,
Display* display, int defaultScreen,
GLXContext lastCtx, uint32_t& visualIdOut)
2015-08-28 00:10:46 +00:00
: m_api(api),
2015-11-21 01:12:22 +00:00
m_pf(EPixelFormat::RGBA8_Z24),
2015-08-28 00:10:46 +00:00
m_parentWindow(parentWindow),
m_xDisp(display),
m_lastCtx(lastCtx)
{
2015-11-12 04:31:59 +00:00
m_dataFactory = new class GLDataFactory(this);
/* Query framebuffer configurations */
GLXFBConfig* fbConfigs = nullptr;
int numFBConfigs = 0;
fbConfigs = glXGetFBConfigs(display, defaultScreen, &numFBConfigs);
if (!fbConfigs || numFBConfigs == 0)
2015-08-28 00:10:46 +00:00
{
Log.report(LogVisor::FatalError, "glXGetFBConfigs failed");
return;
}
2015-08-28 00:10:46 +00:00
for (int i=0 ; i<numFBConfigs ; ++i)
2015-08-28 00:10:46 +00:00
{
GLXFBConfig config = fbConfigs[i];
int visualId, depthSize, colorSize, doubleBuffer;
glXGetFBConfigAttrib(display, config, GLX_VISUAL_ID, &visualId);
glXGetFBConfigAttrib(display, config, GLX_DEPTH_SIZE, &depthSize);
glXGetFBConfigAttrib(display, config, GLX_BUFFER_SIZE, &colorSize);
glXGetFBConfigAttrib(display, config, GLX_DOUBLEBUFFER, &doubleBuffer);
2015-08-28 00:10:46 +00:00
/* Double-buffer only */
if (!doubleBuffer)
continue;
2015-11-21 01:12:22 +00:00
if (m_pf == EPixelFormat::RGBA8 && colorSize >= 32)
2015-08-28 00:10:46 +00:00
{
m_fbconfig = config;
2015-08-28 00:10:46 +00:00
m_visualid = visualId;
break;
}
2015-11-21 01:12:22 +00:00
else if (m_pf == EPixelFormat::RGBA8_Z24 && colorSize >= 32 && depthSize >= 24)
2015-08-28 00:10:46 +00:00
{
m_fbconfig = config;
2015-08-28 00:10:46 +00:00
m_visualid = visualId;
break;
}
2015-11-21 01:12:22 +00:00
else if (m_pf == EPixelFormat::RGBAF32 && colorSize >= 128)
2015-08-28 00:10:46 +00:00
{
m_fbconfig = config;
2015-08-28 00:10:46 +00:00
m_visualid = visualId;
break;
}
2015-11-21 01:12:22 +00:00
else if (m_pf == EPixelFormat::RGBAF32_Z24 && colorSize >= 128 && depthSize >= 24)
2015-08-28 00:10:46 +00:00
{
m_fbconfig = config;
2015-08-28 00:10:46 +00:00
m_visualid = visualId;
break;
}
}
XFree(fbConfigs);
2015-08-28 00:10:46 +00:00
if (!m_fbconfig)
{
Log.report(LogVisor::FatalError, "unable to find suitable pixel format");
2015-08-28 00:10:46 +00:00
return;
}
visualIdOut = m_visualid;
}
~GraphicsContextGLX()
2015-08-28 00:10:46 +00:00
{
2015-10-28 01:47:55 +00:00
if (m_glxCtx)
glXDestroyContext(m_xDisp, m_glxCtx);
2015-10-28 01:47:55 +00:00
if (m_glxWindow)
glXDestroyWindow(m_xDisp, m_glxWindow);
2015-10-30 00:00:56 +00:00
if (m_loadCtx)
glXDestroyContext(m_xDisp, m_loadCtx);
2015-11-17 04:20:11 +00:00
m_vsyncRunning = false;
m_vsyncThread.join();
2015-08-28 00:10:46 +00:00
}
void _setCallback(IWindowCallback* cb)
{
m_callback = cb;
}
EGraphicsAPI getAPI() const
{
return m_api;
}
EPixelFormat getPixelFormat() const
{
return m_pf;
}
void setPixelFormat(EPixelFormat pf)
{
2015-11-21 01:12:22 +00:00
if (pf > EPixelFormat::RGBAF32_Z24)
2015-08-28 00:10:46 +00:00
return;
m_pf = pf;
}
2015-11-17 04:20:11 +00:00
std::mutex m_vsyncmt;
std::condition_variable m_vsynccv;
2015-08-28 00:10:46 +00:00
void initializeContext()
{
2015-11-17 04:20:11 +00:00
if (!glXCreateContextAttribsARB)
{
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
if (!glXCreateContextAttribsARB)
Log.report(LogVisor::FatalError, "unable to resolve glXCreateContextAttribsARB");
}
if (!glXWaitVideoSyncSGI)
{
glXWaitVideoSyncSGI = (glXWaitVideoSyncSGIProc)
glXGetProcAddressARB((const GLubyte*)"glXWaitVideoSyncSGI");
if (!glXWaitVideoSyncSGI)
Log.report(LogVisor::FatalError, "unable to resolve glXWaitVideoSyncSGI");
}
2015-10-31 19:21:23 +00:00
m_glxCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_lastCtx, True, ContextAttribs);
if (!m_glxCtx)
Log.report(LogVisor::FatalError, "unable to make new GLX context");
m_glxWindow = glXCreateWindow(m_xDisp, m_fbconfig, m_parentWindow->getPlatformHandle(), nullptr);
if (!m_glxWindow)
Log.report(LogVisor::FatalError, "unable to make new GLX window");
_XlibUpdateLastGlxCtx(m_glxCtx);
2015-11-17 04:20:11 +00:00
/* Spawn vsync thread */
m_vsyncRunning = true;
std::mutex initmt;
std::condition_variable initcv;
std::unique_lock<std::mutex> outerLk(initmt);
m_vsyncThread = std::thread([&]()
{
Display* vsyncDisp;
GLXContext vsyncCtx;
{
std::unique_lock<std::mutex> innerLk(initmt);
vsyncDisp = XOpenDisplay(0);
if (!vsyncDisp)
Log.report(LogVisor::FatalError, "unable to open new vsync display");
XLockDisplay(vsyncDisp);
2015-11-17 04:20:11 +00:00
2015-11-21 01:12:22 +00:00
static int attributeList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, 0 };
2015-11-18 05:58:37 +00:00
XVisualInfo *vi = glXChooseVisual(vsyncDisp, DefaultScreen(vsyncDisp),attributeList);
vsyncCtx = glXCreateContext(vsyncDisp, vi, nullptr, True);
2015-11-17 04:20:11 +00:00
if (!vsyncCtx)
Log.report(LogVisor::FatalError, "unable to make new vsync GLX context");
if (!glXMakeCurrent(vsyncDisp, DefaultRootWindow(vsyncDisp), vsyncCtx))
Log.report(LogVisor::FatalError, "unable to make vsync context current");
}
initcv.notify_one();
while (m_vsyncRunning)
{
unsigned int sync;
int err = glXWaitVideoSyncSGI(1, 0, &sync);
if (err)
Log.report(LogVisor::FatalError, "wait err");
m_vsynccv.notify_one();
}
2015-11-21 01:12:22 +00:00
glXMakeCurrent(vsyncDisp, 0, nullptr);
2015-11-17 04:20:11 +00:00
glXDestroyContext(vsyncDisp, vsyncCtx);
XUnlockDisplay(vsyncDisp);
2015-11-17 04:20:11 +00:00
XCloseDisplay(vsyncDisp);
});
initcv.wait(outerLk);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
m_commandQueue = _NewGLCommandQueue(this);
XLockDisplay(m_xDisp);
2015-10-28 01:47:55 +00:00
}
void makeCurrent()
{
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_glxCtx))
Log.report(LogVisor::FatalError, "unable to make GLX context current");
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
}
void postInit()
{
GLXExtensionCheck();
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
GLXEnableVSync(m_xDisp, m_glxWindow);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-08-28 00:10:46 +00:00
}
2015-10-30 00:00:56 +00:00
IGraphicsCommandQueue* getCommandQueue()
{
return m_commandQueue;
}
IGraphicsDataFactory* getDataFactory()
{
2015-10-30 00:00:56 +00:00
return m_dataFactory;
}
2015-11-17 06:41:32 +00:00
IGraphicsDataFactory* getMainContextDataFactory()
{
XLockDisplay(m_xDisp);
if (!m_mainCtx)
{
m_mainCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribs);
if (!m_mainCtx)
Log.report(LogVisor::FatalError, "unable to make main GLX context");
}
if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_mainCtx))
Log.report(LogVisor::FatalError, "unable to make main GLX context current");
XUnlockDisplay(m_xDisp);
return getDataFactory();
}
2015-10-30 00:00:56 +00:00
IGraphicsDataFactory* getLoadContextDataFactory()
{
2015-11-13 02:11:32 +00:00
XLockDisplay(m_xDisp);
2015-10-30 00:00:56 +00:00
if (!m_loadCtx)
{
2015-10-31 19:21:23 +00:00
m_loadCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribs);
if (!m_loadCtx)
Log.report(LogVisor::FatalError, "unable to make load GLX context");
2015-10-30 00:00:56 +00:00
}
2015-11-04 01:02:05 +00:00
if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_loadCtx))
Log.report(LogVisor::FatalError, "unable to make load GLX context current");
2015-11-13 02:11:32 +00:00
XUnlockDisplay(m_xDisp);
2015-10-30 00:00:56 +00:00
return getDataFactory();
}
void present()
{
XLockDisplay(m_xDisp);
glXSwapBuffers(m_xDisp, m_glxWindow);
XUnlockDisplay(m_xDisp);
}
2015-08-28 00:10:46 +00:00
};
2015-05-06 00:50:57 +00:00
class WindowXlib : public IWindow
2015-05-06 00:50:57 +00:00
{
Display* m_xDisp;
2015-05-09 05:33:48 +00:00
IWindowCallback* m_callback;
Colormap m_colormapId;
Window m_windowId;
GraphicsContextGLX m_gfxCtx;
2015-08-28 00:10:46 +00:00
uint32_t m_visualId;
2015-05-09 05:33:48 +00:00
2015-05-13 08:51:18 +00:00
/* Last known input device id (0xffff if not yet set) */
int m_lastInputID = 0xffff;
2015-11-21 01:12:22 +00:00
ETouchType m_touchType = ETouchType::None;
2015-05-13 08:51:18 +00:00
/* Scroll valuators */
int m_hScrollValuator = -1;
int m_vScrollValuator = -1;
double m_hScrollLast = 0.0;
double m_vScrollLast = 0.0;
2015-05-09 05:33:48 +00:00
/* Cached window rectangle (to avoid repeated X queries) */
int m_wx, m_wy, m_ww, m_wh;
float m_pixelFactor;
bool m_inFs = false;
2015-11-05 07:30:40 +00:00
/* Cached window style */
EWindowStyle m_styleFlags;
2015-11-30 00:20:20 +00:00
/* Current cursor enum */
EMouseCursor m_cursor = EMouseCursor::None;
bool m_cursorWait = false;
static Cursor GetXCursor(EMouseCursor cur)
{
switch (cur)
{
case EMouseCursor::Pointer:
return X_CURSORS.m_pointer;
case EMouseCursor::HorizontalArrow:
return X_CURSORS.m_hArrow;
case EMouseCursor::VerticalArrow:
return X_CURSORS.m_vArrow;
default: break;
}
return X_CURSORS.m_pointer;
}
2015-05-06 00:50:57 +00:00
public:
WindowXlib(const std::string& title,
Display* display, int defaultScreen,
GLXContext lastCtx)
: m_xDisp(display), m_callback(nullptr),
2015-11-21 01:12:22 +00:00
m_gfxCtx(IGraphicsContext::EGraphicsAPI::OpenGL3_3,
this, display, defaultScreen,
lastCtx, m_visualId)
2015-05-06 00:50:57 +00:00
{
2015-05-09 05:33:48 +00:00
if (!S_ATOMS)
S_ATOMS = new XCBAtoms(display);
2015-05-09 05:33:48 +00:00
/* Default screen */
Screen* screen = ScreenOfDisplay(display, defaultScreen);
m_pixelFactor = screen->width / (float)screen->mwidth / REF_DPMM;
XVisualInfo visTemplate;
visTemplate.screen = defaultScreen;
int numVisuals;
XVisualInfo* visualList = XGetVisualInfo(display, VisualScreenMask, &visTemplate, &numVisuals);
Visual* selectedVisual = nullptr;
for (int i=0 ; i<numVisuals ; ++i)
{
if (visualList[i].visualid == m_visualId)
{
selectedVisual = visualList[i].visual;
break;
}
}
XFree(visualList);
2015-05-09 05:33:48 +00:00
2015-05-10 07:02:18 +00:00
/* Create colormap */
2015-10-31 05:43:16 +00:00
m_colormapId = XCreateColormap(m_xDisp, screen->root, selectedVisual, AllocNone);
2015-05-10 07:02:18 +00:00
2015-05-09 05:33:48 +00:00
/* Create window */
int x, y, w, h;
2015-10-31 19:21:23 +00:00
genFrameDefault(screen, x, y, w, h);
2015-10-31 05:43:16 +00:00
XSetWindowAttributes swa;
swa.colormap = m_colormapId;
2015-11-21 01:12:22 +00:00
swa.border_pixmap = 0;
swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask | LeaveWindowMask | EnterWindowMask;
2015-10-31 05:43:16 +00:00
m_windowId = XCreateWindow(display, screen->root, x, y, w, h, 10,
CopyFromParent, CopyFromParent, selectedVisual,
2015-10-31 05:43:16 +00:00
CWBorderPixel | CWEventMask | CWColormap, &swa);
2015-05-09 05:33:48 +00:00
2015-05-13 08:51:18 +00:00
/* The XInput 2.1 extension enables per-pixel smooth scrolling trackpads */
XIEventMask mask = {XIAllMasterDevices, XIMaskLen(XI_LASTEVENT)};
mask.mask = (unsigned char*)malloc(mask.mask_len);
memset(mask.mask, 0, mask.mask_len);
2015-11-02 09:31:06 +00:00
/* XISetMask(mask.mask, XI_Motion); Can't do this without losing mouse move events :( */
XISetMask(mask.mask, XI_TouchBegin);
XISetMask(mask.mask, XI_TouchUpdate);
XISetMask(mask.mask, XI_TouchEnd);
XISelectEvents(m_xDisp, m_windowId, &mask, 1);
free(mask.mask);
2015-05-12 09:38:37 +00:00
2015-05-13 08:51:18 +00:00
/* Register netwm extension atom for window closing */
XSetWMProtocols(m_xDisp, m_windowId, &S_ATOMS->m_wmDeleteWindow, 1);
2015-05-12 09:38:37 +00:00
2015-05-09 05:33:48 +00:00
/* Set the title of the window */
const unsigned char* c_title = (unsigned char*)title.c_str();
XChangeProperty(m_xDisp, m_windowId, XA_WM_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length());
2015-05-09 05:33:48 +00:00
/* Set the title of the window icon */
XChangeProperty(m_xDisp, m_windowId, XA_WM_ICON_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length());
2015-05-09 05:33:48 +00:00
2015-05-10 07:02:18 +00:00
/* Initialize context */
XMapWindow(m_xDisp, m_windowId);
2015-11-21 01:12:22 +00:00
setStyle(EWindowStyle::Default);
2015-11-30 00:20:20 +00:00
setCursor(EMouseCursor::Pointer);
XFlush(m_xDisp);
2015-11-05 07:30:40 +00:00
2015-08-28 00:10:46 +00:00
m_gfxCtx.initializeContext();
2015-05-06 00:50:57 +00:00
}
~WindowXlib()
2015-05-06 00:50:57 +00:00
{
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
XUnmapWindow(m_xDisp, m_windowId);
XDestroyWindow(m_xDisp, m_windowId);
XFreeColormap(m_xDisp, m_colormapId);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-08-18 19:40:26 +00:00
APP->_deletedWindow(this);
2015-05-06 00:50:57 +00:00
}
void setCallback(IWindowCallback* cb)
{
2015-05-09 05:33:48 +00:00
m_callback = cb;
2015-05-06 00:50:57 +00:00
}
void showWindow()
{
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
XMapWindow(m_xDisp, m_windowId);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-05-06 00:50:57 +00:00
}
void hideWindow()
{
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
XUnmapWindow(m_xDisp, m_windowId);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-05-06 00:50:57 +00:00
}
std::string getTitle()
{
2015-10-31 19:21:23 +00:00
unsigned long nitems;
Atom actualType;
int actualFormat;
unsigned long bytes;
unsigned char* string = nullptr;
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
int ret = XGetWindowProperty(m_xDisp, m_windowId, XA_WM_NAME, 0, ~0l, False,
XA_STRING, &actualType, &actualFormat, &nitems, &bytes, &string);
XUnlockDisplay(m_xDisp);
if (ret == Success)
{
std::string retval((const char*)string);
XFree(string);
return retval;
}
return std::string();
2015-05-06 00:50:57 +00:00
}
void setTitle(const std::string& title)
{
const unsigned char* c_title = (unsigned char*)title.c_str();
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
XChangeProperty(m_xDisp, m_windowId, XA_WM_NAME, XA_STRING, 8,
PropModeReplace, c_title, title.length());
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-05-06 00:50:57 +00:00
}
2015-11-30 00:20:20 +00:00
void setCursor(EMouseCursor cursor)
{
if (cursor == m_cursor && !m_cursorWait)
return;
m_cursor = cursor;
XLockDisplay(m_xDisp);
XDefineCursor(m_xDisp, m_windowId, GetXCursor(cursor));
XUnlockDisplay(m_xDisp);
}
void setWaitCursor(bool wait)
{
if (wait && !m_cursorWait)
{
XLockDisplay(m_xDisp);
XDefineCursor(m_xDisp, m_windowId, X_CURSORS.m_wait);
XUnlockDisplay(m_xDisp);
m_cursorWait = true;
}
else if (!wait && m_cursorWait)
{
setCursor(m_cursor);
m_cursorWait = false;
}
}
2015-05-06 00:50:57 +00:00
void setWindowFrameDefault()
{
2015-05-09 05:33:48 +00:00
int x, y, w, h;
Screen* screen = DefaultScreenOfDisplay(m_xDisp);
2015-10-31 19:21:23 +00:00
genFrameDefault(screen, x, y, w, h);
XWindowChanges values = {(int)x, (int)y, (int)w, (int)h};
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
XConfigureWindow(m_xDisp, m_windowId, CWX|CWY|CWWidth|CWHeight, &values);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-05-06 00:50:57 +00:00
}
void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const
{
2015-10-31 19:21:23 +00:00
XWindowAttributes attrs;
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
2015-10-31 19:21:23 +00:00
XGetWindowAttributes(m_xDisp, m_windowId, &attrs);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-10-31 19:21:23 +00:00
xOut = attrs.x;
yOut = attrs.y;
wOut = attrs.width;
hOut = attrs.height;
}
void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const
{
XWindowAttributes attrs;
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
2015-10-31 19:21:23 +00:00
XGetWindowAttributes(m_xDisp, m_windowId, &attrs);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-10-31 19:21:23 +00:00
xOut = attrs.x;
yOut = attrs.y;
wOut = attrs.width;
hOut = attrs.height;
2015-05-06 00:50:57 +00:00
}
void setWindowFrame(float x, float y, float w, float h)
{
XWindowChanges values = {(int)x, (int)y, (int)w, (int)h};
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
XConfigureWindow(m_xDisp, m_windowId, CWX|CWY|CWWidth|CWHeight, &values);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-05-06 00:50:57 +00:00
}
2015-10-31 19:21:23 +00:00
void setWindowFrame(int x, int y, int w, int h)
{
XWindowChanges values = {x, y, w, h};
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
2015-10-31 19:21:23 +00:00
XConfigureWindow(m_xDisp, m_windowId, CWX|CWY|CWWidth|CWHeight, &values);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-10-31 19:21:23 +00:00
}
2015-05-06 00:50:57 +00:00
float getVirtualPixelFactor() const
{
2015-05-09 05:33:48 +00:00
return m_pixelFactor;
2015-05-06 00:50:57 +00:00
}
2015-05-06 00:50:57 +00:00
bool isFullscreen() const
{
2015-11-05 07:30:40 +00:00
return m_inFs;
unsigned long nitems;
2015-10-31 06:39:11 +00:00
Atom actualType;
int actualFormat;
unsigned long bytes;
Atom* vals = nullptr;
bool fullscreen = false;
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
int ret = XGetWindowProperty(m_xDisp, m_windowId, S_ATOMS->m_netwmState, 0, ~0l, False,
XA_ATOM, &actualType, &actualFormat, &nitems, &bytes, (unsigned char**)&vals);
XUnlockDisplay(m_xDisp);
if (ret == Success)
2015-05-09 05:33:48 +00:00
{
for (int i=0 ; i<nitems ; ++i)
2015-05-09 05:33:48 +00:00
{
if (vals[i] == S_ATOMS->m_netwmStateFullscreen)
{
fullscreen = true;
break;
}
2015-05-09 05:33:48 +00:00
}
XFree(vals);
return fullscreen;
2015-05-09 05:33:48 +00:00
}
return false;
2015-05-06 00:50:57 +00:00
}
2015-11-05 07:30:40 +00:00
void setStyle(EWindowStyle style)
{
struct
{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long inputMode;
unsigned long status;
} wmHints = {0};
if (S_ATOMS->m_motifWmHints)
{
wmHints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS;
2015-11-21 01:12:22 +00:00
if ((style & EWindowStyle::Titlebar) != EWindowStyle::None)
2015-11-05 07:30:40 +00:00
{
wmHints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU;
wmHints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE;
}
2015-11-21 01:12:22 +00:00
if ((style & EWindowStyle::Resize) != EWindowStyle::None)
2015-11-05 07:30:40 +00:00
{
wmHints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH;
wmHints.functions |= MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE;
}
2015-11-21 01:12:22 +00:00
if ((style & EWindowStyle::Close) != EWindowStyle::None)
2015-11-05 07:30:40 +00:00
wmHints.functions |= MWM_FUNC_CLOSE;
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
2015-11-05 07:30:40 +00:00
XChangeProperty(m_xDisp, m_windowId, S_ATOMS->m_motifWmHints, S_ATOMS->m_motifWmHints, 32, PropModeReplace, (unsigned char*)&wmHints, 5);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-11-05 07:30:40 +00:00
}
m_styleFlags = style;
}
EWindowStyle getStyle() const
{
return m_styleFlags;
}
2015-05-06 00:50:57 +00:00
void setFullscreen(bool fs)
{
if (fs == m_inFs)
return;
XEvent fsEvent = {0};
2015-11-05 04:31:30 +00:00
fsEvent.xclient.type = ClientMessage;
2015-11-05 07:30:40 +00:00
fsEvent.xclient.serial = 0;
fsEvent.xclient.send_event = True;
2015-10-31 06:39:11 +00:00
fsEvent.xclient.window = m_windowId;
2015-11-05 07:30:40 +00:00
fsEvent.xclient.message_type = S_ATOMS->m_netwmState;
2015-10-31 06:39:11 +00:00
fsEvent.xclient.format = 32;
fsEvent.xclient.data.l[0] = fs;
2015-11-05 07:30:40 +00:00
fsEvent.xclient.data.l[1] = S_ATOMS->m_netwmStateFullscreen;
2015-10-31 06:39:11 +00:00
fsEvent.xclient.data.l[2] = 0;
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
2015-11-05 04:31:30 +00:00
XSendEvent(m_xDisp, DefaultRootWindow(m_xDisp), False,
StructureNotifyMask | SubstructureRedirectMask, (XEvent*)&fsEvent);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-11-05 07:30:40 +00:00
m_inFs = fs;
2015-05-09 05:33:48 +00:00
}
void waitForRetrace()
2015-08-28 00:10:46 +00:00
{
2015-11-17 04:20:11 +00:00
std::unique_lock<std::mutex> lk(m_gfxCtx.m_vsyncmt);
m_gfxCtx.m_vsynccv.wait(lk);
2015-08-28 00:10:46 +00:00
}
2015-05-09 05:33:48 +00:00
uintptr_t getPlatformHandle() const
{
return (uintptr_t)m_windowId;
}
void _pointingDeviceChanged(int deviceId)
2015-05-09 05:33:48 +00:00
{
int nDevices;
XIDeviceInfo* devices = XIQueryDevice(m_xDisp, deviceId, &nDevices);
2015-05-13 08:51:18 +00:00
for (int i=0 ; i<nDevices ; ++i)
2015-05-12 09:38:37 +00:00
{
XIDeviceInfo* device = &devices[i];
2015-05-13 08:51:18 +00:00
/* First iterate classes for scrollables */
int hScroll = -1;
int vScroll = -1;
m_hScrollLast = 0.0;
m_vScrollLast = 0.0;
m_hScrollValuator = -1;
m_vScrollValuator = -1;
for (int j=0 ; j<device->num_classes ; ++j)
2015-05-12 09:38:37 +00:00
{
XIAnyClassInfo* dclass = device->classes[j];
if (dclass->type == XIScrollClass)
2015-05-13 08:51:18 +00:00
{
XIScrollClassInfo* scrollClass = (XIScrollClassInfo*)dclass;
if (scrollClass->scroll_type == XIScrollTypeVertical)
2015-05-13 08:51:18 +00:00
vScroll = scrollClass->number;
else if (scrollClass->scroll_type == XIScrollTypeHorizontal)
2015-05-13 08:51:18 +00:00
hScroll = scrollClass->number;
}
2015-05-12 09:38:37 +00:00
}
2015-05-13 08:51:18 +00:00
/* Next iterate for touch and scroll valuators */
for (int j=0 ; j<device->num_classes ; ++j)
2015-05-13 08:51:18 +00:00
{
XIAnyClassInfo* dclass = device->classes[j];
if (dclass->type == XIValuatorClass)
2015-05-13 08:51:18 +00:00
{
XIValuatorClassInfo* valClass = (XIValuatorClassInfo*)dclass;
2015-05-13 08:51:18 +00:00
if (valClass->number == vScroll)
{
m_vScrollLast = valClass->value;
2015-05-13 08:51:18 +00:00
m_vScrollValuator = vScroll;
}
else if (valClass->number == hScroll)
{
m_hScrollLast = valClass->value;
2015-05-13 08:51:18 +00:00
m_hScrollValuator = hScroll;
}
}
else if (dclass->type == XITouchClass)
2015-05-13 08:51:18 +00:00
{
XITouchClassInfo* touchClass = (XITouchClassInfo*)dclass;
if (touchClass->mode == XIDirectTouch)
2015-11-21 01:12:22 +00:00
m_touchType = ETouchType::Display;
else if (touchClass->mode == XIDependentTouch)
2015-11-21 01:12:22 +00:00
m_touchType = ETouchType::Trackpad;
2015-05-13 08:51:18 +00:00
else
2015-11-21 01:12:22 +00:00
m_touchType = ETouchType::None;
2015-05-13 08:51:18 +00:00
}
}
2015-05-12 09:38:37 +00:00
}
2015-05-13 08:51:18 +00:00
XIFreeDeviceInfo(devices);
2015-05-13 08:51:18 +00:00
m_lastInputID = deviceId;
}
SWindowCoord MakeButtonEventCoord(XEvent* event) const
{
int x = event->xbutton.x;
int y = m_wh-event->xbutton.y;
return
{
{x, y},
{int(x / m_pixelFactor), int(y / m_pixelFactor)},
{x / float(m_ww), y / float(m_wh)}
};
}
SWindowCoord MakeMotionEventCoord(XEvent* event) const
{
int x = event->xmotion.x;
int y = m_wh-event->xmotion.y;
return
{
{x, y},
{int(x / m_pixelFactor), int(y / m_pixelFactor)},
{x / float(m_ww), y / float(m_wh)}
};
}
SWindowCoord MakeCrossingEventCoord(XEvent* event) const
{
int x = event->xcrossing.x;
int y = m_wh-event->xcrossing.y;
return
{
{x, y},
{int(x / m_pixelFactor), int(y / m_pixelFactor)},
{x / float(m_ww), y / float(m_wh)}
};
}
2015-05-13 08:51:18 +00:00
void _incomingEvent(void* e)
{
XEvent* event = (XEvent*)e;
switch (event->type)
2015-05-13 08:51:18 +00:00
{
case ClientMessage:
{
if (event->xclient.data.l[0] == S_ATOMS->m_wmDeleteWindow && m_callback)
2015-11-26 23:03:01 +00:00
{
m_callback->destroyed();
2015-11-26 23:03:01 +00:00
m_callback = nullptr;
}
return;
}
case Expose:
2015-05-09 05:33:48 +00:00
{
Window nw;
XWindowAttributes wxa;
int x, y;
XTranslateCoordinates(m_xDisp, m_windowId, DefaultRootWindow(m_xDisp), event->xexpose.x, event->xexpose.y, &x, &y, &nw);
XGetWindowAttributes(m_xDisp, m_windowId, &wxa);
m_wx = x - wxa.x;
m_wy = y - wxa.y;
m_ww = event->xexpose.width;
m_wh = event->xexpose.height;
2015-11-02 09:31:06 +00:00
if (m_callback)
{
2015-11-03 04:27:56 +00:00
SWindowRect rect =
2015-11-02 09:31:06 +00:00
{ {m_wx, m_wy}, {m_ww, m_wh} };
m_callback->resized(rect);
}
2015-05-13 08:51:18 +00:00
return;
2015-05-09 05:33:48 +00:00
}
case ConfigureNotify:
2015-05-09 05:33:48 +00:00
{
Window nw;
XWindowAttributes wxa;
int x, y;
XTranslateCoordinates(m_xDisp, m_windowId, DefaultRootWindow(m_xDisp), event->xconfigure.x, event->xconfigure.y, &x, &y, &nw);
XGetWindowAttributes(m_xDisp, m_windowId, &wxa);
m_wx = x - wxa.x;
m_wy = y - wxa.y;
m_ww = event->xconfigure.width;
m_wh = event->xconfigure.height;
2015-11-02 09:31:06 +00:00
if (m_callback)
{
SWindowRect rect =
{ {m_wx, m_wy}, {m_ww, m_wh} };
m_callback->windowMoved(rect);
2015-05-12 09:38:37 +00:00
}
2015-05-13 08:51:18 +00:00
return;
2015-05-09 05:33:48 +00:00
}
case KeyPress:
2015-05-09 05:33:48 +00:00
{
if (m_callback)
{
2015-11-21 01:12:22 +00:00
ESpecialKey specialKey;
EModifierKey modifierKey;
uint32_t charCode = translateKeysym(XLookupKeysym(&event->xkey, 0),
2015-10-28 01:47:55 +00:00
specialKey, modifierKey);
2015-11-21 01:12:22 +00:00
EModifierKey modifierMask = translateModifiers(event->xkey.state);
2015-05-09 05:33:48 +00:00
if (charCode)
2015-11-21 01:12:22 +00:00
m_callback->charKeyDown(charCode, modifierMask, false);
else if (specialKey != ESpecialKey::None)
m_callback->specialKeyDown(specialKey, modifierMask, false);
else if (modifierKey != EModifierKey::None)
m_callback->modKeyDown(modifierKey, false);
2015-05-09 05:33:48 +00:00
}
2015-05-13 08:51:18 +00:00
return;
2015-05-09 05:33:48 +00:00
}
case KeyRelease:
2015-05-09 05:33:48 +00:00
{
if (m_callback)
{
2015-11-21 01:12:22 +00:00
ESpecialKey specialKey;
EModifierKey modifierKey;
uint32_t charCode = translateKeysym(XLookupKeysym(&event->xkey, 0),
2015-10-28 01:47:55 +00:00
specialKey, modifierKey);
2015-11-21 01:12:22 +00:00
EModifierKey modifierMask = translateModifiers(event->xkey.state);
2015-05-09 05:33:48 +00:00
if (charCode)
2015-11-21 01:12:22 +00:00
m_callback->charKeyUp(charCode, modifierMask);
else if (specialKey != ESpecialKey::None)
m_callback->specialKeyUp(specialKey, modifierMask);
else if (modifierKey != EModifierKey::None)
m_callback->modKeyUp(modifierKey);
2015-05-09 05:33:48 +00:00
}
2015-05-13 08:51:18 +00:00
return;
2015-05-09 05:33:48 +00:00
}
case ButtonPress:
2015-05-09 05:33:48 +00:00
{
2015-05-13 08:51:18 +00:00
if (m_callback)
2015-05-09 05:33:48 +00:00
{
2015-11-02 09:31:06 +00:00
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
2015-11-21 01:12:22 +00:00
EMouseButton button = translateButton(event->xbutton.button);
if (button != EMouseButton::None)
2015-05-09 05:33:48 +00:00
{
2015-11-21 01:12:22 +00:00
EModifierKey modifierMask = translateModifiers(event->xbutton.state);
m_callback->mouseDown(MakeButtonEventCoord(event), (EMouseButton)button,
2015-11-03 04:27:56 +00:00
(EModifierKey)modifierMask);
2015-05-13 08:51:18 +00:00
}
/* Also handle legacy scroll events here */
if (event->xbutton.button >= 4 && event->xbutton.button <= 7 &&
2015-05-13 08:51:18 +00:00
m_hScrollValuator == -1 && m_vScrollValuator == -1)
{
2015-11-03 04:27:56 +00:00
SScrollDelta scrollDelta =
2015-05-13 08:51:18 +00:00
{
{0.0, 0.0},
false
};
if (event->xbutton.button == 4)
2015-05-13 08:51:18 +00:00
scrollDelta.delta[1] = 1.0;
else if (event->xbutton.button == 5)
2015-05-13 08:51:18 +00:00
scrollDelta.delta[1] = -1.0;
else if (event->xbutton.button == 6)
2015-05-13 08:51:18 +00:00
scrollDelta.delta[0] = 1.0;
else if (event->xbutton.button == 7)
2015-05-13 08:51:18 +00:00
scrollDelta.delta[0] = -1.0;
m_callback->scroll(MakeButtonEventCoord(event), scrollDelta);
2015-05-13 08:51:18 +00:00
}
2015-05-09 05:33:48 +00:00
}
2015-05-13 08:51:18 +00:00
return;
2015-05-09 05:33:48 +00:00
}
case ButtonRelease:
2015-05-09 05:33:48 +00:00
{
2015-05-13 08:51:18 +00:00
if (m_callback)
2015-05-09 05:33:48 +00:00
{
2015-11-02 09:31:06 +00:00
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
2015-11-21 01:12:22 +00:00
EMouseButton button = translateButton(event->xbutton.button);
if (button != EMouseButton::None)
2015-05-09 05:33:48 +00:00
{
2015-11-21 01:12:22 +00:00
EModifierKey modifierMask = translateModifiers(event->xbutton.state);
m_callback->mouseUp(MakeButtonEventCoord(event), (EMouseButton)button,
2015-11-03 04:27:56 +00:00
(EModifierKey)modifierMask);
2015-05-13 08:51:18 +00:00
}
2015-05-09 05:33:48 +00:00
}
2015-05-13 08:51:18 +00:00
return;
2015-05-09 05:33:48 +00:00
}
case FocusIn:
{
if (m_callback)
m_callback->focusGained();
return;
}
case FocusOut:
{
if (m_callback)
m_callback->focusLost();
return;
}
case MotionNotify:
2015-05-09 05:33:48 +00:00
{
if (m_callback)
{
2015-11-02 09:31:06 +00:00
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
m_callback->mouseMove(MakeMotionEventCoord(event));
2015-05-09 05:33:48 +00:00
}
2015-05-13 08:51:18 +00:00
return;
}
case EnterNotify:
{
if (m_callback)
{
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
m_callback->mouseEnter(MakeCrossingEventCoord(event));
}
return;
}
case LeaveNotify:
{
if (m_callback)
{
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
m_callback->mouseLeave(MakeCrossingEventCoord(event));
}
return;
}
case GenericEvent:
2015-05-13 08:51:18 +00:00
{
if (event->xgeneric.extension == XINPUT_OPCODE)
2015-05-13 08:51:18 +00:00
{
2015-11-02 09:31:06 +00:00
getWindowFrame(m_wx, m_wy, m_ww, m_wh);
switch (event->xgeneric.evtype)
2015-05-13 08:51:18 +00:00
{
case XI_Motion:
2015-05-13 08:51:18 +00:00
{
2015-11-02 09:31:06 +00:00
fprintf(stderr, "motion\n");
XIDeviceEvent* ev = (XIDeviceEvent*)event;
2015-05-13 08:51:18 +00:00
if (m_lastInputID != ev->deviceid)
_pointingDeviceChanged(ev->deviceid);
int cv = 0;
double newScroll[2] = {m_hScrollLast, m_vScrollLast};
bool didScroll = false;
for (int i=0 ; i<ev->valuators.mask_len*8 ; ++i)
2015-05-13 08:51:18 +00:00
{
if (XIMaskIsSet(ev->valuators.mask, i))
2015-05-13 08:51:18 +00:00
{
if (i == m_hScrollValuator)
{
newScroll[0] = ev->valuators.values[cv];
2015-05-13 08:51:18 +00:00
didScroll = true;
}
else if (i == m_vScrollValuator)
{
newScroll[1] = ev->valuators.values[cv];
2015-05-13 08:51:18 +00:00
didScroll = true;
}
++cv;
}
}
2015-11-03 04:27:56 +00:00
SScrollDelta scrollDelta =
2015-05-13 08:51:18 +00:00
{
{newScroll[0] - m_hScrollLast, newScroll[1] - m_vScrollLast},
true
};
m_hScrollLast = newScroll[0];
m_vScrollLast = newScroll[1];
if (m_callback && didScroll)
{
int event_x = int(ev->event_x) >> 16;
int event_y = m_wh - (int(ev->event_y) >> 16);
2015-11-03 04:27:56 +00:00
SWindowCoord coord =
2015-05-13 08:51:18 +00:00
{
{event_x, event_y},
{int(event_x / m_pixelFactor), int(event_y / m_pixelFactor)},
{event_x / float(m_ww), event_y / float(m_wh)}
2015-05-13 08:51:18 +00:00
};
m_callback->scroll(coord, scrollDelta);
}
return;
}
case XI_TouchBegin:
2015-05-13 08:51:18 +00:00
{
XIDeviceEvent* ev = (XIDeviceEvent*)event;
2015-05-13 08:51:18 +00:00
if (m_lastInputID != ev->deviceid)
_pointingDeviceChanged(ev->deviceid);
int cv = 0;
double vals[32] = {};
for (int i=0 ; i<ev->valuators.mask_len*8 && i<32 ; ++i)
2015-05-13 08:51:18 +00:00
{
if (XIMaskIsSet(ev->valuators.mask, i))
2015-05-13 08:51:18 +00:00
{
vals[i] = ev->valuators.values[cv];
2015-05-13 08:51:18 +00:00
++cv;
}
}
2015-11-03 04:27:56 +00:00
STouchCoord coord =
2015-05-13 08:51:18 +00:00
{
{vals[0], vals[1]}
};
if (m_callback)
m_callback->touchDown(coord, ev->detail);
return;
}
case XI_TouchUpdate:
2015-05-13 08:51:18 +00:00
{
XIDeviceEvent* ev = (XIDeviceEvent*)event;
2015-05-13 08:51:18 +00:00
if (m_lastInputID != ev->deviceid)
_pointingDeviceChanged(ev->deviceid);
int cv = 0;
double vals[32] = {};
for (int i=0 ; i<ev->valuators.mask_len*8 && i<32 ; ++i)
2015-05-13 08:51:18 +00:00
{
if (XIMaskIsSet(ev->valuators.mask, i))
2015-05-13 08:51:18 +00:00
{
vals[i] = ev->valuators.values[cv];
2015-05-13 08:51:18 +00:00
++cv;
}
}
2015-11-03 04:27:56 +00:00
STouchCoord coord =
2015-05-13 08:51:18 +00:00
{
{vals[0], vals[1]}
};
if (m_callback)
m_callback->touchMove(coord, ev->detail);
return;
}
case XI_TouchEnd:
2015-05-13 08:51:18 +00:00
{
XIDeviceEvent* ev = (XIDeviceEvent*)event;
2015-05-13 08:51:18 +00:00
if (m_lastInputID != ev->deviceid)
_pointingDeviceChanged(ev->deviceid);
int cv = 0;
double vals[32] = {};
for (int i=0 ; i<ev->valuators.mask_len*8 && i<32 ; ++i)
2015-05-13 08:51:18 +00:00
{
if (XIMaskIsSet(ev->valuators.mask, i))
2015-05-13 08:51:18 +00:00
{
vals[i] = ev->valuators.values[cv];
2015-05-13 08:51:18 +00:00
++cv;
}
}
2015-11-03 04:27:56 +00:00
STouchCoord coord =
2015-05-13 08:51:18 +00:00
{
{vals[0], vals[1]}
};
if (m_callback)
m_callback->touchUp(coord, ev->detail);
return;
}
}
}
2015-05-09 05:33:48 +00:00
}
}
2015-05-06 00:50:57 +00:00
}
ETouchType getTouchType() const
{
2015-05-13 08:51:18 +00:00
return m_touchType;
2015-05-06 00:50:57 +00:00
}
2015-10-30 06:26:02 +00:00
IGraphicsCommandQueue* getCommandQueue()
{
return m_gfxCtx.getCommandQueue();
}
IGraphicsDataFactory* getDataFactory()
{
return m_gfxCtx.getDataFactory();
}
2015-11-17 06:41:32 +00:00
IGraphicsDataFactory* getMainContextDataFactory()
{
return m_gfxCtx.getMainContextDataFactory();
}
2015-10-30 06:26:02 +00:00
IGraphicsDataFactory* getLoadContextDataFactory()
{
return m_gfxCtx.getLoadContextDataFactory();
}
2015-11-05 04:31:30 +00:00
bool _isWindowMapped()
{
XWindowAttributes attr;
2015-11-12 04:31:59 +00:00
XLockDisplay(m_xDisp);
2015-11-05 04:31:30 +00:00
XGetWindowAttributes(m_xDisp, m_windowId, &attr);
2015-11-12 04:31:59 +00:00
XUnlockDisplay(m_xDisp);
2015-11-05 04:31:30 +00:00
return attr.map_state != IsUnmapped;
}
2015-05-06 00:50:57 +00:00
};
IWindow* _WindowXlibNew(const std::string& title,
Display* display, int defaultScreen,
GLXContext lastCtx)
2015-05-06 00:50:57 +00:00
{
2015-11-12 04:31:59 +00:00
XLockDisplay(display);
IWindow* ret = new WindowXlib(title, display, defaultScreen, lastCtx);
XUnlockDisplay(display);
return ret;
2015-05-06 00:50:57 +00:00
}
}