-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[nemo-qml-plugin-utilities] Add Screenshots component #1
Open
amtep
wants to merge
3
commits into
nemomobile-graveyard:master
Choose a base branch
from
amtep:screenshots
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/* | ||
* Copyright (C) 2013 Jolla Ltd. | ||
* Contact: Richard Braakman <[email protected]> | ||
* | ||
* You may use this file under the terms of the BSD license as follows: | ||
* | ||
* "Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are | ||
* met: | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in | ||
* the documentation and/or other materials provided with the | ||
* distribution. | ||
* * Neither the name of Nemo Mobile nor the names of its contributors | ||
* may be used to endorse or promote products derived from this | ||
* software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." | ||
*/ | ||
|
||
#include "declarativescreenshots.h" | ||
|
||
#include <QApplication> | ||
#include <QDateTime> | ||
#include <QDesktopServices> | ||
#include <QDesktopWidget> | ||
#include <QDir> | ||
#include <QFile> | ||
#include <QGraphicsScene> | ||
#include <QImageWriter> | ||
#include <QPainter> | ||
|
||
DeclarativeScreenshots::DeclarativeScreenshots(QDeclarativeItem *parent) | ||
: QDeclarativeItem(parent), m_name("screenshot"), m_target(0), | ||
m_format("png"), m_formatSupported(true) { | ||
m_path = QDesktopServices::storageLocation( | ||
QDesktopServices::PicturesLocation); | ||
} | ||
|
||
void DeclarativeScreenshots::setPath(const QString & path) { | ||
if (path == m_path) | ||
return; | ||
m_path = path; | ||
emit pathChanged(); | ||
} | ||
|
||
void DeclarativeScreenshots::setName(const QString & name) { | ||
if (name == m_name) | ||
return; | ||
m_name = name; | ||
emit nameChanged(); | ||
} | ||
|
||
void DeclarativeScreenshots::setTarget(QDeclarativeItem *target) { | ||
if (target == m_target) | ||
return; | ||
|
||
if (m_target) | ||
disconnect(m_target, SIGNAL(destroyed()), | ||
this, SLOT(targetDestroyed())); | ||
if (target) | ||
connect(target, SIGNAL(destroyed()), | ||
this, SLOT(targetDestroyed())); | ||
|
||
m_target = target; | ||
emit targetChanged(); | ||
} | ||
|
||
// This is connected to m_target's destroyed() signal. | ||
// The connection is maintained by setTarget(). | ||
// This logic effectively makes m_target a weak reference. | ||
void DeclarativeScreenshots::targetDestroyed() { | ||
setTarget(0); | ||
} | ||
|
||
void DeclarativeScreenshots::setFormat(const QString & format) { | ||
if (format == m_format) | ||
return; | ||
bool old_supported = m_formatSupported; | ||
|
||
// Set both m_format and m_formatSupported before sending any signals, | ||
// so that receivers see a consistent state. | ||
|
||
m_format = format; | ||
m_formatSupported = false; | ||
QByteArray cmpformat = format.toAscii().toLower(); | ||
Q_FOREACH(QByteArray fmt, QImageWriter::supportedImageFormats()) { | ||
if (fmt.toLower() == cmpformat) { | ||
m_formatSupported = true; | ||
break; | ||
} | ||
} | ||
|
||
emit formatChanged(); | ||
if (m_formatSupported != old_supported) | ||
emit formatSupportedChanged(); | ||
} | ||
|
||
bool DeclarativeScreenshots::take(qreal x, qreal y, qreal width, qreal height) { | ||
QString timestamp = QDateTime::currentDateTimeUtc() | ||
.toString("-yyyyMMdd-hhmmsszzz."); | ||
QPixmap snapshot; | ||
|
||
if (m_target) { | ||
QGraphicsScene *scene = m_target->scene(); | ||
if (!scene) | ||
return false; | ||
|
||
if (width < 0) | ||
width = m_target->width() - x; | ||
if (height < 0) | ||
height = m_target->height() - y; | ||
|
||
QRectF mappedRect = m_target->mapRectToScene(x, y, width, height); | ||
QRectF targetRect(0, 0, mappedRect.width(), mappedRect.height()); | ||
snapshot = QPixmap(mappedRect.size().toSize()); | ||
snapshot.fill(Qt::transparent); | ||
|
||
QPainter painter(&snapshot); | ||
scene->render(&painter, targetRect, mappedRect); | ||
} else { | ||
// If there's no target item, then take an actual screenshot of the | ||
// desktop root window. | ||
snapshot = QPixmap::grabWindow(QApplication::desktop()->winId(), | ||
x, y, width, height); | ||
} | ||
|
||
QString pathname = QDir(m_path).filePath(m_name + timestamp + m_format); | ||
return snapshot.save(pathname); | ||
} | ||
|
||
bool DeclarativeScreenshots::take() { | ||
return take(0, 0, -1, -1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/* | ||
* Copyright (C) 2013 Jolla Ltd. | ||
* Contact: Richard Braakman <[email protected]> | ||
* | ||
* You may use this file under the terms of the BSD license as follows: | ||
* | ||
* "Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are | ||
* met: | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in | ||
* the documentation and/or other materials provided with the | ||
* distribution. | ||
* * Neither the name of Nemo Mobile nor the names of its contributors | ||
* may be used to endorse or promote products derived from this | ||
* software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." | ||
*/ | ||
|
||
#ifndef DECLARATIVESCREENSHOTS_H | ||
#define DECLARATIVESCREENSHOTS_H | ||
|
||
#include <QDeclarativeItem> | ||
|
||
/*! | ||
\qmlclass Screenshots DeclarativeScreenshots | ||
\brief Utility component to take screenshots and save them as files. | ||
|
||
Screenshots can be taken of the root window or of specific components. | ||
*/ | ||
|
||
class DeclarativeScreenshots : public QDeclarativeItem | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MSameer told me that I can just use a QObject here because it's a non-graphical component, and that might even work for both QtQuick1 and QtQuick2 (whereas QDeclarativeItem usage would definitely need porting) |
||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
DeclarativeScreenshots(QDeclarativeItem *parent = 0); | ||
|
||
/*! | ||
\qmlproperty string path | ||
|
||
Path to the directory where screenshots will be saved. | ||
The default is the the user's pictures directory according to | ||
QDesktopServices. | ||
*/ | ||
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) | ||
QString path() const { return m_path; } | ||
void setPath(const QString & path); | ||
|
||
/*! | ||
\qmlproperty string name | ||
|
||
Base filename for screenshots. The final filename will be constructed | ||
from this property, a timestamp, and the image format. | ||
The default is "screenshot". | ||
*/ | ||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) | ||
QString name() const { return m_name; } | ||
void setName(const QString & name); | ||
|
||
/*! | ||
\qmlproperty Item target | ||
|
||
Component from which to take screenshots. | ||
Leave null to take screenshots from the desktop root window. | ||
*/ | ||
Q_PROPERTY(QDeclarativeItem *target READ target WRITE setTarget NOTIFY targetChanged) | ||
QDeclarativeItem *target() const { return m_target; } | ||
void setTarget(QDeclarativeItem *target); | ||
|
||
/*! | ||
\qmlproperty string format | ||
|
||
Image format to use when encoding the screenshots. This string will | ||
also be used as the filename extension. The default is "png". | ||
*/ | ||
Q_PROPERTY(QString format READ format WRITE setFormat NOTIFY formatChanged) | ||
QString format() const { return m_format; } | ||
void setFormat(const QString & format); | ||
|
||
/*! | ||
\qmlproperty bool formatSupported | ||
|
||
Read-only property that signals whether the currently selected | ||
image format can be used. | ||
*/ | ||
Q_PROPERTY(bool formatSupported READ formatSupported NOTIFY formatSupportedChanged) | ||
bool formatSupported() const { return m_formatSupported; } | ||
|
||
/*! | ||
\qmlmethod bool Screenshots::take() | ||
|
||
Takes a screenshot of the current target and saves it as a file. | ||
Returns true if the operation was successful, otherwise false. | ||
*/ | ||
Q_INVOKABLE bool take(); | ||
|
||
/*! | ||
\qmlmethod bool Screenshots::take(real x, real y, real width, real height) | ||
|
||
Takes a screenshot of the current target, cropped to the specified | ||
rectangle. | ||
Returns true if the operation was successful, otherwise false. | ||
*/ | ||
Q_INVOKABLE bool take(qreal x, qreal y, qreal height, qreal width); | ||
|
||
signals: | ||
void pathChanged(); | ||
void nameChanged(); | ||
void targetChanged(); | ||
void formatChanged(); | ||
void formatSupportedChanged(); | ||
|
||
private slots: | ||
void targetDestroyed(); | ||
|
||
private: | ||
QString m_path; | ||
QString m_name; | ||
QDeclarativeItem *m_target; | ||
QString m_format; | ||
bool m_formatSupported; | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the issues with winId() in client applications, can this cause any issues? I'd assume not, since the desktop() should always have a native rendering window, but thought I'd ask, since I don't know much about that stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, what are these issues? The only one I know of is that only top-level widgets have windows, but that should be ok here as you say. Are there other known issues with winId()?
About the WId type itself, the 4.8 docs say "Portable in principle, but if you use it you are probably about to do something non-portable. Be careful."
I think it's ok here because all I do is pass it right back to a Qt function that knows what to do with it. In fact I was quite happy to not need any X11 specific code :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only issue is that of performance - and as the top level widget has one anyway, this shouldn't be a problem. I just thought I'd mention it in case it hadn't been considered. (eg, I've seen the use of winId() cause framerates in client applications to drop from 60 fps to 12 fps, after a call to winId() to get an id to use in a call to XSetTransientFor()).