|
|
|
/*
|
|
|
|
* Copyright (c) 1999 Matthias Elter <me@kde.org>
|
|
|
|
* Copyright (c) 2004-2006 Adrian Page <adrian@pagenet.plus.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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.g
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
|
|
|
|
Some of the X11-specific event handling code is based upon code from
|
|
|
|
src/kernel/qapplication_x11.cpp from the TQt GUI Toolkit and is subject
|
|
|
|
to the following license and copyright:
|
|
|
|
|
|
|
|
****************************************************************************
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Implementation of X11 startup routines and event handling
|
|
|
|
**
|
|
|
|
** Created : 931029
|
|
|
|
**
|
|
|
|
** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
|
|
|
|
**
|
|
|
|
** This file is part of the kernel module of the TQt GUI Toolkit.
|
|
|
|
**
|
|
|
|
** This file may be distributed under the terms of the Q Public License
|
|
|
|
** as defined by Trolltech AS of Norway and appearing in the file
|
|
|
|
** LICENSE.TQPL included in the packaging of this file.
|
|
|
|
**
|
|
|
|
** This file may be distributed and/or modified under the terms of the
|
|
|
|
** GNU General Public License version 2 as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
|
|
** packaging of this file.
|
|
|
|
**
|
|
|
|
** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition
|
|
|
|
** licenses for Unix/X11 may use this file in accordance with the TQt Commercial
|
|
|
|
** License Agreement provided with the Software.
|
|
|
|
**
|
|
|
|
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
|
|
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**
|
|
|
|
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
|
|
|
|
** information about TQt Commercial License Agreements.
|
|
|
|
** See http://www.trolltech.com/qpl/ for TQPL licensing information.
|
|
|
|
** See http://www.trolltech.com/gpl/ for GPL licensing information.
|
|
|
|
**
|
|
|
|
** Contact info@trolltech.com if any conditions of this licensing are
|
|
|
|
** not clear to you.
|
|
|
|
**
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
#include <tqcursor.h>
|
|
|
|
|
|
|
|
#include "kis_canvas.h"
|
|
|
|
#include "kis_cursor.h"
|
|
|
|
#include "kis_move_event.h"
|
|
|
|
#include "kis_button_press_event.h"
|
|
|
|
#include "kis_button_release_event.h"
|
|
|
|
#include "kis_double_click_event.h"
|
|
|
|
#include "kis_config.h"
|
|
|
|
#include "kis_qpaintdevice_canvas.h"
|
|
|
|
#include "kis_opengl_canvas.h"
|
|
|
|
#include "kis_config.h"
|
|
|
|
#include "kis_input_device.h"
|
|
|
|
#include "fixx11h.h"
|
|
|
|
|
|
|
|
#ifdef Q_WS_X11
|
|
|
|
|
|
|
|
#include <tqdesktopwidget.h>
|
|
|
|
#include <tqapplication.h>
|
|
|
|
|
|
|
|
#include <X11/XKBlib.h>
|
|
|
|
#include <X11/keysym.h>
|
|
|
|
|
|
|
|
bool KisCanvasWidget::X11SupportInitialised = false;
|
|
|
|
long KisCanvasWidget::X11AltMask = 0;
|
|
|
|
long KisCanvasWidget::X11MetaMask = 0;
|
|
|
|
|
|
|
|
#if defined(EXTENDED_X11_TABLET_SUPPORT)
|
|
|
|
|
|
|
|
int KisCanvasWidget::X11DeviceMotionNotifyEvent = -1;
|
|
|
|
int KisCanvasWidget::X11DeviceButtonPressEvent = -1;
|
|
|
|
int KisCanvasWidget::X11DeviceButtonReleaseEvent = -1;
|
|
|
|
int KisCanvasWidget::X11ProximityInEvent = -1;
|
|
|
|
int KisCanvasWidget::X11ProximityOutEvent = -1;
|
|
|
|
|
|
|
|
//X11XIDTabletDeviceMap KisCanvasWidget::X11TabletDeviceMap;
|
|
|
|
std::map<XID, KisCanvasWidget::X11TabletDevice> KisCanvasWidget::X11TabletDeviceMap;
|
|
|
|
|
|
|
|
#endif // EXTENDED_X11_TABLET_SUPPORT
|
|
|
|
|
|
|
|
#endif // Q_WS_X11
|
|
|
|
|
|
|
|
KisCanvasWidget::KisCanvasWidget()
|
|
|
|
{
|
|
|
|
m_enableMoveEventCompressionHint = false;
|
|
|
|
m_lastPressure = 0;
|
|
|
|
|
|
|
|
#ifdef Q_WS_X11
|
|
|
|
if (!X11SupportInitialised) {
|
|
|
|
initX11Support();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_lastRootX = -1;
|
|
|
|
m_lastRootY = -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
KisCanvasWidget::~KisCanvasWidget()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotPaintEvent(TQPaintEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotPaintEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotMousePressEvent(TQMouseEvent *e)
|
|
|
|
{
|
|
|
|
KisButtonPressEvent ke(KisInputDevice::mouse(), KisPoint(e->pos()), KisPoint(e->globalPos()), PRESSURE_DEFAULT, 0, 0, e->button(), e->state());
|
|
|
|
buttonPressEvent(&ke);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotMouseReleaseEvent(TQMouseEvent *e)
|
|
|
|
{
|
|
|
|
KisButtonReleaseEvent ke(KisInputDevice::mouse(), KisPoint(e->pos()), KisPoint(e->globalPos()), PRESSURE_DEFAULT, 0, 0, e->button(), e->state());
|
|
|
|
buttonReleaseEvent(&ke);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotMouseDoubleClickEvent(TQMouseEvent *e)
|
|
|
|
{
|
|
|
|
KisDoubleClickEvent ke(KisInputDevice::mouse(), KisPoint(e->pos()), KisPoint(e->globalPos()), PRESSURE_DEFAULT, 0, 0, e->button(), e->state());
|
|
|
|
doubleClickEvent(&ke);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotMouseMoveEvent(TQMouseEvent *e)
|
|
|
|
{
|
|
|
|
KisMoveEvent ke(KisInputDevice::mouse(), KisPoint(e->pos()), KisPoint(e->globalPos()), PRESSURE_DEFAULT, 0, 0, e->state());
|
|
|
|
moveEvent(&ke);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotTabletEvent(TQTabletEvent *e)
|
|
|
|
{
|
|
|
|
KisInputDevice device;
|
|
|
|
|
|
|
|
switch (e->device()) {
|
|
|
|
default:
|
|
|
|
case TQTabletEvent::NoDevice:
|
|
|
|
case TQTabletEvent::Stylus:
|
|
|
|
device = KisInputDevice::stylus();
|
|
|
|
break;
|
|
|
|
case TQTabletEvent::Puck:
|
|
|
|
device = KisInputDevice::puck();
|
|
|
|
break;
|
|
|
|
case TQTabletEvent::Eraser:
|
|
|
|
device = KisInputDevice::eraser();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
double pressure = e->pressure() / 255.0;
|
|
|
|
|
|
|
|
if (e->type() == TQEvent::TabletPress) {
|
|
|
|
KisButtonPressEvent ke(device, KisPoint(e->pos()), KisPoint(e->globalPos()), pressure, e->xTilt(), e->yTilt(), TQt::LeftButton, TQt::NoButton);
|
|
|
|
translateTabletEvent(&ke);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (e->type() == TQEvent::TabletRelease) {
|
|
|
|
KisButtonReleaseEvent ke(device, KisPoint(e->pos()), KisPoint(e->globalPos()), pressure, e->xTilt(), e->yTilt(), TQt::LeftButton, TQt::NoButton);
|
|
|
|
translateTabletEvent(&ke);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
KisMoveEvent ke(device, KisPoint(e->pos()), KisPoint(e->globalPos()), pressure, e->xTilt(), e->yTilt(), TQt::NoButton);
|
|
|
|
translateTabletEvent(&ke);
|
|
|
|
#ifdef Q_WS_X11
|
|
|
|
// Fix the problem that when you change from using a tablet device to the mouse,
|
|
|
|
// the first mouse button event is not recognised. This is because we handle
|
|
|
|
// X11 core mouse move events directly so TQt does not get to see them. This breaks
|
|
|
|
// the tablet event accept/ignore mechanism, causing TQt to consume the first
|
|
|
|
// mouse button event it sees, instead of a mouse move. 'Ignoring' tablet move events
|
|
|
|
// stops TQt from stealing the next mouse button event. This does not affect the
|
|
|
|
// tablet aware tools as they do not care about mouse moves while the tablet device is
|
|
|
|
// drawing.
|
|
|
|
e->ignore();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotEnterEvent(TQEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotEnterEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotLeaveEvent(TQEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotLeaveEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotWheelEvent(TQWheelEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotMouseWheelEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotKeyPressEvent(TQKeyEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotKeyPressEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotKeyReleaseEvent(TQKeyEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotKeyReleaseEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotDragEnterEvent(TQDragEnterEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotDragEnterEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::widgetGotDropEvent(TQDropEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotDropEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::moveEvent(KisMoveEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotMoveEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::buttonPressEvent(KisButtonPressEvent *e)
|
|
|
|
{
|
|
|
|
TQWidget *widget = dynamic_cast<TQWidget *>(this);
|
|
|
|
Q_ASSERT(widget != 0);
|
|
|
|
|
|
|
|
if (widget) {
|
|
|
|
widget->setFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
emit sigGotButtonPressEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::buttonReleaseEvent(KisButtonReleaseEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotButtonReleaseEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::doubleClickEvent(KisDoubleClickEvent *e)
|
|
|
|
{
|
|
|
|
emit sigGotDoubleClickEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::translateTabletEvent(KisEvent *e)
|
|
|
|
{
|
|
|
|
bool checkThresholdOnly = false;
|
|
|
|
|
|
|
|
if (e->type() == KisEvent::ButtonPressEvent || e->type() == KisEvent::ButtonReleaseEvent) {
|
|
|
|
KisButtonEvent *b = static_cast<KisButtonEvent *>(e);
|
|
|
|
|
|
|
|
if (b->button() == TQt::MidButton || b->button() == TQt::RightButton) {
|
|
|
|
|
|
|
|
if (e->type() == KisEvent::ButtonPressEvent) {
|
|
|
|
buttonPressEvent(static_cast<KisButtonPressEvent *>(e));
|
|
|
|
} else {
|
|
|
|
buttonReleaseEvent(static_cast<KisButtonReleaseEvent *>(e));
|
|
|
|
}
|
|
|
|
|
|
|
|
checkThresholdOnly = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use pressure threshold to detect 'left button' press/release
|
|
|
|
if (e->pressure() >= PRESSURE_THRESHOLD && m_lastPressure < PRESSURE_THRESHOLD) {
|
|
|
|
KisButtonPressEvent ke(e->device(), e->pos(), e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), TQt::LeftButton, e->state());
|
|
|
|
buttonPressEvent(&ke);
|
|
|
|
} else if (e->pressure() < PRESSURE_THRESHOLD && m_lastPressure >= PRESSURE_THRESHOLD) {
|
|
|
|
KisButtonReleaseEvent ke(e->device(), e->pos(), e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), TQt::LeftButton, e->state());
|
|
|
|
buttonReleaseEvent(&ke);
|
|
|
|
} else {
|
|
|
|
if (!checkThresholdOnly) {
|
|
|
|
KisMoveEvent ke(e->device(), e->pos(), e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), e->state());
|
|
|
|
moveEvent(&ke);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_lastPressure = e->pressure();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef Q_WS_X11
|
|
|
|
|
|
|
|
void KisCanvasWidget::initX11Support()
|
|
|
|
{
|
|
|
|
if (X11SupportInitialised)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
X11SupportInitialised = true;
|
|
|
|
|
|
|
|
Display *x11Display = TQApplication::desktop()->x11Display();
|
|
|
|
|
|
|
|
// Look at the modifier mapping and get the correct masks for alt/meta
|
|
|
|
XModifierKeymap *map = XGetModifierMapping(x11Display);
|
|
|
|
|
|
|
|
if (map) {
|
|
|
|
int mapIndex = 0;
|
|
|
|
|
|
|
|
for (int maskIndex = 0; maskIndex < 8; maskIndex++) {
|
|
|
|
for (int i = 0; i < map->max_keypermod; i++) {
|
|
|
|
if (map->modifiermap[mapIndex]) {
|
|
|
|
|
|
|
|
KeySym sym = XkbKeycodeToKeysym(x11Display, map->modifiermap[mapIndex], 0, 0);
|
|
|
|
|
|
|
|
if (X11AltMask == 0 && (sym == XK_Alt_L || sym == XK_Alt_R)) {
|
|
|
|
X11AltMask = 1 << maskIndex;
|
|
|
|
}
|
|
|
|
if (X11MetaMask == 0 && (sym == XK_Meta_L || sym == XK_Meta_R)) {
|
|
|
|
X11MetaMask = 1 << maskIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mapIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
XFreeModifiermap(map);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Assume defaults
|
|
|
|
X11AltMask = Mod1Mask;
|
|
|
|
X11MetaMask = Mod4Mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(EXTENDED_X11_TABLET_SUPPORT)
|
|
|
|
|
|
|
|
int numDevices = 0;
|
|
|
|
const XDeviceInfo *devices = XListInputDevices(x11Display, &numDevices);
|
|
|
|
|
|
|
|
if (devices != NULL) {
|
|
|
|
XID lastStylusSeen = 0;
|
|
|
|
XID lastEraserSeen = 0;
|
|
|
|
bool foundStylus = false;
|
|
|
|
bool foundEraser = false;
|
|
|
|
|
|
|
|
for (int i = 0; i < numDevices; i++) {
|
|
|
|
|
|
|
|
const XDeviceInfo *device = devices + i;
|
|
|
|
X11TabletDevice tabletDevice(device);
|
|
|
|
|
|
|
|
if (tabletDevice.mightBeTabletDevice()) {
|
|
|
|
|
|
|
|
tabletDevice.readSettingsFromConfig();
|
|
|
|
|
|
|
|
TQString lowerCaseName = tabletDevice.name().lower();
|
|
|
|
|
|
|
|
// Find the devices that TQt will use as its stylus and eraser devices.
|
|
|
|
if (!foundStylus || !foundEraser) {
|
|
|
|
if (lowerCaseName.startsWith("stylus") || lowerCaseName.startsWith("pen")) {
|
|
|
|
lastStylusSeen = device->id;
|
|
|
|
foundStylus = true;
|
|
|
|
}
|
|
|
|
else if (lowerCaseName.startsWith("eraser")) {
|
|
|
|
lastEraserSeen = device->id;
|
|
|
|
foundEraser = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
X11TabletDeviceMap[device->id] = tabletDevice;
|
|
|
|
|
|
|
|
// Event types are device-independent. Store any
|
|
|
|
// the device supports.
|
|
|
|
if (tabletDevice.buttonPressEvent() >= 0) {
|
|
|
|
X11DeviceButtonPressEvent = tabletDevice.buttonPressEvent();
|
|
|
|
}
|
|
|
|
if (tabletDevice.buttonReleaseEvent() >= 0) {
|
|
|
|
X11DeviceButtonReleaseEvent = tabletDevice.buttonReleaseEvent();
|
|
|
|
}
|
|
|
|
if (tabletDevice.motionNotifyEvent() >= 0) {
|
|
|
|
X11DeviceMotionNotifyEvent = tabletDevice.motionNotifyEvent();
|
|
|
|
}
|
|
|
|
if (tabletDevice.proximityInEvent() >= 0) {
|
|
|
|
X11ProximityInEvent = tabletDevice.proximityInEvent();
|
|
|
|
}
|
|
|
|
if (tabletDevice.proximityOutEvent() >= 0) {
|
|
|
|
X11ProximityOutEvent = tabletDevice.proximityOutEvent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate input devices.
|
|
|
|
for (X11XIDTabletDeviceMap::iterator it = X11TabletDeviceMap.begin(); it != X11TabletDeviceMap.end(); ++it) {
|
|
|
|
|
|
|
|
X11TabletDevice& tabletDevice = (*it).second;
|
|
|
|
|
|
|
|
if (foundStylus && tabletDevice.id() == lastStylusSeen) {
|
|
|
|
tabletDevice.setInputDevice(KisInputDevice::stylus());
|
|
|
|
} else if (foundEraser && tabletDevice.id() == lastEraserSeen) {
|
|
|
|
tabletDevice.setInputDevice(KisInputDevice::eraser());
|
|
|
|
} else {
|
|
|
|
tabletDevice.setInputDevice(KisInputDevice::allocateInputDevice());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
XFreeDeviceList(const_cast<XDeviceInfo *>(devices));
|
|
|
|
}
|
|
|
|
#endif // EXTENDED_X11_TABLET_SUPPORT
|
|
|
|
}
|
|
|
|
|
|
|
|
TQt::ButtonState KisCanvasWidget::translateX11ButtonState(int state)
|
|
|
|
{
|
|
|
|
int buttonState = 0;
|
|
|
|
|
|
|
|
if (state & Button1Mask)
|
|
|
|
buttonState |= TQt::LeftButton;
|
|
|
|
if (state & Button2Mask)
|
|
|
|
buttonState |= TQt::MidButton;
|
|
|
|
if (state & Button3Mask)
|
|
|
|
buttonState |= TQt::RightButton;
|
|
|
|
if (state & ShiftMask)
|
|
|
|
buttonState |= TQt::ShiftButton;
|
|
|
|
if (state & ControlMask)
|
|
|
|
buttonState |= TQt::ControlButton;
|
|
|
|
if (state & X11AltMask)
|
|
|
|
buttonState |= TQt::AltButton;
|
|
|
|
if (state & X11MetaMask)
|
|
|
|
buttonState |= TQt::MetaButton;
|
|
|
|
|
|
|
|
return static_cast<TQt::ButtonState>(buttonState);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQt::ButtonState KisCanvasWidget::translateX11Button(unsigned int X11Button)
|
|
|
|
{
|
|
|
|
TQt::ButtonState qtButton;
|
|
|
|
|
|
|
|
switch (X11Button) {
|
|
|
|
case Button1:
|
|
|
|
qtButton = TQt::LeftButton;
|
|
|
|
break;
|
|
|
|
case Button2:
|
|
|
|
qtButton = TQt::MidButton;
|
|
|
|
break;
|
|
|
|
case Button3:
|
|
|
|
qtButton = TQt::RightButton;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qtButton = TQt::NoButton;
|
|
|
|
}
|
|
|
|
|
|
|
|
return qtButton;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(EXTENDED_X11_TABLET_SUPPORT)
|
|
|
|
|
|
|
|
KisCanvasWidget::X11TabletDevice::X11TabletDevice()
|
|
|
|
{
|
|
|
|
m_mightBeTabletDevice = false;
|
|
|
|
m_inputDevice = KisInputDevice::unknown();
|
|
|
|
m_enabled = false;
|
|
|
|
m_xAxis = NoAxis;
|
|
|
|
m_yAxis = NoAxis;
|
|
|
|
m_pressureAxis = NoAxis;
|
|
|
|
m_xTiltAxis = NoAxis;
|
|
|
|
m_yTiltAxis = NoAxis;
|
|
|
|
m_wheelAxis = NoAxis;
|
|
|
|
m_toolIDAxis = NoAxis;
|
|
|
|
m_serialNumberAxis = NoAxis;
|
|
|
|
m_buttonPressEvent = -1;
|
|
|
|
m_buttonReleaseEvent = -1;
|
|
|
|
m_motionNotifyEvent = -1;
|
|
|
|
m_proximityInEvent = -1;
|
|
|
|
m_proximityOutEvent = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
KisCanvasWidget::X11TabletDevice::X11TabletDevice(const XDeviceInfo *deviceInfo)
|
|
|
|
{
|
|
|
|
m_mightBeTabletDevice = false;
|
|
|
|
m_inputDevice = KisInputDevice::unknown();
|
|
|
|
m_enabled = false;
|
|
|
|
m_xAxis = NoAxis;
|
|
|
|
m_yAxis = NoAxis;
|
|
|
|
m_pressureAxis = NoAxis;
|
|
|
|
m_xTiltAxis = NoAxis;
|
|
|
|
m_yTiltAxis = NoAxis;
|
|
|
|
m_wheelAxis = NoAxis;
|
|
|
|
m_toolIDAxis = NoAxis;
|
|
|
|
m_serialNumberAxis = NoAxis;
|
|
|
|
|
|
|
|
m_deviceId = deviceInfo->id;
|
|
|
|
m_name = deviceInfo->name;
|
|
|
|
|
|
|
|
// Get the ranges of the valuators
|
|
|
|
XAnyClassPtr classInfo = const_cast<XAnyClassPtr>(deviceInfo->inputclassinfo);
|
|
|
|
|
|
|
|
for (int i = 0; i < deviceInfo->num_classes; i++) {
|
|
|
|
|
|
|
|
if (classInfo->c_class == ValuatorClass) {
|
|
|
|
|
|
|
|
const XValuatorInfo *valuatorInfo = reinterpret_cast<const XValuatorInfo *>(classInfo);
|
|
|
|
|
|
|
|
// Need at least x, y, and pressure.
|
|
|
|
|
|
|
|
if (valuatorInfo->num_axes >= 3) {
|
|
|
|
|
|
|
|
for (unsigned int axis = 0; axis < valuatorInfo->num_axes; axis++) {
|
|
|
|
m_axisInfo.append(valuatorInfo->axes[axis]);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_mightBeTabletDevice = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
classInfo = reinterpret_cast<XAnyClassPtr>(reinterpret_cast<char *>(classInfo) + classInfo->length);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the event types it supports. We're only interested in
|
|
|
|
// buttons and motion at the moment.
|
|
|
|
m_buttonPressEvent = -1;
|
|
|
|
m_buttonReleaseEvent = -1;
|
|
|
|
m_motionNotifyEvent = -1;
|
|
|
|
m_proximityInEvent = -1;
|
|
|
|
m_proximityOutEvent = -1;
|
|
|
|
|
|
|
|
m_XDevice = XOpenDevice(TQApplication::desktop()->x11Display(), m_deviceId);
|
|
|
|
|
|
|
|
if (m_XDevice != NULL) {
|
|
|
|
for (int i = 0; i < m_XDevice->num_classes; i++) {
|
|
|
|
|
|
|
|
XEventClass eventClass;
|
|
|
|
|
|
|
|
if (m_XDevice->classes[i].input_class == ButtonClass) {
|
|
|
|
DeviceButtonPress(m_XDevice, m_buttonPressEvent, eventClass);
|
|
|
|
m_eventClassList.append(eventClass);
|
|
|
|
|
|
|
|
DeviceButtonRelease(m_XDevice, m_buttonReleaseEvent, eventClass);
|
|
|
|
m_eventClassList.append(eventClass);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (m_XDevice->classes[i].input_class == ValuatorClass) {
|
|
|
|
DeviceMotionNotify(m_XDevice, m_motionNotifyEvent, eventClass);
|
|
|
|
m_eventClassList.append(eventClass);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (m_XDevice->classes[i].input_class == ProximityClass) {
|
|
|
|
ProximityIn(m_XDevice, m_proximityInEvent, eventClass);
|
|
|
|
m_eventClassList.append(eventClass);
|
|
|
|
|
|
|
|
ProximityOut(m_XDevice, m_proximityOutEvent, eventClass);
|
|
|
|
m_eventClassList.append(eventClass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: We don't XCloseXDevice() since TQt will have already opened
|
|
|
|
// it, and only one XCloseDevice() call closes it for all opens.
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_buttonPressEvent == -1 || m_buttonReleaseEvent == -1 || m_motionNotifyEvent == -1) {
|
|
|
|
m_mightBeTabletDevice = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::setEnabled(bool enabled)
|
|
|
|
{
|
|
|
|
m_enabled = enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KisCanvasWidget::X11TabletDevice::enabled() const
|
|
|
|
{
|
|
|
|
return m_enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_INT32 KisCanvasWidget::X11TabletDevice::numAxes() const
|
|
|
|
{
|
|
|
|
return m_axisInfo.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::setXAxis(TQ_INT32 axis)
|
|
|
|
{
|
|
|
|
m_xAxis = axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::setYAxis(TQ_INT32 axis)
|
|
|
|
{
|
|
|
|
m_yAxis = axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::setPressureAxis(TQ_INT32 axis)
|
|
|
|
{
|
|
|
|
m_pressureAxis = axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::setXTiltAxis(TQ_INT32 axis)
|
|
|
|
{
|
|
|
|
m_xTiltAxis = axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::setYTiltAxis(TQ_INT32 axis)
|
|
|
|
{
|
|
|
|
m_yTiltAxis = axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::setWheelAxis(TQ_INT32 axis)
|
|
|
|
{
|
|
|
|
m_wheelAxis = axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::setToolIDAxis(TQ_INT32 axis)
|
|
|
|
{
|
|
|
|
m_toolIDAxis = axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::setSerialNumberAxis(TQ_INT32 axis)
|
|
|
|
{
|
|
|
|
m_serialNumberAxis = axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_INT32 KisCanvasWidget::X11TabletDevice::xAxis() const
|
|
|
|
{
|
|
|
|
return m_xAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_INT32 KisCanvasWidget::X11TabletDevice::yAxis() const
|
|
|
|
{
|
|
|
|
return m_yAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_INT32 KisCanvasWidget::X11TabletDevice::pressureAxis() const
|
|
|
|
{
|
|
|
|
return m_pressureAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_INT32 KisCanvasWidget::X11TabletDevice::xTiltAxis() const
|
|
|
|
{
|
|
|
|
return m_xTiltAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_INT32 KisCanvasWidget::X11TabletDevice::yTiltAxis() const
|
|
|
|
{
|
|
|
|
return m_yTiltAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_INT32 KisCanvasWidget::X11TabletDevice::wheelAxis() const
|
|
|
|
{
|
|
|
|
return m_wheelAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_INT32 KisCanvasWidget::X11TabletDevice::toolIDAxis() const
|
|
|
|
{
|
|
|
|
return m_toolIDAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQ_INT32 KisCanvasWidget::X11TabletDevice::serialNumberAxis() const
|
|
|
|
{
|
|
|
|
return m_serialNumberAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::readSettingsFromConfig()
|
|
|
|
{
|
|
|
|
KisConfig cfg;
|
|
|
|
|
|
|
|
m_enabled = cfg.tabletDeviceEnabled(m_name);
|
|
|
|
|
|
|
|
m_xAxis = cfg.tabletDeviceAxis(m_name, "XAxis", DefaultAxis);
|
|
|
|
m_yAxis = cfg.tabletDeviceAxis(m_name, "YAxis", DefaultAxis);
|
|
|
|
m_pressureAxis = cfg.tabletDeviceAxis(m_name, "PressureAxis", DefaultAxis);
|
|
|
|
m_xTiltAxis = cfg.tabletDeviceAxis(m_name, "XTiltAxis", DefaultAxis);
|
|
|
|
m_yTiltAxis = cfg.tabletDeviceAxis(m_name, "YTiltAxis", DefaultAxis);
|
|
|
|
m_wheelAxis = cfg.tabletDeviceAxis(m_name, "WheelAxis", DefaultAxis);
|
|
|
|
m_toolIDAxis = cfg.tabletDeviceAxis(m_name, "ToolIDAxis", DefaultAxis);
|
|
|
|
m_serialNumberAxis = cfg.tabletDeviceAxis(m_name, "SerialNumberAxis", DefaultAxis);
|
|
|
|
|
|
|
|
if (!m_enabled && m_xAxis == DefaultAxis && m_yAxis == DefaultAxis && m_pressureAxis == DefaultAxis &&
|
|
|
|
m_xTiltAxis == DefaultAxis && m_yTiltAxis == DefaultAxis && m_wheelAxis == DefaultAxis &&
|
|
|
|
m_toolIDAxis == DefaultAxis && m_serialNumberAxis == DefaultAxis) {
|
|
|
|
// This is the first time this device has been seen. Set up default values, assuming
|
|
|
|
// it's a Wacom pad.
|
|
|
|
m_xAxis = 0;
|
|
|
|
m_yAxis = 1;
|
|
|
|
m_pressureAxis = 2;
|
|
|
|
|
|
|
|
if (m_axisInfo.count() >= 4) {
|
|
|
|
m_xTiltAxis = 3;
|
|
|
|
} else {
|
|
|
|
m_xTiltAxis = NoAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_axisInfo.count() >= 5) {
|
|
|
|
m_yTiltAxis = 4;
|
|
|
|
} else {
|
|
|
|
m_yTiltAxis = NoAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_axisInfo.count() >= 6) {
|
|
|
|
m_wheelAxis = 5;
|
|
|
|
} else {
|
|
|
|
m_wheelAxis = NoAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Available since driver version 0.7.2.
|
|
|
|
if (m_axisInfo.count() >= 7) {
|
|
|
|
m_toolIDAxis = 6;
|
|
|
|
} else {
|
|
|
|
m_toolIDAxis = NoAxis;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_axisInfo.count() >= 8) {
|
|
|
|
m_serialNumberAxis = 7;
|
|
|
|
} else {
|
|
|
|
m_serialNumberAxis = NoAxis;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::writeSettingsToConfig()
|
|
|
|
{
|
|
|
|
KisConfig cfg;
|
|
|
|
|
|
|
|
cfg.setTabletDeviceEnabled(m_name, m_enabled);
|
|
|
|
|
|
|
|
cfg.setTabletDeviceAxis(m_name, "XAxis", m_xAxis);
|
|
|
|
cfg.setTabletDeviceAxis(m_name, "YAxis", m_yAxis);
|
|
|
|
cfg.setTabletDeviceAxis(m_name, "PressureAxis", m_pressureAxis);
|
|
|
|
cfg.setTabletDeviceAxis(m_name, "XTiltAxis", m_xTiltAxis);
|
|
|
|
cfg.setTabletDeviceAxis(m_name, "YTiltAxis", m_yTiltAxis);
|
|
|
|
cfg.setTabletDeviceAxis(m_name, "WheelAxis", m_wheelAxis);
|
|
|
|
cfg.setTabletDeviceAxis(m_name, "ToolIDAxis", m_toolIDAxis);
|
|
|
|
cfg.setTabletDeviceAxis(m_name, "SerialNumberAxis", m_serialNumberAxis);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::X11TabletDevice::enableEvents(TQWidget *widget) const
|
|
|
|
{
|
|
|
|
if (!m_eventClassList.isEmpty()) {
|
|
|
|
int result = XSelectExtensionEvent(widget->x11AppDisplay(), widget->handle(),
|
|
|
|
const_cast<XEventClass*>(&m_eventClassList[0]),
|
|
|
|
m_eventClassList.count());
|
|
|
|
|
|
|
|
if (result != Success) {
|
|
|
|
kdDebug(41001) << "Failed to select extension events for " << m_name << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double KisCanvasWidget::X11TabletDevice::translateAxisValue(int value, const XAxisInfo& axisInfo) const
|
|
|
|
{
|
|
|
|
int axisRange = axisInfo.max_value - axisInfo.min_value;
|
|
|
|
double translatedValue = 0;
|
|
|
|
|
|
|
|
if (axisRange != 0) {
|
|
|
|
translatedValue = (static_cast<double>(value) - axisInfo.min_value) / axisRange;
|
|
|
|
if (axisInfo.min_value < 0) {
|
|
|
|
translatedValue -= 0.5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return translatedValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
KisCanvasWidget::X11TabletDevice::State::State(const KisPoint& pos, double pressure, const KisVector2D& tilt, double wheel,
|
|
|
|
TQ_UINT32 toolID, TQ_UINT32 serialNumber)
|
|
|
|
: m_pos(pos),
|
|
|
|
m_pressure(pressure),
|
|
|
|
m_tilt(tilt),
|
|
|
|
m_wheel(wheel),
|
|
|
|
m_toolID(toolID),
|
|
|
|
m_serialNumber(serialNumber)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KisCanvasWidget::X11TabletDevice::State KisCanvasWidget::X11TabletDevice::translateAxisData(const int *axisData) const
|
|
|
|
{
|
|
|
|
KisPoint pos(0, 0);
|
|
|
|
|
|
|
|
if (m_xAxis != NoAxis && m_yAxis != NoAxis) {
|
|
|
|
pos = KisPoint(translateAxisValue(axisData[m_xAxis], m_axisInfo[m_xAxis]),
|
|
|
|
translateAxisValue(axisData[m_yAxis], m_axisInfo[m_yAxis]));
|
|
|
|
}
|
|
|
|
|
|
|
|
double pressure = PRESSURE_DEFAULT;
|
|
|
|
|
|
|
|
if (m_pressureAxis != NoAxis) {
|
|
|
|
pressure = translateAxisValue(axisData[m_pressureAxis], m_axisInfo[m_pressureAxis]);
|
|
|
|
}
|
|
|
|
|
|
|
|
KisVector2D tilt = KisVector2D(0, 0);
|
|
|
|
TQ_UINT32 toolID = 0;
|
|
|
|
TQ_UINT32 serialNumber = 0;
|
|
|
|
|
|
|
|
if (m_xTiltAxis != NoAxis) {
|
|
|
|
// Latest wacom driver returns the tool id and serial number in
|
|
|
|
// the upper 16 bits of the x and y tilts and wheel.
|
|
|
|
int xTiltAxisValue = (TQ_INT16)(axisData[m_xTiltAxis] & 0xffff);
|
|
|
|
toolID = ((TQ_UINT32)axisData[m_xTiltAxis] >> 16) & 0xffff;
|
|
|
|
|
|
|
|
tilt.setX(translateAxisValue(xTiltAxisValue, m_axisInfo[m_xTiltAxis]));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_yTiltAxis != NoAxis) {
|
|
|
|
int yTiltAxisValue = (TQ_INT16)(axisData[m_yTiltAxis] & 0xffff);
|
|
|
|
serialNumber = (TQ_UINT32)axisData[m_yTiltAxis] & 0xffff0000;
|
|
|
|
|
|
|
|
tilt.setY(translateAxisValue(yTiltAxisValue, m_axisInfo[m_yTiltAxis]));
|
|
|
|
}
|
|
|
|
|
|
|
|
double wheel = 0;
|
|
|
|
|
|
|
|
if (m_wheelAxis != NoAxis) {
|
|
|
|
int wheelAxisValue = (TQ_INT16)(axisData[m_wheelAxis] & 0xffff);
|
|
|
|
serialNumber |= ((TQ_UINT32)axisData[m_wheelAxis] >> 16) & 0xffff;
|
|
|
|
|
|
|
|
wheel = translateAxisValue(wheelAxisValue, m_axisInfo[m_wheelAxis]);
|
|
|
|
}
|
|
|
|
|
|
|
|
//TQString ids;
|
|
|
|
//ids.sprintf("Tool ID: %8x Serial Number: %8x", toolID, serialNumber);
|
|
|
|
|
|
|
|
return State(pos, pressure, tilt, wheel, toolID, serialNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
KisCanvasWidget::X11XIDTabletDeviceMap& KisCanvasWidget::tabletDeviceMap()
|
|
|
|
{
|
|
|
|
return X11TabletDeviceMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvasWidget::selectTabletDeviceEvents(TQWidget *widget)
|
|
|
|
{
|
|
|
|
for (X11XIDTabletDeviceMap::const_iterator it = X11TabletDeviceMap.begin(); it != X11TabletDeviceMap.end(); ++it) {
|
|
|
|
|
|
|
|
const X11TabletDevice& device = (*it).second;
|
|
|
|
|
|
|
|
if (device.enabled()) {
|
|
|
|
device.enableEvents(widget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // EXTENDED_X11_TABLET_SUPPORT
|
|
|
|
|
|
|
|
bool KisCanvasWidget::x11Event(XEvent *event, Display *x11Display, WId winId, TQPoint widgetOriginPos)
|
|
|
|
{
|
|
|
|
if (event->type == MotionNotify) {
|
|
|
|
// Mouse move
|
|
|
|
if (!m_enableMoveEventCompressionHint) {
|
|
|
|
|
|
|
|
XMotionEvent motion = event->xmotion;
|
|
|
|
TQPoint globalPos(motion.x_root, motion.y_root);
|
|
|
|
|
|
|
|
if (globalPos.x() != m_lastRootX || globalPos.y() != m_lastRootY) {
|
|
|
|
|
|
|
|
int state = translateX11ButtonState(motion.state);
|
|
|
|
TQPoint pos(motion.x, motion.y);
|
|
|
|
TQMouseEvent e(TQEvent::MouseMove, pos, globalPos, TQt::NoButton, state);
|
|
|
|
|
|
|
|
widgetGotMouseMoveEvent(&e);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_lastRootX = globalPos.x();
|
|
|
|
m_lastRootY = globalPos.y();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#if defined(EXTENDED_X11_TABLET_SUPPORT)
|
|
|
|
if (event->type == X11DeviceMotionNotifyEvent || event->type == X11DeviceButtonPressEvent || event->type == X11DeviceButtonReleaseEvent) {
|
|
|
|
// Tablet event.
|
|
|
|
int deviceId;
|
|
|
|
const int *axisData;
|
|
|
|
TQt::ButtonState button;
|
|
|
|
TQt::ButtonState buttonState;
|
|
|
|
|
|
|
|
if (event->type == X11DeviceMotionNotifyEvent) {
|
|
|
|
// Tablet move
|
|
|
|
const XDeviceMotionEvent *motion = reinterpret_cast<const XDeviceMotionEvent *>(event);
|
|
|
|
XEvent mouseEvent;
|
|
|
|
|
|
|
|
// Look for an accompanying core event.
|
|
|
|
if (XCheckTypedWindowEvent(x11Display, winId, MotionNotify, &mouseEvent)) {
|
|
|
|
if (motion->time == mouseEvent.xmotion.time) {
|
|
|
|
// Do nothing
|
|
|
|
} else {
|
|
|
|
XPutBackEvent(x11Display, &mouseEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_enableMoveEventCompressionHint) {
|
|
|
|
while (true) {
|
|
|
|
// Look for another motion notify in the queue and skip
|
|
|
|
// to that if found.
|
|
|
|
if (!XCheckTypedWindowEvent(x11Display, winId, X11DeviceMotionNotifyEvent, &mouseEvent)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
motion = reinterpret_cast<const XDeviceMotionEvent *>(&mouseEvent);
|
|
|
|
|
|
|
|
XEvent coreMotionEvent;
|
|
|
|
|
|
|
|
// Look for an accompanying core event.
|
|
|
|
if (!XCheckTypedWindowEvent(x11Display, winId, MotionNotify, &coreMotionEvent)) {
|
|
|
|
// Do nothing
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
deviceId = motion->deviceid;
|
|
|
|
axisData = motion->axis_data;
|
|
|
|
button = TQt::NoButton;
|
|
|
|
buttonState = translateX11ButtonState(motion->state);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (event->type == X11DeviceButtonPressEvent) {
|
|
|
|
// Tablet button press
|
|
|
|
const XDeviceButtonPressedEvent *buttonPressed = reinterpret_cast<const XDeviceButtonPressedEvent *>(event);
|
|
|
|
deviceId = buttonPressed->deviceid;
|
|
|
|
axisData = buttonPressed->axis_data;
|
|
|
|
button = translateX11Button(buttonPressed->button);
|
|
|
|
buttonState = translateX11ButtonState(buttonPressed->state);
|
|
|
|
|
|
|
|
if (TQApplication::activePopupWidget() == 0) {
|
|
|
|
XEvent mouseEvent;
|
|
|
|
|
|
|
|
// Look for and swallow an accompanying core event, but only if there's
|
|
|
|
// no active popup, as that needs to see it.
|
|
|
|
if (XCheckTypedWindowEvent(x11Display, winId, ButtonPress, &mouseEvent)) {
|
|
|
|
if (buttonPressed->time == mouseEvent.xbutton.time) {
|
|
|
|
// Do nothing
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
XPutBackEvent(x11Display, &mouseEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Tablet button release
|
|
|
|
const XDeviceButtonReleasedEvent *buttonReleased = reinterpret_cast<const XDeviceButtonReleasedEvent *>(event);
|
|
|
|
deviceId = buttonReleased->deviceid;
|
|
|
|
axisData = buttonReleased->axis_data;
|
|
|
|
button = translateX11Button(buttonReleased->button);
|
|
|
|
buttonState = translateX11ButtonState(buttonReleased->state);
|
|
|
|
|
|
|
|
if (TQApplication::activePopupWidget() == 0) {
|
|
|
|
XEvent mouseEvent;
|
|
|
|
|
|
|
|
// Look for and swallow an accompanying core event, but only if there's
|
|
|
|
// no active popup, as that needs to see it.
|
|
|
|
if (XCheckTypedWindowEvent(x11Display, winId, ButtonRelease, &mouseEvent)) {
|
|
|
|
if (buttonReleased->time == mouseEvent.xbutton.time) {
|
|
|
|
// Do nothing
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
XPutBackEvent(x11Display, &mouseEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
X11XIDTabletDeviceMap::const_iterator it = X11TabletDeviceMap.find(deviceId);
|
|
|
|
|
|
|
|
if (it != X11TabletDeviceMap.end()) {
|
|
|
|
|
|
|
|
const X11TabletDevice& tabletDevice = (*it).second;
|
|
|
|
|
|
|
|
if (tabletDevice.enabled()) {
|
|
|
|
X11TabletDevice::State deviceState = tabletDevice.translateAxisData(axisData);
|
|
|
|
|
|
|
|
// Map normalised position coordinates to screen coordinates
|
|
|
|
TQDesktopWidget *desktop = TQApplication::desktop();
|
|
|
|
KisPoint globalPos(deviceState.pos().x() * desktop->width(), deviceState.pos().y() * desktop->height());
|
|
|
|
// Convert screen coordinates to widget coordinates
|
|
|
|
KisPoint pos = globalPos - KoPoint( widgetOriginPos );
|
|
|
|
|
|
|
|
// Map tilt to -60 - +60 degrees
|
|
|
|
KisVector2D tilt(deviceState.tilt().x() * 60, deviceState.tilt().y() * 60);
|
|
|
|
|
|
|
|
if (event->type == X11DeviceMotionNotifyEvent) {
|
|
|
|
KisMoveEvent e(tabletDevice.inputDevice(), pos, globalPos, deviceState.pressure(), tilt.x(), tilt.y(), buttonState);
|
|
|
|
translateTabletEvent(&e);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (event->type == X11DeviceButtonPressEvent) {
|
|
|
|
KisButtonPressEvent e(tabletDevice.inputDevice(), pos, globalPos, deviceState.pressure(), tilt.x(), tilt.y(), button, buttonState);
|
|
|
|
translateTabletEvent(&e);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
KisButtonReleaseEvent e(tabletDevice.inputDevice(), pos, globalPos, deviceState.pressure(), tilt.x(), tilt.y(), button, buttonState);
|
|
|
|
translateTabletEvent(&e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consume the event even if the device is disabled otherwise TQt will
|
|
|
|
// process it and send a TQTabletEvent.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif // EXTENDED_X11_TABLET_SUPPORT
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(EXTENDED_X11_TABLET_SUPPORT)
|
|
|
|
|
|
|
|
KisInputDevice KisCanvasWidget::findActiveInputDevice()
|
|
|
|
{
|
|
|
|
X11XIDTabletDeviceMap::const_iterator it;
|
|
|
|
|
|
|
|
for (it = X11TabletDeviceMap.begin(); it != X11TabletDeviceMap.end(); ++it) {
|
|
|
|
const X11TabletDevice& tabletDevice = (*it).second;
|
|
|
|
|
|
|
|
XDeviceState *deviceState = XQueryDeviceState(TQApplication::desktop()->x11Display(),
|
|
|
|
tabletDevice.xDevice());
|
|
|
|
|
|
|
|
// If your the laptop sleeps, and you remove the mouse from the usb
|
|
|
|
// port, then on wake-up Chalk can crash because the above call will
|
|
|
|
// return 0.
|
|
|
|
if (!deviceState) continue;
|
|
|
|
|
|
|
|
const XInputClass *inputClass = deviceState->data;
|
|
|
|
bool deviceIsInProximity = false;
|
|
|
|
|
|
|
|
for (int i = 0; i < deviceState->num_classes; i++) {
|
|
|
|
|
|
|
|
if (inputClass->c_class == ValuatorClass) {
|
|
|
|
|
|
|
|
const XValuatorState *valuatorState = reinterpret_cast<const XValuatorState *>(inputClass);
|
|
|
|
|
|
|
|
if ((valuatorState->mode & ProximityState) == InProximity) {
|
|
|
|
deviceIsInProximity = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inputClass = reinterpret_cast<const XInputClass *>(reinterpret_cast<const char *>(inputClass) + inputClass->length);
|
|
|
|
}
|
|
|
|
|
|
|
|
XFreeDeviceState(deviceState);
|
|
|
|
|
|
|
|
if (deviceIsInProximity && tabletDevice.enabled()) {
|
|
|
|
return tabletDevice.inputDevice();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return KisInputDevice::mouse();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // EXTENDED_X11_TABLET_SUPPORT
|
|
|
|
|
|
|
|
|
|
|
|
#endif // Q_WS_X11
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
|
|
|
|
#define TQPAINTDEVICE_CANVAS_WIDGET false
|
|
|
|
#define OPENGL_CANVAS_WIDGET true
|
|
|
|
|
|
|
|
KisCanvas::KisCanvas(TQWidget *parent, const char *name)
|
|
|
|
{
|
|
|
|
m_parent = parent;
|
|
|
|
m_name = name;
|
|
|
|
m_enableMoveEventCompressionHint = false;
|
|
|
|
m_canvasWidget = 0;
|
|
|
|
m_useOpenGL = false;
|
|
|
|
createCanvasWidget(TQPAINTDEVICE_CANVAS_WIDGET);
|
|
|
|
}
|
|
|
|
|
|
|
|
KisCanvas::~KisCanvas()
|
|
|
|
{
|
|
|
|
delete m_canvasWidget;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_GL
|
|
|
|
void KisCanvas::createCanvasWidget(bool useOpenGL, TQGLWidget *sharedContextWidget)
|
|
|
|
#else
|
|
|
|
void KisCanvas::createCanvasWidget(bool useOpenGL)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
delete m_canvasWidget;
|
|
|
|
|
|
|
|
#ifndef HAVE_GL
|
|
|
|
useOpenGL = false;
|
|
|
|
#else
|
|
|
|
if (useOpenGL && !TQGLFormat::hasOpenGL()) {
|
|
|
|
kdDebug(41001) << "Tried to create OpenGL widget when system doesn't have OpenGL\n";
|
|
|
|
useOpenGL = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (useOpenGL) {
|
|
|
|
m_canvasWidget = new KisOpenGLCanvasWidget(m_parent, m_name.latin1(), sharedContextWidget);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
m_canvasWidget = new KisTQPaintDeviceCanvasWidget(m_parent, m_name.latin1());
|
|
|
|
}
|
|
|
|
|
|
|
|
m_useOpenGL = useOpenGL;
|
|
|
|
|
|
|
|
TQ_CHECK_PTR(m_canvasWidget);
|
|
|
|
TQWidget *widget = dynamic_cast<TQWidget *>(m_canvasWidget);
|
|
|
|
|
|
|
|
widget->setBackgroundMode(TQWidget::NoBackground);
|
|
|
|
widget->setMouseTracking(true);
|
|
|
|
widget->setAcceptDrops(true);
|
|
|
|
m_canvasWidget->enableMoveEventCompressionHint(m_enableMoveEventCompressionHint);
|
|
|
|
|
|
|
|
#if defined(EXTENDED_X11_TABLET_SUPPORT)
|
|
|
|
selectTabletDeviceEvents();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotPaintEvent(TQPaintEvent *)), TQT_SIGNAL(sigGotPaintEvent(TQPaintEvent *)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotEnterEvent(TQEvent*)), TQT_SIGNAL(sigGotEnterEvent(TQEvent*)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotLeaveEvent(TQEvent*)), TQT_SIGNAL(sigGotLeaveEvent(TQEvent*)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotMouseWheelEvent(TQWheelEvent*)), TQT_SIGNAL(sigGotMouseWheelEvent(TQWheelEvent*)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotKeyPressEvent(TQKeyEvent*)), TQT_SIGNAL(sigGotKeyPressEvent(TQKeyEvent*)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotKeyReleaseEvent(TQKeyEvent*)), TQT_SIGNAL(sigGotKeyReleaseEvent(TQKeyEvent*)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotDragEnterEvent(TQDragEnterEvent*)), TQT_SIGNAL(sigGotDragEnterEvent(TQDragEnterEvent*)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotDropEvent(TQDropEvent*)), TQT_SIGNAL(sigGotDropEvent(TQDropEvent*)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotMoveEvent(KisMoveEvent *)), TQT_SIGNAL(sigGotMoveEvent(KisMoveEvent *)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent *)), TQT_SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent *)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent *)), TQT_SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent *)));
|
|
|
|
connect(m_canvasWidget, TQT_SIGNAL(sigGotDoubleClickEvent(KisDoubleClickEvent *)), TQT_SIGNAL(sigGotDoubleClickEvent(KisDoubleClickEvent *)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::createTQPaintDeviceCanvas()
|
|
|
|
{
|
|
|
|
createCanvasWidget(TQPAINTDEVICE_CANVAS_WIDGET);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_GL
|
|
|
|
void KisCanvas::createOpenGLCanvas(TQGLWidget *sharedContextWidget)
|
|
|
|
{
|
|
|
|
createCanvasWidget(OPENGL_CANVAS_WIDGET, sharedContextWidget);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool KisCanvas::isOpenGLCanvas() const
|
|
|
|
{
|
|
|
|
return m_useOpenGL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::enableMoveEventCompressionHint(bool enableMoveCompression)
|
|
|
|
{
|
|
|
|
m_enableMoveEventCompressionHint = enableMoveCompression;
|
|
|
|
if (m_canvasWidget != 0) {
|
|
|
|
m_canvasWidget->enableMoveEventCompressionHint(enableMoveCompression);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQWidget *KisCanvas::TQPaintDeviceWidget() const
|
|
|
|
{
|
|
|
|
if (m_useOpenGL) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return dynamic_cast<TQWidget *>(m_canvasWidget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_GL
|
|
|
|
TQGLWidget *KisCanvas::OpenGLWidget() const
|
|
|
|
{
|
|
|
|
if (m_useOpenGL) {
|
|
|
|
return dynamic_cast<TQGLWidget *>(m_canvasWidget);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
KisCanvasWidgetPainter *KisCanvas::createPainter()
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget != 0);
|
|
|
|
return m_canvasWidget->createPainter();
|
|
|
|
}
|
|
|
|
|
|
|
|
KisCanvasWidget *KisCanvas::canvasWidget() const
|
|
|
|
{
|
|
|
|
return m_canvasWidget;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::setGeometry(int x, int y, int width, int height)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->setGeometry(x, y, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::show()
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::hide()
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
int KisCanvas::width() const
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
return dynamic_cast<TQWidget *>(m_canvasWidget)->width();
|
|
|
|
}
|
|
|
|
|
|
|
|
int KisCanvas::height() const
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
return dynamic_cast<TQWidget *>(m_canvasWidget)->height();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::update()
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::update(const TQRect& r)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->update(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::update(int x, int y, int width, int height)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->update(x, y, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::repaint()
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->repaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::repaint(bool erase)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->repaint(erase);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::repaint(int x, int y, int width, int height, bool erase)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->repaint(x, y, width, height, erase);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::repaint(const TQRect& r, bool erase)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->repaint(r, erase);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::repaint(const TQRegion& r, bool erase)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->repaint(r, erase);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KisCanvas::isUpdatesEnabled() const
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
return dynamic_cast<TQWidget *>(m_canvasWidget)->isUpdatesEnabled();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::setUpdatesEnabled(bool updatesEnabled)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->setUpdatesEnabled(updatesEnabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::updateGeometry()
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->updateGeometry();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::setFocusPolicy(TQWidget::FocusPolicy focusPolicy)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->setFocusPolicy(focusPolicy);
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQCursor& KisCanvas::cursor() const
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
return dynamic_cast<TQWidget *>(m_canvasWidget)->cursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::setCursor(const TQCursor& cursor)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
dynamic_cast<TQWidget *>(m_canvasWidget)->setCursor(cursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(EXTENDED_X11_TABLET_SUPPORT)
|
|
|
|
void KisCanvas::selectTabletDeviceEvents()
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_canvasWidget);
|
|
|
|
m_canvasWidget->selectTabletDeviceEvents();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool KisCanvas::cursorIsOverCanvas() const
|
|
|
|
{
|
|
|
|
if (TQApplication::activePopupWidget() != 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (TQApplication::activeModalWidget() != 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQWidget *canvasWidget = dynamic_cast<TQWidget *>(m_canvasWidget);
|
|
|
|
Q_ASSERT(canvasWidget != 0);
|
|
|
|
|
|
|
|
if (canvasWidget) {
|
|
|
|
if (TQApplication::widgetAt(TQCursor::pos(), true) == canvasWidget) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KisCanvas::handleKeyEvent(TQEvent *e)
|
|
|
|
{
|
|
|
|
TQKeyEvent *ke = dynamic_cast<TQKeyEvent *>(e);
|
|
|
|
|
|
|
|
Q_ASSERT(ke != 0);
|
|
|
|
|
|
|
|
if (ke) {
|
|
|
|
TQWidget *canvasWidget = dynamic_cast<TQWidget *>(m_canvasWidget);
|
|
|
|
Q_ASSERT(canvasWidget != 0);
|
|
|
|
|
|
|
|
if (canvasWidget) {
|
|
|
|
canvasWidget->setFocus();
|
|
|
|
|
|
|
|
if (e->type() == TQEvent::KeyPress) {
|
|
|
|
emit sigGotKeyPressEvent(ke);
|
|
|
|
} else {
|
|
|
|
emit sigGotKeyReleaseEvent(ke);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "kis_canvas.moc"
|
|
|
|
|