When code starts to become too complex, add some new classes...

- FrameBuffer to encapsulate screen buffer and updates
- handle events
- avoid a timer for the rfb event loop, just use a real loop and qApp->processEvents()

svn path=/trunk/KDE/kdenetwork/krfb/; revision=650928
This commit is contained in:
Alessandro Praduroux
2007-04-05 20:21:15 +00:00
parent e21768e2f6
commit 379d4d2fc0
7 changed files with 209 additions and 135 deletions

View File

@@ -22,6 +22,7 @@ set(krfb_SRCS
personalinvitedialog.cpp
connectioncontroller.cpp
events.cpp
framebuffer.cpp
# rfbcontroller.cc
# xupdatescanner.cc
)

View File

@@ -7,22 +7,12 @@
License as published by the Free Software Foundation; version 2
of the License.
*/
#include "invitationmanager.h"
#include "krfbserver.h"
#include <QThreadStorage>
#include <QX11Info>
#include <QHostInfo>
#include <QApplication>
#include <QDesktopWidget>
#include <QTcpSocket>
#include <QPixmap>
#include <QMutexLocker>
#include <QTimer>
#include <QRegion>
#include <QBitmap>
#include <KConfig>
#include <KGlobal>
@@ -33,6 +23,11 @@
#include "connectioncontroller.h"
#include "connectioncontroller.moc"
#include "events.h"
#include "invitationmanager.h"
#include "krfbserver.h"
#include "framebuffer.h"
#include <X11/Xutil.h>
const int UPDATE_TIME = 100;
@@ -145,20 +140,7 @@ static bool checkPassword(const QString &p, unsigned char *ochallenge, const cha
ConnectionController::ConnectionController(int connFd, KrfbServer *parent)
: QObject(parent), fd(connFd), server(parent), fb(0)
{
#if 0
framebufferImage = XGetImage(QX11Info::display(), QApplication::desktop()->winId(),
0, 0,
QApplication::desktop()->width(),
QApplication::desktop()->height(),
AllPlanes,
ZPixmap);
#endif
QTimer *t = new QTimer(this);
connect(t, SIGNAL(timeout()), SLOT(updateFrameBuffer()));
fbImage = QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
updateFrameBuffer();
t->start(UPDATE_TIME);
fb = new FrameBuffer(QApplication::desktop()->winId(), this);
}
@@ -224,7 +206,6 @@ enum rfbNewClientAction ConnectionController::handleNewClient(rfbClientPtr cl)
bool allowDesktopControl = srvconf.readEntry("allowDesktopControl",false);
bool askOnConnect = srvconf.readEntry("askOnConnect",false);
client = cl;
int socket = cl->sock;
// cl->negotiationFinishedHook = negotiationFinishedHook; ???
@@ -265,7 +246,6 @@ enum rfbNewClientAction ConnectionController::handleNewClient(rfbClientPtr cl)
void ConnectionController::sendKNotifyEvent(const QString & name, const QString & desc)
{
kDebug() << "notification: " << name << " " << desc << endl;
emit notification(name, desc);
}
@@ -274,22 +254,27 @@ void ConnectionController::sendSessionEstablished()
emit sessionEstablished("BAH");
}
void ConnectionController::handleKeyEvent(bool down, KeySym keySym)
void ConnectionController::handleKeyEvent(bool down, rfbKeySym keySym)
{
KeyboardEvent ev(down, keySym);
ev.exec();
}
void ConnectionController::handlePointerEvent(int bm, int x, int y)
{
PointerEvent ev(bm, x, y);
ev.exec();
}
void ConnectionController::handleClientGone()
{
kDebug() << "Client gone" << endl;
rfbCloseClient(client);
}
void ConnectionController::clipboardToServer(const QString &)
void ConnectionController::clipboardToServer(const QString &s)
{
ClipboardEvent ev(this, s);
ev.exec();
}
@@ -297,66 +282,23 @@ void ConnectionController::run()
{
kDebug() << "starting server connection" << endl;
connect(this, SIGNAL(sessionEstablished(QString)), server, SIGNAL(sessionEstablished(QString)));
connect(this, SIGNAL(notification(QString,QString)), server, SLOT(handleNotifications(QString, QString)));
#if 0
int w = framebufferImage->width;
int h = framebufferImage->height;
char *fb = framebufferImage->data;
int w = fb->width();
int h = fb->height();
int depth = fb->depth();
rfbLogEnable(0);
server = rfbGetScreen(0, 0, w, h,
framebufferImage->bits_per_pixel,
8,
framebufferImage->bits_per_pixel/8);
kDebug() << "acquired framebuffer" << endl;
server->paddedWidthInBytes = framebufferImage->bytes_per_line;
kDebug() << "image depth: " << framebufferImage->bits_per_pixel << endl;
kDebug() << "image size: " << w << "x" << h << endl;
kDebug() << "bytes per line: " << framebufferImage->bytes_per_line << endl;
#else
int w = fbImage.width();
int h = fbImage.height();
//fb = (char *)fbImage.bits();
rfbLogEnable(0);
screen = rfbGetScreen(0, 0, w, h,
8,
3,
fbImage.depth()/8);
screen = rfbGetScreen(0, 0, w, h, 8, 3,depth / 8);
screen->screenData = (void *)this;
screen->paddedWidthInBytes = fbImage.bytesPerLine();
screen->paddedWidthInBytes = w * 4;
screen->serverFormat.bitsPerPixel = fbImage.depth();
screen->serverFormat.depth = fbImage.depth();
screen->serverFormat.trueColour = true;
fb->getServerFormat(screen->serverFormat);
screen->serverFormat.bigEndian = false;
screen->serverFormat.redShift = 16;
screen->serverFormat.greenShift = 8;
screen->serverFormat.blueShift = 0;
screen->serverFormat.redMax = 0xff;
screen->serverFormat.greenMax = 0xff;
screen->serverFormat.blueMax = 0xff;
kDebug() << "acquired framebuffer" << endl;
kDebug() << "image format: " << fbImage.format() << endl;
kDebug() << "image depth: " << fbImage.depth() << endl;
kDebug() << "image size: " << fbImage.rect() << endl;
kDebug() << "bytes per line: " << fbImage.bytesPerLine() << endl;
#endif
screen->frameBuffer = fb;
screen->frameBuffer = fb->data();
screen->autoPort = true;
screen->inetdSock = fd;
@@ -378,58 +320,26 @@ void ConnectionController::run()
rfbInitServer(screen);
while (true) {
foreach(QRect r, fb->modifiedTiles()) {
rfbMarkRectAsModified(screen, r.top(), r.left(), r.left() + r.width(), r.top() + r.height());
}
fb->modifiedTiles().clear();
rfbProcessEvents(screen, 100);
qApp->processEvents();
}
/*
QTimer *t = new QTimer();
connect(t, SIGNAL(timeout()), SLOT(processEvents()));
rfbProcessEvents(screen, 100);
rfbProcessEvents(screen, 10);
t->start(UPDATE_TIME);
*/
}
void ConnectionController::updateFrameBuffer()
{
QImage img = QPixmap::grabWindow(QApplication::desktop()->winId()).toImage();
QSize imgSize = img.size();
if (!fb){
fb = new char[img.numBytes()];
}
// verify what part of the image need to be marked as changed
// fbImage is the previous version of the image,
// img is the current one
#if 1 // This is actually slower than updating the whole desktop...
QImage map(imgSize, QImage::Format_Mono);
map.fill(0);
for (int x = 0; x < imgSize.width(); x++) {
for (int y = 0; y < imgSize.height(); y++) {
if (img.pixel(x,y) != fbImage.pixel(x,y)) {
map.setPixel(x,y,1);
}
}
}
QRegion r(QBitmap::fromImage(map));
#else
#endif
tiles = tiles + r.rects();
memcpy(fb, (const char*)img.bits(), img.numBytes());
fbImage = img;
}
void ConnectionController::processEvents()
{
foreach(QRect r, tiles) {
rfbMarkRectAsModified(screen, r.top(), r.left(), r.left() + r.width(), r.top() + r.height());
}
tiles.clear();
rfbProcessEvents(screen, 100);
}

View File

@@ -18,9 +18,8 @@
#include <rfb/rfb.h>
#include <X11/Xlib.h>
class KrfbServer;
class FrameBuffer;
/**
@author Alessandro Praduroux <pradu@pradu.it>
@@ -38,7 +37,7 @@ public:
void sendKNotifyEvent(const QString &name, const QString &desc);
void handleNegotiationFinished(struct _rfbClientRec *cl);
void handleKeyEvent(bool down, KeySym keySym);
void handleKeyEvent(bool down , rfbKeySym keySym );
void handlePointerEvent( int bm, int x, int y);
void handleClientGone();
void clipboardToServer(const QString &);
@@ -51,17 +50,13 @@ Q_SIGNALS:
public Q_SLOTS:
void updateFrameBuffer();
void processEvents();
private:
int fd;
KrfbServer *server;
XImage *framebufferImage;
QImage fbImage;
char *fb;
FrameBuffer *fb;
rfbScreenInfoPtr screen;
QVector<QRect> tiles;
QString remoteIp;
rfbClientPtr client;
};

View File

@@ -33,14 +33,19 @@ const int KeyboardEvent::LEFTSHIFT = 1;
const int KeyboardEvent::RIGHTSHIFT = 2;
const int KeyboardEvent::ALTGR = 4;
char KeyboardEvent::ModifierState;
bool KeyboardEvent::initDone = false;
KeyboardEvent::KeyboardEvent(bool d, KeySym k)
: down(d), keySym(k)
{
initKeycodes();
}
void KeyboardEvent::initKeycodes()
{
if (initDone) return;
initDone = true;
KeySym key,*keymap;
int i,j,minkey,maxkey,syms_per_keycode;
@@ -171,7 +176,7 @@ void PointerEvent::exec() {
}
ClipboardEvent::ClipboardEvent(CurrentController *c, const QString &ctext)
ClipboardEvent::ClipboardEvent(ConnectionController *c, const QString &ctext)
:controller(c),text(ctext)
{
}

View File

@@ -13,7 +13,7 @@
#include <X11/Xlib.h>
class CurrentController;
class ConnectionController;
class VNCEvent {
public:
@@ -32,6 +32,7 @@ class KeyboardEvent : public VNCEvent {
static const int RIGHTSHIFT;
static const int ALTGR;
static char ModifierState;
static bool initDone;
static void tweakModifiers(signed char mod, bool down);
public:
@@ -53,10 +54,10 @@ public:
};
class ClipboardEvent : public VNCEvent {
CurrentController *controller;
ConnectionController *controller;
QString text;
public:
ClipboardEvent(CurrentController *c, const QString &text);
ClipboardEvent(ConnectionController *c, const QString &text);
virtual void exec();
};

111
framebuffer.cpp Normal file
View File

@@ -0,0 +1,111 @@
/* This file is part of the KDE project
Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; version 2
of the License.
*/
#include "framebuffer.h"
#include "framebuffer.moc"
#include <QTimer>
#include <QRegion>
#include <QPixmap>
#include <QBitmap>
const int UPDATE_TIME = 500;
FrameBuffer::FrameBuffer(WId id, QObject *parent)
: QObject(parent), win(id)
{
fbImage = QPixmap::grabWindow(win).toImage();
fb = new char[fbImage.numBytes()];
QTimer *t = new QTimer(this);
connect(t, SIGNAL(timeout()), SLOT(updateFrameBuffer()));
t->start(UPDATE_TIME);
}
FrameBuffer::~FrameBuffer()
{
delete fb;
}
char * FrameBuffer::data()
{
return fb;
}
void FrameBuffer::updateFrameBuffer()
{
QImage img = QPixmap::grabWindow(win).toImage();
QSize imgSize = img.size();
// verify what part of the image need to be marked as changed
// fbImage is the previous version of the image,
// img is the current one
#if 0 // This is actually slower than updating the whole desktop...
QImage map(imgSize, QImage::Format_Mono);
map.fill(0);
for (int x = 0; x < imgSize.width(); x++) {
for (int y = 0; y < imgSize.height(); y++) {
if (img.pixel(x,y) != fbImage.pixel(x,y)) {
map.setPixel(x,y,1);
}
}
}
QRegion r(QBitmap::fromImage(map));
tiles = tiles + r.rects();
#else
tiles.append(img.rect());
#endif
memcpy(fb, (const char*)img.bits(), img.numBytes());
fbImage = img;
}
QVector< QRect > & FrameBuffer::modifiedTiles()
{
return tiles;
}
int FrameBuffer::width()
{
return fbImage.width();
}
int FrameBuffer::height()
{
return fbImage.height();
}
void FrameBuffer::getServerFormat(rfbPixelFormat & format)
{
format.bitsPerPixel = 32;
format.depth = 32;
format.trueColour = true;
format.bigEndian = false;
format.redShift = 16;
format.greenShift = 8;
format.blueShift = 0;
format.redMax = 0xff;
format.greenMax = 0xff;
format.blueMax = 0xff;
}
int FrameBuffer::depth()
{
return fbImage.depth();
}

51
framebuffer.h Normal file
View File

@@ -0,0 +1,51 @@
/* This file is part of the KDE project
Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; version 2
of the License.
*/
#ifndef FRAMEBUFFER_H
#define FRAMEBUFFER_H
#include <QObject>
#include <QImage>
#include <QRect>
#include <QVector>
#include <rfb/rfb.h>
/**
@author Alessandro Praduroux <pradu@pradu.it>
*/
class FrameBuffer : public QObject
{
Q_OBJECT
public:
FrameBuffer(WId id, QObject *parent = 0);
~FrameBuffer();
char * data();
QVector<QRect> &modifiedTiles();
int width();
int height();
int depth();
void getServerFormat(rfbPixelFormat &format);
public Q_SLOTS:
void updateFrameBuffer();
private:
WId win;
char *fb;
QImage fbImage;
QVector<QRect> tiles;
};
#endif