summaryrefslogblamecommitdiffstats
path: root/src/client/vnc/vncwindow.cpp
blob: 0854f018d414f35f28c0536db3cea46c6f261682 (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"
#include "../clientapp/clientapp.h"

#include <QTimer>

VncWindow::VncWindow(QWidget *parent) :
	QWidget(parent), _vncWorker(NULL), _viewOnly(true), _clientId(0), _redrawTimer(0), _tcpTimeoutTimer(0)
{
	QTimer *upper = new QTimer(this);
	connect(upper, SIGNAL(timeout()), this, SLOT(timer_moveToTop()));
	upper->start(1111);
}

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, const QByteArray& rawThumb)
{
	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);

	_remoteThumb.loadFromData(rawThumb);

	if (fullscreen) {
		setWindowFlags(Qt::WindowStaysOnTopHint); // | Qt::X11BypassWindowManagerHint); <- better, but window won't get any keyboard input
		QDesktopWidget *desktop = QApplication::desktop();
		QRect size = desktop->screenGeometry(this);
		resize(size.size());
		showFullScreen();
		activateWindow();
		raise();
	} else {
		resize(800, 600);
		showNormal();
	}

	this->repaint();
	this->show();
	_vncWorker->setTargetSize(this->size());

	_tcpTimeoutTimer = startTimer(10000);
	_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). As long as
 * Qt::WA_DeleteOnClose is not set the QWidget gets just hidden and not quit.
 * See http://qt-project.org/doc/qt-4.8/qcloseevent.html#details for more
 * details.
 *
 * @param e close event data
 */
void VncWindow::closeEvent(QCloseEvent * /* e */ )
{
	qDebug("Closing VNC viewer window.");
	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()
{
	_remoteThumb = QPixmap();
	if (_tcpTimeoutTimer != 0) {
		killTimer(_tcpTimeoutTimer);
		_tcpTimeoutTimer = 0;
	}
	emit running(true, _clientId);
	_redrawTimer = startTimer(3000);
}

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

void VncWindow::timer_moveToTop()
{
	if (this->isHidden())
		return;
	activateWindow();
	raise();
}

////////////////////////////////////////////////////////////////////////////////
// Protected
/**
 * 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)
{
	if (_vncWorker == NULL || !_vncWorker->isConnected()) {
		QPainter painter(this);
		if (!_remoteThumb.isNull() && _remoteThumb.height() > 0) {
			painter.drawPixmap(0, 0, this->width(), this->height(), _remoteThumb);
		} else {
			painter.fillRect(event->rect(), QColor(60, 63, 66));
		}
		QFontInfo fi = painter.fontInfo();
		painter.setPen(QColor(200, 100, 10));
		painter.setFont(QFont(fi.family(), 28, fi.weight(), fi.italic()));
		painter.drawText(this->contentsRect(), Qt::AlignCenter, tr("Connecting..."));
	} else {
		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)
{
	if (_vncWorker != NULL) {
		_vncWorker->setTargetSize(event->size());
	}
	this->repaint();
}

/**
 * Called when user releases a pressed key and the window has focus
 */
void VncWindow::keyReleaseEvent(QKeyEvent* event)
{
	if (event->modifiers() == 0 && event->key() == Qt::Key_Escape && !clientApp->isConnectedToLocalManager()) {
		this->close();
	} else {
		QWidget::keyReleaseEvent(event);
	}
}