summaryrefslogblamecommitdiffstats
path: root/src/gui/clientVNCViewer.cpp
blob: d794b0bb44ceac0275aee4122f05bb2b7d315bec (plain) (tree)























                                                                                






















































































































































































































































                                                                                              
/*
 # 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<QKeyEvent*>(event));
        return true;
        break;
    case QEvent::MouseButtonDblClick:
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonRelease:
    case QEvent::MouseMove:
        mouseEventHandler(static_cast<QMouseEvent*>(event));
        return true;
        break;
    case QEvent::Wheel:
        wheelEventHandler(static_cast<QWheelEvent*>(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<unsigned int> keys = _modkeys.keys();
    QList<unsigned int>::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);
}