/*
# 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);
}