mirror of
https://github.com/KDE/krfb
synced 2026-07-01 07:41:17 -07:00
quite working
svn path=/trunk/kdenetwork/krfb/; revision=127687
This commit is contained in:
4
TODO
4
TODO
@@ -1,2 +1,6 @@
|
||||
Todo:
|
||||
- fix what's-this help in dialogs
|
||||
- remove help button?
|
||||
|
||||
Possible features:
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "trayicon.h"
|
||||
#include "configuration.h"
|
||||
#include "rfbcontroller.h"
|
||||
|
||||
#include <kpixmap.h>
|
||||
#include <kaction.h>
|
||||
@@ -50,6 +51,7 @@ int main(int argc, char *argv[])
|
||||
KApplication app;
|
||||
TrayIcon trayicon;
|
||||
Configuration config;
|
||||
RFBController controller(&config);
|
||||
|
||||
QObject::connect(&trayicon, SIGNAL(showConfigure()),
|
||||
&config, SLOT(showDialog()));
|
||||
@@ -57,5 +59,15 @@ int main(int argc, char *argv[])
|
||||
QObject::connect(&app, SIGNAL(lastWindowClosed()),
|
||||
&app, SLOT(quit()));
|
||||
|
||||
QObject::connect(&controller, SIGNAL(sessionEstablished()),
|
||||
&trayicon, SLOT(openConnection()));
|
||||
QObject::connect(&controller, SIGNAL(sessionFinished()),
|
||||
&trayicon, SLOT(closeConnection()));
|
||||
QObject::connect(&trayicon, SIGNAL(connectionClosed()),
|
||||
&controller, SLOT(closeSession()));
|
||||
|
||||
QObject::connect(&config, SIGNAL(portChanged()),
|
||||
&controller, SLOT(rebind()));
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "rfbconnection.h"
|
||||
|
||||
#include <kdebug.h>
|
||||
#include <qapplication.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <unistd.h>
|
||||
@@ -29,25 +30,29 @@
|
||||
#include <string.h>
|
||||
|
||||
|
||||
RFBConnection::RFBConnection(Display *dpy, int fd, const QString &cpassword) :
|
||||
RFBConnection::RFBConnection(Display *_dpy,
|
||||
int _fd,
|
||||
const QString &cpassword,
|
||||
bool _allowInput) :
|
||||
Server(),
|
||||
dpy(dpy),
|
||||
fd(fd),
|
||||
dpy(_dpy),
|
||||
fd(_fd),
|
||||
allowInput(_allowInput),
|
||||
buttonMask(0)
|
||||
{
|
||||
memcpy(password, "\0\0\0\0\0\0\0\0", 8);
|
||||
if (!cpassword.isNull())
|
||||
strncpy(password, cpassword.latin1(),
|
||||
8 <= cpassword.length() ? 8 : cpassword.length());
|
||||
(8 <= cpassword.length()) ? 8 : cpassword.length());
|
||||
|
||||
bufferedConnection = new BufferedConnection(32768, 32768);
|
||||
connection = bufferedConnection;
|
||||
|
||||
InitBlocks(32, 32);
|
||||
|
||||
XTestGrabControl(dpy, true);
|
||||
createFramebuffer();
|
||||
|
||||
InitBlocks(32, 32);
|
||||
|
||||
connection->send((unsigned char*) RFB_PROTOCOL_VERSION, 12);
|
||||
}
|
||||
|
||||
@@ -62,6 +67,8 @@ RFBConnection::~RFBConnection() {
|
||||
}
|
||||
|
||||
void RFBConnection::handleKeyEvent(KeyEvent &keyEvent) {
|
||||
if (!allowInput)
|
||||
return;
|
||||
KeyCode kc = XKeysymToKeycode(dpy, keyEvent.key);
|
||||
if (kc != NoSymbol)
|
||||
XTestFakeKeyEvent(dpy,
|
||||
@@ -71,6 +78,8 @@ void RFBConnection::handleKeyEvent(KeyEvent &keyEvent) {
|
||||
}
|
||||
|
||||
void RFBConnection::handlePointerEvent(PointerEvent &pointerEvent) {
|
||||
if (!allowInput)
|
||||
return;
|
||||
XTestFakeMotionEvent(dpy,
|
||||
0,
|
||||
pointerEvent.x_position,
|
||||
@@ -97,48 +106,50 @@ void RFBConnection::createFramebuffer()
|
||||
QApplication::desktop()->height(),
|
||||
AllPlanes,
|
||||
ZPixmap);
|
||||
framebuffer.width = framebufferImage->width;
|
||||
framebuffer.height = framebufferImage->height;
|
||||
framebuffer.bytesPerLine = framebufferImage->bytes_per_line;
|
||||
framebuffer.data = (unsigned char*) framebufferImage->data;
|
||||
framebuffer = new Framebuffer();
|
||||
framebuffer->width = framebufferImage->width;
|
||||
framebuffer->height = framebufferImage->height;
|
||||
framebuffer->bytesPerLine = framebufferImage->bytes_per_line;
|
||||
framebuffer->data = (unsigned char*) framebufferImage->data;
|
||||
|
||||
framebuffer.pixelFormat.bits_per_pixel =
|
||||
framebuffer->pixelFormat.bits_per_pixel =
|
||||
framebufferImage->bits_per_pixel;
|
||||
framebuffer.pixelFormat.depth = framebufferImage->depth;
|
||||
framebuffer.pixelFormat.big_endian_flag =
|
||||
framebuffer->pixelFormat.depth = framebufferImage->depth;
|
||||
framebuffer->pixelFormat.big_endian_flag =
|
||||
(framebufferImage->bitmap_bit_order == MSBFirst);
|
||||
framebuffer.pixelFormat.true_colour_flag = true;
|
||||
framebuffer->pixelFormat.true_colour_flag = true;
|
||||
|
||||
if (framebuffer.pixelFormat.bits_per_pixel == 8) {
|
||||
framebuffer.pixelFormat.red_shift = 0;
|
||||
framebuffer.pixelFormat.green_shift = 2;
|
||||
framebuffer.pixelFormat.blue_shift = 5;
|
||||
framebuffer.pixelFormat.red_max = 3;
|
||||
framebuffer.pixelFormat.green_max = 7;
|
||||
framebuffer.pixelFormat.blue_max = 3;
|
||||
if (framebuffer->pixelFormat.bits_per_pixel == 8) {
|
||||
framebuffer->pixelFormat.red_shift = 0;
|
||||
framebuffer->pixelFormat.green_shift = 2;
|
||||
framebuffer->pixelFormat.blue_shift = 5;
|
||||
framebuffer->pixelFormat.red_max = 3;
|
||||
framebuffer->pixelFormat.green_max = 7;
|
||||
framebuffer->pixelFormat.blue_max = 3;
|
||||
} else {
|
||||
framebuffer.pixelFormat.red_shift = 0;
|
||||
framebuffer->pixelFormat.red_shift = 0;
|
||||
if ( framebufferImage->red_mask )
|
||||
while (!(framebufferImage->red_mask & (1 << framebuffer.pixelFormat.red_shift)))
|
||||
framebuffer.pixelFormat.red_shift++;
|
||||
framebuffer.pixelFormat.green_shift = 0;
|
||||
while (!(framebufferImage->red_mask & (1 << framebuffer->pixelFormat.red_shift)))
|
||||
framebuffer->pixelFormat.red_shift++;
|
||||
framebuffer->pixelFormat.green_shift = 0;
|
||||
if (framebufferImage->green_mask)
|
||||
while (!(framebufferImage->green_mask & (1 << framebuffer.pixelFormat.green_shift)))
|
||||
framebuffer.pixelFormat.green_shift++;
|
||||
framebuffer.pixelFormat.blue_shift = 0;
|
||||
while (!(framebufferImage->green_mask & (1 << framebuffer->pixelFormat.green_shift)))
|
||||
framebuffer->pixelFormat.green_shift++;
|
||||
framebuffer->pixelFormat.blue_shift = 0;
|
||||
if (framebufferImage->blue_mask)
|
||||
while (!(framebufferImage->blue_mask & (1 << framebuffer.pixelFormat.blue_shift)))
|
||||
framebuffer.pixelFormat.blue_shift++;
|
||||
framebuffer.pixelFormat.red_max = framebufferImage->red_mask >> framebuffer.pixelFormat.red_shift;
|
||||
framebuffer.pixelFormat.green_max = framebufferImage->green_mask >> framebuffer.pixelFormat.green_shift;
|
||||
framebuffer.pixelFormat.blue_max = framebufferImage->blue_mask >> framebuffer.pixelFormat.blue_shift;
|
||||
while (!(framebufferImage->blue_mask & (1 << framebuffer->pixelFormat.blue_shift)))
|
||||
framebuffer->pixelFormat.blue_shift++;
|
||||
framebuffer->pixelFormat.red_max = framebufferImage->red_mask >> framebuffer->pixelFormat.red_shift;
|
||||
framebuffer->pixelFormat.green_max = framebufferImage->green_mask >> framebuffer->pixelFormat.green_shift;
|
||||
framebuffer->pixelFormat.blue_max = framebufferImage->blue_mask >> framebuffer->pixelFormat.blue_shift;
|
||||
}
|
||||
scanner = new XUpdateScanner( dpy, QApplication::desktop()->winId(), &framebuffer );
|
||||
scanner = new XUpdateScanner( dpy, QApplication::desktop()->winId(), framebuffer );
|
||||
}
|
||||
|
||||
void RFBConnection::destroyFramebuffer()
|
||||
{
|
||||
delete scanner;
|
||||
delete framebuffer;
|
||||
XDestroyImage(framebufferImage);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,8 @@ using namespace rfb;
|
||||
class RFBConnection : public QObject, public Server {
|
||||
Q_OBJECT
|
||||
public:
|
||||
RFBConnection(Display *dpy, int fd, const QString &cpassword);
|
||||
RFBConnection(Display *dpy, int fd,
|
||||
const QString &cpassword, bool allowInput);
|
||||
~RFBConnection();
|
||||
virtual void handleKeyEvent(KeyEvent &keyEvent);
|
||||
virtual void handlePointerEvent(PointerEvent &pointerEvent);
|
||||
@@ -65,8 +66,8 @@ private:
|
||||
|
||||
int fd;
|
||||
int buttonMask;
|
||||
bool allowInput;
|
||||
|
||||
Framebuffer framebuffer;
|
||||
XUpdateScanner *scanner;
|
||||
|
||||
Display *dpy;
|
||||
|
||||
@@ -33,84 +33,99 @@
|
||||
|
||||
RFBController::RFBController(Configuration *c) :
|
||||
configuration(c),
|
||||
socket(0),
|
||||
connection(0),
|
||||
idleUpdateScheduled(false)
|
||||
{
|
||||
start();
|
||||
startServer();
|
||||
}
|
||||
|
||||
RFBController::~RFBController() {
|
||||
delete serversocket;
|
||||
delete connection;
|
||||
delete socket;
|
||||
if (socket)
|
||||
delete socket;
|
||||
if (connection)
|
||||
delete connection;
|
||||
}
|
||||
|
||||
void RFBController::start() {
|
||||
void RFBController::startServer() {
|
||||
serversocket = new KServerSocket(configuration->port(), false);
|
||||
connect(serversocket, SIGNAL(accepted()), SLOT(accepted()));
|
||||
connect(serversocket, SIGNAL(accepted(KSocket*)), SLOT(accepted(KSocket*)));
|
||||
serversocket->bindAndListen();
|
||||
// TODO: error message if bindAndListen fails (port in use)
|
||||
}
|
||||
|
||||
void RFBController::rebind() {
|
||||
if (serversocket) {
|
||||
delete serversocket;
|
||||
start();
|
||||
}
|
||||
delete serversocket;
|
||||
startServer();
|
||||
}
|
||||
|
||||
void RFBController::idleSlot() {
|
||||
idleUpdateScheduled = false;
|
||||
if (connection) {
|
||||
connection->sendIncrementalFramebufferUpdate();
|
||||
checkWritable();
|
||||
}
|
||||
}
|
||||
|
||||
// called when KServerSocket accepted a connection. Closes KServerSocket.
|
||||
void RFBController::accepted() {
|
||||
int sockFd = serversocket->socket();
|
||||
KSocket *s;
|
||||
/* called when KServerSocket accepted a connection.
|
||||
Refuses the connection if there is already a connection.
|
||||
*/
|
||||
void RFBController::accepted(KSocket *s) {
|
||||
int sockFd = s->socket();
|
||||
if (sockFd < 0)
|
||||
kdDebug("Negative server socket?");
|
||||
kdError() << "Got negative socket (error)" << endl;
|
||||
|
||||
if (socket) {
|
||||
kdWarning() << "refuse 2nd connection" << endl;
|
||||
delete s;
|
||||
return;
|
||||
}
|
||||
|
||||
int one = 1;
|
||||
setsockopt(sockFd, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&one, sizeof(one));
|
||||
fcntl(sockFd, F_SETFL, O_NONBLOCK);
|
||||
s = new KSocket(sockFd);
|
||||
socket = s;
|
||||
|
||||
// TODO: ASK USER FOR PERMISSION HERE BEFORE GOING ON
|
||||
// TODO: also handle case if remote closes while dialog is shown
|
||||
|
||||
delete serversocket;
|
||||
serversocket = 0;
|
||||
|
||||
socket = s;
|
||||
connect(s, SIGNAL(readEvent(KSocket*)), SLOT(sockedReadable()));
|
||||
connect(s, SIGNAL(writeEvent(KSocket*)), SLOT(sockedWritable()));
|
||||
connect(s, SIGNAL(closeEvent(KSocket*)), SLOT(sockedClosed()));
|
||||
connect(s, SIGNAL(readEvent(KSocket*)), SLOT(socketReadable()));
|
||||
connect(s, SIGNAL(writeEvent(KSocket*)), SLOT(socketWritable()));
|
||||
connect(s, SIGNAL(closeEvent(KSocket*)), SLOT(closeSession()));
|
||||
s->enableRead(true);
|
||||
s->enableWrite(true);
|
||||
connection = new RFBConnection(qt_xdisplay(), sockFd,
|
||||
configuration->password());
|
||||
checkWritable();
|
||||
configuration->password(),
|
||||
configuration->allowDesktopControl());
|
||||
|
||||
emit sessionEstablished();
|
||||
}
|
||||
|
||||
void RFBController::checkWritable() {
|
||||
void RFBController::checkWriteBuffer() {
|
||||
BufferedConnection *bc = connection->bufferedConnection;
|
||||
socket->enableWrite((bc->senderBuffer.end - bc->senderBuffer.pos) > 0);
|
||||
}
|
||||
|
||||
void RFBController::idleSlot() {
|
||||
kdDebug() << "Idle 1" << endl;
|
||||
idleUpdateScheduled = false;
|
||||
if (connection) {
|
||||
kdDebug() << "Idle 2" << endl;
|
||||
connection->scanUpdates();
|
||||
connection->sendIncrementalFramebufferUpdate();
|
||||
checkWriteBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void RFBController::prepareIdleUpdate() {
|
||||
if (!idleUpdateScheduled)
|
||||
kdDebug() << "test schedule, isScheduled? " << idleUpdateScheduled<< endl;
|
||||
BufferedConnection *bc = connection->bufferedConnection;
|
||||
if (((bc->senderBuffer.end - bc->senderBuffer.pos) == 0) &&
|
||||
!idleUpdateScheduled) {
|
||||
QTimer::singleShot(0, this, SLOT(idleSlot()));
|
||||
idleUpdateScheduled = true;
|
||||
idleUpdateScheduled = true;
|
||||
kdDebug() << "Scheduled!" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void RFBController::socketReadable() {
|
||||
ASSERT(socket);
|
||||
int fd = socket->socket();
|
||||
BufferedConnection *bc = connection->bufferedConnection;
|
||||
prepareIdleUpdate();
|
||||
int count = read(fd,
|
||||
bc->receiverBuffer.data,
|
||||
bc->receiverBuffer.size);
|
||||
@@ -121,7 +136,7 @@ void RFBController::socketReadable() {
|
||||
}
|
||||
while (connection->currentState && bc->hasReceiverBufferData()) {
|
||||
connection->update();
|
||||
checkWritable();
|
||||
checkWriteBuffer();
|
||||
}
|
||||
bc->receiverBuffer.pos = 0;
|
||||
bc->receiverBuffer.end = 0;
|
||||
@@ -132,31 +147,34 @@ void RFBController::socketReadable() {
|
||||
|
||||
void RFBController::socketWritable() {
|
||||
ASSERT(socket);
|
||||
kdDebug() << "write slot" << endl;
|
||||
int fd = socket->socket();
|
||||
BufferedConnection *bc = connection->bufferedConnection;
|
||||
ASSERT((bc->senderBuffer.end - bc->senderBuffer.pos) > 0);
|
||||
// TODO: what to do if fd < 0?
|
||||
prepareIdleUpdate();
|
||||
int count = write(fd,
|
||||
bc->senderBuffer.data + bc->senderBuffer.pos,
|
||||
bc->senderBuffer.end - bc->senderBuffer.pos);
|
||||
if (count >= 0)
|
||||
if (count >= 0) {
|
||||
bc->senderBuffer.pos += count;
|
||||
else {
|
||||
} else {
|
||||
// TODO: what to do if write failed
|
||||
}
|
||||
checkWritable();
|
||||
kdDebug() << "written " << count << " left " << (bc->senderBuffer.end - bc->senderBuffer.pos) << endl;
|
||||
prepareIdleUpdate();
|
||||
checkWriteBuffer();
|
||||
}
|
||||
|
||||
void RFBController::closeSession() {
|
||||
if (!connection)
|
||||
if (!socket)
|
||||
return;
|
||||
delete connection;
|
||||
if (connection) {
|
||||
delete connection;
|
||||
connection = 0;
|
||||
emit sessionFinished();
|
||||
}
|
||||
delete socket;
|
||||
connection = 0;
|
||||
socket = 0;
|
||||
emit sessionFinished();
|
||||
start();
|
||||
}
|
||||
|
||||
#include "rfbcontroller.moc"
|
||||
|
||||
@@ -34,9 +34,10 @@ using namespace rfb;
|
||||
/**
|
||||
* Manages sockets, drives the RGBConnection and triggers the connection
|
||||
* dialog.
|
||||
* The controller has two states: 'waiting for connection' and 'connected'.
|
||||
* In the former serversocket is set and socket and connection are null, in
|
||||
* the latter serversocket is null and socket and connection are set.
|
||||
* The controller has three states: 'waiting for connection',
|
||||
* 'waiting for confirmation' and 'connected'. In the first state socket and
|
||||
* connection are null, in the second socket is set and in the last both are
|
||||
* set.
|
||||
* @author Tim Jansen
|
||||
*/
|
||||
class RFBController : public QObject {
|
||||
@@ -54,8 +55,8 @@ signals:
|
||||
void sessionFinished();
|
||||
|
||||
private:
|
||||
void start();
|
||||
void checkWritable();
|
||||
void startServer();
|
||||
void checkWriteBuffer();
|
||||
void prepareIdleUpdate();
|
||||
|
||||
Configuration *configuration;
|
||||
@@ -66,7 +67,7 @@ private:
|
||||
|
||||
private slots:
|
||||
void idleSlot();
|
||||
void accepted();
|
||||
void accepted(KSocket*);
|
||||
void socketReadable();
|
||||
void socketWritable();
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
trayicon.cpp - description
|
||||
trayicon.cpp
|
||||
-------------------
|
||||
begin : Tue Dec 11 2001
|
||||
copyright : (C) 2001 by Tim Jansen
|
||||
@@ -30,7 +30,11 @@ TrayIcon::TrayIcon() : KSystemTray() {
|
||||
configureAction = new KAction(i18n("&Configure KRfb"));
|
||||
configureAction->plug(contextMenu());
|
||||
closeConnectionAction = new KAction(i18n("Close connection"));
|
||||
closeConnectionAction->plug(contextMenu());
|
||||
closeConnectionAction->setEnabled(false);
|
||||
connect(configureAction, SIGNAL(activated()), SIGNAL(showConfigure()));
|
||||
connect(closeConnectionAction, SIGNAL(activated()),
|
||||
SIGNAL(connectionClosed()));
|
||||
show();
|
||||
}
|
||||
|
||||
@@ -39,10 +43,10 @@ TrayIcon::~TrayIcon(){
|
||||
|
||||
void TrayIcon::openConnection(){
|
||||
setPixmap(trayIconOpen);
|
||||
closeConnectionAction->plug(contextMenu());
|
||||
closeConnectionAction->setEnabled(true);
|
||||
}
|
||||
|
||||
void TrayIcon::closeConnection(){
|
||||
setPixmap(trayIconClosed);
|
||||
closeConnectionAction->unplug(contextMenu());
|
||||
closeConnectionAction->setEnabled(false);
|
||||
}
|
||||
|
||||
@@ -33,13 +33,16 @@ public:
|
||||
TrayIcon();
|
||||
~TrayIcon();
|
||||
|
||||
public slots:
|
||||
void closeConnection();
|
||||
void openConnection();
|
||||
|
||||
private:
|
||||
KPixmap trayIconOpen;
|
||||
KPixmap trayIconClosed;
|
||||
KAction* closeConnectionAction;
|
||||
KAction* configureAction;
|
||||
|
||||
signals:
|
||||
void connectionClosed();
|
||||
void showConfigure();
|
||||
|
||||
Reference in New Issue
Block a user