/*
# 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 "vncwindow.h"
#include "vncthread.h"
VncWindow::VncWindow(QWidget *parent) :
QDialog(parent), _vncWorker(NULL), _viewOnly(true), _buttonMask(0), _clientId(0), _redrawTimer(0)
{
//
}
VncWindow::~VncWindow()
{
//
}
////////////////////////////////////////////////////////////////////////////////
// Public
void VncWindow::open(const QString& host, int port, const QString& passwd, bool ro, bool fullscreen, const QString& caption, const int clientId)
{
// start thread for vnc-updates
this->onProjectionStopped();
_clientId = clientId;
_vncWorker = new VncThread(host, port, passwd, 1);
connect(_vncWorker, SIGNAL(projectionStopped()), this, SLOT(onProjectionStopped()), Qt::QueuedConnection);
connect(_vncWorker, SIGNAL(projectionStarted()), this, SLOT(onProjectionStarted()), Qt::QueuedConnection);
_tcpTimeoutTimer = startTimer(4000);
_vncWorker->start(QThread::LowPriority);
//_rfbclient = _thread->getRfbClient();
//installEventFilter(this);
setMouseTracking(true); // get mouse events even when there is no mousebutton pressed
setFocusPolicy(Qt::WheelFocus); //needed?!?
setWindowTitle(caption);
setAttribute(Qt::WA_OpaquePaintEvent);
if (fullscreen)
{
setWindowFlags(Qt::WindowStaysOnTopHint);
showFullScreen();
activateWindow();
raise();
}
else
{
resize(800, 600);
showNormal();
}
this->show();
_vncWorker->setTargetSize(this->size());
connect(_vncWorker, SIGNAL(imageUpdated(const int, const int, const int, const int)), this,
SLOT(onUpdateImage(const int, const int, const int, const int)),
Qt::QueuedConnection);
}
void VncWindow::closeEvent(QCloseEvent *e)
{
e->ignore();
qDebug("Closing VNC viewer window.");
this->setVisible(false);
this->onProjectionStopped();
emit running(false, _clientId);
}
void VncWindow::onUpdateImage(const int x, const int y, const int w, const int h)
{
this->repaint(x, y, w, h);
}
/**
* VNC Thread successfully connected to remote end - projection will start
*/
void VncWindow::onProjectionStarted()
{
emit running(true, _clientId);
_redrawTimer = startTimer(5000);
}
void VncWindow::onProjectionStopped()
{
if(_vncWorker == NULL)
return;
_vncWorker->blockSignals(true);
_vncWorker->stop();
_vncWorker = NULL;
if(_redrawTimer != 0)
{
killTimer(_redrawTimer);
_redrawTimer = 0;
}
this->close();
}
////////////////////////////////////////////////////////////////////////////////
// Protected
void VncWindow::close()
{
if (this->isVisible())
QDialog::close();
else
emit running(false, _clientId);
}
void VncWindow::timerEvent(QTimerEvent *event)
{
if (event->timerId() == _redrawTimer)
{
if (this->isVisible())
this->repaint();
}
else if (event->timerId() == _tcpTimeoutTimer)
{
killTimer(_tcpTimeoutTimer);
if (_vncWorker != NULL && !_vncWorker->isConnected()){
this->onProjectionStopped();
}
}
else
killTimer(event->timerId());
}
void VncWindow::paintEvent(QPaintEvent *event)
{
const QRect &r = event->rect();
this->draw(r.left(), r.top(), r.width(), r.height());
event->accept();
}
void VncWindow::resizeEvent(QResizeEvent* event)
{
_vncWorker->setTargetSize(event->size());
}
void VncWindow::draw(const int x, const int y, const int w, const int h)
{
if (_vncWorker == NULL)
return;
QPainter painter(this);
painter.drawImage(x, y, _vncWorker->getImage(), x, y, w, h);
//painter.drawRect(x,y,w,h); // for debugging updated area
}
//returns true if event was processed
/*bool VncWindow::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 VncWindow::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;
}
}
_vncWorker->mouseEvent(e->x(), e->y(), _buttonMask);
}
//handles mousewheel
void VncWindow::wheelEventHandler(QWheelEvent *event)
{
int eb = 0;
if (event->delta() < 0)
eb |= 0x10;
else
eb |= 0x8;
const int x = event->x();
const int y = event->y();
_vncWorker->mouseEvent(x, y, eb | _buttonMask);
_vncWorker->mouseEvent(x, y, _buttonMask);
}
//Handles keypress
void VncWindow::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)
{
_vncWorker->keyEvent(k, pressed);
}
}
void VncWindow::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_Escape)
{
_clientId = 0;
this->close();
}
}
//removes modifier keys which have been pressed
void VncWindow::unpressModifiers()
{
const QList<unsigned int> keys = _modkeys.keys();
QList<unsigned int>::const_iterator it = keys.constBegin();
while (it != keys.end())
{
_vncWorker->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 VncWindow::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);
}