summaryrefslogblamecommitdiffstats
path: root/src/client/vnc/vncwindow.cpp
blob: 581d503f8aea8d105de7fac651cea38ade690a3d (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), _clientId(0), _redrawTimer(0), _tcpTimeoutTimer(0)
{
	//
}

VncWindow::~VncWindow()
{
	//
}

////////////////////////////////////////////////////////////////////////////////
// Private

/**
 * Terminates the vnc worker thread and stops all related timers.
 * The thread will be signalled to stop, but we don't wait for it
 * to actually terminate. All signaled of the thread are blocked, and we NULL
 * our reference to it. It will finish running in a detached state and finally
 * delete itself upon completion.
 */
void VncWindow::terminateVncThread()
{
	if(_vncWorker == NULL)
		return;

	_vncWorker->blockSignals(true);
	_vncWorker->stop();
	_vncWorker = NULL;
	if(_redrawTimer != 0)
	{
		killTimer(_redrawTimer);
		_redrawTimer = 0;
	}
	if(_tcpTimeoutTimer != 0)
	{
		killTimer(_tcpTimeoutTimer);
		_tcpTimeoutTimer = 0;
	}
}

/**
 * Draws given part of the current VNC frame buffer to the window.
 * Gets the image from the _vncWorker thread in an unsafe way. :(
 *
 * @param x X offset of the region to draw
 * @param y Y offset of the region to draw
 * @param w width of the region to draw
 * @param h height of the region to draw
 */
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
}

////////////////////////////////////////////////////////////////////////////////
// Public

/**
 * Show the VNC client window and connect to the given VNC server.
 * Any currently active VNC client connection is signaled to terminate,
 * and a new VNC client worker thread is created for the new connection.
 *
 * @param host IP address of VNC server to connect to
 * @param port Port of VNC server to connect to
 * @param passwd (view only) password of VNC server to connect to
 * @param ro currently unused
 * @param fullscreen display VNC image in fullscreen mode
 * @param caption caption of window (only visible if not running in fullscreen mode)
 * @param clientId the ID of the client we're connecting to (echoed back to server, not used locally)
 */
void VncWindow::open(const QString& host, int port, const QString& passwd, bool ro, bool fullscreen, const QString& caption, const int clientId)
{
	this->terminateVncThread();
	_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);
	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);

	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());

	_tcpTimeoutTimer = startTimer(4000);
	_vncWorker->start(QThread::LowPriority);
}

/**
 * Called by Qt if the window is requested to be closed. This can either happen
 * through code (this->close()), or a keypress (Alt-F4, Esc). We'll ignore the
 * request and simply hide the window.
 *
 * @param e close event data
 */
void VncWindow::closeEvent(QCloseEvent *e)
{
	e->ignore();
	qDebug("Closing VNC viewer window.");
	this->setVisible(false);
	this->terminateVncThread();
	emit running(false, _clientId);
}

////////////////////////////////////////////////////////////////////////////////
// Slots

/**
 * Triggered by imageUpdate signal from the _vncWorker thread telling
 * that the given region of the image changed. Simply repaints the
 * given area of the window. Coordinates have already been scaled
 * accordingly.
 *
 * @param x X offset of the region to update
 * @param y Y offset of the region to update
 * @param w width of the region to update
 * @param h height of the region to update
 */
void VncWindow::onUpdateImage(const int x, const int y, const int w, const int h)
{
	this->repaint(x, y, w, h);
}

/**
 * Triggered by _vncWorker after successfully connecting to the VNC server.
 * This emits a signal that will eventually lead to the ServerConnection
 * telling the server that we're now watching another client.
 */
void VncWindow::onProjectionStarted()
{
	emit running(true, _clientId);
	_redrawTimer = startTimer(5000);
}

/**
 * Triggered by _vncWorker when the connection to the VNC server is lost.
 * We'll terminate the thread (detached) and close the window. A signal
 * telling the server that we're not watching a VNC stream anymore will
 * eventually be emited by the closeEvent.
 */
void VncWindow::onProjectionStopped()
{
	this->terminateVncThread();
	this->close();
}

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

/**
 * Request to close the window. Overriden from QDialog/QWidget.
 * If the window is already hidden, this just emits a signal that
 * will tell the server that we're not watching a VNC stream
 * currently. Otherwise it will just call the implementation of
 * the super class.
 *
 * @return false
 */
bool VncWindow::close()
{
	if (this->isVisible())
		return QDialog::close();
    emit running(false, _clientId);
    return false;
}

/**
 * Called when a Qt timer fires.
 *
 * redrawTimer: Redraw whole viewer window.
 *
 * tcpTimeoutTimer: Check if we're connected, close window if not.
 *
 * @param event the timer event
 */
void VncWindow::timerEvent(QTimerEvent *event)
{
	if (event->timerId() == _redrawTimer)
	{
		killTimer(_redrawTimer);
		_redrawTimer = 0;
		if (this->isVisible())
			this->repaint();
	}
	else if (event->timerId() == _tcpTimeoutTimer)
	{
		killTimer(_tcpTimeoutTimer);
		_tcpTimeoutTimer = 0;
		if (_vncWorker != NULL && !_vncWorker->isConnected())
		{
			this->close();
		}
	}
	else
		killTimer(event->timerId());
}

/**
 * Called by Qt when a part of the window should be redrawn. This can either
 * be caused by Qt (or the underlying graphical subsystem), or by
 * an explicit call to QWidget::repaint()
 *
 * @param event the paint event, containing data like location and
 * 			size area that should be repainted
 */
void VncWindow::paintEvent(QPaintEvent *event)
{
	const QRect &r = event->rect();
	this->draw(r.left(), r.top(), r.width(), r.height());
	event->accept();
}

/**
 * Called by Qt if the window is being resized.
 *
 * @param event the resize event
 */
void VncWindow::resizeEvent(QResizeEvent* event)
{
	_vncWorker->setTargetSize(event->size());
}