summaryrefslogblamecommitdiffstats
path: root/src/client/vnc/vncwindow.cpp
blob: f55aa28c293a53b5c22d0c3ef88a5bf7a4702562 (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 "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->onThreadFinished();
	_clientId = clientId;
	_vncWorker = new VncThread(host, port, passwd, 1);
	connect(_vncWorker, SIGNAL(finished()), this, SLOT(onThreadFinished()), Qt::QueuedConnection);
	connect(_vncWorker, SIGNAL(projectionStarted()), this, SLOT(onProjectionStarted()), Qt::QueuedConnection);
	_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->onThreadFinished();
	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);
}

/**
 * Thread finished, clean up and close window
 */
void VncWindow::onThreadFinished()
{
	if (_vncWorker)
	{
		disconnect(_vncWorker, SIGNAL(imageUpdated(const int, const int, const int, const int)), this,
		   SLOT(onUpdateImage(const int, const int, const int, const int)));
		disconnect(_vncWorker, SIGNAL(finished()), this, SLOT(onThreadFinished()));
		_vncWorker->stop();
		delete _vncWorker;
		_vncWorker = NULL;
		this->close();
	}
	if(_redrawTimer != 0)
	{
		killTimer(_redrawTimer);
		_redrawTimer = 0;
	}
}

/**
 * VNC Thread successfully connected to remote end - projection will start
 */
void VncWindow::onProjectionStarted()
{
	emit running(true, _clientId);
	//_redrawTimer = startTimer(5000);
}

////////////////////////////////////////////////////////////////////////////////
// Protected

void VncWindow::timerEvent(QTimerEvent *event)
{
	if (event->timerId() == _redrawTimer)
	{
		if (this->isVisible())
			this->repaint();
	}
	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);
}