\chapter{PVS-Client}
Der PVS-Client ist in ein Backend (\textbf{pvs}) und ein Frontend (\textbf{pvsgui}) aufgeteilt. Erster läuft als Daemon im Hintergrund und kommuniziert über ein gegebenes Netzwerk mit der Steuerkonsole (\textbf{pvsmgr}). Die Interprozesskommunikation (inter-process communication, IPC) zwischen Back- und Frontend erfolgt über D-Bus und wurde mit Hilfe der von Qt4 bereitgestellten Bibliothek QtDBus realisiert. Um das Backend von einer GUI komplett unabhängig zu halten, wurde darauf geachtet, dass alle Nachrichten, die an die GUI gerichtet sind, vom Backend als Signale über D-Bus verteilt werden. Umgekehrt, wenn das Frontend eine Nachricht an das Backend schicken will, muss es sich der im Backend implementierten Slots bedienen (s. Abbildung \ref{pdf:dbus}). Somit ist es sogar möglich, dass mehrere GUIs gleichzeitig ein und das selbe Backend benutzen. Ein weiteres Feature ist, dass das Frontend beim Start das Backend durch einen D-Bus Aufruf automatisch startet. Hierzu muss allerdings die Applikation zuvor mit \textbf{make install} auf dem System installiert worden sein.\\

\begin{figure}
  \begin{center}
    \includegraphics[scale=0.7]{bilder/DBus}
    \caption{Back- und Frontend des PVS-Clients kommunizieren über D-Bus}
    \label{pdf:dbus}
  \end{center}
\end{figure}
Zunächst muss in der Hauptklasse des Backends (\textit{pvs.cpp}) das Qt-Makro
\begin{verbatim}
Q_CLASSINFO("D-Bus Interface","org.openslx.pvs")
\end{verbatim}
eingefügt werden, um dem späteren D-Bus-Interface einen Namen zu geben. Als nächstes werden alle zu exportierenden Slots wie gewohnt mit \texttt{Q\_SLOTS} bzw. Signale mit \texttt{Q\_SIGNALS} in der \textit{pvs.h} gekennzeichnet. Schließlich folgen ein paar Definitionen in der \textit{\mbox{CMakeLists.txt}}, deren Bedeutung aus den Kommentaren entnommen werden kann:
\begin{verbatim}
# QtDBus Modul aktivieren
SET( QT_USE_QTDBUS TRUE )
# Signale und Slots aus pvs.h ins XML-Format exportieren
QT4_GENERATE_DBUS_INTERFACE( src/pvs.h org.openslx.pvs.xml )
# D-Bus Adapter für Backend erzeugen
QT4_ADD_DBUS_ADAPTOR( PVS_SRCS ${CMAKE_BINARY_DIR}/org.openslx.pvs.xml 
  src/pvs.h PVS )
# Aus der zuvor erstellten XML-Datei ein Interface in C++ Syntax 
# generieren
QT4_ADD_DBUS_INTERFACE( PVSGUI_SRCS 
  ${CMAKE_BINARY_DIR}/org.openslx.pvs.xml pvsinterface )
\end{verbatim}
Sind die Vorbedingungen erfüllt, wird beim ersten Kompilieren eine Datei namens \textit{pvsinterface.h} erstellt, in der die Definition der Klasse \texttt{\mbox{OrgOpenslxPvsInterface}} gespeichert wurde. Diese Klasse kann nun in anderen Programmen (wie z.B. in der \textbf{pvsgui}) dazu benutzt werden, um Zugriff auf die freigegebenen Ressourcen des Backends zu erhalten.

\section{Grafische Benutzeroberfläche}
Die Hauptklasse der Benutzeroberfläche des Clients heißt \texttt{PVSGUI} und befindet sich in der Datei \textit{pvsgui.cpp}. In dieser werden Referenzen auf alle benutzten Dialoge, das System Tray Icon sowie das D-Bus Interface zur Kommunikation mit dem Backend erzeugt. Weiter beinhaltet diese Klasse die \texttt{main()}-Funktion und bildet somit den Einstiegt für das Betriebssystem. Damit der Zugriff auf die Toolbar immer gewährleistet bleibt (auch wenn Videos oder eine virtuelle Maschine im Vollbild laufen), muss beim Zeichnen dieser der laufende Windowmanager umgangen werden. Hierbei hilft uns Qt mit der Anweisung:
\begin{verbatim}
setWindowFlags(Qt::WindowStaysOnTopHint|Qt::X11BypassWindowManagerHint);
\end{verbatim}
Wie bereits in der Einleitung erwähnt, wird das komplette Projekt mit Hilfe von CMake erstellt. Aus diesem Grund soll an dieser Stelle ebenfalls eine kleine Beschreibung folgen, wie man mit CMake Qt-Klassen einbindet, die mit dem Qt-Werkzeug \textbf{designer} erstellt worden sind. Als Beispiel dient die Klasse \texttt{PVSGUI}, wobei wir hier nicht auf die Qt eigenen Details eingehen werden.
\begin{verbatim}
# CMake anweisen, Qt4 auf lokalem System zu suchen
FIND_PACKAGE( Qt4 4.5.0 REQUIRED )
INCLUDE( ${QT_USE_FILE} )
# Sowohl Quell- als auch Zielverzeichnis auf Quelldateien durchsuchen
INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} )

# Alle von der Software benötigten Quelldateien
SET( PVSGUI_SRCS src/pvsgui.cpp )
# Vom Meta Object Compiler benötigte Header-Dateien
SET( PVSGUI_MOC_HDRS src/pvsgui.h )
# Auflistung aller benötigten .ui Dateien 
SET( PVSGUI_UIS src/gui/ui/clientToolbar.ui )
# Ressourcendateien 
SET( PVSGUI_RCS pvsgui.qrc )

# Qt Meta Object Compiler ausführen (moc)
QT4_WRAP_CPP( PVSGUI_MOC_SRCS ${PVSGUI_MOC_HDRS} )
# Qt User Interface Compiler ausführen (uic)
QT4_WRAP_UI( PVSGUI_UI_HDRS ${PVSGUI_UIS} )
# Qt Resource Compiler ausführen (rrc)
QT4_ADD_RESOURCES( PVSGUI_RC_SRCS ${PVSGUI_RCS} )

# Applikation mit allen benötigten Variablen bauen
ADD_EXECUTABLE( pvs ${PVS_SRCS} ${PVS_MOC_SRCS} ${PVS_RC_SRCS} )
# Mit der Qt-Bibliothek linken
TARGET_LINK_LIBRARIES( pvsgui ${QT_LIBRARIES} )
\end{verbatim}

\section{User-Interface für Benutzerkonfiguration}
Der eingebaute Konfigurationsdialog besteht hauptsächlich aus der Klasse \texttt{ClientConfig\-Dialog} und ist in der Datei \textit{clientConfigDialog.cpp} definiert. Es handelt sich hierbei um einen gewöhnlichen \texttt{QDialog}, dessen graphische Implementierung in der Datei \textit{clientConfigDialog.ui} gespeichert ist.\\
Den Kern dieser Klasse bildet ein \texttt{QSettings} Objekt, das sowohl zum Speichern als auch zum Laden der Benutzerkonfiguration benutzt wird. Ablage aller Einstellungen ist die Datei \textit{\textasciitilde/.config/openslx/pvsgui.conf}. Diese kann jedoch zentral für die gesamte Applikation in der Funktion \texttt{PVSGUI::main(int argc, char *argv[])} geändert werden.\\
Um weitere Komponenten der GUI über Änderungen der aktuellen Konfiguration zu informieren, wird das Signal \texttt{configChanged()} emittiert.

\section{Darstellung von VNC-Datenströmen}
\label{pvsclient-datenstrom}
Die übertragenen Bildinformationen können in einem separaten Fenster oder im Vollbildmodus dargestellt werden. Hierzu wählt der Dozent über die Steuerkonsole (\textbf{pvsmgr}) eine Quelle und ein oder mehrere Ziele zur Projektion aus, was zur Folge hat, dass an alle gewählten Clients (\textbf{pvs}) eine Nachricht mit den benötigten Informationen geschickt wird. Als nächstes sendet das Backend ein Signal über D-Bus an sein Frontend, das die benötigten Informationen (Host, Port, Passwort, Qualität) enthält. Somit kann nun die GUI eine Verbindung zum gegebenen VNC-Server aufbauen und den Datenstrom darstellen.\\

Der Aufbau des VNC-Viewers besteht aus zwei Klassen:
\begin{itemize}
  \item Die Klasse \texttt{VNCClientThread} stellt mit Hilfe eines \texttt{rfbclient} (aus libvncserver0) eine Verbindung zum VNC-Server her. Zunächst werden sämtliche Verbindungsparameter über den Konstruktor definiert und nach einem Aufruf von \texttt{VNCClientThread::start()} eine Verbindung aufgebaut. Da diese Klasse selbst von \texttt{QThread} abgeleitet ist, läuft sie in einem eigenständigem Thread, um die GUI nicht zu blockieren. Der Informationsaustausch erfolgt über das Signal \texttt{VNCClientThread::imageUpdated(int x, int y, int w, int h)}, welches die Koordinaten einer Änderung des Framebuffers enthält.
 \item Die Darstellung des Datenstroms wird von der Klasse \texttt{ClientVNCViewer} übernommen. Da beide Klassen auf ein und den selben Ressourcen arbeiten, müssen die Signale des \texttt{VNCClientThread} mit dem Parameter \texttt{Qt::BlockingQueuedConnection} verbunden werden. Dies stellt sicher, dass der Thread solange pausiert, bis der Slot des \texttt{ClientVNCViewer} abgearbeitet wurde (\texttt{ClientVNCViewer::updateImage(int x, int y, int w, int h)}).
\end{itemize}
Bei der Entwicklung des VNC-Viewers musste stark auf die Performanz geachtet werden. Das Ziel ist es, sowohl Bandbreite als auch CPU-Last einzusparen. Um die Netzwerkauslastung konfigurierbar zu machen, stehen drei Qualitätsstufen zur Wahl, von denen eine gewählt werden muss. Durch diese serverseitige Konfiguration wird beispielsweise auf der niedrigsten Qualitätsstufe die Farbtiefe verringert und die Kompressionsstufe erhöht (verlustbehaftet), was die zu übertragenen Bildinformationen minimiert. Um den Prozessor des Zielrechners nicht unnötig zu belasten, werden wie im VNC-Protokoll vorgesehen, nur die Bereiche des Framebuffers neu gezeichnet und skaliert, die sich auch geändert haben.

\section{Chat-Interface}
Die vom Chat-Interface verwendeten Klassen und Dialoge befinden sich in den Dateien \textit{clientChatDialog.cpp} und \textit{clientChatDialog.ui}. Der Informationsaustausch erfolgt hier wieder über D-Bus direkt mit dem Backend.\\
Zum Versenden einer Nachricht wird der Slot \texttt{PVS::chat\_send()} und zum Empfang das Signal \texttt{PVS::chat\_receive()} des Backends benutzt. Um die Liste aller Chatteilnehmer aktuell zu halten, wird analog vorgegangen. Hierzu existieren die Slots \texttt{PVS::chat\_client\_add()} und \texttt{PVS::chat\_client\_remove()}.\\
Um neben dem öffentlichen Chat auch private Unterhaltungen zwischen zwei Teilnehmern zu ermöglichen, wurde ein \texttt{QTabWidget} benutzt. Auf diesem wird bei jeder neu begonnenen Unterhaltung ein \texttt{QTextEdit} platziert, dass dem Gesprächspartner durch ein \texttt{QHash<QString, QTextEdit*>} direkt zugeordnet wird.

\section{Dateiübertragung und Interface}
Die graphische Benutzerschnittstelle des Clients ermöglicht allen Chatteilnehmern binäre Dateien untereinander zu tauschen. Dazu wurden zwei Dialoge entwickelt -- einer zum Senden und einer zum Empfang. Diese  Dialoge stellen nicht nur das Benutzerinterface dar sondern bilden ebenfalls die komplette Grundlage (Client-Server) zur Übertragung binärer Daten. Die hierfür entworfenen Klassen sind \texttt{ClientFileSendDialog} und \texttt{ClientFileReceiveDialog}, zu denen die gleichnamigen .ui Dateien gehören.\\

Daten senden:\\
Um eine Datei zu senden, sind der Name des Chatteilnehmers (Nickname) sowie der Pfad der zu sendenden Datei erforderlich. Falls diese Informationen nicht vorhanden sind, wird der Benutzer durch Pop-Ups danach gefragt. Der nächste Schritt besteht darin, die IP bzw. den Hostnamen des Chatteilnehmers zu erfragen. Dies geschieht automatisch, indem das Backend (\textbf{pvs}) diesbezüglich über D-Bus befragt wird. Stehen alle Angaben zur Verfügung, wird an den Zielrechner ein kleiner Header mit folgenden Informationen geschickt:
\begin{verbatim}
Nickname_des_Senders;Dateiname;Dateigröße\n
\end{verbatim}
Sollte sich der Kommunikationspartner für den Empfang der angebotenen Datei entscheiden, wird von diesem eine Bestätigung verschickt (ack), die den eigentlichen Übertragungsvorgang startet. Das Ende der Übertragung wird dem Empfänger durch das Schließen des benutzen Sockets signalisiert.\\
Während der Übertragung wird ein Dialog angezeigt der den Sender über den Fortschritt mit Hilfe einer \texttt{QProgressBar} informiert. Der Vorgang kann jederzeit abgebrochen werden und über aufgetretene Fehler wird durch Pop-Ups informiert.\\

Daten empfangen:\\
Sobald die graphische Benutzeroberfläche des Clients startet, wird durch eine Instanz des \texttt{QTcpServer} der Port 29481 geöffnet und auf eingehende Verbindungen gewartet. Wird nun von einem anderen Teilnehmer eine Datei angeboten, so wird eine Instanz des \texttt{ClientFile\-ReceiveDialog} angelegt, die sich um den weiteren Verlauf kümmert. Der Empfänger kann nun, die Übertragung akzeptieren und einen Speicherort wählen. Danach wird eine Bestätigung an den Sender verschickt und die eigentliche Datenübertragung gestartet.\\
Auch der Empfänger wird durch einen Dialog über den Fortschritt informiert und kann die Übertragung jederzeit abbrechen.\\

Wichtig an dieser Stelle ist die Speicherfreigabe beendeter Übertragungsdialoge. Da wir gleichzeitig beliebig viele Übertragungen erlauben wollen, muss natürlich für jede ein eigenständiger Dialog erzeugt werden. Um keine Liste mit laufenden Dialogen führen zu müssen (und einzelne zu löschen) wird hier auf einen komfortablen Qt-Mechanismus zurückgegriffen. Sobald ein Dialog mit \texttt{accept()} oder \texttt{reject()} beendet wird, sendet dieser das Signal \mbox{\texttt{finished(int)}}. Auf der anderen Seite besitzt jede Klasse, die von \texttt{QObject} abgeleitet wurde, den Slot \texttt{deleteLater()}. Die Qt-API garantiert, dass Qt nach dem Aufruf dieser Methode dieses Objekt selbstständig aus dem Speicher entfernt. Also müssen wir dieses Signal dem Slot zuordnen (in \texttt{ClientFileSendDialog} und \texttt{ClientFileReceiveDialog}):
\begin{verbatim}
connect(this, SIGNAL(finished(int)), this, SLOT(deleteLater()));
\end{verbatim}

\section{VNC Server}
Um den Bildschirminhalt von Clients zum einen in der Übersicht (Thumbnails) der Steuerkonsole und zum anderen auf anderen Clients und dem Beamer darstellen zu können, wird das sogenannte Remote Framebuffer Protokoll (RFB), welches auch der Virtual Network Computing (VNC) Software zugrundeliegt, benutzt. Um VNC bzw RFB nutzen zu können, wird ein VNC Server und ein VNC Viewer benötigt. Aktuell wird als VNC Server \texttt{x11vnc} verwendet sowie der, wie in \ref{pvsclient-datenstrom} beschrieben, in den den PVS-Client integrierte rfbclient bzw. ClientVNCViewer. Bei der VNC Verbindung wird zwischen einer Verbindung ohne Maus und Tastatursteuerung, dem sogenannten Viewonly oder Readonly Modus, und einer Verbindung mit Maus und Tastatursteuerung, im folgendenden Read-Write (RW) Modus genannt, unterschieden.

\subsection{Vergleich von VNC Servern}
Es gibt zwei Arten von VNC Servern. Server, die eine laufende Sitzung bzw. ein vorhandenes Display darstellen bzw. übermitteln können, und Server, die eine eigene Sitzung bzw. ein eigenes Display bereitstellen (virtuell). Für PVS ist die zweite Art, welche auf dem ursprünglichen VNC basiert, nicht verwendbar, da man hierbei nicht den aktuellen Bildschirminhalt der Clients in der Steuerkonsole anzeigen bzw. projezieren kann. Daher wurden folgende VNC Server im Weiteren nicht betrachtet: Xvnc (RealVNC), vnc4server, TightVNC. 

Motivation für den eigentlichen Vergleich ist die Integration mancher VNC Server in die Desktopumgebung. Hier müsste der x11vnc nicht extra installiert werden. Wichtig für den Einsatz im PVS ist vor allem die Unterstützung von Shared Modus, d.h. mehrere VNC Viewer können sich gleichzeitig mit dem VNC Server verbinden, und Forever Modus, d.h. der VNC Server wird nicht nach Trennung des letzten Clients beendet. Sicherheitsoptionen wie die Vergabe von Passwörtern und die Unterscheidung von RW und Viewonly Modus sind ebenso nicht zu vernachlässigen.

\paragraph{Vino}
\begin{sloppypar}
~\\
Vino ist der VNC Server der Gnome Desktopumgebung.
Er wird standardmäßig über die graphische Oberfläche \textbf{vino-preferences} konfiguriert. Über die Kommandozeile ist Vino entweder über \textbf{gconftool-2} oder über direktes editieren der Datei \\ 
\textit{\~{}/.gconf/desktop/gnome/remote\_access/\%gconf.xml} konfigurierbar. 
Parameter können nicht übergeben werden, was die Verwendbarkeit im PVS einschränkt.
Vino benutzt standardmäßig den Port 5900, um auf eingehende Verbindungen zu warten. Dieser Port kann nur durch
\texttt{gconftool-2 -s -t int \/desktop/gnome/remote\_access/alternative\_port <portnumber>} bzw. das Einfügen von z.B.
\texttt{<entry name=``alternative\_port'' mtime=``1259858032'' type= ``int'' value=``<portnumber>''/>}
in die entsprechende \%gconf.xml Datei geändert werden. Hierbei ist zu beachten, dass nicht überprüft wird, ob der entsprechende Port schon belegt ist. Dementsprechend wird auch kein anderer freier Port gewählt.
Außerdem wird eine Änderung des Ports erst nach dem Neustart der grafischen Oberfläche aktiv.
Vino unterstützt die Vergabe eines Passworts, welches base64 kodiert in der gconf Datei abgelegt wird. Ebenso kann man den Zugriff auf den Viewonly Modus beschränken. Unterschiedliche Passwörter für den RW Modus und den Viewonly Modus können jedoch nicht vergeben werden. Der Shared und Forever Modus sind standardmäßig aktiv.
\end{sloppypar}

\paragraph{Krfb}
~\\
Krfb ist das Pendant zu Vino der KDE Desktopumgebung und kann entweder über eine Konfigurationsdatei oder über die grafische Oberfläche konfiguriert werden. Es kann entweder das Einladungssystem verwendet werden, bei dem eine Einladung mit einem Einmalpasswort generiert wird, oder man erlaubt uneingeladene Verbindungen und vergibt ein eigenes Passwort. Um Krfb über eine Konfigurationsdatei mit einem selbstgewählten Passwort für uneingeladene Verbindungen zu konfigurieren, erstellt man die Datei wie im folgenden angegeben und übergibt sie an krfb mit \texttt{krfb --config <Pfad> } bzw überschreibt oder bearbeitet die eigentliche Konfigurationsdatei in \textit{~/.kde/share/config/krfbrc}.
%\label{pvs-client-krfbconfig}
\begin{verbatim}
[Security]
allowDesktopControl=false
allowUninvitedConnections=true
uninvitedConnectionPassword=<passwort>

[TCP]
port=<port>
useDefaultPort=false
\end{verbatim} 

Mit allowDesktopControl kann zwischen RW und Viewonly Modus gewechselt werden, unterschiedliche Passwörter können hierfür nicht vergeben werden. Zu beachten ist, dass die Passwörter für uneingeladene Verbindungen unverschlüsselt gespeichert werden. Wie auch Vino läuft Krfb standardmäßig im Shared und Forever Modus.

\paragraph{x11vnc}
~\\
x11vnc ist ein auf libvncserver basierender VNC-Server, der von Karl Runge entwickelt wurde, um unter Linux/Unix Systemen existierende Displays über VNC anzeigen zu lassen.
x11vnc wird über Parameter von der Kommandozeile aus konfiguriert.
Eine ausführliche Liste aller verfügbaren Parameter findet sich unter 
\url{http://www.karlrunge.com/x11vnc/x11vnc_opts.html}. Zu beachten ist hierbei, dass alle Parameter, die an x11vnc übergeben werden (also beispielsweise auch Passwörter), in der z.B. durch \textbf{ps aux} abrufbaren Prozessliste anzeigbar sind.
Daher sollte eine Passwortdatei, welche auch nach dem Auslesen automatisch von x11vnc gelöscht werden kann (s.h. \ref{pvs-vnc-script}), benutzt werden. Die Struktur einer solchen Passwortdatei ist wie folgt:
\begin{verbatim}
 rwpassword1
       .
       .
 [rwpasswordX]
 [\_\_BEGIN_VIEWONLY\_\_]
 [password1]
 	.
	.
 [passwordX]
\end{verbatim} 
Es muss mindestens ein Passwort vorhanden sein. Alle Passwörter bis zu der Zeile, welche \_\_BEGIN\_VIEWONLY\_\_ enthält, werden als rw-Passwörter angesehen (außer in dem Spezialfall, dass nur zwei Passwörter und keine Zeile mit BEGIN\_VIEWONLY vorhanden sind, dann wird das zweite Passwort automatisch als Viewonly Passwort behandelt). Alle Passwörter nach der entsprechenden Viewonly-Zeile werden als Viewonly Passwörter gesehen. So ist es möglich beliebig viele Viewonly und bzw. oder RW-Passwörter zu generieren.


\subsection{VNC Script}
\label{pvs-vnc-script}
Der VNC Server wird durch ein Bash-Skript (\textit{/misc/pvs-vncsrv}) von der Klasse \textit{pvs} gestartet. Es wird zufällig jeweils ein Passwort für Standardzugriff und ein Passwort für den Zugriff mit Maus und Tastaturunterstützung generiert. Die generierten Passwörter werden dem Skript als Parameter übergeben. \textbf{pvs-vncsrv} wird zum Starten wie folgt aufgerufen:
\texttt{pvs-vncsrv start port passwort [rwpasswort]}.
Der Parameter \texttt{rwpasswort} ist optional und kann beim Starten des x11vnc zur Verwendung im Viewonly Modus weggelassen werden.
Um den VNC Server zu stoppen, kann das VNC Script mit dem Parameter \texttt{stop} aufgerufen werden.
Die übergebenen Passwörter werden zunächst auf folgende Weise in die Datei \textit{~/.pvs/vncpassword} geschrieben: \verb|rwpasswort __BEGIN_VIEWONLY__ passwort|. 
Als nächstes wird x11vnc mit folgenden Parametern ausgeführt:
\begin{itemize}
  \item -auth ... - die Xauthority Datei
  \item -bg - im Hintergrund starten
  \item -forever - den X Server nicht beenden, wenn sich ein Client trennt
  \item -display :0 - das anzuzeigende Display
  \item -passwdfile rm:... - Pfad der Passwortdatei 
  \item -o ... - Pfad der Logdatei (~/.pvs/log.vncsrv)
  \item -shared - erlaube mehreren Clients, sich zu verbinden
\end{itemize}

Zu beachten ist vor allem das \texttt{rm:} vor der Pfadangabe bei \texttt{-passwdfile}. Dies bewirkt das Löschen der Passwortdatei, nachdem x11vnc sie eingelesen hat.
Die Passwortdatei wird verwendet, da man ansonsten Passwörter, die nur als Parameter im Klartext an x11vnc übergeben werden, mittels \textbf{ps aux} lesen könnte.

Um einen Mehrfachstart des VNC Servers zu verhindern, wird zunächst immer ein \texttt{pvs-vncsrv stop} ausgeführt, welches nach der Prozessid des x11vnc sucht und diesen mit kill -9 beendet.

\section{VNC Viewer}
Der VNC Viewer ist, wie in der \ref{pvsclient-datenstrom} Darstellung von VNC-Datenströmen beschrieben, implementiert.
Die direkte Integration des Viewers im Gegensatz zum Einsatz eines externen VNC Servers bietet sich hier wegen der Integrationsmöglichkeiten in die GUI an (der VNC-Server ist GUI unabhängig). Jedoch muss der VNC-Viewer zur Unterstützung des RW-Modus des VNC-Servers noch verändert werden. 
\subsection{Tastatur und Maussteuerung}
\label{pvsclient-remotehelp}
\begin{sloppypar}
Um die Maus- und Tastatureingaben an den VNC-Server weiterzuleiten, müssen zunächst die Eingaben in der Klasse \texttt{ClientVNCViewer} abgefangen und verarbeitet werden. Dies kann durch Überschreiben der geerbten Methode \texttt{event} erreicht werden \texttt{bool ClientVNCViewer::event(QEvent *event)}. Hier kann durch \texttt{event->type()} der Typ des Events herausgefunden werden.
Zu behandelnde Eventtypen sind: 
\end{sloppypar}

\begin{itemize}
\item QEvent:KeyPress - Eine Taste wurde gedrückt
\item QEvent:KeyRelease - Eine Taste wurde losgelassen
\item QEvent:MouseButtonDblClick - Mausdoppelklick
\item QEvent:MouseButtonPress - Maustaste gedrückt
\item QEvent:MouseButtonRelease - Maustaste losgelassen
\item QEvent:MouseMove - Maus wurde bewegt
\item QEvent:Wheel - Mausrad wurde bewegt
\end{itemize}

Hier können nun die jeweils zuständigen Funktionen aufgerufen werden. Dabei ist zu beachten, dass die Methode \texttt{event()} bei allen Eingaben, die von einer eigenen Funktion behandelt werden, true zurückgibt (d.h. das Event wurde akzeptiert und behandelt). In den aufgerufenen Methoden kann dann zwischen den verschiedenen Maustasten (Qt:LeftButton, Qt:MidButton, Qt:RightButton) und den verschiedenen Tasten der Tastatur (z.B. Qt:Key\_A, Qt:Key\_B, Qt:Key\_Alt siehe hierzu auch \url{http://doc.trolltech.com/4.6/qt.html#Key-enum}) unterschieden werden.
Die Tastatur- und Mauseingaben müssen dann entsprechend an \texttt{vncClientThread} weitergeleitet werden.
In der Klasse vncClientThread werden die Eingaben dann in Objekte gekapselt in einer Queue, welche regelmäßig geleert wird, gespeichert. Die Objekte sind dabei zum einen ein \texttt{PointerEvent} und ein \texttt{KeyEvent}. \texttt{PointerEvents} enthalten die Koordinaten des Mauszeigers (x,y) und einen hexadezimalen Wert, der die Maustasten und deren Zustand repräsentiert.
Werte sind dabei: 
\begin{itemize}
	\item 0x01 = linke Maustaste gedrückt
	\item 0x02 = mittlere Maustaste gedrückt
	\item 0x03 = rechte Maustaste gedrückt
	\item 0xfe = linke Maustaste losgelassen
	\item 0xfd = mittlere Maustaste losgelassen
	\item 0xfb = rechte Maustaste losgelassen
\end{itemize}
\begin{sloppypar}
\texttt{KeyEvents} bestehen aus einem hexadezimalen Wert, der die Taste repräsentiert, und True oder False je nachdem, ob die Taste gedrückt wurde oder nicht. Die hexadezimalen Werte entsprechen den Werten in einem X Window System und können in der Headerdatei \texttt{<X11/keysymdef.h>} nachgeschlagen werden (siehe hierzu auch \url{http://www.realvnc.com/docs/rfbproto.pdf} - RFB Protokollspezifikation, Abschnitt KeyEvent). Beim Leeren der Queue werden die Methoden der rfbclient Klasse der libvnc Bibliothek \texttt{SendPointerEvent(cl, \_x, \_y, \_buttonMask)} und \texttt{SendKeyEvent(cl, \_key, \_pressed)} mit den entsprechenden Werten aufgerufen (cl entspricht dabei einem Pointer auf die eigentliche rfbClient Instanz).
\end{sloppypar}

\section{Signalbehandlung}

\begin{sloppypar}
Um zu gewährleisten, dass bei einer Terminierung des PVS-Clients auch der gegebenenfalls gestartete VNC-Server gestoppt wird, werden Sigterm, Sighup, Sigquit und Sigint Signale abgefangen und weiterbehandelt.
Um die Signale behandeln zu können, muss die C Bibliothek \texttt{signals.h} eingebunden werden und ein sigaction Objekt erstellt werden. Das Feld sa\_handler des sigaction Objektes gibt dabei die aufzurufende Funktion an (Pointer auf die Funktion). Diese Funktion (in der Klasse \texttt{pvs} die Funktion \texttt{signalHandler}) muss dabei vom Typ void sein und die Signalnummer als Parameter erwarten (\texttt{void PVS::signalHandler(int signal)}).
\end{sloppypar}

\begin{verbatim}
 struct sigaction act;
 act.sa_handler = &PVS::signalHandler;
\end{verbatim} 

\begin{sloppypar}
Um Signale abfangen zu können, muss nun noch das sigaction Objekt durch \texttt{sigaction(SIGTERM, \&act, 0)} mit den entsprechenden Signalen (hier SIGTERM) verknüpft werden (muss für alle zu behandelnde Signale durchgeführt werden).
Danach wird, sobald ein entsprechendes Signal erhalten wird, die Funktion aufgerufen und die Signalnummer übergeben. 
Für alle Signale kann die gleiche Funktion aufgerufen werden, hier kann die Unterscheidung dann mittels der in \texttt{signal.h} vorhandenen Konstanten SIGHUP, SIGTERM, SIGQUIT usw. erfolgen. Zu beachten ist hierbei, dass ein SIGKILL nicht abgefangen werden kann.
\end{sloppypar}