krita

kis_canvas.cc

00001 /*
00002  *  Copyright (c) 1999 Matthias Elter  <me@kde.org>
00003  *  Copyright (c) 2004-2006 Adrian Page <adrian@pagenet.plus.com>
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.g
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019 
00020  Some of the X11-specific event handling code is based upon code from
00021  src/kernel/qapplication_x11.cpp from the Qt GUI Toolkit and is subject
00022  to the following license and copyright:
00023 
00024  ****************************************************************************
00025 **
00026 **
00027 ** Implementation of X11 startup routines and event handling
00028 **
00029 ** Created : 931029
00030 **
00031 ** Copyright (C) 1992-2003 Trolltech AS.  All rights reserved.
00032 **
00033 ** This file is part of the kernel module of the Qt GUI Toolkit.
00034 **
00035 ** This file may be distributed under the terms of the Q Public License
00036 ** as defined by Trolltech AS of Norway and appearing in the file
00037 ** LICENSE.QPL included in the packaging of this file.
00038 **
00039 ** This file may be distributed and/or modified under the terms of the
00040 ** GNU General Public License version 2 as published by the Free Software
00041 ** Foundation and appearing in the file LICENSE.GPL included in the
00042 ** packaging of this file.
00043 **
00044 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
00045 ** licenses for Unix/X11 may use this file in accordance with the Qt Commercial
00046 ** License Agreement provided with the Software.
00047 **
00048 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00049 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00050 **
00051 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
00052 **   information about Qt Commercial License Agreements.
00053 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
00054 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00055 **
00056 ** Contact info@trolltech.com if any conditions of this licensing are
00057 ** not clear to you.
00058 **
00059 **********************************************************************/
00060 
00061 #include <qcursor.h>
00062 
00063 #include "kis_canvas.h"
00064 #include "kis_cursor.h"
00065 #include "kis_move_event.h"
00066 #include "kis_button_press_event.h"
00067 #include "kis_button_release_event.h"
00068 #include "kis_double_click_event.h"
00069 #include "kis_config.h"
00070 #include "kis_qpaintdevice_canvas.h"
00071 #include "kis_opengl_canvas.h"
00072 #include "kis_config.h"
00073 #include "kis_input_device.h"
00074 #include "fixx11h.h"
00075 
00076 #ifdef Q_WS_X11
00077 
00078 #include <qdesktopwidget.h>
00079 #include <qapplication.h>
00080 
00081 #include <X11/keysym.h>
00082 
00083 bool KisCanvasWidget::X11SupportInitialised = false;
00084 long KisCanvasWidget::X11AltMask = 0;
00085 long KisCanvasWidget::X11MetaMask = 0;
00086 
00087 #if defined(EXTENDED_X11_TABLET_SUPPORT)
00088 
00089 int KisCanvasWidget::X11DeviceMotionNotifyEvent = -1;
00090 int KisCanvasWidget::X11DeviceButtonPressEvent = -1;
00091 int KisCanvasWidget::X11DeviceButtonReleaseEvent = -1;
00092 int KisCanvasWidget::X11ProximityInEvent = -1;
00093 int KisCanvasWidget::X11ProximityOutEvent = -1;
00094 
00095 //X11XIDTabletDeviceMap KisCanvasWidget::X11TabletDeviceMap;
00096 std::map<XID, KisCanvasWidget::X11TabletDevice> KisCanvasWidget::X11TabletDeviceMap;
00097 
00098 #endif // EXTENDED_X11_TABLET_SUPPORT
00099 
00100 #endif // Q_WS_X11
00101 
00102 namespace {
00103 
00104     static Q_INT32 correctPressureScale( Q_INT32 inPressure )
00105     {
00106         KisConfig cfg;
00107         Q_INT32 correction = cfg.getPressureCorrection();
00108 
00109         Q_INT32 x1, y1, x2, y2;
00110 
00111         if ( correction == 0 ) {
00112             x1 = 20;
00113             y1 = 0;
00114             x2 = 80;
00115             y2 = 100;
00116         } else if ( correction < 50 ) {
00117             x1 = 20 - ( correction / 50 * 20 );
00118             y1 = 0;
00119             x2 = 80 + ( correction / 50 * 20 );
00120             y2 = 100;
00121         } else if ( correction == 50 ) {
00122             x1 = 0;
00123             y1 = 0;
00124             x2 = 100;
00125             y2 = 100;
00126         } else if ( correction > 50 && correction < 100 ){
00127             x1 = 0;
00128             y1 = correction / 50 * 20;
00129             x2 = 100;
00130             y2 = 100 - ( correction / 50 * 20 );
00131         } else {
00132             x1 = 0;
00133             y1 = 20;
00134             x2 = 100;
00135             y2 = 80;
00136         }
00137 
00138         return inPressure;
00139     }
00140 }
00141 
00142 KisCanvasWidget::KisCanvasWidget()
00143 {
00144     m_enableMoveEventCompressionHint = false;
00145     m_lastPressure = 0;
00146 
00147 #ifdef Q_WS_X11
00148     if (!X11SupportInitialised) {
00149         initX11Support();
00150     }
00151 
00152     m_lastRootX = -1;
00153     m_lastRootY = -1;
00154 #endif
00155 }
00156 
00157 KisCanvasWidget::~KisCanvasWidget()
00158 {
00159 }
00160 
00161 void KisCanvasWidget::widgetGotPaintEvent(QPaintEvent *e)
00162 {
00163     emit sigGotPaintEvent(e);
00164 }
00165 
00166 void KisCanvasWidget::widgetGotMousePressEvent(QMouseEvent *e)
00167 {
00168     KisButtonPressEvent ke(KisInputDevice::mouse(), e->pos(), e->globalPos(), PRESSURE_DEFAULT, 0, 0, e->button(), e->state());
00169     buttonPressEvent(&ke);
00170 }
00171 
00172 void KisCanvasWidget::widgetGotMouseReleaseEvent(QMouseEvent *e)
00173 {
00174     KisButtonReleaseEvent ke(KisInputDevice::mouse(), e->pos(), e->globalPos(), PRESSURE_DEFAULT, 0, 0, e->button(), e->state());
00175     buttonReleaseEvent(&ke);
00176 }
00177 
00178 void KisCanvasWidget::widgetGotMouseDoubleClickEvent(QMouseEvent *e)
00179 {
00180     KisDoubleClickEvent ke(KisInputDevice::mouse(), e->pos(), e->globalPos(), PRESSURE_DEFAULT, 0, 0, e->button(), e->state());
00181     doubleClickEvent(&ke);
00182 }
00183 
00184 void KisCanvasWidget::widgetGotMouseMoveEvent(QMouseEvent *e)
00185 {
00186     KisMoveEvent ke(KisInputDevice::mouse(), e->pos(), e->globalPos(), PRESSURE_DEFAULT, 0, 0, e->state());
00187     moveEvent(&ke);
00188 }
00189 
00190 void KisCanvasWidget::widgetGotTabletEvent(QTabletEvent *e)
00191 {
00192     KisInputDevice device;
00193 
00194     switch (e->device()) {
00195     default:
00196     case QTabletEvent::NoDevice:
00197     case QTabletEvent::Stylus:
00198         device = KisInputDevice::stylus();
00199         break;
00200     case QTabletEvent::Puck:
00201         device = KisInputDevice::puck();
00202         break;
00203     case QTabletEvent::Eraser:
00204         device = KisInputDevice::eraser();
00205         break;
00206     }
00207 
00208     double pressure = correctPressureScale( e->pressure() ) / 255.0;
00209 
00210     if (e->type() == QEvent::TabletPress) {
00211         KisButtonPressEvent ke(device, e->pos(), e->globalPos(), pressure, e->xTilt(), e->yTilt(), Qt::LeftButton, Qt::NoButton);
00212         translateTabletEvent(&ke);
00213     }
00214     else
00215     if (e->type() == QEvent::TabletRelease) {
00216         KisButtonReleaseEvent ke(device, e->pos(), e->globalPos(), pressure, e->xTilt(), e->yTilt(), Qt::LeftButton, Qt::NoButton);
00217         translateTabletEvent(&ke);
00218     }
00219     else {
00220         KisMoveEvent ke(device, e->pos(), e->globalPos(), pressure, e->xTilt(), e->yTilt(), Qt::NoButton);
00221         translateTabletEvent(&ke);
00222 #ifdef Q_WS_X11
00223         // Fix the problem that when you change from using a tablet device to the mouse,
00224         // the first mouse button event is not recognised. This is because we handle
00225         // X11 core mouse move events directly so Qt does not get to see them. This breaks
00226         // the tablet event accept/ignore mechanism, causing Qt to consume the first
00227         // mouse button event it sees, instead of a mouse move. 'Ignoring' tablet move events
00228         // stops Qt from stealing the next mouse button event. This does not affect the
00229         // tablet aware tools as they do not care about mouse moves while the tablet device is
00230         // drawing.
00231         e->ignore();
00232 #endif
00233     }
00234 }
00235 
00236 void KisCanvasWidget::widgetGotEnterEvent(QEvent *e)
00237 {
00238     emit sigGotEnterEvent(e);
00239 }
00240 
00241 void KisCanvasWidget::widgetGotLeaveEvent(QEvent *e)
00242 {
00243     emit sigGotLeaveEvent(e);
00244 }
00245 
00246 void KisCanvasWidget::widgetGotWheelEvent(QWheelEvent *e)
00247 {
00248     emit sigGotMouseWheelEvent(e);
00249 }
00250 
00251 void KisCanvasWidget::widgetGotKeyPressEvent(QKeyEvent *e)
00252 {
00253     emit sigGotKeyPressEvent(e);
00254 }
00255 
00256 void KisCanvasWidget::widgetGotKeyReleaseEvent(QKeyEvent *e)
00257 {
00258     emit sigGotKeyReleaseEvent(e);
00259 }
00260 
00261 void KisCanvasWidget::widgetGotDragEnterEvent(QDragEnterEvent *e)
00262 {
00263     emit sigGotDragEnterEvent(e);
00264 }
00265 
00266 void KisCanvasWidget::widgetGotDropEvent(QDropEvent *e)
00267 {
00268     emit sigGotDropEvent(e);
00269 }
00270 
00271 void KisCanvasWidget::moveEvent(KisMoveEvent *e)
00272 {
00273     emit sigGotMoveEvent(e);
00274 }
00275 
00276 void KisCanvasWidget::buttonPressEvent(KisButtonPressEvent *e)
00277 {
00278     QWidget *widget = dynamic_cast<QWidget *>(this);
00279     Q_ASSERT(widget != 0);
00280 
00281     if (widget) {
00282         widget->setFocus();
00283     }
00284 
00285     emit sigGotButtonPressEvent(e);
00286 }
00287 
00288 void KisCanvasWidget::buttonReleaseEvent(KisButtonReleaseEvent *e)
00289 {
00290     emit sigGotButtonReleaseEvent(e);
00291 }
00292 
00293 void KisCanvasWidget::doubleClickEvent(KisDoubleClickEvent *e)
00294 {
00295     emit sigGotDoubleClickEvent(e);
00296 }
00297 
00298 void KisCanvasWidget::translateTabletEvent(KisEvent *e)
00299 {
00300     if (QApplication::activeModalWidget() == 0) {
00301 
00302         bool checkThresholdOnly = false;
00303 
00304         if (e->type() == KisEvent::ButtonPressEvent || e->type() == KisEvent::ButtonReleaseEvent) {
00305             KisButtonEvent *b = static_cast<KisButtonEvent *>(e);
00306 
00307             if (b->button() == Qt::MidButton || b->button() == Qt::RightButton) {
00308 
00309                 if (e->type() == KisEvent::ButtonPressEvent) {
00310                     buttonPressEvent(static_cast<KisButtonPressEvent *>(e));
00311                 } else {
00312                     buttonReleaseEvent(static_cast<KisButtonReleaseEvent *>(e));
00313                 }
00314 
00315                 checkThresholdOnly = true;
00316             }
00317         }
00318 
00319         double previousPressure = m_lastPressure;
00320 
00321         // Store the last pressure before we generate a button press/release event as the event might cause
00322         // us to enter another event loop, and then the same pressure difference would generate another button event,
00323         // leading to endless recursion.
00324         m_lastPressure = e->pressure();
00325 
00326         // Use pressure threshold to detect 'left button' press/release
00327         if (e->pressure() >= PRESSURE_THRESHOLD && previousPressure < PRESSURE_THRESHOLD) {
00328             KisButtonPressEvent ke(e->device(), e->pos(), e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), Qt::LeftButton, e->state());
00329             buttonPressEvent(&ke);
00330         } else if (e->pressure() < PRESSURE_THRESHOLD && previousPressure >= PRESSURE_THRESHOLD) {
00331             KisButtonReleaseEvent ke(e->device(), e->pos(), e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), Qt::LeftButton, e->state());
00332             buttonReleaseEvent(&ke);
00333         } else {
00334             if (!checkThresholdOnly) {
00335                 KisMoveEvent ke(e->device(), e->pos(), e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), e->state());
00336                 moveEvent(&ke);
00337             }
00338         }
00339     }
00340 }
00341 
00342 #ifdef Q_WS_X11
00343 
00344 void KisCanvasWidget::initX11Support()
00345 {
00346     if (X11SupportInitialised)
00347     {
00348         return;
00349     }
00350 
00351     X11SupportInitialised = true;
00352 
00353     Display *x11Display = QApplication::desktop()->x11Display();
00354 
00355     // Look at the modifier mapping and get the correct masks for alt/meta
00356     XModifierKeymap *map = XGetModifierMapping(x11Display);
00357 
00358     if (map) {
00359         int mapIndex = 0;
00360 
00361         for (int maskIndex = 0; maskIndex < 8; maskIndex++) {
00362             for (int i = 0; i < map->max_keypermod; i++) {
00363                 if (map->modifiermap[mapIndex]) {
00364 
00365                     KeySym sym = XKeycodeToKeysym(x11Display, map->modifiermap[mapIndex], 0);
00366 
00367                     if (X11AltMask == 0 && (sym == XK_Alt_L || sym == XK_Alt_R)) {
00368                         X11AltMask = 1 << maskIndex;
00369                     }
00370                     if (X11MetaMask == 0 && (sym == XK_Meta_L || sym == XK_Meta_R)) {
00371                         X11MetaMask = 1 << maskIndex;
00372                     }
00373                 }
00374 
00375                 mapIndex++;
00376             }
00377         }
00378 
00379         XFreeModifiermap(map);
00380     }
00381     else {
00382         // Assume defaults
00383         X11AltMask = Mod1Mask;
00384         X11MetaMask = Mod4Mask;
00385     }
00386 
00387 #if defined(EXTENDED_X11_TABLET_SUPPORT)
00388 
00389     int numDevices = 0;
00390     const XDeviceInfo *devices = XListInputDevices(x11Display, &numDevices);
00391 
00392     if (devices != NULL) {
00393         XID lastStylusSeen = 0;
00394         XID lastEraserSeen = 0;
00395         bool foundStylus = false;
00396         bool foundEraser = false;
00397 
00398         for (int i = 0; i < numDevices; i++) {
00399 
00400             const XDeviceInfo *device = devices + i;
00401             X11TabletDevice tabletDevice(device);
00402 
00403             if (tabletDevice.mightBeTabletDevice()) {
00404 
00405                 tabletDevice.readSettingsFromConfig();
00406 
00407                 QString lowerCaseName = tabletDevice.name().lower();
00408 
00409                 // Find the devices that Qt will use as its stylus and eraser devices.
00410                 if (!foundStylus || !foundEraser) {
00411                     if (lowerCaseName.startsWith("stylus") || lowerCaseName.startsWith("pen")) {
00412                         lastStylusSeen = device->id;
00413                         foundStylus = true;
00414                     }
00415                     else if (lowerCaseName.startsWith("eraser")) {
00416                         lastEraserSeen = device->id;
00417                         foundEraser = true;
00418                     }
00419                 }
00420 
00421                 X11TabletDeviceMap[device->id] = tabletDevice;
00422 
00423                 // Event types are device-independent. Store any
00424                 // the device supports.
00425                 if (tabletDevice.buttonPressEvent() >= 0) {
00426                     X11DeviceButtonPressEvent = tabletDevice.buttonPressEvent();
00427                 }
00428                 if (tabletDevice.buttonReleaseEvent() >= 0) {
00429                     X11DeviceButtonReleaseEvent = tabletDevice.buttonReleaseEvent();
00430                 }
00431                 if (tabletDevice.motionNotifyEvent() >= 0) {
00432                     X11DeviceMotionNotifyEvent = tabletDevice.motionNotifyEvent();
00433                 }
00434                 if (tabletDevice.proximityInEvent() >= 0) {
00435                     X11ProximityInEvent = tabletDevice.proximityInEvent();
00436                 }
00437                 if (tabletDevice.proximityOutEvent() >= 0) {
00438                     X11ProximityOutEvent = tabletDevice.proximityOutEvent();
00439                 }
00440             }
00441         }
00442 
00443         // Allocate input devices.
00444         for (X11XIDTabletDeviceMap::iterator it = X11TabletDeviceMap.begin(); it != X11TabletDeviceMap.end(); ++it) {
00445 
00446             X11TabletDevice& tabletDevice = (*it).second;
00447 
00448             if (foundStylus && tabletDevice.id() == lastStylusSeen) {
00449                 tabletDevice.setInputDevice(KisInputDevice::stylus());
00450             } else if (foundEraser && tabletDevice.id() == lastEraserSeen) {
00451                 tabletDevice.setInputDevice(KisInputDevice::eraser());
00452             } else {
00453                 tabletDevice.setInputDevice(KisInputDevice::allocateInputDevice());
00454             }
00455         }
00456 
00457         XFreeDeviceList(const_cast<XDeviceInfo *>(devices));
00458     }
00459 #endif // EXTENDED_X11_TABLET_SUPPORT
00460 }
00461 
00462 Qt::ButtonState KisCanvasWidget::translateX11ButtonState(int state)
00463 {
00464     int buttonState = 0;
00465 
00466     if (state & Button1Mask)
00467         buttonState |= Qt::LeftButton;
00468     if (state & Button2Mask)
00469         buttonState |= Qt::MidButton;
00470     if (state & Button3Mask)
00471         buttonState |= Qt::RightButton;
00472     if (state & ShiftMask)
00473         buttonState |= Qt::ShiftButton;
00474     if (state & ControlMask)
00475         buttonState |= Qt::ControlButton;
00476     if (state & X11AltMask)
00477         buttonState |= Qt::AltButton;
00478     if (state & X11MetaMask)
00479         buttonState |= Qt::MetaButton;
00480 
00481     return static_cast<Qt::ButtonState>(buttonState);
00482 }
00483 
00484 Qt::ButtonState KisCanvasWidget::translateX11Button(unsigned int X11Button)
00485 {
00486     Qt::ButtonState qtButton;
00487 
00488     switch (X11Button) {
00489     case Button1:
00490         qtButton = Qt::LeftButton;
00491         break;
00492     case Button2:
00493         qtButton = Qt::MidButton;
00494         break;
00495     case Button3:
00496         qtButton = Qt::RightButton;
00497         break;
00498     default:
00499         qtButton = Qt::NoButton;
00500     }
00501 
00502     return qtButton;
00503 }
00504 
00505 #if defined(EXTENDED_X11_TABLET_SUPPORT)
00506 
00507 KisCanvasWidget::X11TabletDevice::X11TabletDevice()
00508 {
00509     m_mightBeTabletDevice = false;
00510     m_inputDevice = KisInputDevice::unknown();
00511     m_enabled = false;
00512     m_xAxis = NoAxis;
00513     m_yAxis = NoAxis;
00514     m_pressureAxis = NoAxis;
00515     m_xTiltAxis = NoAxis;
00516     m_yTiltAxis = NoAxis;
00517     m_wheelAxis = NoAxis;
00518     m_toolIDAxis = NoAxis;
00519     m_serialNumberAxis = NoAxis;
00520     m_buttonPressEvent = -1;
00521     m_buttonReleaseEvent = -1;
00522     m_motionNotifyEvent = -1;
00523     m_proximityInEvent = -1;
00524     m_proximityOutEvent = -1;
00525 }
00526 
00527 KisCanvasWidget::X11TabletDevice::X11TabletDevice(const XDeviceInfo *deviceInfo)
00528 {
00529     m_mightBeTabletDevice = false;
00530     m_inputDevice = KisInputDevice::unknown();
00531     m_enabled = false;
00532     m_xAxis = NoAxis;
00533     m_yAxis = NoAxis;
00534     m_pressureAxis = NoAxis;
00535     m_xTiltAxis = NoAxis;
00536     m_yTiltAxis = NoAxis;
00537     m_wheelAxis = NoAxis;
00538     m_toolIDAxis = NoAxis;
00539     m_serialNumberAxis = NoAxis;
00540 
00541     m_deviceId = deviceInfo->id;
00542     m_name = deviceInfo->name;
00543 
00544     // Get the ranges of the valuators
00545     XAnyClassPtr classInfo = const_cast<XAnyClassPtr>(deviceInfo->inputclassinfo);
00546 
00547     for (int i = 0; i < deviceInfo->num_classes; i++) {
00548 
00549         if (classInfo->c_class == ValuatorClass) {
00550 
00551             const XValuatorInfo *valuatorInfo = reinterpret_cast<const XValuatorInfo *>(classInfo);
00552 
00553             // Need at least x, y, and pressure.
00554 
00555             if (valuatorInfo->num_axes >= 3) {
00556 
00557                 for (unsigned int axis = 0; axis < valuatorInfo->num_axes; axis++) {
00558                     m_axisInfo.append(valuatorInfo->axes[axis]);
00559                 }
00560 
00561                 m_mightBeTabletDevice = true;
00562             }
00563         }
00564 
00565         classInfo = reinterpret_cast<XAnyClassPtr>(reinterpret_cast<char *>(classInfo) + classInfo->length);
00566     }
00567 
00568     // Determine the event types it supports. We're only interested in
00569     // buttons and motion at the moment.
00570     m_buttonPressEvent = -1;
00571     m_buttonReleaseEvent = -1;
00572     m_motionNotifyEvent = -1;
00573     m_proximityInEvent = -1;
00574     m_proximityOutEvent = -1;
00575 
00576     m_XDevice = XOpenDevice(QApplication::desktop()->x11Display(), m_deviceId);
00577 
00578     if (m_XDevice != NULL) {
00579         for (int i = 0; i < m_XDevice->num_classes; i++) {
00580 
00581             XEventClass eventClass;
00582 
00583             if (m_XDevice->classes[i].input_class == ButtonClass) {
00584                 DeviceButtonPress(m_XDevice, m_buttonPressEvent, eventClass);
00585                 m_eventClassList.append(eventClass);
00586 
00587                 DeviceButtonRelease(m_XDevice, m_buttonReleaseEvent, eventClass);
00588                 m_eventClassList.append(eventClass);
00589             }
00590             else
00591             if (m_XDevice->classes[i].input_class == ValuatorClass) {
00592                 DeviceMotionNotify(m_XDevice, m_motionNotifyEvent, eventClass);
00593                 m_eventClassList.append(eventClass);
00594             }
00595             else
00596             if (m_XDevice->classes[i].input_class == ProximityClass) {
00597                 ProximityIn(m_XDevice, m_proximityInEvent, eventClass);
00598                 m_eventClassList.append(eventClass);
00599 
00600                 ProximityOut(m_XDevice, m_proximityOutEvent, eventClass);
00601                 m_eventClassList.append(eventClass);
00602             }
00603         }
00604 
00605         // Note: We don't XCloseXDevice() since Qt will have already opened
00606         // it, and only one XCloseDevice() call closes it for all opens.
00607     }
00608 
00609     if (m_buttonPressEvent == -1 || m_buttonReleaseEvent == -1 || m_motionNotifyEvent == -1) {
00610         m_mightBeTabletDevice = false;
00611     }
00612 }
00613 
00614 bool KisCanvasWidget::X11TabletDevice::needsFindingActiveByProximity() const
00615 {
00616     // Devices that Qt is aware of will generate QTabletEvents which the view
00617     // can use to determine if the device is active. We only need to check
00618     // using proximity for other devices which do not generate QTabletEvents.
00619     if (m_inputDevice == KisInputDevice::stylus() || m_inputDevice == KisInputDevice::eraser()
00620         || m_inputDevice == KisInputDevice::puck()) {
00621         return false;
00622     } else {
00623         return true;
00624     }
00625 }
00626 
00627 void KisCanvasWidget::X11TabletDevice::setEnabled(bool enabled)
00628 {
00629     m_enabled = enabled;
00630 }
00631 
00632 bool KisCanvasWidget::X11TabletDevice::enabled() const
00633 {
00634     return m_enabled;
00635 }
00636 
00637 Q_INT32 KisCanvasWidget::X11TabletDevice::numAxes() const
00638 {
00639     return m_axisInfo.count();
00640 }
00641 
00642 void KisCanvasWidget::X11TabletDevice::setXAxis(Q_INT32 axis)
00643 {
00644     m_xAxis = axis;
00645 }
00646 
00647 void KisCanvasWidget::X11TabletDevice::setYAxis(Q_INT32 axis)
00648 {
00649     m_yAxis = axis;
00650 }
00651 
00652 void KisCanvasWidget::X11TabletDevice::setPressureAxis(Q_INT32 axis)
00653 {
00654     m_pressureAxis = axis;
00655 }
00656 
00657 void KisCanvasWidget::X11TabletDevice::setXTiltAxis(Q_INT32 axis)
00658 {
00659     m_xTiltAxis = axis;
00660 }
00661 
00662 void KisCanvasWidget::X11TabletDevice::setYTiltAxis(Q_INT32 axis)
00663 {
00664     m_yTiltAxis = axis;
00665 }
00666 
00667 void KisCanvasWidget::X11TabletDevice::setWheelAxis(Q_INT32 axis)
00668 {
00669     m_wheelAxis = axis;
00670 }
00671 
00672 void KisCanvasWidget::X11TabletDevice::setToolIDAxis(Q_INT32 axis)
00673 {
00674     m_toolIDAxis = axis;
00675 }
00676 
00677 void KisCanvasWidget::X11TabletDevice::setSerialNumberAxis(Q_INT32 axis)
00678 {
00679     m_serialNumberAxis = axis;
00680 }
00681 
00682 Q_INT32 KisCanvasWidget::X11TabletDevice::xAxis() const
00683 {
00684     return m_xAxis;
00685 }
00686 
00687 Q_INT32 KisCanvasWidget::X11TabletDevice::yAxis() const
00688 {
00689     return m_yAxis;
00690 }
00691 
00692 Q_INT32 KisCanvasWidget::X11TabletDevice::pressureAxis() const
00693 {
00694     return m_pressureAxis;
00695 }
00696 
00697 Q_INT32 KisCanvasWidget::X11TabletDevice::xTiltAxis() const
00698 {
00699     return m_xTiltAxis;
00700 }
00701 
00702 Q_INT32 KisCanvasWidget::X11TabletDevice::yTiltAxis() const
00703 {
00704     return m_yTiltAxis;
00705 }
00706 
00707 Q_INT32 KisCanvasWidget::X11TabletDevice::wheelAxis() const
00708 {
00709     return m_wheelAxis;
00710 }
00711 
00712 Q_INT32 KisCanvasWidget::X11TabletDevice::toolIDAxis() const
00713 {
00714     return m_toolIDAxis;
00715 }
00716 
00717 Q_INT32 KisCanvasWidget::X11TabletDevice::serialNumberAxis() const
00718 {
00719     return m_serialNumberAxis;
00720 }
00721 
00722 void KisCanvasWidget::X11TabletDevice::readSettingsFromConfig()
00723 {
00724     KisConfig cfg;
00725 
00726     m_enabled = cfg.tabletDeviceEnabled(m_name);
00727 
00728     m_xAxis = cfg.tabletDeviceAxis(m_name, "XAxis", DefaultAxis);
00729     m_yAxis = cfg.tabletDeviceAxis(m_name, "YAxis", DefaultAxis);
00730     m_pressureAxis = cfg.tabletDeviceAxis(m_name, "PressureAxis", DefaultAxis);
00731     m_xTiltAxis = cfg.tabletDeviceAxis(m_name, "XTiltAxis", DefaultAxis);
00732     m_yTiltAxis = cfg.tabletDeviceAxis(m_name, "YTiltAxis", DefaultAxis);
00733     m_wheelAxis = cfg.tabletDeviceAxis(m_name, "WheelAxis", DefaultAxis);
00734     m_toolIDAxis = cfg.tabletDeviceAxis(m_name, "ToolIDAxis", DefaultAxis);
00735     m_serialNumberAxis = cfg.tabletDeviceAxis(m_name, "SerialNumberAxis", DefaultAxis);
00736 
00737     if (!m_enabled && m_xAxis == DefaultAxis && m_yAxis == DefaultAxis && m_pressureAxis == DefaultAxis &&
00738          m_xTiltAxis == DefaultAxis && m_yTiltAxis == DefaultAxis && m_wheelAxis == DefaultAxis &&
00739          m_toolIDAxis == DefaultAxis && m_serialNumberAxis == DefaultAxis) {
00740         // This is the first time this device has been seen. Set up default values, assuming
00741         // it's a Wacom pad.
00742         m_xAxis = 0;
00743         m_yAxis = 1;
00744         m_pressureAxis = 2;
00745 
00746         if (m_axisInfo.count() >= 4) {
00747             m_xTiltAxis = 3;
00748         } else {
00749             m_xTiltAxis = NoAxis;
00750         }
00751 
00752         if (m_axisInfo.count() >= 5) {
00753             m_yTiltAxis = 4;
00754         } else {
00755             m_yTiltAxis = NoAxis;
00756         }
00757 
00758         if (m_axisInfo.count() >= 6) {
00759             m_wheelAxis = 5;
00760         } else {
00761             m_wheelAxis = NoAxis;
00762         }
00763 
00764         // Available since driver version 0.7.2.
00765         if (m_axisInfo.count() >= 7) {
00766             m_toolIDAxis = 6;
00767         } else {
00768             m_toolIDAxis = NoAxis;
00769         }
00770 
00771         if (m_axisInfo.count() >= 8) {
00772             m_serialNumberAxis = 7;
00773         } else {
00774             m_serialNumberAxis = NoAxis;
00775         }
00776     }
00777 }
00778 
00779 void KisCanvasWidget::X11TabletDevice::writeSettingsToConfig()
00780 {
00781     KisConfig cfg;
00782 
00783     cfg.setTabletDeviceEnabled(m_name, m_enabled);
00784 
00785     cfg.setTabletDeviceAxis(m_name, "XAxis", m_xAxis);
00786     cfg.setTabletDeviceAxis(m_name, "YAxis", m_yAxis);
00787     cfg.setTabletDeviceAxis(m_name, "PressureAxis", m_pressureAxis);
00788     cfg.setTabletDeviceAxis(m_name, "XTiltAxis", m_xTiltAxis);
00789     cfg.setTabletDeviceAxis(m_name, "YTiltAxis", m_yTiltAxis);
00790     cfg.setTabletDeviceAxis(m_name, "WheelAxis", m_wheelAxis);
00791     cfg.setTabletDeviceAxis(m_name, "ToolIDAxis", m_toolIDAxis);
00792     cfg.setTabletDeviceAxis(m_name, "SerialNumberAxis", m_serialNumberAxis);
00793 }
00794 
00795 void KisCanvasWidget::X11TabletDevice::enableEvents(QWidget *widget) const
00796 {
00797     if (!m_eventClassList.isEmpty()) {
00798         int result = XSelectExtensionEvent(widget->x11AppDisplay(), widget->handle(), 
00799                                            const_cast<XEventClass*>(&m_eventClassList[0]), 
00800                                            m_eventClassList.count());
00801     
00802         if (result != Success) {
00803             kdDebug(41001) << "Failed to select extension events for " << m_name << endl;
00804         }
00805     }
00806 }
00807 
00808 double KisCanvasWidget::X11TabletDevice::translateAxisValue(int value, const XAxisInfo& axisInfo) const
00809 {
00810     int axisRange = axisInfo.max_value - axisInfo.min_value;
00811     double translatedValue = 0;
00812 
00813     if (axisRange != 0) {
00814         translatedValue = (static_cast<double>(value) - axisInfo.min_value) / axisRange;
00815         if (axisInfo.min_value < 0) {
00816             translatedValue -= 0.5;
00817         }
00818     }
00819 
00820     return translatedValue;
00821 }
00822 
00823 KisCanvasWidget::X11TabletDevice::State::State(const KisPoint& pos, double pressure, const KisVector2D& tilt, double wheel,
00824                                                Q_UINT32 toolID, Q_UINT32 serialNumber)
00825     : m_pos(pos), 
00826       m_pressure(pressure), 
00827       m_tilt(tilt),
00828       m_wheel(wheel),
00829       m_toolID(toolID),
00830       m_serialNumber(serialNumber)
00831 {
00832 }
00833 
00834 KisCanvasWidget::X11TabletDevice::State KisCanvasWidget::X11TabletDevice::translateAxisData(const int *axisData) const
00835 {
00836     KisPoint pos(0, 0);
00837 
00838     if (m_xAxis != NoAxis && m_yAxis != NoAxis) {
00839         pos = KisPoint(translateAxisValue(axisData[m_xAxis], m_axisInfo[m_xAxis]), 
00840                        translateAxisValue(axisData[m_yAxis], m_axisInfo[m_yAxis]));
00841     }
00842 
00843     double pressure = PRESSURE_DEFAULT;
00844 
00845     if (m_pressureAxis != NoAxis) {
00846         pressure = translateAxisValue(axisData[m_pressureAxis], m_axisInfo[m_pressureAxis]);
00847     }
00848 
00849     KisVector2D tilt = KisVector2D(0, 0);
00850     Q_UINT32 toolID = 0;
00851     Q_UINT32 serialNumber = 0;
00852 
00853     if (m_xTiltAxis != NoAxis) {
00854         // Latest wacom driver returns the tool id and serial number in 
00855         // the upper 16 bits of the x and y tilts and wheel.
00856         int xTiltAxisValue = (Q_INT16)(axisData[m_xTiltAxis] & 0xffff);
00857         toolID = ((Q_UINT32)axisData[m_xTiltAxis] >> 16) & 0xffff;
00858 
00859         tilt.setX(translateAxisValue(xTiltAxisValue, m_axisInfo[m_xTiltAxis]));
00860     }
00861 
00862     if (m_yTiltAxis != NoAxis) {
00863         int yTiltAxisValue = (Q_INT16)(axisData[m_yTiltAxis] & 0xffff);
00864         serialNumber = (Q_UINT32)axisData[m_yTiltAxis] & 0xffff0000;
00865 
00866         tilt.setY(translateAxisValue(yTiltAxisValue, m_axisInfo[m_yTiltAxis]));
00867     }
00868 
00869     double wheel = 0;
00870 
00871     if (m_wheelAxis != NoAxis) {
00872         int wheelAxisValue = (Q_INT16)(axisData[m_wheelAxis] & 0xffff);
00873         serialNumber |= ((Q_UINT32)axisData[m_wheelAxis] >> 16) & 0xffff;
00874 
00875         wheel = translateAxisValue(wheelAxisValue, m_axisInfo[m_wheelAxis]);
00876     }
00877 
00878     //QString ids;
00879     //ids.sprintf("Tool ID: %8x Serial Number: %8x", toolID, serialNumber);
00880 
00881     return State(pos, pressure, tilt, wheel, toolID, serialNumber);
00882 }
00883 
00884 KisCanvasWidget::X11XIDTabletDeviceMap& KisCanvasWidget::tabletDeviceMap()
00885 {
00886     return X11TabletDeviceMap;
00887 }
00888 
00889 void KisCanvasWidget::selectTabletDeviceEvents(QWidget *widget)
00890 {
00891     for (X11XIDTabletDeviceMap::const_iterator it = X11TabletDeviceMap.begin(); it != X11TabletDeviceMap.end(); ++it) {
00892 
00893         const X11TabletDevice& device = (*it).second;
00894 
00895         if (device.enabled()) {
00896             device.enableEvents(widget);
00897         }
00898     }
00899 }
00900 
00901 #endif // EXTENDED_X11_TABLET_SUPPORT
00902 
00903 bool KisCanvasWidget::x11Event(XEvent *event, Display *x11Display, WId winId, QPoint widgetOriginPos)
00904 {
00905     if (event->type == MotionNotify) {
00906         // Mouse move
00907         if (!m_enableMoveEventCompressionHint) {
00908 
00909             XMotionEvent motion = event->xmotion;
00910             QPoint globalPos(motion.x_root, motion.y_root);
00911 
00912             if (globalPos.x() != m_lastRootX || globalPos.y() != m_lastRootY) {
00913 
00914                 int state = translateX11ButtonState(motion.state);
00915                 QPoint pos(motion.x, motion.y);
00916                 QMouseEvent e(QEvent::MouseMove, pos, globalPos, Qt::NoButton, state);
00917 
00918                 widgetGotMouseMoveEvent(&e);
00919             }
00920 
00921             m_lastRootX = globalPos.x();
00922             m_lastRootY = globalPos.y();
00923 
00924             return true;
00925         }
00926         else {
00927             return false;
00928         }
00929     }
00930     else
00931 #if defined(EXTENDED_X11_TABLET_SUPPORT)
00932     if ((event->type == X11DeviceMotionNotifyEvent || event->type == X11DeviceButtonPressEvent || event->type == X11DeviceButtonReleaseEvent)
00933         && QApplication::activeModalWidget() == 0) {
00934         // Tablet event.
00935         int deviceId;
00936         const int *axisData;
00937         Qt::ButtonState button;
00938         Qt::ButtonState buttonState;
00939 
00940         if (event->type == X11DeviceMotionNotifyEvent) {
00941             // Tablet move
00942             const XDeviceMotionEvent *motion = reinterpret_cast<const XDeviceMotionEvent *>(event);
00943             XEvent mouseEvent;
00944 
00945             // Look for an accompanying core event.
00946             if (XCheckTypedWindowEvent(x11Display, winId, MotionNotify, &mouseEvent)) {
00947                 if (motion->time == mouseEvent.xmotion.time) {
00948                     // Do nothing
00949                 } else {
00950                     XPutBackEvent(x11Display, &mouseEvent);
00951                 }
00952             }
00953 
00954             if (m_enableMoveEventCompressionHint) {
00955                 while (true) {
00956                     // Look for another motion notify in the queue and skip
00957                     // to that if found.
00958                     if (!XCheckTypedWindowEvent(x11Display, winId, X11DeviceMotionNotifyEvent, &mouseEvent)) {
00959                         break;
00960                     }
00961 
00962                     motion = reinterpret_cast<const XDeviceMotionEvent *>(&mouseEvent);
00963 
00964                     XEvent coreMotionEvent;
00965 
00966                     // Look for an accompanying core event.
00967                     if (!XCheckTypedWindowEvent(x11Display, winId, MotionNotify, &coreMotionEvent)) {
00968                         // Do nothing
00969                     }
00970                 }
00971             }
00972 
00973             deviceId = motion->deviceid;
00974             axisData = motion->axis_data;
00975             button = Qt::NoButton;
00976             buttonState = translateX11ButtonState(motion->state);
00977         }
00978         else
00979         if (event->type == X11DeviceButtonPressEvent) {
00980             // Tablet button press
00981             const XDeviceButtonPressedEvent *buttonPressed = reinterpret_cast<const XDeviceButtonPressedEvent *>(event);
00982             deviceId = buttonPressed->deviceid;
00983             axisData = buttonPressed->axis_data;
00984             button = translateX11Button(buttonPressed->button);
00985             buttonState = translateX11ButtonState(buttonPressed->state);
00986 
00987             if (QApplication::activePopupWidget() == 0) {
00988                 XEvent mouseEvent;
00989 
00990                 // Look for and swallow an accompanying core event, but only if there's
00991                 // no active popup, as that needs to see it.
00992                 if (XCheckTypedWindowEvent(x11Display, winId, ButtonPress, &mouseEvent)) {
00993                     if (buttonPressed->time == mouseEvent.xbutton.time) {
00994                         // Do nothing
00995                     }
00996                     else {
00997                         XPutBackEvent(x11Display, &mouseEvent);
00998                     }
00999                 }
01000             }
01001         }
01002         else {
01003             // Tablet button release
01004             const XDeviceButtonReleasedEvent *buttonReleased = reinterpret_cast<const XDeviceButtonReleasedEvent *>(event);
01005             deviceId = buttonReleased->deviceid;
01006             axisData = buttonReleased->axis_data;
01007             button = translateX11Button(buttonReleased->button);
01008             buttonState = translateX11ButtonState(buttonReleased->state);
01009 
01010             if (QApplication::activePopupWidget() == 0) {
01011                 XEvent mouseEvent;
01012 
01013                 // Look for and swallow an accompanying core event, but only if there's
01014                 // no active popup, as that needs to see it.
01015                 if (XCheckTypedWindowEvent(x11Display, winId, ButtonRelease, &mouseEvent)) {
01016                     if (buttonReleased->time == mouseEvent.xbutton.time) {
01017                         // Do nothing
01018                     }
01019                     else {
01020                         XPutBackEvent(x11Display, &mouseEvent);
01021                     }
01022                 }
01023             }
01024         }
01025 
01026         X11XIDTabletDeviceMap::const_iterator it = X11TabletDeviceMap.find(deviceId);
01027 
01028         if (it != X11TabletDeviceMap.end()) {
01029 
01030             const X11TabletDevice& tabletDevice = (*it).second;
01031 
01032             if (tabletDevice.enabled()) {
01033                 X11TabletDevice::State deviceState = tabletDevice.translateAxisData(axisData);
01034 
01035                 // Map normalised position coordinates to screen coordinates
01036                 QDesktopWidget *desktop = QApplication::desktop();
01037                 KisPoint globalPos(deviceState.pos().x() * desktop->width(), deviceState.pos().y() * desktop->height());
01038                 // Convert screen coordinates to widget coordinates
01039                 KisPoint pos = globalPos - KoPoint( widgetOriginPos );
01040 
01041                 // Map tilt to -60 - +60 degrees
01042                 KisVector2D tilt(deviceState.tilt().x() * 60, deviceState.tilt().y() * 60);
01043 
01044                 if (event->type == X11DeviceMotionNotifyEvent) {
01045                     KisMoveEvent e(tabletDevice.inputDevice(), pos, globalPos, deviceState.pressure(), tilt.x(), tilt.y(), buttonState);
01046                     translateTabletEvent(&e);
01047                 }
01048                 else
01049                 if (event->type == X11DeviceButtonPressEvent) {
01050                     KisButtonPressEvent e(tabletDevice.inputDevice(), pos, globalPos, deviceState.pressure(), tilt.x(), tilt.y(), button, buttonState);
01051                     translateTabletEvent(&e);
01052                 }
01053                 else {
01054                     KisButtonReleaseEvent e(tabletDevice.inputDevice(), pos, globalPos, deviceState.pressure(), tilt.x(), tilt.y(), button, buttonState);
01055                     translateTabletEvent(&e);
01056                 }
01057             }
01058 
01059             // Consume the event even if the device is disabled otherwise Qt will
01060             // process it and send a QTabletEvent.
01061             return true;
01062         }
01063         else {
01064             return false;
01065         }
01066     }
01067     else
01068 #endif // EXTENDED_X11_TABLET_SUPPORT
01069     {
01070         return false;
01071     }
01072 }
01073 
01074 #if defined(EXTENDED_X11_TABLET_SUPPORT)
01075 
01076 KisInputDevice KisCanvasWidget::findActiveInputDevice()
01077 {
01078     X11XIDTabletDeviceMap::const_iterator it;
01079 
01080     for (it = X11TabletDeviceMap.begin(); it != X11TabletDeviceMap.end(); ++it) {
01081         const X11TabletDevice& tabletDevice = (*it).second;
01082 
01083         if (!tabletDevice.needsFindingActiveByProximity()) {
01084             continue;
01085         }
01086 
01087         XDeviceState *deviceState = XQueryDeviceState(QApplication::desktop()->x11Display(),
01088                                                       tabletDevice.xDevice());
01089 
01090         // If your the laptop sleeps, and you remove the mouse from the usb
01091         // port, then on wake-up Krita can crash because the above call will
01092         // return 0. 
01093         if (!deviceState) continue;
01094         
01095         const XInputClass *inputClass = deviceState->data;
01096         bool deviceIsInProximity = false;
01097 
01098         for (int i = 0; i < deviceState->num_classes; i++) {
01099 
01100             if (inputClass->c_class == ValuatorClass) {
01101 
01102                 const XValuatorState *valuatorState = reinterpret_cast<const XValuatorState *>(inputClass);
01103 
01104                 if ((valuatorState->mode & ProximityState) == InProximity) {
01105                     deviceIsInProximity = true;
01106                     break;
01107                 }
01108             }
01109 
01110             inputClass = reinterpret_cast<const XInputClass *>(reinterpret_cast<const char *>(inputClass) + inputClass->length);
01111         }
01112 
01113         XFreeDeviceState(deviceState);
01114 
01115         if (deviceIsInProximity && tabletDevice.enabled()) {
01116             return tabletDevice.inputDevice();
01117         }
01118     }
01119 
01120     return KisInputDevice::mouse();
01121 }
01122 
01123 #endif // EXTENDED_X11_TABLET_SUPPORT
01124 
01125 
01126 #endif // Q_WS_X11
01127 
01128 /*************************************************************************/
01129 
01130 #define QPAINTDEVICE_CANVAS_WIDGET false
01131 #define OPENGL_CANVAS_WIDGET true
01132 
01133 KisCanvas::KisCanvas(QWidget *parent, const char *name)
01134 {
01135     m_parent = parent;
01136     m_name = name;
01137     m_enableMoveEventCompressionHint = false;
01138     m_canvasWidget = 0;
01139     m_useOpenGL = false;
01140     createCanvasWidget(QPAINTDEVICE_CANVAS_WIDGET);
01141 }
01142 
01143 KisCanvas::~KisCanvas()
01144 {
01145     delete m_canvasWidget;
01146 }
01147 
01148 #ifdef HAVE_GL
01149 void KisCanvas::createCanvasWidget(bool useOpenGL, QGLWidget *sharedContextWidget)
01150 #else
01151 void KisCanvas::createCanvasWidget(bool useOpenGL)
01152 #endif
01153 {
01154     delete m_canvasWidget;
01155 
01156 #ifndef HAVE_GL
01157     useOpenGL = false;
01158 #else
01159     if (useOpenGL && !QGLFormat::hasOpenGL()) {
01160         kdDebug(41001) << "Tried to create OpenGL widget when system doesn't have OpenGL\n";
01161         useOpenGL = false;
01162     }
01163 
01164     if (useOpenGL) {
01165         m_canvasWidget = new KisOpenGLCanvasWidget(m_parent, m_name.latin1(), sharedContextWidget);
01166     } else
01167 #endif
01168     {
01169         m_canvasWidget = new KisQPaintDeviceCanvasWidget(m_parent, m_name.latin1());
01170     }
01171 
01172     m_useOpenGL = useOpenGL;
01173 
01174     Q_CHECK_PTR(m_canvasWidget);
01175     QWidget *widget = dynamic_cast<QWidget *>(m_canvasWidget);
01176 
01177     widget->setBackgroundMode(QWidget::NoBackground);
01178     widget->setMouseTracking(true);
01179     widget->setAcceptDrops(true);
01180     m_canvasWidget->enableMoveEventCompressionHint(m_enableMoveEventCompressionHint);
01181 
01182 #if defined(EXTENDED_X11_TABLET_SUPPORT)
01183     selectTabletDeviceEvents();
01184 #endif
01185 
01186     connect(m_canvasWidget, SIGNAL(sigGotPaintEvent(QPaintEvent *)), SIGNAL(sigGotPaintEvent(QPaintEvent *)));
01187     connect(m_canvasWidget, SIGNAL(sigGotEnterEvent(QEvent*)), SIGNAL(sigGotEnterEvent(QEvent*)));
01188     connect(m_canvasWidget, SIGNAL(sigGotLeaveEvent(QEvent*)), SIGNAL(sigGotLeaveEvent(QEvent*)));
01189     connect(m_canvasWidget, SIGNAL(sigGotMouseWheelEvent(QWheelEvent*)), SIGNAL(sigGotMouseWheelEvent(QWheelEvent*)));
01190     connect(m_canvasWidget, SIGNAL(sigGotKeyPressEvent(QKeyEvent*)), SIGNAL(sigGotKeyPressEvent(QKeyEvent*)));
01191     connect(m_canvasWidget, SIGNAL(sigGotKeyReleaseEvent(QKeyEvent*)), SIGNAL(sigGotKeyReleaseEvent(QKeyEvent*)));
01192     connect(m_canvasWidget, SIGNAL(sigGotDragEnterEvent(QDragEnterEvent*)), SIGNAL(sigGotDragEnterEvent(QDragEnterEvent*)));
01193     connect(m_canvasWidget, SIGNAL(sigGotDropEvent(QDropEvent*)), SIGNAL(sigGotDropEvent(QDropEvent*)));
01194     connect(m_canvasWidget, SIGNAL(sigGotMoveEvent(KisMoveEvent *)), SIGNAL(sigGotMoveEvent(KisMoveEvent *)));
01195     connect(m_canvasWidget, SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent *)), SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent *)));
01196     connect(m_canvasWidget, SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent *)), SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent *)));
01197     connect(m_canvasWidget, SIGNAL(sigGotDoubleClickEvent(KisDoubleClickEvent *)), SIGNAL(sigGotDoubleClickEvent(KisDoubleClickEvent *)));
01198 }
01199 
01200 void KisCanvas::createQPaintDeviceCanvas()
01201 {
01202     createCanvasWidget(QPAINTDEVICE_CANVAS_WIDGET);
01203 }
01204 
01205 #ifdef HAVE_GL
01206 void KisCanvas::createOpenGLCanvas(QGLWidget *sharedContextWidget)
01207 {
01208     createCanvasWidget(OPENGL_CANVAS_WIDGET, sharedContextWidget);
01209 }
01210 #endif
01211 
01212 bool KisCanvas::isOpenGLCanvas() const
01213 {
01214     return m_useOpenGL;
01215 }
01216 
01217 void KisCanvas::enableMoveEventCompressionHint(bool enableMoveCompression)
01218 {
01219     m_enableMoveEventCompressionHint = enableMoveCompression;
01220     if (m_canvasWidget != 0) {
01221         m_canvasWidget->enableMoveEventCompressionHint(enableMoveCompression);
01222     }
01223 }
01224 
01225 QWidget *KisCanvas::QPaintDeviceWidget() const
01226 {
01227     if (m_useOpenGL) {
01228         return 0;
01229     } else {
01230         return dynamic_cast<QWidget *>(m_canvasWidget);
01231     }
01232 }
01233 
01234 #ifdef HAVE_GL
01235 QGLWidget *KisCanvas::OpenGLWidget() const
01236 {
01237     if (m_useOpenGL) {
01238         return dynamic_cast<QGLWidget *>(m_canvasWidget);
01239     } else {
01240         return 0;
01241     }
01242 }
01243 #endif
01244 
01245 KisCanvasWidgetPainter *KisCanvas::createPainter()
01246 {
01247     Q_ASSERT(m_canvasWidget != 0);
01248     return m_canvasWidget->createPainter();
01249 }
01250 
01251 KisCanvasWidget *KisCanvas::canvasWidget() const
01252 {
01253     return m_canvasWidget;
01254 }
01255 
01256 void KisCanvas::setGeometry(int x, int y, int width, int height)
01257 {
01258     Q_ASSERT(m_canvasWidget);
01259     dynamic_cast<QWidget *>(m_canvasWidget)->setGeometry(x, y, width, height);
01260 }
01261 
01262 void KisCanvas::show()
01263 {
01264     Q_ASSERT(m_canvasWidget);
01265     dynamic_cast<QWidget *>(m_canvasWidget)->show();
01266 }
01267 
01268 void KisCanvas::hide()
01269 {
01270     Q_ASSERT(m_canvasWidget);
01271     dynamic_cast<QWidget *>(m_canvasWidget)->hide();
01272 }
01273 
01274 int KisCanvas::width() const
01275 {
01276     Q_ASSERT(m_canvasWidget);
01277     return dynamic_cast<QWidget *>(m_canvasWidget)->width();
01278 }
01279 
01280 int KisCanvas::height() const
01281 {
01282     Q_ASSERT(m_canvasWidget);
01283     return dynamic_cast<QWidget *>(m_canvasWidget)->height();
01284 }
01285 
01286 void KisCanvas::update()
01287 {
01288     Q_ASSERT(m_canvasWidget);
01289     dynamic_cast<QWidget *>(m_canvasWidget)->update();
01290 }
01291 
01292 void KisCanvas::update(const QRect& r)
01293 {
01294     Q_ASSERT(m_canvasWidget);
01295     dynamic_cast<QWidget *>(m_canvasWidget)->update(r);
01296 }
01297 
01298 void KisCanvas::update(int x, int y, int width, int height)
01299 {
01300     Q_ASSERT(m_canvasWidget);
01301     dynamic_cast<QWidget *>(m_canvasWidget)->update(x, y, width, height);
01302 }
01303 
01304 void KisCanvas::repaint()
01305 {
01306     Q_ASSERT(m_canvasWidget);
01307     dynamic_cast<QWidget *>(m_canvasWidget)->repaint();
01308 }
01309 
01310 void KisCanvas::repaint(bool erase)
01311 {
01312     Q_ASSERT(m_canvasWidget);
01313     dynamic_cast<QWidget *>(m_canvasWidget)->repaint(erase);
01314 }
01315 
01316 void KisCanvas::repaint(int x, int y, int width, int height, bool erase)
01317 {
01318     Q_ASSERT(m_canvasWidget);
01319     dynamic_cast<QWidget *>(m_canvasWidget)->repaint(x, y, width, height, erase);
01320 }
01321 
01322 void KisCanvas::repaint(const QRect& r, bool erase)
01323 {
01324     Q_ASSERT(m_canvasWidget);
01325     dynamic_cast<QWidget *>(m_canvasWidget)->repaint(r, erase);
01326 }
01327 
01328 void KisCanvas::repaint(const QRegion& r, bool erase)
01329 {
01330     Q_ASSERT(m_canvasWidget);
01331     dynamic_cast<QWidget *>(m_canvasWidget)->repaint(r, erase);
01332 }
01333 
01334 bool KisCanvas::isUpdatesEnabled() const
01335 {
01336     Q_ASSERT(m_canvasWidget);
01337     return dynamic_cast<QWidget *>(m_canvasWidget)->isUpdatesEnabled();
01338 }
01339 
01340 void KisCanvas::setUpdatesEnabled(bool updatesEnabled)
01341 {
01342     Q_ASSERT(m_canvasWidget);
01343     dynamic_cast<QWidget *>(m_canvasWidget)->setUpdatesEnabled(updatesEnabled);
01344 }
01345 
01346 void KisCanvas::updateGeometry()
01347 {
01348     Q_ASSERT(m_canvasWidget);
01349     dynamic_cast<QWidget *>(m_canvasWidget)->updateGeometry();
01350 }
01351 
01352 void KisCanvas::setFocusPolicy(QWidget::FocusPolicy focusPolicy)
01353 {
01354     Q_ASSERT(m_canvasWidget);
01355     dynamic_cast<QWidget *>(m_canvasWidget)->setFocusPolicy(focusPolicy);
01356 }
01357 
01358 const QCursor& KisCanvas::cursor() const
01359 {
01360     Q_ASSERT(m_canvasWidget);
01361     return dynamic_cast<QWidget *>(m_canvasWidget)->cursor();
01362 }
01363 
01364 void KisCanvas::setCursor(const QCursor& cursor)
01365 {
01366     Q_ASSERT(m_canvasWidget);
01367     dynamic_cast<QWidget *>(m_canvasWidget)->setCursor(cursor);
01368 }
01369 
01370 #if defined(EXTENDED_X11_TABLET_SUPPORT)
01371 void KisCanvas::selectTabletDeviceEvents()
01372 {
01373     Q_ASSERT(m_canvasWidget);
01374     m_canvasWidget->selectTabletDeviceEvents();
01375 }
01376 #endif
01377 
01378 bool KisCanvas::cursorIsOverCanvas() const
01379 {
01380     if (QApplication::activePopupWidget() != 0) {
01381         return false;
01382     }
01383     if (QApplication::activeModalWidget() != 0) {
01384         return false;
01385     }
01386 
01387     QWidget *canvasWidget = dynamic_cast<QWidget *>(m_canvasWidget);
01388     Q_ASSERT(canvasWidget != 0);
01389 
01390     if (canvasWidget) {
01391         if (QApplication::widgetAt(QCursor::pos(), true) == canvasWidget) {
01392             return true;
01393         }
01394     }
01395     return false;
01396 }
01397 
01398 void KisCanvas::handleKeyEvent(QEvent *e)
01399 {
01400     QKeyEvent *ke = dynamic_cast<QKeyEvent *>(e);
01401 
01402     Q_ASSERT(ke != 0);
01403 
01404     if (ke) {
01405         QWidget *canvasWidget = dynamic_cast<QWidget *>(m_canvasWidget);
01406         Q_ASSERT(canvasWidget != 0);
01407 
01408         if (canvasWidget) {
01409             canvasWidget->setFocus();
01410 
01411             if (e->type() == QEvent::KeyPress) {
01412                 emit sigGotKeyPressEvent(ke);
01413             } else {
01414                 emit sigGotKeyReleaseEvent(ke);
01415             }
01416         }
01417     }
01418 }
01419 
01420 #include "kis_canvas.moc"
01421 
KDE Home | KDE Accessibility Home | Description of Access Keys