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; either
8 version 2 of the License, or (at your option) any later version.
12 #include "krfbserver.h"
13 #include "krfbserver.moc"
19 #include <QApplication>
20 #include <QDesktopWidget>
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
;
130 class KrfbServerPrivate
136 K_GLOBAL_STATIC(KrfbServerPrivate
, krfbServerPrivate
)
138 KrfbServer
* KrfbServer::self() {
139 return &krfbServerPrivate
->instance
;
143 KrfbServer::KrfbServer()
146 kDebug() << "starting ";
148 d
->fb
= FrameBuffer::getFrameBuffer(QApplication::desktop()->winId(), this);
149 QTimer::singleShot(0, this, SLOT(startListening()));
150 connect(InvitationManager::self(), SIGNAL(invitationNumChanged(int)),SLOT(updatePassword()));
153 KrfbServer::~KrfbServer()
159 void KrfbServer::startListening()
161 rfbScreenInfoPtr screen
;
163 int port
= KrfbConfig::port();
165 int w
= d
->fb
->width();
166 int h
= d
->fb
->height();
167 int depth
= d
->fb
->depth();
170 screen
= rfbGetScreen(0, 0, w
, h
, 8, 3,depth
/ 8);
171 screen
->paddedWidthInBytes
= d
->fb
->paddedWidth();
173 d
->fb
->getServerFormat(screen
->serverFormat
);
175 screen
->frameBuffer
= d
->fb
->data();
177 screen
->autoPort
= 0;
181 screen
->newClientHook
= newClientHook
;
183 screen
->kbdAddEvent
= keyboardHook
;
184 screen
->ptrAddEvent
= pointerHook
;
185 screen
->newClientHook
= newClientHook
;
186 screen
->passwordCheck
= passwordCheck
;
187 screen
->setXCutText
= clipboardHook
;
189 d
->desktopName
= i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()).toLatin1();
190 screen
->desktopName
= d
->desktopName
.constData();
193 myCursor
= rfbMakeXCursor(19, 19, (char*) cur
, (char*) mask
);
195 screen
->cursor
= myCursor
;
197 // configure passwords and desktop control here
200 rfbInitServer(screen
);
201 if (!rfbIsActive(screen
)) {
202 KMessageBox::error(0,"krfb","Address already in use");
206 if (KrfbConfig::publishService()) {
207 DNSSD::PublicService
*service
= new DNSSD::PublicService(i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()),"_rfb._tcp",port
);
208 service
->publishAsync();
212 foreach(const QRect
&r
, d
->fb
->modifiedTiles()) {
213 rfbMarkRectAsModified(screen
, r
.x(), r
.y(), r
.right(), r
.bottom());
215 rfbProcessEvents(screen
, 100);
216 qApp
->processEvents();
218 rfbShutdownServer(screen
, true);
219 // framebuffer has to be deleted before X11 connection goes down
227 void KrfbServer::enableDesktopControl(bool enable
)
229 foreach (QPointer
<ConnectionController
> ptr
, d
->controllers
) {
231 ptr
->setControlEnabled(enable
);
236 void KrfbServer::disconnectAndQuit()
241 enum rfbNewClientAction
KrfbServer::handleNewClient(struct _rfbClientRec
* cl
)
243 ConnectionController
*cc
= new ConnectionController(cl
, this);
244 if (d
->numClients
++ == 0)
245 d
->fb
->startMonitor();
247 d
->controllers
.append(cc
);
248 cc
->setControlEnabled(KrfbConfig::allowDesktopControl());
250 connect(cc
, SIGNAL(sessionEstablished(QString
)), SIGNAL(sessionEstablished(QString
)));
251 connect(cc
, SIGNAL(clientDisconnected(ConnectionController
*)),SLOT(clientDisconnected(ConnectionController
*)));
253 return cc
->handleNewClient();
256 void KrfbServer::updateSettings()
258 enableDesktopControl(KrfbConfig::allowDesktopControl());
262 void KrfbServer::updatePassword()
265 if (!d
->screen
) return;
266 QString pw
= KrfbConfig::uninvitedConnectionPassword();
267 kDebug() << "password: " << pw
<< " allow " <<
268 KrfbConfig::allowUninvitedConnections() <<
269 " invitations " << InvitationManager::self()->activeInvitations() << endl
;
271 if (pw
.isEmpty() && InvitationManager::self()->activeInvitations() == 0) {
272 kDebug() << "no password from now on";
273 d
->screen
->authPasswdData
= (void *)0;
275 kDebug() << "Ask for password to accept connections";
276 d
->screen
->authPasswdData
= (void *)1;
280 bool KrfbServer::checkX11Capabilities() {
281 int bp1
, bp2
, majorv
, minorv
;
282 Bool r
= XTestQueryExtension(QX11Info::display(), &bp1
, &bp2
,
284 if ((!r
) || (((majorv
*1000)+minorv
) < 2002)) {
285 KMessageBox::error(0,
286 i18n("Your X11 Server does not support the required XTest extension version 2.2. Sharing your desktop is not possible."),
287 i18n("Desktop Sharing Error"));
294 void KrfbServer::clientDisconnected(ConnectionController
*cc
)
296 kDebug() << "clients--: " << d
->numClients
;
297 if (!--d
->numClients
) {
298 d
->fb
->stopMonitor();
300 disconnect(cc
, SIGNAL(clientDisconnected(ConnectionController
)),this, SLOT(clientDisconnected(ConnectionController
)));