2015-08-18 22:43:30 +00:00
|
|
|
#include "boo/IWindow.hpp"
|
|
|
|
#include "boo/IGraphicsContext.hpp"
|
|
|
|
#include "boo/IApplication.hpp"
|
2015-10-31 04:28:21 +00:00
|
|
|
#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-10-31 04:28:21 +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>
|
2015-10-31 04:28:21 +00:00
|
|
|
#include <xkbcommon/xkbcommon.h>
|
|
|
|
#include <X11/extensions/XInput2.h>
|
|
|
|
#include <X11/Xatom.h>
|
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-10-31 04:28:21 +00:00
|
|
|
#include <LogVisor/LogVisor.hpp>
|
|
|
|
|
2015-05-06 00:50:57 +00:00
|
|
|
namespace boo
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
static LogVisor::LogModule Log("boo::WindowXCB");
|
2015-10-30 00:00:56 +00:00
|
|
|
IGraphicsCommandQueue* _NewGLES3CommandQueue(IGraphicsContext* parent);
|
2015-10-31 04:28:21 +00:00
|
|
|
void _XCBUpdateLastGlxCtx(GLXContext lastGlxCtx);
|
|
|
|
void GLXExtensionCheck();
|
|
|
|
void GLXWaitForVSync();
|
|
|
|
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-10-31 04:28:21 +00:00
|
|
|
static uint32_t translateKeysym(KeySym sym, int& specialSym, int& modifierSym)
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
|
|
|
specialSym = IWindowCallback::KEY_NONE;
|
|
|
|
modifierSym = IWindowCallback::MKEY_NONE;
|
|
|
|
if (sym >= XK_F1 && sym <= XK_F12)
|
|
|
|
specialSym = IWindowCallback::KEY_F1 + sym - XK_F1;
|
|
|
|
else if (sym == XK_Escape)
|
|
|
|
specialSym = IWindowCallback::KEY_ESC;
|
|
|
|
else if (sym == XK_Return)
|
|
|
|
specialSym = IWindowCallback::KEY_ENTER;
|
|
|
|
else if (sym == XK_BackSpace)
|
|
|
|
specialSym = IWindowCallback::KEY_BACKSPACE;
|
|
|
|
else if (sym == XK_Insert)
|
|
|
|
specialSym = IWindowCallback::KEY_INSERT;
|
|
|
|
else if (sym == XK_Delete)
|
|
|
|
specialSym = IWindowCallback::KEY_DELETE;
|
|
|
|
else if (sym == XK_Home)
|
|
|
|
specialSym = IWindowCallback::KEY_HOME;
|
|
|
|
else if (sym == XK_End)
|
|
|
|
specialSym = IWindowCallback::KEY_END;
|
|
|
|
else if (sym == XK_Page_Up)
|
|
|
|
specialSym = IWindowCallback::KEY_PGUP;
|
|
|
|
else if (sym == XK_Page_Down)
|
|
|
|
specialSym = IWindowCallback::KEY_PGDOWN;
|
|
|
|
else if (sym == XK_Left)
|
|
|
|
specialSym = IWindowCallback::KEY_LEFT;
|
|
|
|
else if (sym == XK_Right)
|
|
|
|
specialSym = IWindowCallback::KEY_RIGHT;
|
|
|
|
else if (sym == XK_Up)
|
|
|
|
specialSym = IWindowCallback::KEY_UP;
|
|
|
|
else if (sym == XK_Down)
|
|
|
|
specialSym = IWindowCallback::KEY_DOWN;
|
|
|
|
else if (sym == XK_Shift_L || sym == XK_Shift_R)
|
|
|
|
modifierSym = IWindowCallback::MKEY_SHIFT;
|
|
|
|
else if (sym == XK_Control_L || sym == XK_Control_R)
|
|
|
|
modifierSym = IWindowCallback::MKEY_CTRL;
|
|
|
|
else if (sym == XK_Alt_L || sym == XK_Alt_R)
|
|
|
|
modifierSym = IWindowCallback::MKEY_ALT;
|
|
|
|
else
|
|
|
|
return xkb_keysym_to_utf32(sym);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int translateModifiers(unsigned state)
|
|
|
|
{
|
|
|
|
int retval = 0;
|
2015-10-31 04:28:21 +00:00
|
|
|
if (state & ShiftMask)
|
2015-05-09 05:33:48 +00:00
|
|
|
retval |= IWindowCallback::MKEY_SHIFT;
|
2015-10-31 04:28:21 +00:00
|
|
|
if (state & ControlMask)
|
2015-05-09 05:33:48 +00:00
|
|
|
retval |= IWindowCallback::MKEY_CTRL;
|
2015-10-31 04:28:21 +00:00
|
|
|
if (state & Mod1Mask)
|
2015-05-09 05:33:48 +00:00
|
|
|
retval |= IWindowCallback::MKEY_ALT;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2015-05-12 09:38:37 +00:00
|
|
|
static int translateButton(unsigned detail)
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
|
|
|
int retval = 0;
|
2015-05-12 09:38:37 +00:00
|
|
|
if (detail == 1)
|
2015-05-09 05:33:48 +00:00
|
|
|
retval = IWindowCallback::BUTTON_PRIMARY;
|
2015-05-12 09:38:37 +00:00
|
|
|
else if (detail == 3)
|
2015-05-09 05:33:48 +00:00
|
|
|
retval = IWindowCallback::BUTTON_SECONDARY;
|
2015-05-12 09:38:37 +00:00
|
|
|
else if (detail == 2)
|
2015-05-09 05:33:48 +00:00
|
|
|
retval = IWindowCallback::BUTTON_MIDDLE;
|
2015-05-12 09:38:37 +00:00
|
|
|
else if (detail == 8)
|
2015-05-09 05:33:48 +00:00
|
|
|
retval = IWindowCallback::BUTTON_AUX1;
|
2015-05-12 09:38:37 +00:00
|
|
|
else if (detail == 9)
|
|
|
|
retval =
|
|
|
|
IWindowCallback::BUTTON_AUX2;
|
2015-05-09 05:33:48 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2015-08-18 19:40:26 +00:00
|
|
|
struct XCBAtoms
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +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;
|
|
|
|
//xcb_key_symbols_t* m_keySyms = NULL;
|
|
|
|
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);
|
|
|
|
//m_keySyms = xcb_key_symbols_alloc(conn);
|
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 04:28:21 +00:00
|
|
|
static void genFrameDefault(Screen* screen, int* xOut, int* yOut, int* wOut, int* hOut)
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
float width = screen->width * 2.0 / 3.0;
|
|
|
|
float height = screen->height * 2.0 / 3.0;
|
|
|
|
*xOut = (screen->width - width) / 2.0;
|
|
|
|
*yOut = (screen->height - height) / 2.0;
|
2015-05-09 05:33:48 +00:00
|
|
|
*wOut = width;
|
|
|
|
*hOut = height;
|
|
|
|
}
|
2015-05-06 00:50:57 +00:00
|
|
|
|
2015-08-28 00:10:46 +00:00
|
|
|
struct GraphicsContextXCB : IGraphicsContext
|
|
|
|
{
|
|
|
|
EGraphicsAPI m_api;
|
|
|
|
EPixelFormat m_pf;
|
|
|
|
IWindow* m_parentWindow;
|
2015-10-31 04:28:21 +00:00
|
|
|
Display* m_xDisp = nullptr;
|
|
|
|
GLXContext m_lastCtx = 0;
|
2015-08-28 00:10:46 +00:00
|
|
|
|
2015-10-31 04:28:21 +00:00
|
|
|
GLXFBConfig m_fbconfig = 0;
|
|
|
|
int m_visualid = 0;
|
|
|
|
GLXWindow m_glxWindow = 0;
|
|
|
|
GLXContext m_glxCtx = 0;
|
|
|
|
GLXContext m_timerCtx = 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-10-31 04:28:21 +00:00
|
|
|
GLXContext m_loadCtx = 0;
|
2015-10-30 00:00:56 +00:00
|
|
|
|
2015-08-28 00:10:46 +00:00
|
|
|
public:
|
|
|
|
IWindowCallback* m_callback;
|
|
|
|
|
2015-10-28 01:47:55 +00:00
|
|
|
GraphicsContextXCB(EGraphicsAPI api, IWindow* parentWindow,
|
2015-10-31 04:28:21 +00:00
|
|
|
Display* display, int defaultScreen,
|
|
|
|
GLXContext lastCtx, uint32_t& visualIdOut)
|
2015-08-28 00:10:46 +00:00
|
|
|
: m_api(api),
|
2015-10-31 04:28:21 +00:00
|
|
|
m_pf(PF_RGBA8_Z24),
|
2015-08-28 00:10:46 +00:00
|
|
|
m_parentWindow(parentWindow),
|
2015-10-31 04:28:21 +00:00
|
|
|
m_xDisp(display),
|
|
|
|
m_lastCtx(lastCtx)
|
|
|
|
{
|
|
|
|
/* 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
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
Log.report(LogVisor::FatalError, "glXGetFBConfigs failed");
|
|
|
|
return;
|
|
|
|
}
|
2015-08-28 00:10:46 +00:00
|
|
|
|
2015-10-31 04:28:21 +00:00
|
|
|
for (int i=0 ; i<numFBConfigs ; ++i)
|
2015-08-28 00:10:46 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +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;
|
|
|
|
|
|
|
|
if (m_pf == PF_RGBA8 && colorSize >= 32)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_fbconfig = config;
|
2015-08-28 00:10:46 +00:00
|
|
|
m_visualid = visualId;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (m_pf == PF_RGBA8_Z24 && colorSize >= 32 && depthSize >= 24)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_fbconfig = config;
|
2015-08-28 00:10:46 +00:00
|
|
|
m_visualid = visualId;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (m_pf == PF_RGBAF32 && colorSize >= 128)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_fbconfig = config;
|
2015-08-28 00:10:46 +00:00
|
|
|
m_visualid = visualId;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (m_pf == PF_RGBAF32_Z24 && colorSize >= 128 && depthSize >= 24)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_fbconfig = config;
|
2015-08-28 00:10:46 +00:00
|
|
|
m_visualid = visualId;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
XFree(fbConfigs);
|
2015-08-28 00:10:46 +00:00
|
|
|
|
|
|
|
if (!m_fbconfig)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
Log.report(LogVisor::FatalError, "unable to find suitable pixel format");
|
2015-08-28 00:10:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
visualIdOut = m_visualid;
|
|
|
|
}
|
|
|
|
|
|
|
|
~GraphicsContextXCB()
|
|
|
|
{
|
2015-10-28 01:47:55 +00:00
|
|
|
if (m_glxCtx)
|
2015-10-31 04:28:21 +00:00
|
|
|
glXDestroyContext(m_xDisp, m_glxCtx);
|
2015-10-28 01:47:55 +00:00
|
|
|
if (m_glxWindow)
|
2015-10-31 04:28:21 +00:00
|
|
|
glXDestroyWindow(m_xDisp, m_glxWindow);
|
2015-10-30 00:00:56 +00:00
|
|
|
if (m_loadCtx)
|
2015-10-31 04:28:21 +00:00
|
|
|
glXDestroyContext(m_xDisp, m_loadCtx);
|
|
|
|
if (m_timerCtx)
|
|
|
|
glXDestroyContext(m_xDisp, m_timerCtx);
|
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)
|
|
|
|
{
|
|
|
|
if (pf > PF_RGBAF32_Z24)
|
|
|
|
return;
|
|
|
|
m_pf = pf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void initializeContext()
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_glxCtx = glXCreateNewContext(m_xDisp, m_fbconfig, GLX_RGBA_TYPE, m_lastCtx, True);
|
|
|
|
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");
|
2015-10-30 06:26:02 +00:00
|
|
|
_XCBUpdateLastGlxCtx(m_glxCtx);
|
2015-10-31 04:28:21 +00:00
|
|
|
|
|
|
|
/* Make additional shared context for vsync timing */
|
|
|
|
m_timerCtx = glXCreateNewContext(m_xDisp, m_fbconfig, GLX_RGBA_TYPE, m_glxCtx, True);
|
|
|
|
if (!m_timerCtx)
|
|
|
|
Log.report(LogVisor::FatalError, "unable to make new timer GLX context");
|
2015-10-28 01:47:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void makeCurrent()
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_glxCtx))
|
|
|
|
Log.report(LogVisor::FatalError, "unable to make GLX context current");
|
|
|
|
}
|
|
|
|
|
|
|
|
void postInit()
|
|
|
|
{
|
|
|
|
GLXExtensionCheck();
|
|
|
|
GLXEnableVSync(m_xDisp, m_glxWindow);
|
2015-08-28 00:10:46 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 00:00:56 +00:00
|
|
|
IGraphicsCommandQueue* getCommandQueue()
|
|
|
|
{
|
|
|
|
if (!m_commandQueue)
|
|
|
|
m_commandQueue = _NewGLES3CommandQueue(this);
|
|
|
|
return m_commandQueue;
|
|
|
|
}
|
|
|
|
|
|
|
|
IGraphicsDataFactory* getDataFactory()
|
2015-10-29 04:44:38 +00:00
|
|
|
{
|
2015-10-30 00:00:56 +00:00
|
|
|
if (!m_dataFactory)
|
|
|
|
m_dataFactory = new struct GLES3DataFactory(this);
|
|
|
|
return m_dataFactory;
|
2015-10-29 04:44:38 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 00:00:56 +00:00
|
|
|
IGraphicsDataFactory* getLoadContextDataFactory()
|
2015-10-29 04:44:38 +00:00
|
|
|
{
|
2015-10-30 00:00:56 +00:00
|
|
|
if (!m_loadCtx)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_loadCtx = glXCreateNewContext(m_xDisp, m_fbconfig, GLX_RGBA_TYPE, m_glxCtx, True);
|
|
|
|
if (!m_loadCtx)
|
|
|
|
Log.report(LogVisor::FatalError, "unable to make load GLX context");
|
|
|
|
if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_loadCtx))
|
|
|
|
Log.report(LogVisor::FatalError, "unable to make load GLX context current");
|
2015-10-30 00:00:56 +00:00
|
|
|
}
|
|
|
|
return getDataFactory();
|
2015-10-29 04:44:38 +00:00
|
|
|
}
|
|
|
|
|
2015-10-31 04:28:21 +00:00
|
|
|
void present()
|
|
|
|
{
|
|
|
|
glXSwapBuffers(m_xDisp, m_glxWindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool m_timerBound = false;
|
|
|
|
void bindTimerContext()
|
|
|
|
{
|
|
|
|
if (m_timerBound)
|
|
|
|
return;
|
|
|
|
if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_timerCtx))
|
|
|
|
Log.report(LogVisor::FatalError, "unable to make timer GLX context current");
|
|
|
|
m_timerBound = true;
|
|
|
|
}
|
|
|
|
|
2015-08-28 00:10:46 +00:00
|
|
|
};
|
2015-05-06 00:50:57 +00:00
|
|
|
|
2015-08-18 19:40:26 +00:00
|
|
|
struct WindowXCB : IWindow
|
2015-05-06 00:50:57 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
Display* m_xDisp;
|
2015-05-09 05:33:48 +00:00
|
|
|
IWindowCallback* m_callback;
|
2015-10-31 04:28:21 +00:00
|
|
|
Colormap m_colormapId;
|
|
|
|
Window m_windowId;
|
2015-08-28 00:10:46 +00:00
|
|
|
GraphicsContextXCB m_gfxCtx;
|
|
|
|
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) */
|
2015-10-31 04:28:21 +00:00
|
|
|
int m_lastInputID = 0xffff;
|
2015-05-13 08:51:18 +00:00
|
|
|
ETouchType m_touchType = TOUCH_NONE;
|
|
|
|
|
|
|
|
/* 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;
|
2015-05-06 00:50:57 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2015-10-31 04:28:21 +00:00
|
|
|
WindowXCB(const std::string& title,
|
|
|
|
Display* display, int defaultScreen,
|
|
|
|
GLXContext lastCtx)
|
|
|
|
: m_xDisp(display), m_callback(nullptr),
|
|
|
|
m_gfxCtx(IGraphicsContext::API_OPENGL_3_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)
|
2015-10-31 04:28:21 +00:00
|
|
|
S_ATOMS = new XCBAtoms(display);
|
2015-05-09 05:33:48 +00:00
|
|
|
|
|
|
|
/* Default screen */
|
2015-10-31 04:28:21 +00:00
|
|
|
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;
|
|
|
|
genFrameDefault(screen, &x, &y, &w, &h);
|
2015-10-31 05:43:16 +00:00
|
|
|
XSetWindowAttributes swa;
|
|
|
|
swa.colormap = m_colormapId;
|
|
|
|
swa.border_pixmap = None;
|
|
|
|
swa.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask;
|
|
|
|
|
2015-10-31 04:28:21 +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 */
|
2015-10-31 04:28:21 +00:00
|
|
|
XIEventMask mask = {XIAllMasterDevices, XIMaskLen(XI_LASTEVENT)};
|
|
|
|
mask.mask = (unsigned char*)malloc(mask.mask_len);
|
|
|
|
memset(mask.mask, 0, mask.mask_len);
|
|
|
|
XISetMask(mask.mask, XI_Motion);
|
|
|
|
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 */
|
|
|
|
#if 0
|
2015-05-12 09:38:37 +00:00
|
|
|
xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, S_ATOMS->m_wmProtocols,
|
|
|
|
XCB_ATOM_ATOM, 32, 1, &S_ATOMS->m_wmDeleteWindow);
|
|
|
|
const xcb_atom_t wm_protocols[1] = {
|
|
|
|
S_ATOMS->m_wmDeleteWindow,
|
|
|
|
};
|
|
|
|
xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId,
|
|
|
|
S_ATOMS->m_wmProtocols, 4,
|
|
|
|
32, 1, wm_protocols);
|
2015-05-13 08:51:18 +00:00
|
|
|
#endif
|
2015-05-12 09:38:37 +00:00
|
|
|
|
2015-05-09 05:33:48 +00:00
|
|
|
/* Set the title of the window */
|
2015-10-31 04:28:21 +00:00
|
|
|
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 */
|
2015-10-31 04:28:21 +00:00
|
|
|
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 */
|
2015-10-31 04:28:21 +00:00
|
|
|
XMapWindow(m_xDisp, m_windowId);
|
|
|
|
XFlush(m_xDisp);
|
2015-05-09 05:33:48 +00:00
|
|
|
|
2015-08-28 00:10:46 +00:00
|
|
|
m_gfxCtx.initializeContext();
|
2015-05-06 00:50:57 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 19:40:26 +00:00
|
|
|
~WindowXCB()
|
2015-05-06 00:50:57 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
XUnmapWindow(m_xDisp, m_windowId);
|
|
|
|
XDestroyWindow(m_xDisp, m_windowId);
|
|
|
|
XFreeColormap(m_xDisp, m_colormapId);
|
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-10-31 04:28:21 +00:00
|
|
|
XMapWindow(m_xDisp, m_windowId);
|
|
|
|
XFlush(m_xDisp);
|
2015-05-06 00:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void hideWindow()
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
XUnmapWindow(m_xDisp, m_windowId);
|
|
|
|
XFlush(m_xDisp);
|
2015-05-06 00:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string getTitle()
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
unsigned char* string = nullptr;
|
|
|
|
if (XGetWindowProperty(m_xDisp, m_windowId, XA_WM_NAME, 0, 65536, False,
|
|
|
|
XA_STRING, nullptr, nullptr, nullptr, nullptr, &string))
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
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-06 00:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void setWindowFrameDefault()
|
|
|
|
{
|
2015-05-09 05:33:48 +00:00
|
|
|
int x, y, w, h;
|
2015-10-31 04:28:21 +00:00
|
|
|
Screen* screen = DefaultScreenOfDisplay(m_xDisp);
|
2015-05-09 05:33:48 +00:00
|
|
|
genFrameDefault(screen, &x, &y, &w, &h);
|
2015-10-31 04:28:21 +00:00
|
|
|
XWindowChanges values = {(int)x, (int)y, (int)w, (int)h};
|
|
|
|
XConfigureWindow(m_xDisp, m_windowId, CWX|CWY|CWWidth|CWHeight, &values);
|
2015-05-06 00:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const
|
|
|
|
{
|
2015-05-09 05:33:48 +00:00
|
|
|
xOut = m_wx;
|
|
|
|
yOut = m_wy;
|
|
|
|
wOut = m_ww;
|
|
|
|
hOut = m_wh;
|
2015-05-06 00:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void setWindowFrame(float x, float y, float w, float h)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
XWindowChanges values = {(int)x, (int)y, (int)w, (int)h};
|
|
|
|
XConfigureWindow(m_xDisp, m_windowId, CWX|CWY|CWWidth|CWHeight, &values);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
bool isFullscreen() const
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
unsigned long nitems;
|
|
|
|
Atom* vals = nullptr;
|
|
|
|
bool fullscreen = false;
|
|
|
|
if (XGetWindowProperty(m_xDisp, m_windowId, S_ATOMS->m_netwmState, 0, 65536, False,
|
|
|
|
XA_ATOM, nullptr, nullptr, &nitems, nullptr, (unsigned char**)&vals))
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
for (int i=0 ; i<nitems ; ++i)
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
if (vals[i] == S_ATOMS->m_netwmStateFullscreen)
|
|
|
|
{
|
|
|
|
fullscreen = true;
|
|
|
|
break;
|
|
|
|
}
|
2015-05-09 05:33:48 +00:00
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
XFree(vals);
|
|
|
|
return fullscreen;
|
2015-05-09 05:33:48 +00:00
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
return false;
|
2015-05-06 00:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void setFullscreen(bool fs)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
XClientMessageEvent fsEvent =
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
ClientMessage,
|
2015-05-09 05:33:48 +00:00
|
|
|
0,
|
2015-10-31 04:28:21 +00:00
|
|
|
True,
|
|
|
|
m_xDisp,
|
2015-05-09 05:33:48 +00:00
|
|
|
m_windowId,
|
2015-05-10 07:02:18 +00:00
|
|
|
S_ATOMS->m_netwmState,
|
2015-10-31 04:28:21 +00:00
|
|
|
32
|
2015-05-09 05:33:48 +00:00
|
|
|
};
|
2015-10-31 04:28:21 +00:00
|
|
|
fsEvent.data.l[0] = fs ? S_ATOMS->m_netwmStateAdd : S_ATOMS->m_netwmStateRemove;
|
|
|
|
fsEvent.data.l[1] = S_ATOMS->m_netwmStateFullscreen;
|
|
|
|
XSendEvent(m_xDisp, m_windowId, False,
|
|
|
|
StructureNotifyMask | SubstructureRedirectMask, (XEvent*)&fsEvent);
|
2015-05-09 05:33:48 +00:00
|
|
|
}
|
|
|
|
|
2015-10-31 04:28:21 +00:00
|
|
|
void waitForRetrace()
|
2015-08-28 00:10:46 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_gfxCtx.bindTimerContext();
|
|
|
|
GLXWaitForVSync();
|
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;
|
|
|
|
}
|
|
|
|
|
2015-10-31 04:28:21 +00:00
|
|
|
void _pointingDeviceChanged(int deviceId)
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
int nDevices;
|
|
|
|
XIDeviceInfo* devices = XIQueryDevice(m_xDisp, deviceId, &nDevices);
|
2015-05-13 08:51:18 +00:00
|
|
|
|
2015-10-31 04:28:21 +00:00
|
|
|
for (int i=0 ; i<nDevices ; ++i)
|
2015-05-12 09:38:37 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +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;
|
2015-10-31 04:28:21 +00:00
|
|
|
for (int j=0 ; j<device->num_classes ; ++j)
|
2015-05-12 09:38:37 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
XIAnyClassInfo* dclass = device->classes[j];
|
|
|
|
if (dclass->type == XIScrollClass)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
XIScrollClassInfo* scrollClass = (XIScrollClassInfo*)dclass;
|
|
|
|
if (scrollClass->scroll_type == XIScrollTypeVertical)
|
2015-05-13 08:51:18 +00:00
|
|
|
vScroll = scrollClass->number;
|
2015-10-31 04:28:21 +00:00
|
|
|
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 */
|
2015-10-31 04:28:21 +00:00
|
|
|
for (int j=0 ; j<device->num_classes ; ++j)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
XIAnyClassInfo* dclass = device->classes[j];
|
|
|
|
if (dclass->type == XIValuatorClass)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
XIValuatorClassInfo* valClass = (XIValuatorClassInfo*)dclass;
|
2015-05-13 08:51:18 +00:00
|
|
|
if (valClass->number == vScroll)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_vScrollLast = valClass->value;
|
2015-05-13 08:51:18 +00:00
|
|
|
m_vScrollValuator = vScroll;
|
|
|
|
}
|
|
|
|
else if (valClass->number == hScroll)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_hScrollLast = valClass->value;
|
2015-05-13 08:51:18 +00:00
|
|
|
m_hScrollValuator = hScroll;
|
|
|
|
}
|
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
else if (dclass->type == XITouchClass)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
XITouchClassInfo* touchClass = (XITouchClassInfo*)dclass;
|
|
|
|
if (touchClass->mode == XIDirectTouch)
|
2015-05-13 08:51:18 +00:00
|
|
|
m_touchType = TOUCH_DISPLAY;
|
2015-10-31 04:28:21 +00:00
|
|
|
else if (touchClass->mode == XIDependentTouch)
|
2015-05-13 08:51:18 +00:00
|
|
|
m_touchType = TOUCH_TRACKPAD;
|
|
|
|
else
|
|
|
|
m_touchType = TOUCH_NONE;
|
|
|
|
}
|
|
|
|
}
|
2015-05-12 09:38:37 +00:00
|
|
|
}
|
2015-05-13 08:51:18 +00:00
|
|
|
|
2015-10-31 04:28:21 +00:00
|
|
|
XIFreeDeviceInfo(devices);
|
2015-05-13 08:51:18 +00:00
|
|
|
m_lastInputID = deviceId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _incomingEvent(void* e)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
XEvent* event = (XEvent*)e;
|
|
|
|
switch (event->type)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
case Expose:
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_wx = event->xexpose.x;
|
|
|
|
m_wy = event->xexpose.y;
|
|
|
|
m_ww = event->xexpose.width;
|
|
|
|
m_wh = event->xexpose.height;
|
2015-05-13 08:51:18 +00:00
|
|
|
return;
|
2015-05-09 05:33:48 +00:00
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
case ConfigureNotify:
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
if (event->xconfigure.width && event->xconfigure.height)
|
2015-05-12 09:38:37 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
m_wx = event->xconfigure.x;
|
|
|
|
m_wy = event->xconfigure.y;
|
|
|
|
m_ww = event->xconfigure.width;
|
|
|
|
m_wh = event->xconfigure.height;
|
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
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
case KeyPress:
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
|
|
|
if (m_callback)
|
|
|
|
{
|
|
|
|
int specialKey;
|
|
|
|
int modifierKey;
|
2015-10-31 04:28:21 +00:00
|
|
|
uint32_t charCode = translateKeysym(XLookupKeysym(&event->xkey, 0),
|
2015-10-28 01:47:55 +00:00
|
|
|
specialKey, modifierKey);
|
2015-10-31 04:28:21 +00:00
|
|
|
int modifierMask = translateModifiers(event->xkey.state);
|
2015-05-09 05:33:48 +00:00
|
|
|
if (charCode)
|
|
|
|
m_callback->charKeyDown(charCode,
|
|
|
|
(IWindowCallback::EModifierKey)modifierMask, false);
|
|
|
|
else if (specialKey)
|
|
|
|
m_callback->specialKeyDown((IWindowCallback::ESpecialKey)specialKey,
|
|
|
|
(IWindowCallback::EModifierKey)modifierMask, false);
|
|
|
|
else if (modifierKey)
|
|
|
|
m_callback->modKeyDown((IWindowCallback::EModifierKey)modifierKey, false);
|
|
|
|
}
|
2015-05-13 08:51:18 +00:00
|
|
|
return;
|
2015-05-09 05:33:48 +00:00
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
case KeyRelease:
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
|
|
|
if (m_callback)
|
|
|
|
{
|
|
|
|
int specialKey;
|
|
|
|
int modifierKey;
|
2015-10-31 04:28:21 +00:00
|
|
|
uint32_t charCode = translateKeysym(XLookupKeysym(&event->xkey, 0),
|
2015-10-28 01:47:55 +00:00
|
|
|
specialKey, modifierKey);
|
2015-10-31 04:28:21 +00:00
|
|
|
int modifierMask = translateModifiers(event->xkey.state);
|
2015-05-09 05:33:48 +00:00
|
|
|
if (charCode)
|
|
|
|
m_callback->charKeyUp(charCode,
|
|
|
|
(IWindowCallback::EModifierKey)modifierMask);
|
|
|
|
else if (specialKey)
|
|
|
|
m_callback->specialKeyUp((IWindowCallback::ESpecialKey)specialKey,
|
|
|
|
(IWindowCallback::EModifierKey)modifierMask);
|
|
|
|
else if (modifierKey)
|
|
|
|
m_callback->modKeyUp((IWindowCallback::EModifierKey)modifierKey);
|
|
|
|
}
|
2015-05-13 08:51:18 +00:00
|
|
|
return;
|
2015-05-09 05:33:48 +00:00
|
|
|
}
|
2015-10-31 04:28:21 +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-10-31 04:28:21 +00:00
|
|
|
int button = translateButton(event->xbutton.button);
|
2015-05-13 08:51:18 +00:00
|
|
|
if (button)
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
int modifierMask = translateModifiers(event->xbutton.state);
|
2015-05-13 08:51:18 +00:00
|
|
|
IWindowCallback::SWindowCoord coord =
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
{(unsigned)event->xbutton.x, (unsigned)event->xbutton.y},
|
|
|
|
{(unsigned)(event->xbutton.x / m_pixelFactor), (unsigned)(event->xbutton.y / m_pixelFactor)},
|
|
|
|
{event->xbutton.x / (float)m_ww, event->xbutton.y / (float)m_wh}
|
2015-05-13 08:51:18 +00:00
|
|
|
};
|
|
|
|
m_callback->mouseDown(coord, (IWindowCallback::EMouseButton)button,
|
|
|
|
(IWindowCallback::EModifierKey)modifierMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Also handle legacy scroll events here */
|
2015-10-31 04:28:21 +00:00
|
|
|
if (event->xbutton.button >= 4 && event->xbutton.button <= 7 &&
|
2015-05-13 08:51:18 +00:00
|
|
|
m_hScrollValuator == -1 && m_vScrollValuator == -1)
|
|
|
|
{
|
|
|
|
IWindowCallback::SWindowCoord coord =
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
{(unsigned)event->xbutton.x, (unsigned)event->xbutton.y},
|
|
|
|
{(unsigned)(event->xbutton.x / m_pixelFactor), (unsigned)(event->xbutton.y / m_pixelFactor)},
|
|
|
|
{event->xbutton.x / (float)m_ww, event->xbutton.y / (float)m_wh}
|
2015-05-13 08:51:18 +00:00
|
|
|
};
|
|
|
|
IWindowCallback::SScrollDelta scrollDelta =
|
|
|
|
{
|
|
|
|
{0.0, 0.0},
|
|
|
|
false
|
|
|
|
};
|
2015-10-31 04:28:21 +00:00
|
|
|
if (event->xbutton.button == 4)
|
2015-05-13 08:51:18 +00:00
|
|
|
scrollDelta.delta[1] = 1.0;
|
2015-10-31 04:28:21 +00:00
|
|
|
else if (event->xbutton.button == 5)
|
2015-05-13 08:51:18 +00:00
|
|
|
scrollDelta.delta[1] = -1.0;
|
2015-10-31 04:28:21 +00:00
|
|
|
else if (event->xbutton.button == 6)
|
2015-05-13 08:51:18 +00:00
|
|
|
scrollDelta.delta[0] = 1.0;
|
2015-10-31 04:28:21 +00:00
|
|
|
else if (event->xbutton.button == 7)
|
2015-05-13 08:51:18 +00:00
|
|
|
scrollDelta.delta[0] = -1.0;
|
|
|
|
m_callback->scroll(coord, scrollDelta);
|
|
|
|
}
|
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
|
|
|
}
|
2015-10-31 04:28:21 +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-10-31 04:28:21 +00:00
|
|
|
int button = translateButton(event->xbutton.button);
|
2015-05-13 08:51:18 +00:00
|
|
|
if (button)
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
int modifierMask = translateModifiers(event->xbutton.state);
|
2015-05-13 08:51:18 +00:00
|
|
|
IWindowCallback::SWindowCoord coord =
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
{(unsigned)event->xbutton.x, (unsigned)event->xbutton.y},
|
|
|
|
{(unsigned)(event->xbutton.x / m_pixelFactor), (unsigned)(event->xbutton.y / m_pixelFactor)},
|
|
|
|
{event->xbutton.x / (float)m_ww, event->xbutton.y / (float)m_wh}
|
2015-05-13 08:51:18 +00:00
|
|
|
};
|
|
|
|
m_callback->mouseUp(coord, (IWindowCallback::EMouseButton)button,
|
|
|
|
(IWindowCallback::EModifierKey)modifierMask);
|
|
|
|
}
|
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
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
case MotionNotify:
|
2015-05-09 05:33:48 +00:00
|
|
|
{
|
|
|
|
if (m_callback)
|
|
|
|
{
|
|
|
|
IWindowCallback::SWindowCoord coord =
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
{(unsigned)event->xmotion.x, (unsigned)event->xmotion.y},
|
|
|
|
{(unsigned)(event->xmotion.x / m_pixelFactor), (unsigned)(event->xmotion.y / m_pixelFactor)},
|
|
|
|
{event->xmotion.x / (float)m_ww, event->xmotion.y / (float)m_wh}
|
2015-05-09 05:33:48 +00:00
|
|
|
};
|
|
|
|
m_callback->mouseMove(coord);
|
|
|
|
}
|
2015-05-13 08:51:18 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
case GenericEvent:
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
if (event->xgeneric.extension == XINPUT_OPCODE)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
switch (event->xgeneric.evtype)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
case XI_Motion:
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +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 newScroll[2] = {m_hScrollLast, m_vScrollLast};
|
|
|
|
bool didScroll = false;
|
2015-10-31 04:28:21 +00:00
|
|
|
for (int i=0 ; i<ev->valuators.mask_len*8 ; ++i)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
if (XIMaskIsSet(ev->valuators.mask, i))
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
|
|
|
if (i == m_hScrollValuator)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
newScroll[0] = ev->valuators.values[cv];
|
2015-05-13 08:51:18 +00:00
|
|
|
didScroll = true;
|
|
|
|
}
|
|
|
|
else if (i == m_vScrollValuator)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
newScroll[1] = ev->valuators.values[cv];
|
2015-05-13 08:51:18 +00:00
|
|
|
didScroll = true;
|
|
|
|
}
|
|
|
|
++cv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IWindowCallback::SScrollDelta scrollDelta =
|
|
|
|
{
|
|
|
|
{newScroll[0] - m_hScrollLast, newScroll[1] - m_vScrollLast},
|
|
|
|
true
|
|
|
|
};
|
|
|
|
|
|
|
|
m_hScrollLast = newScroll[0];
|
|
|
|
m_vScrollLast = newScroll[1];
|
|
|
|
|
|
|
|
if (m_callback && didScroll)
|
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
unsigned event_x = unsigned(ev->event_x) >> 16;
|
|
|
|
unsigned event_y = unsigned(ev->event_y) >> 16;
|
2015-05-13 08:51:18 +00:00
|
|
|
IWindowCallback::SWindowCoord coord =
|
|
|
|
{
|
|
|
|
{event_x, event_y},
|
|
|
|
{(unsigned)(event_x / m_pixelFactor), (unsigned)(event_y / m_pixelFactor)},
|
|
|
|
{event_x / (float)m_ww, event_y / (float)m_wh}
|
|
|
|
};
|
|
|
|
m_callback->scroll(coord, scrollDelta);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
case XI_TouchBegin:
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +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] = {};
|
2015-10-31 04:28:21 +00:00
|
|
|
for (int i=0 ; i<ev->valuators.mask_len*8 && i<32 ; ++i)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
if (XIMaskIsSet(ev->valuators.mask, i))
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
vals[i] = ev->valuators.values[cv];
|
2015-05-13 08:51:18 +00:00
|
|
|
++cv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IWindowCallback::STouchCoord coord =
|
|
|
|
{
|
|
|
|
{vals[0], vals[1]}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (m_callback)
|
|
|
|
m_callback->touchDown(coord, ev->detail);
|
|
|
|
return;
|
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
case XI_TouchUpdate:
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +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] = {};
|
2015-10-31 04:28:21 +00:00
|
|
|
for (int i=0 ; i<ev->valuators.mask_len*8 && i<32 ; ++i)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
if (XIMaskIsSet(ev->valuators.mask, i))
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
vals[i] = ev->valuators.values[cv];
|
2015-05-13 08:51:18 +00:00
|
|
|
++cv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IWindowCallback::STouchCoord coord =
|
|
|
|
{
|
|
|
|
{vals[0], vals[1]}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (m_callback)
|
|
|
|
m_callback->touchMove(coord, ev->detail);
|
|
|
|
return;
|
|
|
|
}
|
2015-10-31 04:28:21 +00:00
|
|
|
case XI_TouchEnd:
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +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] = {};
|
2015-10-31 04:28:21 +00:00
|
|
|
for (int i=0 ; i<ev->valuators.mask_len*8 && i<32 ; ++i)
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
if (XIMaskIsSet(ev->valuators.mask, i))
|
2015-05-13 08:51:18 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
vals[i] = ev->valuators.values[cv];
|
2015-05-13 08:51:18 +00:00
|
|
|
++cv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IWindowCallback::STouchCoord coord =
|
|
|
|
{
|
|
|
|
{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();
|
|
|
|
}
|
|
|
|
|
|
|
|
IGraphicsDataFactory* getLoadContextDataFactory()
|
|
|
|
{
|
|
|
|
return m_gfxCtx.getLoadContextDataFactory();
|
|
|
|
}
|
|
|
|
|
2015-05-06 00:50:57 +00:00
|
|
|
};
|
|
|
|
|
2015-10-31 04:28:21 +00:00
|
|
|
IWindow* _WindowXCBNew(const std::string& title,
|
|
|
|
Display* display, int defaultScreen,
|
|
|
|
GLXContext lastCtx)
|
2015-05-06 00:50:57 +00:00
|
|
|
{
|
2015-10-31 04:28:21 +00:00
|
|
|
return new WindowXCB(title, display, defaultScreen, lastCtx);
|
2015-05-06 00:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|