/* Copyright (C) 2013 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "screenshotdialog.h" #include #include #include #include #include "application.h" #include #include #include #include #include using namespace LxImage; ScreenshotDialog::ScreenshotDialog(QWidget* parent, Qt::WindowFlags f): QDialog(parent, f) { ui.setupUi(this); Application* app = static_cast(qApp); app->addWindow(); int event_base, error_base; hasXfixes_ = XFixesQueryExtension(QX11Info::display(), &event_base, &error_base) ? true : false; if(!hasXfixes_) ui.includeCursor->hide(); } ScreenshotDialog::~ScreenshotDialog() { Application* app = static_cast(qApp); app->removeWindow(); } void ScreenshotDialog::done(int r) { if(r == QDialog::Accepted) { hide(); QDialog::done(r); XSync(QX11Info::display(), 0); // is this useful? int delay = ui.delay->value(); if(delay == 0) { // NOTE: // Well, we need to give X and the window manager some time to // really hide our own dialog from the screen. // Nobody knows how long it will take, and there is no reliable // way to ensure that. Let's wait for 400 ms here for it. delay = 400; } else delay *= 1000; // the dialog object will be deleted in doScreenshot(). QTimer::singleShot(delay, this, SLOT(doScreenshot())); } else { deleteLater(); } } QRect ScreenshotDialog::windowFrame(WId wid) { QRect result; XWindowAttributes wa; if(XGetWindowAttributes(QX11Info::display(), wid, &wa)) { Window child; int x, y; // translate to root coordinate XTranslateCoordinates(QX11Info::display(), wid, wa.root, 0, 0, &x, &y, &child); qDebug("%d, %d, %d, %d", x, y, wa.width, wa.height); result.setRect(x, y, wa.width, wa.height); // get the frame widths added by the window manager Atom atom = XInternAtom(QX11Info::display(), "_NET_FRAME_EXTENTS", false); unsigned long type, resultLen, rest; int format; unsigned char* data = NULL; if(XGetWindowProperty(QX11Info::display(), wid, atom, 0, G_MAXLONG, false, XA_CARDINAL, &type, &format, &resultLen, &rest, &data) == Success) { } if(data) { // left, right, top, bottom long* offsets = reinterpret_cast(data); result.setLeft(result.left() - offsets[0]); result.setRight(result.right() + offsets[1]); result.setTop(result.top() - offsets[2]); result.setBottom(result.bottom() + offsets[3]); XFree(data); } } return result; } WId ScreenshotDialog::activeWindowId() { WId root = WId(QX11Info::appRootWindow()); Atom atom = XInternAtom(QX11Info::display(), "_NET_ACTIVE_WINDOW", false); unsigned long type, resultLen, rest; int format; WId result = 0; unsigned char* data = NULL; if(XGetWindowProperty(QX11Info::display(), root, atom, 0, 1, false, XA_WINDOW, &type, &format, &resultLen, &rest, &data) == Success) { result = *reinterpret_cast(data); XFree(data); } return result; } void ScreenshotDialog::doScreenshot() { WId wid = 0; int x = 0, y = 0, width = -1, height = -1; wid = QApplication::desktop()->winId(); // get desktop window if(ui.currentWindow->isChecked()) { WId activeWid = activeWindowId(); if(activeWid) { if(ui.includeFrame->isChecked()) { QRect rect = windowFrame(activeWid); x = rect.x(); y = rect.y(); width = rect.width(); height = rect.height(); } else wid = activeWid; } } QPixmap pixmap; pixmap = QPixmap::grabWindow(wid, x, y, width, height); QImage image = pixmap.toImage(); if(hasXfixes_ && ui.includeCursor->isChecked()) { // capture the cursor if needed XFixesCursorImage* cursor = XFixesGetCursorImage(QX11Info::display()); if(cursor) { if(cursor->pixels) { // pixles should be an ARGB array QImage cursorImage; quint32* buf = NULL; if(sizeof(long) == 4) { // FIXME: will we encounter byte-order problems here? cursorImage = QImage((uchar*)cursor->pixels, cursor->width, cursor->height, QImage::Format_ARGB32); } else { // XFixes returns long integers which is not 32 bit on 64 bit systems. long len = cursor->width * cursor->height; quint32* buf = new quint32[len]; for(long i = 0; i < len; ++i) buf[i] = (quint32)cursor->pixels[i]; cursorImage = QImage((uchar*)buf, cursor->width, cursor->height, QImage::Format_ARGB32); } // paint the cursor on the current image QPainter painter(&image); painter.drawImage(cursor->x - cursor->xhot, cursor->y - cursor->yhot, cursorImage); if(buf) delete []buf; } XFree(cursor); } } Application* app = static_cast(qApp); MainWindow* window = app->createWindow(); window->pasteImage(image); window->show(); deleteLater(); // destroy ourself }