mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-24 02:42:52 +00:00
387 lines
10 KiB
C++
387 lines
10 KiB
C++
/* 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; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
*/
|
|
|
|
#include "x11framebuffer.h"
|
|
#include "moc_x11framebuffer.cpp"
|
|
|
|
#include <config-krfb.h>
|
|
|
|
#include <QX11Info>
|
|
#include <QApplication>
|
|
#include <QDesktopWidget>
|
|
|
|
#include <KApplication>
|
|
#include <KDebug>
|
|
|
|
#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;
|
|
#else
|
|
d->useShm = false;
|
|
#endif
|
|
d->running = false;
|
|
d->framebufferImage = XGetImage(QX11Info::display(),
|
|
id,
|
|
0,
|
|
0,
|
|
QApplication::desktop()->width(), //arg, must get a widget ???
|
|
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
|
|
<< " (sent: " << d->framebufferImage->width * 4 << ")";
|
|
|
|
fb = d->framebufferImage->data;
|
|
#ifdef HAVE_XDAMAGE
|
|
d->ev = new EvWidget(this);
|
|
kapp->installX11EventFilter(d->ev);
|
|
#endif
|
|
}
|
|
|
|
|
|
X11FrameBuffer::~X11FrameBuffer()
|
|
{
|
|
XDestroyImage(d->framebufferImage);
|
|
#ifdef HAVE_XDAMAGE
|
|
kapp->removeX11EventFilter(d->ev);
|
|
#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;
|
|
fb = 0; // already deleted by XDestroyImage
|
|
}
|
|
|
|
|
|
int X11FrameBuffer::depth()
|
|
{
|
|
return d->framebufferImage->depth;
|
|
}
|
|
|
|
int X11FrameBuffer::height()
|
|
{
|
|
return d->framebufferImage->height;
|
|
}
|
|
|
|
int X11FrameBuffer::width()
|
|
{
|
|
return d->framebufferImage->width;
|
|
}
|
|
|
|
int X11FrameBuffer::paddedWidth()
|
|
{
|
|
return d->framebufferImage->bytes_per_line;
|
|
}
|
|
|
|
void X11FrameBuffer::getServerFormat(rfbPixelFormat &format)
|
|
{
|
|
format.bitsPerPixel = d->framebufferImage->bits_per_pixel;
|
|
format.depth = d->framebufferImage->depth;
|
|
format.trueColour = true;
|
|
format.bigEndian = ((d->framebufferImage->bitmap_bit_order == MSBFirst) ? true : false);
|
|
|
|
if (format.bitsPerPixel == 8) {
|
|
format.redShift = 0;
|
|
format.greenShift = 3;
|
|
format.blueShift = 6;
|
|
format.redMax = 7;
|
|
format.greenMax = 7;
|
|
format.blueMax = 3;
|
|
} else {
|
|
format.redShift = 0;
|
|
|
|
if (d->framebufferImage->red_mask)
|
|
while (!(d->framebufferImage->red_mask & (1 << format.redShift))) {
|
|
format.redShift++;
|
|
}
|
|
|
|
format.greenShift = 0;
|
|
|
|
if (d->framebufferImage->green_mask)
|
|
while (!(d->framebufferImage->green_mask & (1 << format.greenShift))) {
|
|
format.greenShift++;
|
|
}
|
|
|
|
format.blueShift = 0;
|
|
|
|
if (d->framebufferImage->blue_mask)
|
|
while (!(d->framebufferImage->blue_mask & (1 << format.blueShift))) {
|
|
format.blueShift++;
|
|
}
|
|
|
|
format.redMax = d->framebufferImage->red_mask >> format.redShift;
|
|
format.greenMax = d->framebufferImage->green_mask >> format.greenShift;
|
|
format.blueMax = d->framebufferImage->blue_mask >> format.blueShift;
|
|
}
|
|
}
|
|
|
|
void X11FrameBuffer::handleXDamage(XEvent *event)
|
|
{
|
|
#ifdef HAVE_XDAMAGE
|
|
XDamageNotifyEvent *dev = (XDamageNotifyEvent *)event;
|
|
QRect r(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
|
|
tiles.append(r);
|
|
|
|
/*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();
|
|
foreach(const QRect & r, cpy) {
|
|
if (tiles.size() > 0) {
|
|
for (int i = 0; i < tiles.size(); i++) {
|
|
// kDebug() << r << tiles[i];
|
|
if (r.intersects(tiles[i])) {
|
|
tiles[i] |= r;
|
|
inserted = true;
|
|
break;
|
|
// kDebug() << "merged into " << tiles[i];
|
|
}
|
|
}
|
|
|
|
if (!inserted) {
|
|
tiles.append(r);
|
|
// kDebug() << "appended " << r;
|
|
}
|
|
} else {
|
|
// kDebug() << "appended " << r;
|
|
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();
|
|
}
|
|
|
|
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(const QRect & r, tiles) {
|
|
// kDebug() << r;
|
|
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;
|
|
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(const 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;
|
|
// kDebug() << tiles.size();
|
|
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)
|
|
{
|
|
#ifdef HAVE_XDAMAGE
|
|
int er;
|
|
XDamageQueryExtension(QX11Info::display(), &xdamageBaseEvent, &er);
|
|
#endif
|
|
}
|
|
|
|
bool EvWidget::x11Event(XEvent *event)
|
|
{
|
|
#ifdef HAVE_XDAMAGE
|
|
|
|
if (event->type == xdamageBaseEvent + XDamageNotify) {
|
|
fb->handleXDamage(event);
|
|
return true;
|
|
}
|
|
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
|
|
|