597 lines
18 KiB
C++
597 lines
18 KiB
C++
/*
|
|
This file is part of Mitsuba, a physically based rendering system.
|
|
|
|
Copyright (c) 2007-2011 by Wenzel Jakob and others.
|
|
|
|
Mitsuba is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License Version 3
|
|
as published by the Free Software Foundation.
|
|
|
|
Mitsuba is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <mitsuba/hw/glxrenderer.h>
|
|
#include <mitsuba/hw/x11device.h>
|
|
#include <X11/keysym.h>
|
|
|
|
#define DEFINE_KEY(xsym, sym) m_keymap[xsym & 0xFF] = sym
|
|
|
|
MTS_NAMESPACE_BEGIN
|
|
|
|
X11Device::X11Device(X11Session *session)
|
|
: Device(session), m_visinfo(NULL), m_visible(false) {
|
|
m_title = "Mitsuba [x11]";
|
|
for (int i=0; i<256; i++)
|
|
m_keymap[i] = ENoSpecial;
|
|
|
|
/* X11 <-> Mitsuba Keyboard mappings */
|
|
DEFINE_KEY(XK_BackSpace, EKeyBackspace);
|
|
DEFINE_KEY(XK_Tab, EKeyTab);
|
|
DEFINE_KEY(XK_Clear, EKeyClear);
|
|
DEFINE_KEY(XK_Return, EKeyReturn);
|
|
DEFINE_KEY(XK_Linefeed, EKeyReturn);
|
|
DEFINE_KEY(XK_Pause, EKeyPause);
|
|
DEFINE_KEY(XK_Escape, EKeyEscape);
|
|
DEFINE_KEY(XK_Delete, EKeyDelete);
|
|
DEFINE_KEY(XK_KP_0, EKeyKeyPad0);
|
|
DEFINE_KEY(XK_KP_1, EKeyKeyPad1);
|
|
DEFINE_KEY(XK_KP_2, EKeyKeyPad2);
|
|
DEFINE_KEY(XK_KP_3, EKeyKeyPad3);
|
|
DEFINE_KEY(XK_KP_4, EKeyKeyPad4);
|
|
DEFINE_KEY(XK_KP_5, EKeyKeyPad5);
|
|
DEFINE_KEY(XK_KP_6, EKeyKeyPad6);
|
|
DEFINE_KEY(XK_KP_7, EKeyKeyPad7);
|
|
DEFINE_KEY(XK_KP_8, EKeyKeyPad8);
|
|
DEFINE_KEY(XK_KP_9, EKeyKeyPad9);
|
|
DEFINE_KEY(XK_KP_Insert, EKeyKeyPad0);
|
|
DEFINE_KEY(XK_KP_End, EKeyKeyPad1);
|
|
DEFINE_KEY(XK_KP_Down, EKeyKeyPad2);
|
|
DEFINE_KEY(XK_KP_Page_Down, EKeyKeyPad3);
|
|
DEFINE_KEY(XK_KP_Left, EKeyKeyPad4);
|
|
DEFINE_KEY(XK_KP_Begin, EKeyKeyPad5);
|
|
DEFINE_KEY(XK_KP_Right, EKeyKeyPad6);
|
|
DEFINE_KEY(XK_KP_Home, EKeyKeyPad7);
|
|
DEFINE_KEY(XK_KP_Up, EKeyKeyPad8);
|
|
DEFINE_KEY(XK_KP_Page_Up, EKeyKeyPad9);
|
|
DEFINE_KEY(XK_KP_Delete, EKeyKeyPadPeriod);
|
|
DEFINE_KEY(XK_KP_Decimal, EKeyKeyPadPeriod);
|
|
DEFINE_KEY(XK_KP_Divide, EKeyKeyPadDivide);
|
|
DEFINE_KEY(XK_KP_Multiply, EKeyKeyPadMultiply);
|
|
DEFINE_KEY(XK_KP_Subtract, EKeyKeyPadMinus);
|
|
DEFINE_KEY(XK_KP_Add, EKeyKeyPadPlus);
|
|
DEFINE_KEY(XK_KP_Enter, EKeyKeyPadEnter);
|
|
DEFINE_KEY(XK_KP_Equal, EKeyKeyPadEquals);
|
|
DEFINE_KEY(XK_Up, EKeyUp);
|
|
DEFINE_KEY(XK_Down, EKeyDown);
|
|
DEFINE_KEY(XK_Right, EKeyRight);
|
|
DEFINE_KEY(XK_Left, EKeyLeft);
|
|
DEFINE_KEY(XK_Insert, EKeyInsert);
|
|
DEFINE_KEY(XK_Home, EKeyHome);
|
|
DEFINE_KEY(XK_End, EKeyEnd);
|
|
DEFINE_KEY(XK_Page_Up, EKeyPageUp);
|
|
DEFINE_KEY(XK_Page_Down, EKeyPageDown);
|
|
DEFINE_KEY(XK_F1, EKeyF1);
|
|
DEFINE_KEY(XK_F2, EKeyF2);
|
|
DEFINE_KEY(XK_F3, EKeyF3);
|
|
DEFINE_KEY(XK_F4, EKeyF4);
|
|
DEFINE_KEY(XK_F5, EKeyF5);
|
|
DEFINE_KEY(XK_F6, EKeyF6);
|
|
DEFINE_KEY(XK_F7, EKeyF7);
|
|
DEFINE_KEY(XK_F8, EKeyF8);
|
|
DEFINE_KEY(XK_F9, EKeyF9);
|
|
DEFINE_KEY(XK_F10, EKeyF10);
|
|
DEFINE_KEY(XK_F11, EKeyF11);
|
|
DEFINE_KEY(XK_F12, EKeyF12);
|
|
DEFINE_KEY(XK_F13, EKeyF13);
|
|
DEFINE_KEY(XK_F14, EKeyF14);
|
|
DEFINE_KEY(XK_F15, EKeyF15);
|
|
DEFINE_KEY(XK_Num_Lock, EKeyNumLock);
|
|
DEFINE_KEY(XK_Caps_Lock, EKeyCapsLock);
|
|
DEFINE_KEY(XK_Scroll_Lock, EKeyScrollLock);
|
|
DEFINE_KEY(XK_Shift_L, EKeyLShift);
|
|
DEFINE_KEY(XK_Shift_R, EKeyRShift);
|
|
DEFINE_KEY(XK_Meta_L, EKeyLMeta);
|
|
DEFINE_KEY(XK_Meta_R, EKeyRMeta);
|
|
DEFINE_KEY(XK_Alt_L, EKeyLAlt);
|
|
DEFINE_KEY(XK_Alt_R, EKeyRAlt);
|
|
DEFINE_KEY(XK_Control_L, EKeyLControl);
|
|
DEFINE_KEY(XK_Control_R, EKeyRControl);
|
|
}
|
|
|
|
X11Device::~X11Device() {
|
|
Log(EDebug, "Destroying X11 device");
|
|
if (m_initialized)
|
|
shutdown();
|
|
}
|
|
|
|
namespace algo {
|
|
struct vsync_sort {
|
|
/**
|
|
* Approximate the vertical retrace speed of the mode info structure
|
|
* (taken from bzflag)
|
|
*/
|
|
inline int getVSync(XF86VidModeModeInfo *mode) {
|
|
return ((int) (0.5f + (1000.0f * mode->dotclock) / (mode->htotal * mode->vtotal)));
|
|
}
|
|
|
|
bool operator() (XF86VidModeModeInfo *mode1, XF86VidModeModeInfo *mode2) {
|
|
return getVSync(mode1) > getVSync(mode2);
|
|
}
|
|
};
|
|
}
|
|
|
|
XVisualInfo *X11Device::createVisual() {
|
|
XVisualInfo visTempl;
|
|
int visCount;
|
|
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
/* Search for visuals on the current screen matching the requrested color depth */
|
|
visTempl.screen = session->m_screen;
|
|
visTempl.depth = m_redBits + m_blueBits + m_greenBits + m_alphaBits;
|
|
XVisualInfo *visinfo = XGetVisualInfo(session->m_display, VisualScreenMask | VisualDepthMask, &visTempl, &visCount);
|
|
|
|
if (visinfo == NULL)
|
|
Log(EError, "Could not find a matching visual!");
|
|
|
|
return visinfo;
|
|
}
|
|
|
|
void X11Device::init(Device *other) {
|
|
Device::init(other);
|
|
|
|
Log(EDebug, "Initializing X11 device");
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
|
|
/* Find matching visuals */
|
|
m_visinfo = createVisual();
|
|
|
|
/* Fullscreen mode selection */
|
|
std::vector<XF86VidModeModeInfo *> modeList;
|
|
|
|
if (m_fullscreen) {
|
|
if (!session->m_hasVidMode)
|
|
Log(EError, "VidMode extension is required for fullscreen display");
|
|
|
|
/* Retrieve a list of all video modes */
|
|
int modeCount;
|
|
XF86VidModeModeInfo** modes;
|
|
XF86VidModeGetAllModeLines(session->m_display, session->m_screen, &modeCount, &modes);
|
|
|
|
/* Save the current mode */
|
|
m_previousMode = *modes[0];
|
|
|
|
/* Find the best matching screen resolution */
|
|
for (int i=0; i<modeCount; ++i) {
|
|
if (modes[i]->hdisplay == m_size.x &&
|
|
modes[i]->vdisplay == m_size.y)
|
|
modeList.push_back(modes[i]);
|
|
}
|
|
/* Release the memory held by the resolution list */
|
|
XFree(modes);
|
|
|
|
std::sort(modeList.begin(), modeList.end(), algo::vsync_sort());
|
|
|
|
if (modeList.size() == 0) {
|
|
Log(EWarn, "No matching fullscreen resolution found, using windowed mode!");
|
|
m_fullscreen = false;
|
|
}
|
|
}
|
|
|
|
/* Create the window's attributes */
|
|
XSetWindowAttributes x11attr;
|
|
x11attr.background_pixel = x11attr.border_pixel =
|
|
BlackPixel(session->m_display, session->m_screen);
|
|
|
|
/* Create a colormap for the window */
|
|
Colormap colormap = XCreateColormap(session->m_display, session->m_root, m_visinfo->visual, AllocNone);
|
|
x11attr.colormap = colormap;
|
|
|
|
if (m_fullscreen) {
|
|
/* Switch to the best matching resolution */
|
|
XF86VidModeSwitchToMode(session->m_display, session->m_screen, modeList[0]);
|
|
XF86VidModeSetViewPort(session->m_display, session->m_screen, 0, 0);
|
|
|
|
x11attr.override_redirect = True;
|
|
|
|
m_window = XCreateWindow(session->m_display, session->m_root,
|
|
0, 0, /* x,y position*/
|
|
m_size.x, m_size.y,
|
|
0, m_visinfo->depth, /* border width, color depth */
|
|
InputOutput, m_visinfo->visual,
|
|
CWBackPixel | CWBorderPixel | CWColormap |
|
|
CWOverrideRedirect, &x11attr);
|
|
|
|
XWarpPointer(session->m_display, None, m_window, 0, 0, 0, 0, 0, 0);
|
|
XMapRaised(session->m_display, m_window);
|
|
|
|
/* Grab the pointer & keyboard */
|
|
XGrabKeyboard(session->m_display, m_window, True,
|
|
GrabModeAsync, GrabModeAsync, CurrentTime);
|
|
XGrabPointer(session->m_display, m_window, True,
|
|
ButtonPressMask, GrabModeAsync, GrabModeAsync,
|
|
m_window, None, CurrentTime);
|
|
|
|
m_visible = true;
|
|
} else {
|
|
/* Center the window if needed */
|
|
if (m_center) {
|
|
m_position.x = (DisplayWidth(session->m_display, session->m_screen) - m_size.x) / 2;
|
|
m_position.y = (DisplayHeight(session->m_display, session->m_screen) - m_size.y) / 2;
|
|
}
|
|
|
|
/* Create the X window */
|
|
unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap;
|
|
m_window = XCreateWindow(session->m_display, session->m_root,
|
|
m_position.x, m_position.y, m_size.x, m_size.y, 0, m_visinfo->depth,
|
|
InputOutput, m_visinfo->visual, mask, &x11attr);
|
|
|
|
if (!m_window)
|
|
Log(EError, "Could not create the window");
|
|
|
|
/* Make the window non-resizable */
|
|
XSizeHints *hints = XAllocSizeHints();
|
|
hints->width = m_size.x;
|
|
hints->height = m_size.y;
|
|
|
|
if (m_resizeAllowed) {
|
|
hints->min_width = hints->min_height = 10;
|
|
hints->max_width = hints->max_height = INT_MAX;
|
|
} else {
|
|
hints->min_width = hints->max_width = m_size.x;
|
|
hints->min_height = hints->max_height = m_size.y;
|
|
}
|
|
|
|
hints->x = m_position.x; hints->y = m_position.y;
|
|
hints->flags = PMaxSize | PMinSize | USSize | USPosition;
|
|
XSetNormalHints(session->m_display, m_window, hints);
|
|
XFree(hints);
|
|
|
|
/* Set input hints */
|
|
XWMHints *wmHints = XAllocWMHints();
|
|
wmHints->input = True;
|
|
wmHints->flags = InputHint;
|
|
XSetWMHints(session->m_display, m_window, wmHints);
|
|
XFree(wmHints);
|
|
|
|
/* Make the window closeable */
|
|
m_deleteWindow = XInternAtom(session->m_display, "WM_DELETE_WINDOW", False);
|
|
XSetWMProtocols(session->m_display, m_window, &m_deleteWindow, 1);
|
|
}
|
|
|
|
/* Mark events types in which we are interested */
|
|
XSelectInput(session->m_display, m_window, FocusChangeMask | KeyPressMask | KeyReleaseMask
|
|
| ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
|
|
|
|
/* Initialize member variables */
|
|
m_cursor = None;
|
|
m_mouse = Point2i(-1, -1);
|
|
m_modifierState = 0;
|
|
m_buttonState = 0;
|
|
m_grab = false;
|
|
|
|
m_initialized = true;
|
|
setTitle(m_title);
|
|
}
|
|
|
|
void X11Device::setTitle(const std::string &title) {
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
|
|
Device::setTitle(title);
|
|
if (m_initialized) {
|
|
std::string finalTitle;
|
|
|
|
if (m_showFPS && m_fps != 0) {
|
|
finalTitle = formatString("%s - %i FPS", title.c_str(), m_fps);
|
|
} else {
|
|
finalTitle = title;
|
|
}
|
|
|
|
XStoreName(session->m_display, m_window, finalTitle.c_str());
|
|
XFlush(session->m_display);
|
|
}
|
|
}
|
|
|
|
void X11Device::setPosition(const Point2i &position) {
|
|
Assert(m_initialized);
|
|
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
|
|
Device::setPosition(position);
|
|
if (m_initialized && !m_fullscreen) {
|
|
XMoveWindow(session->m_display, m_window, m_position.x, m_position.y);
|
|
XFlush(session->m_display);
|
|
}
|
|
}
|
|
|
|
void X11Device::setVisible(bool visible) {
|
|
Assert(m_initialized);
|
|
|
|
if (visible && !m_visible) {
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
XMapRaised(session->m_display, m_window);
|
|
XSync(session->m_display, 0);
|
|
m_visible = true;
|
|
} else if (!visible && m_visible) {
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
XUnmapWindow(session->m_display, m_window);
|
|
XSync(session->m_display, 0);
|
|
m_visible = false;
|
|
}
|
|
}
|
|
|
|
void X11Device::warpMouse(const Point2i &position) {
|
|
Assert(m_initialized);
|
|
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
XEvent event;
|
|
XWarpPointer(session->m_display, None, m_window, 0, 0, 0, 0, position.x, position.y);
|
|
XSync(session->m_display, False);
|
|
/* Remove the caused event from the queue */
|
|
XCheckTypedWindowEvent(session->m_display, m_window, MotionNotify, &event);
|
|
m_mouse = Point2i(position.x, position.y);
|
|
}
|
|
|
|
void X11Device::showCursor(bool enabled) {
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
if (enabled) {
|
|
if (m_cursor != None) {
|
|
XFreeCursor(session->m_display, m_cursor);
|
|
m_cursor = None;
|
|
}
|
|
XUndefineCursor(session->m_display, m_window);
|
|
XSync(session->m_display, False);
|
|
} else {
|
|
if (m_cursor == None) {
|
|
/* Create a transparent cursor */
|
|
char bm[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
Pixmap pix = XCreateBitmapFromData(session->m_display, m_window, bm, 8, 8);
|
|
XColor black;
|
|
|
|
memset(&black, 0, sizeof(XColor));
|
|
black.flags = DoRed | DoGreen | DoBlue;
|
|
m_cursor = XCreatePixmapCursor(session->m_display, pix, pix, &black, &black, 0, 0);
|
|
XFreePixmap(session->m_display, pix);
|
|
}
|
|
XDefineCursor(session->m_display, m_window, m_cursor);
|
|
XSync(session->m_display, False);
|
|
}
|
|
}
|
|
|
|
void X11Device::shutdown() {
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
Log(EDebug, "Shutting down X11 device");
|
|
Device::shutdown();
|
|
setVisible(false);
|
|
XDestroyWindow(session->m_display, m_window);
|
|
XFree(m_visinfo);
|
|
|
|
if (m_fullscreen) {
|
|
/* Switch back to the previous screen resolution */
|
|
XF86VidModeSwitchToMode(session->m_display, session->m_screen, &m_previousMode);
|
|
XF86VidModeSetViewPort(session->m_display, session->m_screen, 0, 0);
|
|
}
|
|
|
|
/* In case auto_repeat was left on */
|
|
XKeyboardState xkbs;
|
|
XAutoRepeatOn(session->m_display);
|
|
XGetKeyboardControl(session->m_display, &xkbs);
|
|
|
|
if (!xkbs.global_auto_repeat)
|
|
Log(EWarn, "Unable to restore the keyboard auto-repeat flag");
|
|
|
|
m_initialized = false;
|
|
}
|
|
|
|
void X11Device::flip() {
|
|
Assert(m_initialized);
|
|
}
|
|
|
|
void X11Device::processEvent(const XEvent &event) {
|
|
DeviceEvent deviceEvent(ENoEvent);
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
|
|
if (m_callbacks.size() == 0)
|
|
return;
|
|
|
|
switch (event.type) {
|
|
case ClientMessage:
|
|
/* The window close button pressed */
|
|
if ((event.xclient.format == 32) && ((unsigned) event.xclient.data.l[0] == m_deleteWindow)) {
|
|
deviceEvent.setType(EQuitEvent);
|
|
}
|
|
break;
|
|
case FocusIn:
|
|
/* Deactivate auto-repeat */
|
|
XAutoRepeatOff(session->m_display);
|
|
deviceEvent.setType(EGainFocusEvent);
|
|
m_modifierState = 0;
|
|
m_buttonState = 0;
|
|
break;
|
|
case FocusOut:
|
|
/* Reactivate auto-repeat */
|
|
XAutoRepeatOn(session->m_display);
|
|
deviceEvent.setType(ELoseFocusEvent);
|
|
m_modifierState = 0;
|
|
m_buttonState = 0;
|
|
break;
|
|
case ButtonPress:
|
|
deviceEvent.setType(EMouseButtonDownEvent);
|
|
translateMouse(event, deviceEvent);
|
|
m_buttonState |= deviceEvent.getMouseButton();
|
|
break;
|
|
case ButtonRelease:
|
|
deviceEvent.setType(EMouseButtonUpEvent);
|
|
translateMouse(event, deviceEvent);
|
|
m_buttonState &= ~deviceEvent.getMouseButton();
|
|
break;
|
|
case MotionNotify: {
|
|
deviceEvent.setType(m_buttonState == 0 ? EMouseMotionEvent : EMouseDragEvent);
|
|
translateMouse(event, deviceEvent);
|
|
deviceEvent.setMouseButton(m_buttonState);
|
|
if (m_grab)
|
|
warpMouse(Point2i(getSize().x / 2, getSize().y/2));
|
|
int xpos = deviceEvent.getMousePosition().x;
|
|
int ypos = deviceEvent.getMousePosition().y;
|
|
if (xpos > m_size.x || xpos < 0 || ypos > m_size.y || ypos < 0)
|
|
return;
|
|
}
|
|
break;
|
|
case KeyPress:
|
|
if (translateKeyboard(event, deviceEvent)) {
|
|
deviceEvent.setType(EKeyDownEvent);
|
|
|
|
int special = deviceEvent.getKeyboardSpecial();
|
|
|
|
/* Update the current modifier state */
|
|
if (special == EKeyLShift || special == EKeyRShift) {
|
|
m_modifierState |= EShiftModifier;
|
|
} else if (special == EKeyLAlt || special == EKeyRAlt) {
|
|
m_modifierState |= EAltModifier;
|
|
} else if (special == EKeyLControl || special == EKeyRControl) {
|
|
m_modifierState |= EControlModifier;
|
|
}
|
|
|
|
deviceEvent.setKeyboardModifiers(m_modifierState);
|
|
}
|
|
break;
|
|
case KeyRelease:
|
|
if (translateKeyboard(event, deviceEvent)) {
|
|
deviceEvent.setType(EKeyUpEvent);
|
|
|
|
int special = deviceEvent.getKeyboardSpecial();
|
|
|
|
/* Update the current modifier state */
|
|
if (special == EKeyLShift || special == EKeyRShift) {
|
|
m_modifierState = m_modifierState & (~EShiftModifier);
|
|
} else if (special == EKeyLAlt || special == EKeyRAlt) {
|
|
m_modifierState = m_modifierState & (~EAltModifier);
|
|
} else if (special == EKeyLControl || special == EKeyRControl) {
|
|
m_modifierState = m_modifierState & (~EControlModifier);
|
|
}
|
|
|
|
deviceEvent.setKeyboardModifiers(m_modifierState);
|
|
}
|
|
break;
|
|
case MapNotify:
|
|
case UnmapNotify:
|
|
m_modifierState = 0;
|
|
break;
|
|
case ConfigureNotify: {
|
|
Vector2i size(event.xconfigure.width, event.xconfigure.height);
|
|
if (m_size != size) {
|
|
m_size = size;
|
|
deviceEvent.setType(EResizeEvent);
|
|
}
|
|
}
|
|
break;
|
|
case ReparentNotify:
|
|
case Expose:
|
|
break;
|
|
default:
|
|
Log(EWarn, "Unknown event %i received", event.type);
|
|
}
|
|
if (deviceEvent.getType() != ENoEvent)
|
|
fireDeviceEvent(deviceEvent);
|
|
}
|
|
|
|
|
|
void X11Device::translateMouse(const XEvent &xEvent, DeviceEvent &event) {
|
|
event.setMousePosition(Point2i(xEvent.xbutton.x, xEvent.xbutton.y));
|
|
|
|
/* Calculate relative coordinates */
|
|
if (m_mouse.x != -1 && m_mouse.y != -1) {
|
|
event.setMouseRelative(Vector2i(event.getMousePosition() - m_mouse));
|
|
} else {
|
|
event.setMouseRelative(Vector2i(0,0));
|
|
}
|
|
|
|
m_mouse = event.getMousePosition();
|
|
|
|
if (xEvent.xbutton.button == Button1)
|
|
event.setMouseButton(ELeftButton);
|
|
else if (xEvent.xbutton.button == Button2)
|
|
event.setMouseButton(EMiddleButton);
|
|
else if (xEvent.xbutton.button == Button3)
|
|
event.setMouseButton(ERightButton);
|
|
else if (xEvent.xbutton.button == Button4)
|
|
event.setMouseButton(EWheelUpButton);
|
|
else if (xEvent.xbutton.button == Button5)
|
|
event.setMouseButton(EWheelDownButton);
|
|
else
|
|
event.setMouseButton(ENoButton);
|
|
}
|
|
|
|
bool X11Device::translateKeyboard(const XEvent &xEvent, DeviceEvent &event) {
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
|
|
KeySym sym = XKeycodeToKeysym(session->m_display, xEvent.xkey.keycode, 0);
|
|
|
|
/* Default: 0 */
|
|
event.setKeyboardKey(0);
|
|
event.setKeyboardSpecial(0);
|
|
|
|
/* Retrieve an 'interpreted' version of the key event */
|
|
int noc = XLookupString(const_cast<XKeyEvent *>(&xEvent.xkey), event.getKeyboardInterpreted(),
|
|
15, NULL, NULL);
|
|
event.getKeyboardInterpreted()[noc] = 0;
|
|
|
|
if (sym != 0) {
|
|
int type = sym >> 8;
|
|
if (type >= 0x00 && type <= 0x0D) {
|
|
/* Alphanumeric key */
|
|
|
|
char key = sym & 0xFF;
|
|
if (key >= 'A' && key <= 'Z') {
|
|
/* Convert to lower-case */
|
|
key += ('a' - 'A');
|
|
}
|
|
|
|
event.setKeyboardKey(key);
|
|
} else if (type == 0xFE) {
|
|
/* Ignore */
|
|
return false;
|
|
} else if (type == 0xFF) {
|
|
/* Lookup special key */
|
|
event.setKeyboardSpecial(m_keymap[sym & 0xFF]);
|
|
if (event.getKeyboardSpecial() == ENoSpecial)
|
|
return false;
|
|
} else {
|
|
Log(EWarn, "Unknown X11 keysym: 0x%x", (int) sym);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void X11Device::setGrab(bool grab) {
|
|
Assert(m_initialized);
|
|
|
|
m_grab = grab;
|
|
showCursor(!grab);
|
|
}
|
|
|
|
void X11Device::makeCurrent(Renderer *renderer) {
|
|
Assert(m_initialized);
|
|
|
|
X11Session *session = static_cast<X11Session *>(getSession());
|
|
GLXRenderer *glxRenderer = static_cast<GLXRenderer *>(renderer);
|
|
int retval;
|
|
if (glxRenderer == NULL)
|
|
retval = glXMakeCurrent(session->m_display, None, NULL);
|
|
else
|
|
retval = glXMakeCurrent(session->m_display, m_window, glxRenderer->getGLXContext());
|
|
|
|
if (retval != True)
|
|
Log(EError, "Error in glXMakeCurrent - unable to activate the rendering context");
|
|
}
|
|
|
|
MTS_IMPLEMENT_CLASS(X11Device, false, Device)
|
|
MTS_NAMESPACE_END
|