Skip to content

Commit b44665c

Browse files
authored
examples,build: add Qt client example
* CMake: Adds C++ as project language * CMake: Adds WITH_QT option to build Qt client example * Examples: Adds qt5client.cpp * CMake: adds specific way of building Qt client example * CMake: try to find Qt if needed * CMake: makes Qt not required, quiet if not found * CMake: removes CXX as language * CMake: checks if we have C++ compiler before setting standard * CMake: checks C++ compiler before setting project languages I could not find a better solution. It seems like the languages must be set before almost everything. * CMake: check if C++ compiler defined instead of string comparison * CMake: appends CXX to languages, in a better syntax As suggested by dantti * Examples: changes to static_cast in Qt5 client example As suggested by @dantti * Examples: adds description to Qt example * Examples: Qt example can't handle new fb size * Examples: adds additional condition to build Qt example This is need to remove the following message: 'CMake Error: Cannot determine link language for target' * CMake: adds comment about C++ example (Qt client) * Examples: adds CMake remarks to Qt client example * CMake: changes Qt5::Widgets to Qt5Widgets_LIBRARIES Just for standardization
1 parent 6e777e6 commit b44665c

2 files changed

Lines changed: 174 additions & 2 deletions

File tree

CMakeLists.txt

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
cmake_minimum_required(VERSION 3.4)
22

3-
project(LibVNCServer VERSION 0.9.14 LANGUAGES C)
3+
set(PROJECT_LANGUAGES C)
4+
5+
if(DEFINED CMAKE_CXX_COMPILER)
6+
set(CMAKE_CXX_STANDARD 17)
7+
list(APPEND PROJECT_LANGUAGES CXX)
8+
endif(DEFINED CMAKE_CXX_COMPILER)
9+
10+
project(LibVNCServer VERSION 0.9.14 LANGUAGES ${PROJECT_LANGUAGES})
411
include(CheckFunctionExists)
512
include(CheckSymbolExists)
613
include(CheckIncludeFile)
@@ -25,6 +32,7 @@ set(TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test)
2532
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
2633
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
2734
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
35+
2836
if(CMAKE_GENERATOR MATCHES "Unix Makefiles|Ninja")
2937
# some LSP servers expect compile_commands.json in the project root
3038
add_custom_target(
@@ -67,7 +75,7 @@ option(WITH_SASL "Build with SASL support" ON)
6775
option(WITH_XCB "Build with XCB support" ON)
6876
option(WITH_EXAMPLES "Build examples" ON)
6977
option(WITH_TESTS "Build tests" ON)
70-
78+
option(WITH_QT "Build the Qt client example" ON)
7179

7280

7381
if(WITH_ZLIB)
@@ -147,6 +155,10 @@ if(WITH_GTK)
147155
find_package(GTK2)
148156
endif(WITH_GTK)
149157

158+
if(WITH_QT)
159+
find_package(Qt5 COMPONENTS Core Widgets QUIET)
160+
endif(WITH_QT)
161+
150162
if(WITH_LIBSSHTUNNEL)
151163
find_path(LIBSSHTUNNEL_INCLUDE_DIR libsshtunnel.h)
152164
find_library(LIBSSHTUNNEL_LIBRARY sshtunnel)
@@ -656,6 +668,17 @@ if(WITH_EXAMPLES)
656668
set_target_properties(client_examples_${e} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/examples/client)
657669
target_link_libraries(client_examples_${e} vncclient ${CMAKE_THREAD_LIBS_INIT} ${SDL2_LIBRARY} ${GTK2_LIBRARIES} ${FFMPEG_LIBRARIES} ${LIBSSHTUNNEL_LIBRARY})
658670
endforeach(e ${LIBVNCCLIENT_EXAMPLES})
671+
672+
#This example must have its own building instructions,
673+
#apart from the other examples because it is written in
674+
#C++, so it has a distinct file extension and depends on
675+
#a C++ compiler
676+
if(Qt5Widgets_FOUND AND WITH_QT AND DEFINED CMAKE_CXX_COMPILER)
677+
add_executable(client_examples_qt5client ${LIBVNCCLIEXAMPLE_DIR}/qt5client.cpp ${LIBVNCCLIEXAMPLE_DIR}/${qt5client_EXTRA_SOURCES})
678+
set_target_properties(client_examples_qt5client PROPERTIES OUTPUT_NAME qt5client)
679+
set_target_properties(client_examples_qt5client PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/examples/client)
680+
target_link_libraries(client_examples_qt5client vncclient ${CMAKE_THREAD_LIBS_INIT} ${Qt5Widgets_LIBRARIES})
681+
endif(Qt5Widgets_FOUND AND WITH_QT AND DEFINED CMAKE_CXX_COMPILER)
659682
endif(WITH_EXAMPLES)
660683

661684
#

examples/client/qt5client.cpp

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
*
3+
* This program is free software; you can redistribute it and/or modify
4+
* it under the terms of the GNU General Public License as published by
5+
* the Free Software Foundation; either version 2 of the License, or
6+
* (at your option) any later version.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program; if not, write to the Free Software
15+
* Foundation, Inc., 59 Temple Place, Suite 330,
16+
* Boston, MA 02111-1307, USA.
17+
*/
18+
19+
/*
20+
* This is an example on how to make a simple VNC client with
21+
* Qt5 Widgets. It suitable for desktop apps, but may not be
22+
* good for mobile.
23+
* It does not implement any form of cryptography,
24+
* authentication support, client-side cursors or framebuffer
25+
* resizing. If you want to make this a part of your
26+
* application, please notice that you may need to change
27+
* the while(true) loop to disconnect the client.
28+
*
29+
* To build this example with all the other components of
30+
* libvncserver, you may need to explicitly define a C++
31+
* compiler and the path to Qt libs when calling CMake.
32+
* e.g. cmake -DCMAKE_PREFIX_PATH=~/Qt/5.15.2/gcc_64
33+
* -DCMAKE_CXX_COMPILER=g++
34+
*/
35+
36+
#include <QApplication>
37+
#include <iostream>
38+
#include <thread>
39+
#include <QPaintEvent>
40+
#include <QPainter>
41+
#include "rfb/rfbclient.h"
42+
#include <QWidget>
43+
44+
class VncViewer : public QWidget
45+
{
46+
//if you want to make use of signals/slots, uncomment the line bellow:
47+
//Q_OBJECT
48+
public:
49+
VncViewer(QWidget *parent = nullptr) {};
50+
virtual ~VncViewer() {};
51+
void start();
52+
std::string serverIp;
53+
int serverPort;
54+
std::thread *vncThread() const;
55+
void paintEvent(QPaintEvent *event) override;
56+
57+
private:
58+
QImage m_image;
59+
rfbClient *cl;
60+
std::thread *m_vncThread;
61+
static void finishedFramebufferUpdateStatic(rfbClient *cl);
62+
void finishedFramebufferUpdate(rfbClient *cl);
63+
};
64+
65+
void VncViewer::finishedFramebufferUpdateStatic(rfbClient *cl)
66+
{
67+
VncViewer *ptr = static_cast<VncViewer*>(rfbClientGetClientData(cl, nullptr));
68+
ptr->finishedFramebufferUpdate(cl);
69+
}
70+
71+
void VncViewer::finishedFramebufferUpdate(rfbClient *cl)
72+
{
73+
m_image = QImage(cl->frameBuffer, cl->width, cl->height, QImage::Format_RGB16);
74+
75+
update();
76+
}
77+
void VncViewer::paintEvent(QPaintEvent *event)
78+
{
79+
event->accept();
80+
81+
QPainter painter(this);
82+
painter.drawImage(this->rect(), m_image);
83+
}
84+
85+
void VncViewer::start()
86+
{
87+
cl = rfbGetClient(8, 3, 4);
88+
cl->format.depth = 24;
89+
cl->format.depth = 16;
90+
cl->format.bitsPerPixel = 16;
91+
cl->format.redShift = 11;
92+
cl->format.greenShift = 5;
93+
cl->format.blueShift = 0;
94+
cl->format.redMax = 0x1f;
95+
cl->format.greenMax = 0x3f;
96+
cl->format.blueMax = 0x1f;
97+
cl->appData.compressLevel = 9;
98+
cl->appData.qualityLevel = 1;
99+
cl->appData.encodingsString = "tight ultra";
100+
cl->FinishedFrameBufferUpdate = finishedFramebufferUpdateStatic;
101+
cl->serverHost = strdup(serverIp.c_str());
102+
cl->serverPort = serverPort;
103+
cl->appData.useRemoteCursor = TRUE;
104+
105+
rfbClientSetClientData(cl, nullptr, this);
106+
107+
if (rfbInitClient(cl, 0, nullptr)) {
108+
} else {
109+
std::cout << "[INFO] disconnected" << std::endl;
110+
return;
111+
}
112+
113+
m_vncThread = new std::thread([this]() {
114+
while (true) {
115+
int i = WaitForMessage(cl, 500);
116+
if (i < 0) {
117+
std::cout << "[INFO] disconnected" << std::endl;
118+
rfbClientCleanup(cl);
119+
break;
120+
}
121+
122+
if (i && !HandleRFBServerMessage(cl)) {
123+
std::cout << "[INFO] disconnected" << std::endl;
124+
rfbClientCleanup(cl);
125+
break;
126+
}
127+
};
128+
});
129+
}
130+
131+
int main(int argc, char *argv[])
132+
{
133+
if(argc < 3) {
134+
std::cout << "Usage: "
135+
<< argv[0]
136+
<< " <server ip>"
137+
<< " <port>"
138+
<< "\n";
139+
return 1;
140+
}
141+
142+
QApplication a(argc, argv);
143+
VncViewer vncViewer;
144+
vncViewer.serverIp = std::string{argv[1]};
145+
vncViewer.serverPort = std::atoi(argv[2]);
146+
vncViewer.show();
147+
vncViewer.start();
148+
return a.exec();
149+
}

0 commit comments

Comments
 (0)