1 /* This file is part of the KDE project
2 Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
3 (C) 2001-2003 by Tim Jansen <tim@tjansen.de>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public
7 License as published by the Free Software Foundation; version 2
12 #include "krfbserver.h"
13 #include "krfbserver.moc"
19 #include <QApplication>
20 #include <QDesktopWidget>
26 #include <KStaticDeleter>
27 #include <KMessageBox>
28 #include <dnssd/publicservice.h>
30 #include "connectioncontroller.h"
31 #include "framebuffer.h"
32 #include "krfbconfig.h"
33 #include "invitationmanager.h"
35 #include <X11/Xutil.h>
36 #include <X11/extensions/XTest.h>
39 static const char* cur
=
60 static const char* mask
=
81 static rfbCursorPtr myCursor
;
84 static enum rfbNewClientAction
newClientHook(struct _rfbClientRec
*cl
)
86 KrfbServer
*server
= KrfbServer::self();
87 return server
->handleNewClient(cl
);
90 static rfbBool
passwordCheck(rfbClientPtr cl
,
91 const char* encryptedPassword
,
94 ConnectionController
*cc
= static_cast<ConnectionController
*>(cl
->clientData
);
95 return cc
->handleCheckPassword(cl
, encryptedPassword
, len
);
98 static void keyboardHook(rfbBool down
, rfbKeySym keySym
, rfbClientPtr cl
)
100 ConnectionController
*cc
= static_cast<ConnectionController
*>(cl
->clientData
);
101 cc
->handleKeyEvent(down
? true : false, keySym
);
104 static void pointerHook(int bm
, int x
, int y
, rfbClientPtr cl
)
106 ConnectionController
*cc
= static_cast<ConnectionController
*>(cl
->clientData
);
107 cc
->handlePointerEvent(bm
, x
, y
);
110 static void clipboardHook(char* str
,int len
, rfbClientPtr cl
)
112 ConnectionController
*cc
= static_cast<ConnectionController
*>(cl
->clientData
);
113 cc
->clipboardToServer(QString::fromUtf8(str
, len
));
117 class KrfbServer::KrfbServerP
{
120 KrfbServerP() : fb(0), screen(0), numClients(0) {};
123 QList
< QPointer
<ConnectionController
> > controllers
;
124 rfbScreenInfoPtr screen
;
127 QByteArray desktopName
;
131 static KStaticDeleter
<KrfbServer
> sdServer
;
132 KrfbServer
* KrfbServer::_self
= 0;
133 KrfbServer
* KrfbServer::self() {
134 if (!_self
) sdServer
.setObject(_self
, new KrfbServer
);
139 KrfbServer::KrfbServer()
142 kDebug() << "starting " << endl
;
144 d
->fb
= FrameBuffer::getFrameBuffer(QApplication::desktop()->winId(), this);
145 QTimer::singleShot(0, this, SLOT(startListening()));
146 connect(InvitationManager::self(), SIGNAL(invitationNumChanged(int)),SLOT(updatePassword()));
150 KrfbServer::~KrfbServer()
156 void KrfbServer::startListening()
158 rfbScreenInfoPtr screen
;
160 int port
= KrfbConfig::port();
162 int w
= d
->fb
->width();
163 int h
= d
->fb
->height();
164 int depth
= d
->fb
->depth();
167 screen
= rfbGetScreen(0, 0, w
, h
, 8, 3,depth
/ 8);
168 screen
->paddedWidthInBytes
= d
->fb
->paddedWidth();
170 d
->fb
->getServerFormat(screen
->serverFormat
);
172 screen
->frameBuffer
= d
->fb
->data();
174 screen
->autoPort
= 0;
178 screen
->newClientHook
= newClientHook
;
180 screen
->kbdAddEvent
= keyboardHook
;
181 screen
->ptrAddEvent
= pointerHook
;
182 screen
->newClientHook
= newClientHook
;
183 screen
->passwordCheck
= passwordCheck
;
184 screen
->setXCutText
= clipboardHook
;
186 d
->desktopName
= i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()).toLatin1();
187 screen
->desktopName
= d
->desktopName
.constData();
190 myCursor
= rfbMakeXCursor(19, 19, (char*) cur
, (char*) mask
);
192 screen
->cursor
= myCursor
;
194 // configure passwords and desktop control here
197 rfbInitServer(screen
);
198 if (!rfbIsActive(screen
)) {
199 KMessageBox::error(0,"krfb","Address already in use");
203 if (KrfbConfig::publishService()) {
204 DNSSD::PublicService
*service
= new DNSSD::PublicService(i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()),"_rfb._tcp",port
);
205 service
->publishAsync();
209 foreach(QRect r
, d
->fb
->modifiedTiles()) {
210 rfbMarkRectAsModified(screen
, r
.x(), r
.y(), r
.right(), r
.bottom());
212 rfbProcessEvents(screen
, 100);
213 qApp
->processEvents();
215 rfbShutdownServer(screen
, true);
220 void KrfbServer::enableDesktopControl(bool enable
)
222 foreach (QPointer
<ConnectionController
> ptr
, d
->controllers
) {
224 ptr
->setControlEnabled(enable
);
229 void KrfbServer::disconnectAndQuit()
234 enum rfbNewClientAction
KrfbServer::handleNewClient(struct _rfbClientRec
* cl
)
236 ConnectionController
*cc
= new ConnectionController(cl
, this);
237 if (d
->numClients
== 0) {
238 d
->fb
->startMonitor();
242 d
->controllers
.append(cc
);
243 cc
->setControlEnabled(KrfbConfig::allowDesktopControl());
245 connect(cc
, SIGNAL(sessionEstablished(QString
)), SIGNAL(sessionEstablished(QString
)));
246 connect(cc
, SIGNAL(clientDisconnected(ConnectionController
*)),SLOT(clientDisconnected(ConnectionController
*)));
248 return cc
->handleNewClient();
251 void KrfbServer::updateSettings()
253 enableDesktopControl(KrfbConfig::allowDesktopControl());
257 void KrfbServer::updatePassword()
260 if (!d
->screen
) return;
261 QString pw
= KrfbConfig::uninvitedConnectionPassword();
262 kDebug() << "password: " << pw
<< " allow " <<
263 KrfbConfig::allowUninvitedConnections() <<
264 " invitations " << InvitationManager::self()->activeInvitations() << endl
;
266 if (pw
.isEmpty() && InvitationManager::self()->activeInvitations() == 0) {
267 kDebug() << "no password from now on" << endl
;
268 d
->screen
->authPasswdData
= (void *)0;
270 kDebug() << "Ask for password to accept connections" << endl
;
271 d
->screen
->authPasswdData
= (void *)1;
275 bool KrfbServer::checkX11Capabilities() {
276 int bp1
, bp2
, majorv
, minorv
;
277 Bool r
= XTestQueryExtension(QX11Info::display(), &bp1
, &bp2
,
279 if ((!r
) || (((majorv
*1000)+minorv
) < 2002)) {
280 KMessageBox::error(0,
281 i18n("Your X11 Server does not support the required XTest extension version 2.2. Sharing your desktop is not possible."),
282 i18n("Desktop Sharing Error"));
289 void KrfbServer::clientDisconnected(ConnectionController
*cc
)
291 kDebug() << "clients--: " << d
->numClients
<< endl
;
293 if (d
->numClients
== 0) {
294 d
->fb
->stopMonitor();
296 disconnect(cc
, SIGNAL(clientDisconnected(ConnectionController
)),this, SLOT(clientDisconnected(ConnectionController
)));