/* # Copyright (c) 2009, 2010 - OpenSLX Project, Computer Center University of # Freiburg # # This program is free software distributed under the GPL version 2. # See http://openslx.org/COPYING # # If you have any feedback please consult http://openslx.org/feedback and # send your suggestions, praise, or complaints to feedback@openslx.org # # General information about OpenSLX can be found at http://openslx.org/ # ----------------------------------------------------------------------------- # clientVNCViewer.cpp # - connetct to vnc server and show remote screen (window/full) # ----------------------------------------------------------------------------- */ #include "clientVNCViewer.h" ClientVNCViewer::ClientVNCViewer(QWidget *parent) : QDialog(parent), _thread(0), _viewOnly(true), _buttonMask(0) { // connect to D-Bus and get interface QDBusConnection dbus = QDBusConnection::sessionBus(); _ifaceDBus = new OrgOpenslxPvsInterface("org.openslx.pvs", "/", dbus, this); connect(_ifaceDBus, SIGNAL(project(QString, int, QString, bool, bool, int)), this, SLOT(open(QString, int, QString, bool, bool, int))); connect(_ifaceDBus, SIGNAL(unproject()), this, SLOT(close())); } ClientVNCViewer::~ClientVNCViewer() { close(); } //////////////////////////////////////////////////////////////////////////////// // Public void ClientVNCViewer::open(QString host, int port, QString passwd, bool fs, bool mode, int quality) { // start thread for vnc-updates _thread = new VNCClientThread(host, port, passwd, quality); _thread->start(); //_rfbclient = _thread->getRfbClient(); //installEventFilter(this); setMouseTracking(true); // get mouse events even when there is no mousebutton pressed setFocusPolicy(Qt::WheelFocus); //needed?!? setAttribute(Qt::WA_OpaquePaintEvent); // smooth transformation? if (mode) _mode = Qt::SmoothTransformation; else _mode = Qt::FastTransformation; // fullscreen? if (fs) { setWindowFlags(Qt::WindowStaysOnTopHint); showFullScreen(); activateWindow(); raise(); } else showNormal(); connect(this, SIGNAL(rejected()), this, SLOT(close())); connect(_thread, SIGNAL(imageUpdated(int,int,int,int)), this, SLOT(updateImage(int,int,int,int)), Qt::BlockingQueuedConnection); } void ClientVNCViewer::close() { setVisible(false); if (_thread) { disconnect(_thread, SIGNAL(imageUpdated(int,int,int,int)), this, SLOT(updateImage(int,int,int,int))); _thread->terminate = true; _thread->wait(1000); delete _thread; _thread = NULL; } disconnect(this, SIGNAL(rejected()), this, SLOT(close())); } void ClientVNCViewer::updateImage(int x, int y, int w, int h) { if (_thread->getSize() != size()) // scaling needed? { // grow the update rectangle to avoid artifacts x -= 1; y -= 1; w += 2; h += 2; _img = _thread->getImage().copy(x, y, w, h); qreal sx = qreal(width()) / qreal(_thread->getSize().width()); qreal sy = qreal(height()) / qreal(_thread->getSize().height()); x = qRound(qreal(x) * sx); y = qRound(qreal(y) * sy); w = qRound(qreal(w) * sx); h = qRound(qreal(h) * sy); } else { _img = _thread->getImage().copy(x, y, w, h); } repaint(x, y, w, h); } //////////////////////////////////////////////////////////////////////////////// // Protected void ClientVNCViewer::paintEvent(QPaintEvent *event) { if (_img.isNull()) return; QPainter painter(this); QRect r = event->rect(); if (r == rect()) _img = _thread->getImage(); // redraw complete image (e.g. on resize) if (_thread->getSize() == size()) { painter.drawImage(r.topLeft(), _img); // don't scale } else { QImage i = _img.scaled(r.size(), Qt::IgnoreAspectRatio, _mode); painter.drawImage(r.topLeft(), i); } event->accept(); } //returns true if event was processed /*bool ClientVNCViewer::event(QEvent *event) { switch (event->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: keyEventHandler(static_cast(event)); return true; break; case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: mouseEventHandler(static_cast(event)); return true; break; case QEvent::Wheel: wheelEventHandler(static_cast(event)); return true; break; default: return false; } }*/ //handles mouseevents void ClientVNCViewer::mouseEventHandler(QMouseEvent *e) { if (e->type() != QEvent::MouseMove) { if ((e->type() == QEvent::MouseButtonPress) || (e->type() == QEvent::MouseButtonDblClick)) { if (e->button() & Qt::LeftButton) _buttonMask |= 0x01; if (e->button() & Qt::MidButton) _buttonMask |= 0x02; if (e->button() & Qt::RightButton) _buttonMask |= 0x04; } else if (e->type() == QEvent::MouseButtonRelease) { if (e->button() & Qt::LeftButton) _buttonMask &= 0xfe; if (e->button() & Qt::MidButton) _buttonMask &= 0xfd; if (e->button() & Qt::RightButton) _buttonMask &= 0xfb; } } qreal sx = qreal(width()) / qreal(_thread->getSize().width()); qreal sy = qreal(height()) / qreal(_thread->getSize().height()); _thread->mouseEvent(qRound(e->x() / sx), qRound(e->y() / sy), _buttonMask); } //handles mousewheel void ClientVNCViewer::wheelEventHandler(QWheelEvent *event) { int eb = 0; if (event->delta() < 0) eb |= 0x10; else eb |= 0x8; qreal sx = qreal(width()) / qreal(_thread->getSize().width()); qreal sy = qreal(height()) / qreal(_thread->getSize().height()); const int x = qRound(event->x() / sx); const int y = qRound(event->y() / sy); _thread->mouseEvent(x, y, eb | _buttonMask); _thread->mouseEvent(x, y, _buttonMask); } //Handles keypress void ClientVNCViewer::keyEventHandler(QKeyEvent *e) { rfbKeySym k = e->nativeVirtualKey(); // do not handle Key_Backtab separately because the Shift-modifier // is already enabled if (e->key() == Qt::Key_Backtab) { k = XK_Tab; } const bool pressed = (e->type() == QEvent::KeyPress); // handle modifiers if (k == XK_Shift_L || k == XK_Control_L || k == XK_Meta_L || k == XK_Alt_L) { if (pressed) { _modkeys[k] = true; } else if (_modkeys.contains(k)) { _modkeys.remove(k); } else { unpressModifiers(); } } if (k) { _thread->keyEvent(k, pressed); } } //removes modifier keys which have been pressed void ClientVNCViewer::unpressModifiers() { const QList keys = _modkeys.keys(); QList::const_iterator it = keys.constBegin(); while (it != keys.end()) { _thread->keyEvent(*it, false); it++; } _modkeys.clear(); } //(QT Function) Filters events, if _viewOnly is set, true is returned and the event is ignored //TODO use this function when implementing viewonly switch bool ClientVNCViewer::eventFilter(QObject *obj, QEvent *event) { if (_viewOnly) { if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease || event->type() == QEvent::MouseButtonDblClick || event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::Wheel || event->type() == QEvent::MouseMove) return true; } return false; //return RemoteView::eventFilter(obj, event); }