X11 screenshot of active window fails for GTK windows - c++

this is a sub-project of a much larger research project. I am trying to take screenshots of an active window (browser) every 100ms, which are then to be stored in memory for OpenCV processing. I found from a similar question a solution to taking a screenshot, and I'm currently playing with the code to see if I can use it. The following snippet seems to be working either when taking an entire Desktop screenshot, or a specific Window screenshot, but it doesn't work for GTK windows. I've tried to take a screenshot of Iceweasel & Nautilus on Debian Squeeze, and it simply doesn't work. I am a total noob in X11, and don't know how to check for errors, or if there is something I am missing for GTK, as this seems to work for QT windows.
typedef int (*handler)(Display *, XErrorEvent *);
int handleX11Error(Display *d, XErrorEvent *er)
{
std::cout << "X11 Error: " << er->error_code << std::endl;
}
int main()
{
std::cout << "Sleeping 5 seconds" << std::endl;
// we may need to sleep if we want to focus another window.
sleep(5);
std::cout << "taking screenshot" << std::endl;
Display *display = XOpenDisplay(NULL);
//Window root = DefaultRootWindow(display);
XWindowAttributes gwa;
int revert = RevertToNone;
Window active;
XErrorEvent *error;
handler myHandler = &handleX11Error;
XSetErrorHandler(myHandler);
// X11 - Get Window that has focus
XGetInputFocus(display,&active,&revert);
//XGetWindowAttributes(display, root, &gwa);
if (!XGetWindowAttributes(display, active, &gwa))
std::cout << "XGetWindowAttributes failed" << std::endl;
int width = gwa.width;
int height = gwa.height;
//XImage *image = XGetImage(display,root, 0,0 , width,height,AllPlanes, ZPixmap);
XImage *image = XGetImage(display,active, 0,0 , width,height,XAllPlanes(), ZPixmap);
unsigned char *array = new unsigned char[width * height * 3];
CImg<unsigned char> pic(array,width,height,1,3);
for (int x = 0; x < width; x++){
for (int y = 0; y < height ; y++){
pic(x,y,0) = (XGetPixel(image,x,y) & image->red_mask ) >> 16;
pic(x,y,1) = (XGetPixel(image,x,y) & image->green_mask ) >> 8;
pic(x,y,2) = XGetPixel(image,x,y) & image->blue_mask;
}
}
delete[] array;
pic.save_png("blah.png");
std::cout << "Finished" << std::endl;
return 0;
}
The above code works either for full desktop screenshots or QT. I get no error (don't know if I'm handling them correctly). Just an empty picture of a few bytes, which makes me think that one of the X functions fails (XGetInputFocus, XGetWindowAttributes, XGetImage), with my bet on XGetFocus not properly working.
What is it that I am missing, or, is there an alternative to this ?
Please note that I am running KDE (4.4.5) if it is of any importance.
UPDATE:
I have tried to take a screenshot using Qt4, and while it works fine, it runs in the same problem when trying to get focused windows from X11:
int main(int argc, char **argv)
{
sleep(5);
Display *display = XOpenDisplay(NULL);
int revert = RevertToNone;
Window active;
XGetInputFocus(display,&active,&revert);
QApplication app(argc, argv);
QPixmap pixmap = QPixmap::grabWindow(active);
pixmap.save("test.png","PNG");
QPushButton quit("Quit");
quit.resize(75, 30);
quit.setFont(QFont("Times", 18, QFont::Bold));
QObject::connect(&quit, SIGNAL(clicked()), &app, SLOT(quit()));
quit.show();
return app.exec();
}
I am therefore convinced, that it is XGetInputFocus() that somehow fails.

Since I haven't gotten any answers yet, and sice I've spend the better part of an entire day looking for a solution, I'd thought I'd share how I managed to get this working.
The system is Debian Squeeze, running KDE 4.4.5.
Apparently KDE and GTK apps don't play nice with eachother. Quoting people from other posts on stackoverflow and the internet in general, a non-kde application may not honor the _NET_WM_STATE, or it could be somethig else, I really don't know. But the fact that the GTK apps I tried did not work with the piece of code that all Qt4 apps worked, hints to an issue related to some form of reporting. Some rare (and a I really mean rare) solutions found on the net point that maybe X11 windows tree could be traversed to find the active window, but that seemed too complicated to me, and I read posts of people not getting succesful results.
What I came up with (which is bits and pieces of snippets found online) is the following using xdo (libxdo on Debian):
Display *display = XOpenDisplay(NULL);
Window active;
XWindowAttributes gwa;
// Use xdo to find the active window - care on the display !
xdo_t* xdocontext = xdo_new(0);
xdo_window_get_active(xdocontext, &active);
if(active){
XGetWindowAttributes(display, active, &gwa);
XImage *image = XGetImage(display,active, 0,0 , gwa.width,gwa.height,XAllPlanes(), ZPixmap);
unsigned char *array = new unsigned char[gwa.width * gwa.height * 3];
CImg<unsigned char> pic(array,gwa.width,gwa.height,1,3);
for (int x = 0; x < gwa.width; x++){
for (int y = 0; y < gwa.height ; y++){
pic(x,y,0) = (XGetPixel(image,x,y) & image->red_mask ) >> 16;
pic(x,y,1) = (XGetPixel(image,x,y) & image->green_mask ) >> 8;
pic(x,y,2) = XGetPixel(image,x,y) & image->blue_mask;
}
}
delete[] array;
pic.save_png("blah.png");
} else std::cout << "xdo failed to get active window" << std::endl;
The above works with GTK & KDE apps, I really hope it may help someone stuck at this as there seem to be very few posts on this.

Related

Qt5 C++ resize font based on label width

I have written what I think is a pretty good font resize algorithm that I use on labels in a QGridLayout. The algorithm works rather well on its own. However, the first time I run the algorithm, the layout hasn't been painted yet, and as such, the grid widgets which own the labels haven't been sized to the layout, which means my width() call is wrong, though I have assigned the label text prior to the resize (which doesn't matter). My question is, what is the best way to know the bounding rectangles have been created to fit the layout so my calculation is on the actual label width?
Note, this is Qt5.7, so I know that fm.width() is obsolete, but that's what's available in Raspbian.
My app is reading Sonos metadata and showing it on a 7" RPi display. I'm resizing the metadata that is too long to fit in the layout grids. So, I have a QStackedLayout with a set of layouts to show (clock when Sonos isn't playing, metadata when it is), and I frequently poll the a local Sonos server to find out if there is metadata to show. This works well. What doesn't happen is that on the first time the Sonos metadata layout is shown, the QGridLayout hasn't actually been laid out yet (I believe), so the labels are too big. At some point after the first time I fill in the metadata, the grid layout gets "shown" and the labels are then the correct size. The problem is, by then, it's all done setting metadata and the labels look funny in some cases.
int pointSize = FontSize::Default;
for (auto label : m_labels) {
QFont f = label->font();
if (label->accessibleName() == "title")
pointSize = FontSize::Title;
QFontMetrics fm(f);
if (fm.width(label->text()) > label->width()) {
float factor = (float)label->width() / (float)fm.width(label->text());
if (factor <= .6) {
factor = .6;
}
f.setPointSizeF((f.pointSize() * factor) * .9);
qDebug() << __FUNCTION__ << ": label width:" << label->width();
qDebug() << __FUNCTION__ << ": font width:" << fm.width(label->text());
qDebug() << __FUNCTION__ << ": Calculated font scaling factor to be" << (float)(factor * .9);
qDebug() << __FUNCTION__ << ": Reset font size for text\"" << label->text() << "\" to" << f.pointSize();
}
else
f.setPointSize(pointSize);
label->setFont(f);
}
On an 800x480 display, this results in the first event label width being wrong
calculateLabelFontSize : label width: 640
calculateLabelFontSize : font width: 2051
The label width the next time it's called would end up being correct with a width of 584. However, because I don't always call it a second time, and because sometimes, the Sonos metadata hiccups and causes the display to revert, it may always be wrong, or it may just be right the first time no matter what.
I've considered trying to overload my gui app paintEvent(QPaintEvent *event), but the QPaintEvent class doesn't give me a way to determine which widget called for the event, so I can't just ignore the event until I want it. At least, not that I have determined, so if that's possible, please let me know.
I've tried overloading showEvent, but that doesn't run except when the frame is first shown, so no help there.
I've considered subclassing QGridLayout to simply overload the paintEvent() and use that, but I do have an issue with that solution. There is a progress bar in this layout, which means that the paintEvent is going to fire every half second as I get metadata from the Sonos server. Since I don't know if the paintEvent is firing for the time update, or for the text being set, I get a lot of resize attempts.
I've also simply run the algorithm a second time on the next event, but it's a really weird looking graphical hiccup when the fonts realign, and I don't like it.
Last up, I may just subclass QLabel, simply to overload paintEvent, and use that custom label just for the labels that would be resizable. However, is the label in the layout painted before or after the container it lives in inside the layout? I'll be testing this today I think, but I'm not convinced it would work.
I figure this has a much easier solution though. I just can't figure it out.
I borrowed code from https://github.com/jonaias/DynamicFontSizeWidgets which provided the resize algorithm. It's nice, but iterative. I have been tinkering with a math based solution to calculate instead of just trying to fit by resizing until it works. However, that solution still doesn't work well enough to use. This isn't slow, and does what is implied. It resizes the font until it fits.
This all is done in paintEvent() because using resizeEvent() may result in either an infinite resize loop or the layout may resize itself and suddenly everything looks shifted/squished/stretched. Doing it in paintEvent means it's only called once every time you update the text, but not otherwise.
I may come back to this to try to find a math based solution. I still think this isn't the correct way, but I found something that worked well enough for now.
NewLabel.h
#ifndef NEWLABEL_H
#define NEWLABEL_H
#include <QtCore/QtCore>
#include <QtWidgets/QtWidgets>
#include <cmath>
class NewLabel : public QLabel
{
Q_OBJECT
public:
explicit NewLabel(const QString &text, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
explicit NewLabel(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
virtual ~NewLabel() {}
void setDefaultPointSize(int p)
{
m_defaultPointSize = static_cast<float>(p);
}
protected:
void paintEvent(QPaintEvent *e) override;
private:
float getWidgetMaximumFontSize(QWidget *widget, QString text);
float m_defaultPointSize;
};
#endif
NewLabel.cpp
#define FONT_PRECISION (0.5)
NewLabel::NewLabel(const QString &text, QWidget *parent, Qt::WindowFlags f) : QLabel(text, parent, f)
{
m_defaultPointSize = 12;
}
NewLabel::NewLabel(QWidget *parent, Qt::WindowFlags f) :
QLabel(parent, f)
{
m_defaultPointSize = 12;
}
void NewLabel::paintEvent(QPaintEvent *e)
{
QFont newFont = font();
float fontSize = getWidgetMaximumFontSize(this, this->text());
if (fontSize < m_defaultPointSize) {
newFont.setPointSizeF(fontSize);
setFont(newFont);
}
QLabel::paintEvent(e);
}
float NewLabel::getWidgetMaximumFontSize(QWidget *widget, QString text)
{
QFont font = widget->font();
const QRect widgetRect = widget->contentsRect();
const float widgetWidth = widgetRect.width();
const float widgetHeight = widgetRect.height();
QRectF newFontSizeRect;
float currentSize = font.pointSizeF();
float step = currentSize/2.0;
/* If too small, increase step */
if (step<=FONT_PRECISION){
step = FONT_PRECISION*4.0;
}
float lastTestedSize = currentSize;
float currentHeight = 0;
float currentWidth = 0;
if (text==""){
return currentSize;
}
/* Only stop when step is small enough and new size is smaller than QWidget */
while(step>FONT_PRECISION || (currentHeight > widgetHeight) || (currentWidth > widgetWidth)){
/* Keep last tested value */
lastTestedSize = currentSize;
/* Test label with its font */
font.setPointSizeF(currentSize);
/* Use font metrics to test */
QFontMetricsF fm(font);
/* Check if widget is QLabel */
QLabel *label = qobject_cast<QLabel*>(widget);
if (label) {
newFontSizeRect = fm.boundingRect(widgetRect, (label->wordWrap()?Qt::TextWordWrap:0) | label->alignment(), text);
}
else{
newFontSizeRect = fm.boundingRect(widgetRect, 0, text);
}
currentHeight = newFontSizeRect.height();
currentWidth = newFontSizeRect.width();
/* If new font size is too big, decrease it */
if ((currentHeight > widgetHeight) || (currentWidth > widgetWidth)){
//qDebug() << "-- contentsRect()" << label->contentsRect() << "rect"<< label->rect() << " newFontSizeRect" << newFontSizeRect << "Tight" << text << currentSize;
currentSize -=step;
/* if step is small enough, keep it constant, so it converge to biggest font size */
if (step>FONT_PRECISION){
step/=2.0;
}
/* Do not allow negative size */
if (currentSize<=0){
break;
}
}
/* If new font size is smaller than maximum possible size, increase it */
else{
//qDebug() << "++ contentsRect()" << label->contentsRect() << "rect"<< label->rect() << " newFontSizeRect" << newFontSizeRect << "Tight" << text << currentSize;
currentSize +=step;
}
}
return lastTestedSize;
}

Screenshot capture of dual monitor in Qt 5

In the context of a Qt application, I'm using the following code snippet for taking a screenshot of full desktop:
QDesktopWidget* dw = QApplication::desktop();
QPixmap pixmap = QPixmap::grabWindow(dw->winId(), 0, 0,
dw->width(), dw->height());
pixmap.save(name, "JPG", screenshot_quality);
This approach works pretty well in Linux and Windows and with dual monitor, independently of screen's resolutions; that is, it works still if the two monitors are working with different resolutions. However, with Qt 5 I get the following run-time warning:
static QPixmap QPixmap::grabWindow(WId, int, int, int, int) is deprecated, use QScreen::grabWindow() instead. Defaulting to primary screen.
So I reviewed the Qt 5 doc and I wrote this:
QScreen * screen = QGuiApplication::primaryScreen();
QPixmap pixmap = screen->grabWindow(0);
pixmap.save(name, "JPG", screenshot_quality);
But this approach does not capture the second screen.
So I searched a little more and, according to this thread, Taking Screenshot of Full Desktop with Qt5, I designed the screenshot capture as follows:
QScreen * screen = QGuiApplication::primaryScreen();
QRect g = screen->geometry();
QPixmap pixmap = screen->grabWindow(0, g.x(), g.y(), g.width(), g.height());
pixmap.save(name, "JPG", screenshot_quality);
Unfortunately, this does not work too.
What catches my attention is that the method with Qt 4 works well. Since I imagine there must be some way to make it in Qt 5.
So, my question is how can be done with Qt 5?
EDIT: This is the way as I solved:
QPixmap grabScreens()
{
QList<QScreen*> screens = QGuiApplication::screens();
QList<QPixmap> scrs;
int w = 0, h = 0, p = 0;
foreach (auto scr, screens)
{
QRect g = scr->geometry();
QPixmap pix = scr->grabWindow(0, g.x(), g.y(), g.width(), g.height());
w += pix.width();
h = max(h, pix.height());
scrs.append(pix);
}
QPixmap final(w, h);
QPainter painter(&final);
final.fill(Qt::black);
foreach (auto scr, scrs)
{
painter.drawPixmap(QPoint(p, 0), scr);
p += scr.width();
}
return final;
}
Thanks to #ddriver!
Naturally, QGuiApplication::primaryScreen() will give you a single screen.
You could use QList<QScreen *> QGuiApplication::screens() to get all screens associated with the application, take screenshots for all of them, then create another blank image, size it according to how you want to compose the screens, and manually compose into a final image using QPainter.
QPixmap grabScreens() {
auto screens = QGuiApplication::screens();
QList<QPixmap> scrs;
int w = 0, h = 0, p = 0;
foreach (auto scr, screens) {
QPixmap pix = scr->grabWindow(0);
w += pix.width();
if (h < pix.height()) h = pix.height();
scrs << pix;
}
QPixmap final(w, h);
QPainter painter(&final);
final.fill(Qt::black);
foreach (auto scr, scrs) {
painter.drawPixmap(QPoint(p, 0), scr);
p += scr.width();
}
return final;
}
Also, you can use primary screen's (desktop) virtual geometry and capture entire desktop without additional loops and calculations:
QRect desktopGeometry = qApp->primaryScreen()->virtualGeometry();
QPixmap desktopPixmap = qApp->primaryScreen()->grabWindow(qApp->desktop()->winId(), desktopGeometry.x(), desktopGeometry.y(), desktopGeometry.width(), desktopGeometry.height());
See also: QDesktopWidget
Update:
At the moment, QApplication::desktop() and QDesktopWidget are marked as obsolete by the Qt for some reason, so for new projects it's recommended to use approach with screen enumerating. Anyway, for old and current Qt versions this solution has to work as expected.

Mouse cursor position deviations when scrolling

I'm trying to write little project for programming class. It's simple graphic library using only ascii characters, working on Windows console (I use win7 64bit). The problems occur when i'm trying to add mouse handling. Here's the code
void importantMouseThings()
{
DWORD numEvents = 0;
DWORD numEventsRead = 0;
GetNumberOfConsoleInputEvents( cgWindow::inputHandle, &numEvents);
if (numEvents != 0)
{
INPUT_RECORD *eventBuffer = new INPUT_RECORD[numEvents];
ReadConsoleInput(cgWindow::inputHandle, eventBuffer, numEvents, &numEventsRead);
for (DWORD i = 0; i < numEventsRead; i++)
{
if (eventBuffer[i].EventType == MOUSE_EVENT)
{
int mousex = eventBuffer[i].Event.MouseEvent.dwMousePosition.X;
int mousey = eventBuffer[i].Event.MouseEvent.dwMousePosition.Y;
std::cout << mousex << " " << mousey << std::endl;
}
}
delete[] eventBuffer;
}
}
The problem is when I move cursor to upper-left corner of console window, cout writes "0 0", but when I use scroll wheel (I mean when i scroll down or up) valuses change to something like "20 14". When I call another mouse event, simply by moving cursor a bit, values come back to return state "0 0".
Maybe I just don't get what dwMousePosition is, maybe it's something with console window (both, window and buffer sizes are set to 80x80, so there's no visible scrollbars).
EDIT:
Okey, I just realized, that value changes depends on window position. So if the window is on the left side of screen, the X divergence is very small and grows as I move window to the right. Any ideas, what is wrong?

Get pixel's color in C++, Linux

I'm looking for a possibility to get the color of a pixel with given screen coordinates (x,y) in c++ / Linux? Maybe something similarly like getPixel() in Windows. I spent the whole day to find sth but without any success.
Thanks, Stefan
Assuming you mean using C and GTK the answer can be using:
gdk_get_default_root_window()
And
GdkPixbuf* gdk_pixbuf_get_from_drawable (GdkPixbuf *dest,
GdkDrawable *src,
GdkColormap *cmap,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height);
EDIT: sample c++ code using Gdkmm (note that this is just a sample that assume an RGB color space, you should check the colorspace of the drawable before giving a meaning to the raw bytes).
#include <iostream>
#include <gtkmm.h>
#include <gdkmm.h>
int main(int argc, char* argv[])
{
Gtk::Main kit(argc, argv);
if(argc != 3) { std::cerr << argv[0] << " x y" << std::endl; return 1;}
int x = atoi(argv[1]);
int y = atoi(argv[2]);
Glib::RefPtr<Gdk::Screen> screen = Gdk::Screen::get_default();
Glib::RefPtr<Gdk::Drawable> win = screen->get_root_window();
Glib::RefPtr<Gdk::Pixbuf> pb = Gdk::Pixbuf::create(win, x, y, 1, 1);
unsigned char* rgb = pb->get_pixels();
std::cerr << (int)rgb[0] << ", " << (int)rgb[1] << ", " << (int)rgb[2] << std::endl;
return 0;
}
See various different techniques posted at http://ubuntuforums.org/showthread.php?t=715256
I have come across this same issue and have found the solution to be dependant on the situation at hand. A great way to go about doing it is to capture a bitmap of the window you are looking at. Then have a function search for the pixel in there that you are looking for. Keep in mind the x,y coords will start from the windows upper left corner as apposed to the screen's upper left. As to how to do this, I suggest you take a look at SCAR Divi witten by Freddy1990 http://freddy1990.com/ and Simba http://villavu.com/.
Those programs are used to program automated tasks on the computer and use pixel colour finding to achieve some tasks. Simba is open source and still in its infant stages. It uses pascal. However you could use the library it uses as an extention from C and sacrifice a little speed.

Keep QPixmap copy of screen contents using X11, XDamage, XRender, and other tricks

I'm attempting to solve what I thought would be a very simple problem. I want to keep a QPixmap updated with the entire screen contents. You can get such a pixmap by doing this:
QDesktopWidget *w = QApplication::desktop();
if (w)
{
QRect r = w->screenGeometry();
QPixmap p = QPixmap::grabWindow(w->winId(), 0, 0, r.width(), r.height())
QByteArray bitmap;
}
The problem with this is that QDesktopWidget ends up re-grabbing the entire screen pixmap from the X11 server every time you ask for it, even if nothing has changed.
I need this code to be fast, so I'm trying to do this myself. My starting point was the qx11mirror demo, however, that basically does the same thing. It uses the XDamage extension to work out when something has changed, but instead of using the damaged rectangle information to just update that part of the cached pixmap, it just sets a "dirty" flag, which triggers an entire refresh anyway.
So I'm trying to modify the qx11mirror example to just update the damaged portion of the windows, but I can't seem to get anything to work - all I get is a blank (black) pixmap. The code I'm using is:
void QX11Mirror::x11Event(XEvent *event)
{
if (event->type == m_damageEvent + XDamageNotify)
{
XDamageNotifyEvent *e = reinterpret_cast<XDamageNotifyEvent*>(event);
XWindowAttributes attr;
XGetWindowAttributes(QX11Info::display(), m_window, &attr);
XRenderPictFormat *format = XRenderFindVisualFormat(QX11Info::display(), attr.visual);
bool hasAlpha = ( format->type == PictTypeDirect && format->direct.alphaMask );
int x = attr.x;
int y = attr.y;
int width = attr.width;
int height = attr.height;
// debug output so I can see the window pos vs the damaged area:
qDebug() << "repainting dirty area:" << x << y << width << height << "vs" << e->area.x << e->area.y << e->area.width << e->area.height;
XRenderPictureAttributes pa;
pa.subwindow_mode = IncludeInferiors; // Don't clip child widgets
Picture picture = XRenderCreatePicture(QX11Info::display(),
m_window,
format,
CPSubwindowMode,
&pa);
XserverRegion region = XFixesCreateRegionFromWindow(QX11Info::display(),
m_window, WindowRegionBounding);
XFixesTranslateRegion(QX11Info::display(), region, -x, -y);
XFixesSetPictureClipRegion(QX11Info::display(), picture, 0, 0, region);
XFixesDestroyRegion(QX11Info::display(), region);
//QPixmap dest(width, height);
XRenderComposite(QX11Info::display(), // display
hasAlpha ? PictOpOver : PictOpSrc, // operation mode
picture, // src drawable
None, // src mask
dest.x11PictureHandle(), // dest drawable
e->area.x, // src X
e->area.y, // src Y
0, // mask X
0, // mask Y
e->area.x, // dest X
e->area.y, // dest Y
e->area.width, // width
e->area.height); // height
m_px = dest;
XDamageSubtract(QX11Info::display(), e->damage, None, None);
emit windowChanged();
}
else if (event->type == ConfigureNotify)
{
XConfigureEvent *e = &event->xconfigure;
m_position = QRect(e->x, e->y, e->width, e->height);
emit positionChanged(m_position);
}
}
Can anyone point me in the right direction? The documetnation for XRender, XDamage, and the other X11 extensions is pretty bad.
Reasons for using XRender over XCopyArea
The following text taken from here.
It is perfectly possible to create a GC for a window and use XCopyArea() to copy the contents of the window if you want to use the core protocol, but since the Composite extension exposes new visuals (ones with alpha channels e.g.), there's no guarantee that the format of the source drawable will match that of the destination. With the core protocol that situation will result in a match error, something that won't happen with the Xrender extension.
In addition the core protocol has no understanding of alpha channels, which means that it can't composite windows that use the new ARGB visual. When the source and destination have the same format, there's also no performance advantage to using the core protocol as of X11R6.8. That release is also the first to support the new Composite extension.
So in conclusion there are no drawbacks, and only advantages to choosing Xrender over the core protocol for these operations.
First you need to change the DamageReportLevel in the call to DamageCreate in QX11Mirror::setWindow from DamageReportNotEmpty to XDamageReportBoundingBox.
Next you need to call dest.detach() before the call to XRenderComposite. You don't really need both m_px and dest as member variables though - you can just use m__px.
There is also a missing call to XRenderFreePicture in that example which should go after the call to XRenderComposite:
XRenderFreePicture(QX11Info::display(), picture);
You don't need to duplicate all the code QX11Mirror::pixmap in QX11Mirror::x11Event. Instead change the type of m_dirty from bool to QRect, then have x11Event update m_dirty with the rectangle from the XDamageNotifyEvent,i.e. e->area. Then in QX11Mirror:pixmap rather than checking if m_dirty is true, check if m_dirty is not an empty rectangle. You would then pass the rectangle from m_dirty to XRenderComposite.
Edit:
The dest.detach is the key bit - without that you'll never get it to work.