mirror of
https://github.com/KDE/krfb
synced 2026-07-01 07:41:17 -07:00
X11 framebuffer implementation based on XDamage and XShm completed.
Still has some weirdness when updating large portions of the screen svn path=/trunk/KDE/kdenetwork/krfb/; revision=654248
This commit is contained in:
@@ -3,6 +3,7 @@ project(krfb)
|
||||
|
||||
check_symbol_exists(rfbInitServer "rfb/rfb.h" HAVE_LIBVNCSERVER)
|
||||
macro_bool_to_01(X11_Xdamage_FOUND HAVE_XDAMAGE)
|
||||
macro_bool_to_01(X11_XShm_FOUND HAVE_XSHM)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-krfb.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-krfb.h )
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}) # for config-krfb.h
|
||||
|
||||
|
||||
@@ -6,3 +6,6 @@
|
||||
|
||||
/* Define if XDamage is available */
|
||||
#cmakedefine HAVE_XDAMAGE 1
|
||||
|
||||
/* Define if XShm is available */
|
||||
#cmakedefine HAVE_XSHM 1
|
||||
|
||||
@@ -183,6 +183,7 @@ void ConnectionController::handlePointerEvent(int bm, int x, int y)
|
||||
|
||||
void ConnectionController::handleClientGone()
|
||||
{
|
||||
emit clientDisconnected(this);
|
||||
kDebug() << "client gone" << endl;
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
Q_SIGNALS:
|
||||
void sessionEstablished(QString);
|
||||
void notification(QString, QString);
|
||||
void clientDisconnected(ConnectionController *);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void dialogAccepted();
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "framebuffer.h"
|
||||
#include "framebuffer.moc"
|
||||
|
||||
#include "config-krfb.h"
|
||||
#include <config-krfb.h>
|
||||
|
||||
#include <QX11Info>
|
||||
|
||||
@@ -42,9 +42,11 @@ char * FrameBuffer::data()
|
||||
return fb;
|
||||
}
|
||||
|
||||
QVector< QRect > & FrameBuffer::modifiedTiles()
|
||||
QList< QRect > FrameBuffer::modifiedTiles()
|
||||
{
|
||||
return tiles;
|
||||
QList<QRect> ret = tiles;
|
||||
tiles.clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int FrameBuffer::width()
|
||||
@@ -75,6 +77,7 @@ FrameBuffer * FrameBuffer::getFrameBuffer(WId id, QObject * parent)
|
||||
}
|
||||
#endif
|
||||
return new QtFrameBuffer(id, parent);
|
||||
|
||||
}
|
||||
|
||||
int FrameBuffer::paddedWidth()
|
||||
@@ -82,4 +85,12 @@ int FrameBuffer::paddedWidth()
|
||||
return width() * depth() / 8;
|
||||
}
|
||||
|
||||
void FrameBuffer::startMonitor()
|
||||
{
|
||||
}
|
||||
|
||||
void FrameBuffer::stopMonitor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QRect>
|
||||
#include <QVector>
|
||||
#include <QList>
|
||||
#include <QWidget>
|
||||
|
||||
#include <rfb/rfb.h>
|
||||
@@ -32,11 +32,13 @@ public:
|
||||
|
||||
char * data();
|
||||
|
||||
QVector<QRect> &modifiedTiles();
|
||||
virtual QList<QRect> modifiedTiles();
|
||||
virtual int paddedWidth();
|
||||
virtual int width();
|
||||
virtual int height();
|
||||
virtual int depth();
|
||||
virtual void startMonitor();
|
||||
virtual void stopMonitor();
|
||||
|
||||
virtual void getServerFormat(rfbPixelFormat &format);
|
||||
|
||||
@@ -45,7 +47,7 @@ protected:
|
||||
|
||||
WId win;
|
||||
char *fb;
|
||||
QVector<QRect> tiles;
|
||||
QList<QRect> tiles;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -116,12 +116,13 @@ static void clipboardHook(char* str,int len, rfbClientPtr cl)
|
||||
class KrfbServer::KrfbServerP {
|
||||
|
||||
public:
|
||||
KrfbServerP() : fb(0), screen(0) {};
|
||||
KrfbServerP() : fb(0), screen(0), numClients(0) {};
|
||||
|
||||
FrameBuffer *fb;
|
||||
QList< QPointer<ConnectionController> > controllers;
|
||||
rfbScreenInfoPtr screen;
|
||||
bool running;
|
||||
int numClients;
|
||||
};
|
||||
|
||||
|
||||
@@ -198,9 +199,8 @@ void KrfbServer::startListening()
|
||||
|
||||
while (d->running) {
|
||||
foreach(QRect r, d->fb->modifiedTiles()) {
|
||||
rfbMarkRectAsModified(screen, r.top(), r.left(), r.left() + r.width(), r.top() + r.height());
|
||||
rfbMarkRectAsModified(screen, r.x(), r.y(), r.right(), r.bottom());
|
||||
}
|
||||
d->fb->modifiedTiles().clear();
|
||||
rfbProcessEvents(screen, 100);
|
||||
qApp->processEvents();
|
||||
}
|
||||
@@ -226,11 +226,16 @@ void KrfbServer::disconnectAndQuit()
|
||||
enum rfbNewClientAction KrfbServer::handleNewClient(struct _rfbClientRec * cl)
|
||||
{
|
||||
ConnectionController *cc = new ConnectionController(cl, this);
|
||||
if (d->numClients == 0) {
|
||||
d->fb->startMonitor();
|
||||
d->numClients++;
|
||||
}
|
||||
|
||||
d->controllers.append(cc);
|
||||
cc->setControlEnabled(KrfbConfig::allowDesktopControl());
|
||||
|
||||
connect(cc, SIGNAL(sessionEstablished(QString)), SIGNAL(sessionEstablished(QString)));
|
||||
connect(cc, SIGNAL(clientDisconnected(ConnectionController *)),SLOT(clientDisconnected(ConnectionController *)));
|
||||
|
||||
return cc->handleNewClient();
|
||||
}
|
||||
@@ -273,5 +278,15 @@ bool KrfbServer::checkX11Capabilities() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void KrfbServer::clientDisconnected(ConnectionController *cc)
|
||||
{
|
||||
kDebug() << "clients--: " << d->numClients << endl;
|
||||
d->numClients--;
|
||||
if (d->numClients == 0) {
|
||||
d->fb->stopMonitor();
|
||||
}
|
||||
disconnect(cc, SIGNAL(clientDisconnected(ConnectionController)),this, SLOT(clientDisconnected(ConnectionController)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <rfb/rfb.h>
|
||||
|
||||
class FrameBuffer;
|
||||
|
||||
class ConnectionController;
|
||||
/**
|
||||
This class implements the listening server for the RFB protocol.
|
||||
|
||||
@@ -45,6 +45,7 @@ public Q_SLOTS:
|
||||
void disconnectAndQuit();
|
||||
void updateSettings();
|
||||
void updatePassword();
|
||||
void clientDisconnected(ConnectionController *);
|
||||
|
||||
private:
|
||||
KrfbServer();
|
||||
|
||||
@@ -23,9 +23,8 @@ QtFrameBuffer::QtFrameBuffer(WId id, QObject *parent)
|
||||
{
|
||||
fbImage = QPixmap::grabWindow(win).toImage();
|
||||
fb = new char[fbImage.numBytes()];
|
||||
QTimer *t = new QTimer(this);
|
||||
t = new QTimer(this);
|
||||
connect(t, SIGNAL(timeout()), SLOT(updateFrameBuffer()));
|
||||
t->start(UPDATE_TIME);
|
||||
}
|
||||
|
||||
|
||||
@@ -103,3 +102,13 @@ int QtFrameBuffer::paddedWidth()
|
||||
return fbImage.width() * 4;
|
||||
}
|
||||
|
||||
void QtFrameBuffer::startMonitor()
|
||||
{
|
||||
t->start(UPDATE_TIME);
|
||||
}
|
||||
|
||||
void QtFrameBuffer::stopMonitor()
|
||||
{
|
||||
t->stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <QImage>
|
||||
#include "framebuffer.h"
|
||||
|
||||
class QTimer;
|
||||
/**
|
||||
@author Alessandro Praduroux <pradu@pradu.it>
|
||||
*/
|
||||
@@ -29,13 +30,15 @@ public:
|
||||
virtual int width();
|
||||
virtual int paddedWidth();
|
||||
virtual void getServerFormat(rfbPixelFormat& format);
|
||||
virtual void startMonitor();
|
||||
virtual void stopMonitor();
|
||||
|
||||
public Q_SLOTS:
|
||||
void updateFrameBuffer();
|
||||
|
||||
private:
|
||||
QImage fbImage;
|
||||
|
||||
QTimer *t;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
|
||||
#include "x11framebuffer.h"
|
||||
#include "x11framebuffer.moc"
|
||||
#include "config-krfb.h"
|
||||
|
||||
#include <config-krfb.h>
|
||||
|
||||
#include <QX11Info>
|
||||
#include <QApplication>
|
||||
@@ -17,25 +18,47 @@
|
||||
|
||||
#include <KApplication>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#ifdef HAVE_XDAMAGE
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XSHM
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
#endif
|
||||
|
||||
class X11FrameBuffer::P {
|
||||
|
||||
public:
|
||||
#ifdef HAVE_XDAMAGE
|
||||
Damage damage;
|
||||
#endif
|
||||
#ifdef HAVE_XSHM
|
||||
XShmSegmentInfo shminfo;
|
||||
#endif
|
||||
|
||||
XImage *framebufferImage;
|
||||
XImage *updateTile;
|
||||
EvWidget *ev;
|
||||
bool useShm;
|
||||
int xdamageBaseEvent;
|
||||
bool running;
|
||||
};
|
||||
|
||||
X11FrameBuffer::X11FrameBuffer(WId id, QObject* parent)
|
||||
:FrameBuffer(id, parent), d(new X11FrameBuffer::P)
|
||||
{
|
||||
#ifdef HAVE_XSHM
|
||||
d->useShm = XShmQueryExtension(QX11Info::display());
|
||||
kDebug() << "shm: " << d->useShm << endl;
|
||||
#else
|
||||
d->useShm = false;
|
||||
#endif
|
||||
d->running = false;
|
||||
d->framebufferImage = XGetImage(QX11Info::display(),
|
||||
id,
|
||||
0,
|
||||
@@ -44,7 +67,29 @@ X11FrameBuffer::X11FrameBuffer(WId id, QObject* parent)
|
||||
QApplication::desktop()->height(),
|
||||
AllPlanes,
|
||||
ZPixmap);
|
||||
if (d->useShm) {
|
||||
#ifdef HAVE_XSHM
|
||||
d->updateTile = XShmCreateImage(QX11Info::display(),
|
||||
DefaultVisual( QX11Info::display(), 0 ),
|
||||
d->framebufferImage->bits_per_pixel,
|
||||
ZPixmap,
|
||||
NULL,
|
||||
&d->shminfo,
|
||||
32,
|
||||
32);
|
||||
d->shminfo.shmid = shmget(IPC_PRIVATE,
|
||||
d->updateTile->bytes_per_line * d->updateTile->height,
|
||||
IPC_CREAT | 0777);
|
||||
|
||||
d->shminfo.shmaddr = d->updateTile->data = (char *)
|
||||
shmat(d->shminfo.shmid, 0, 0);
|
||||
d->shminfo.readOnly = False;
|
||||
|
||||
XShmAttach(QX11Info::display(), &d->shminfo);
|
||||
#endif
|
||||
} else {
|
||||
;
|
||||
}
|
||||
kDebug() << "Got image. bpp: " << d->framebufferImage->bits_per_pixel
|
||||
<< ", depth: " << d->framebufferImage->depth
|
||||
<< ", padded width: " << d->framebufferImage->bytes_per_line
|
||||
@@ -54,8 +99,6 @@ X11FrameBuffer::X11FrameBuffer(WId id, QObject* parent)
|
||||
fb = d->framebufferImage->data;
|
||||
#ifdef HAVE_XDAMAGE
|
||||
d->ev = new EvWidget(this);
|
||||
d->damage = XDamageCreate(QX11Info::display(), id, XDamageReportRawRectangles);
|
||||
XDamageSubtract(QX11Info::display(),d->damage, None, None);
|
||||
kapp->installX11EventFilter(d->ev);
|
||||
#endif
|
||||
}
|
||||
@@ -66,7 +109,12 @@ X11FrameBuffer::~X11FrameBuffer()
|
||||
XDestroyImage(d->framebufferImage);
|
||||
#ifdef HAVE_XDAMAGE
|
||||
kapp->removeX11EventFilter(d->ev);
|
||||
XDamageDestroy(QX11Info::display(),d->damage);
|
||||
#endif
|
||||
#ifdef HAVE_XSHM
|
||||
XShmDetach(QX11Info::display(), &d->shminfo);
|
||||
XDestroyImage(d->updateTile);
|
||||
shmdt(d->shminfo.shmaddr);
|
||||
shmctl(d->shminfo.shmid, IPC_RMID, 0);
|
||||
#endif
|
||||
delete d;
|
||||
}
|
||||
@@ -132,25 +180,151 @@ void X11FrameBuffer::handleXDamage(XEvent * event)
|
||||
QRect r(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
|
||||
tiles.append(r);
|
||||
|
||||
XGetSubImage(QX11Info::display(),
|
||||
win,
|
||||
dev->area.x,
|
||||
dev->area.y,
|
||||
dev->area.width,
|
||||
dev->area.height,
|
||||
AllPlanes,
|
||||
ZPixmap,
|
||||
d->framebufferImage,
|
||||
dev->area.x,
|
||||
dev->area.y);
|
||||
|
||||
if (!dev->more) {
|
||||
/*if (!dev->more) {
|
||||
XDamageSubtract(QX11Info::display(),d->damage, None, None);
|
||||
}
|
||||
}*/
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void X11FrameBuffer::cleanupRects() {
|
||||
|
||||
QList<QRect> cpy = tiles;
|
||||
bool inserted = false;
|
||||
tiles.clear();
|
||||
// kDebug() << "before cleanup: " << cpy.size() << endl;
|
||||
foreach (QRect r, cpy) {
|
||||
if (tiles.size() > 0) {
|
||||
for(int i = 0; i < tiles.size(); i++) {
|
||||
// kDebug() << r << tiles[i] << endl;
|
||||
if (r.intersects(tiles[i])) {
|
||||
tiles[i] |= r;
|
||||
inserted = true;
|
||||
break;
|
||||
// kDebug() << "merged into " << tiles[i] << endl;
|
||||
}
|
||||
}
|
||||
if (!inserted) {
|
||||
tiles.append(r);
|
||||
// kDebug() << "appended " << r << endl;
|
||||
}
|
||||
} else {
|
||||
// kDebug() << "appended " << r << endl;
|
||||
tiles.append(r);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < tiles.size(); i++) {
|
||||
tiles[i].adjust(-30,-30,30,30);
|
||||
if (tiles[i].top() < 0){
|
||||
tiles[i].setTop(0);
|
||||
}
|
||||
if (tiles[i].left() < 0){
|
||||
tiles[i].setLeft(0);
|
||||
}
|
||||
if (tiles[i].bottom() > d->framebufferImage->height) {
|
||||
tiles[i].setBottom(d->framebufferImage->height);
|
||||
}
|
||||
if (tiles[i].right() > d->framebufferImage->width) {
|
||||
tiles[i].setRight(d->framebufferImage->width);
|
||||
}
|
||||
}
|
||||
// kDebug() << "after cleanup: " << tiles.size() << endl;
|
||||
}
|
||||
|
||||
void X11FrameBuffer::acquireEvents() {
|
||||
|
||||
XEvent ev;
|
||||
while (XCheckTypedEvent(QX11Info::display(), d->xdamageBaseEvent+XDamageNotify, &ev)) {
|
||||
handleXDamage(&ev);
|
||||
}
|
||||
XDamageSubtract(QX11Info::display(),d->damage, None, None);
|
||||
}
|
||||
|
||||
QList< QRect > X11FrameBuffer::modifiedTiles()
|
||||
{
|
||||
QList<QRect> ret;
|
||||
if (!d->running) return ret;
|
||||
kapp->processEvents(); // try to make sure every damage event goes trough;
|
||||
cleanupRects();
|
||||
QRect gl;
|
||||
//d->useShm = false;
|
||||
if (tiles.size() > 0) {
|
||||
if (d->useShm) {
|
||||
#ifdef HAVE_XSHM
|
||||
|
||||
foreach(QRect r, tiles) {
|
||||
// kDebug() << r << endl;
|
||||
gl |= r;
|
||||
int y = r.y();
|
||||
int x = r.x();
|
||||
while (x < r.right() ) {
|
||||
while (y < r.bottom() ) {
|
||||
if (y+d->updateTile->height > d->framebufferImage->height) {
|
||||
y = d->framebufferImage->height - d->updateTile->height;
|
||||
}
|
||||
if (x+d->updateTile->width > d->framebufferImage->width) {
|
||||
x = d->framebufferImage->width - d->updateTile->width;
|
||||
}
|
||||
// kDebug() << "x: " << x << " (" << r.x() << ") y: " << y << " (" << r.y() << ") " << r << endl;
|
||||
XShmGetImage(QX11Info::display(), win, d->updateTile, x, y, AllPlanes);
|
||||
int pxsize = d->framebufferImage->bits_per_pixel / 8;
|
||||
char *dest = fb + ((d->framebufferImage->bytes_per_line * y) + (x*pxsize));
|
||||
char *src = d->updateTile->data;
|
||||
for (int i = 0; i < d->updateTile->height; i++) {
|
||||
memcpy(dest, src, d->updateTile->bytes_per_line);
|
||||
dest += d->framebufferImage->bytes_per_line;
|
||||
src += d->updateTile->bytes_per_line;
|
||||
}
|
||||
y += d->updateTile->height;
|
||||
}
|
||||
x += d->updateTile->width;
|
||||
y = r.y();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
foreach(QRect r, tiles) {
|
||||
XGetSubImage(QX11Info::display(),
|
||||
win,
|
||||
r.left(),
|
||||
r.top(),
|
||||
r.width(),
|
||||
r.height(),
|
||||
AllPlanes,
|
||||
ZPixmap,
|
||||
d->framebufferImage,
|
||||
r.left(),
|
||||
r.top()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// kDebug() << "tot: " << gl << endl;
|
||||
// kDebug() << tiles.size() << endl;
|
||||
ret = tiles;
|
||||
tiles.clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void X11FrameBuffer::startMonitor()
|
||||
{
|
||||
d->running = true;
|
||||
#ifdef HAVE_XDAMAGE
|
||||
d->damage = XDamageCreate(QX11Info::display(), win, XDamageReportRawRectangles);
|
||||
XDamageSubtract(QX11Info::display(),d->damage, None, None);
|
||||
#endif
|
||||
}
|
||||
|
||||
void X11FrameBuffer::stopMonitor()
|
||||
{
|
||||
d->running = false;
|
||||
#ifdef HAVE_XDAMAGE
|
||||
XDamageDestroy(QX11Info::display(),d->damage);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
EvWidget::EvWidget(X11FrameBuffer * x11fb)
|
||||
:QWidget(0), fb(x11fb)
|
||||
{
|
||||
|
||||
@@ -39,14 +39,21 @@ public:
|
||||
|
||||
~X11FrameBuffer();
|
||||
|
||||
virtual QList<QRect> modifiedTiles();
|
||||
virtual int depth();
|
||||
virtual int height();
|
||||
virtual int width();
|
||||
virtual int paddedWidth();
|
||||
virtual void getServerFormat(rfbPixelFormat& format);
|
||||
virtual void startMonitor();
|
||||
virtual void stopMonitor();
|
||||
|
||||
|
||||
void handleXDamage( XEvent *event);
|
||||
private:
|
||||
void cleanupRects();
|
||||
void acquireEvents();
|
||||
|
||||
class P;
|
||||
P * const d;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user