Merge lp:~albaguirre/unity8/add-screenshotter into lp:unity8
- add-screenshotter
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Albert Astals Cid |
Approved revision: | 1308 |
Merged at revision: | 1398 |
Proposed branch: | lp:~albaguirre/unity8/add-screenshotter |
Merge into: | lp:unity8 |
Diff against target: |
569 lines (+413/-4) 15 files modified
debian/unity8-private.install (+1/-0) plugins/CMakeLists.txt (+1/-0) plugins/ScreenGrabber/CMakeLists.txt (+13/-0) plugins/ScreenGrabber/ScreenGrabber.qmltypes (+17/-0) plugins/ScreenGrabber/plugin.cpp (+28/-0) plugins/ScreenGrabber/plugin.h (+33/-0) plugins/ScreenGrabber/qmldir (+3/-0) plugins/ScreenGrabber/screengrabber.cpp (+94/-0) plugins/ScreenGrabber/screengrabber.h (+42/-0) qml/Components/ScreenGrabber.qml (+72/-0) qml/Components/VolumeKeyFilter.qml (+63/-0) qml/Shell.qml (+14/-4) tests/mocks/QtMultimedia/QtMultimedia.qmltypes (+10/-0) tests/mocks/QtMultimedia/audio.cpp (+10/-0) tests/mocks/QtMultimedia/audio.h (+12/-0) |
To merge this branch: | bzr merge lp:~albaguirre/unity8/add-screenshotter |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Albert Astals Cid (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Daniel d'Andrada (community) | Abstain | ||
Michael Zanetti (community) | Needs Information | ||
Gerry Boland (community) | Needs Fixing | ||
Review via email: mp+235834@code.launchpad.net |
Commit message
Add a plugin to take screenshots on vol up + vol down
The screenshots are saved into <Pictures dir>/Screenshots/
Description of the change
Add a plugin to take screenshots on vol up + vol down
The screenshots are saved into <Pictures dir>/Screenshots/
Are there any related MPs required for this MP to build/function as expected?
No
Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
Did you make sure that your branch does not contain spurious tags?
Yes
If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
If you changed the UI, has there been a design review?
Yes design has reviewed (see https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
Albert Astals Cid (aacid) wrote : | # |
Does this actually take screenshot of running applications? ScreenShotter:
Gerry Boland (gerboland) wrote : | # |
+QString ScreenShotter:
+QString ScreenShotter:
+ // First lets look for existing files using our numbering pattern
instead of this complex numbering pattern, why not just use current date & time?
Alberto Aguirre (albaguirre) wrote : | # |
> Does this actually take screenshot of running applications?
> ScreenShotter:
> shell itself, no?
Yes it takes screenshots of whatever is being rendered to the screen by qtmir. This is because the shell window will be backed by qtmir's DisplayWindow, which is where all the shell and apps surfaces will be rendered into.
Alberto Aguirre (albaguirre) wrote : | # |
> +QString ScreenShotter:
> +QString ScreenShotter:
> + // First lets look for existing files using our numbering pattern
> instead of this complex numbering pattern, why not just use current date &
> time?
Ok I guess I can do that. I suppose I just wanted it to produce sequentially numbered files as most other products do when saving say camera snapshots.
Alberto Aguirre (albaguirre) wrote : | # |
@Albert:
This is an example screenshot taken with this branch:
https:/
Alberto Aguirre (albaguirre) wrote : | # |
> +QString ScreenShotter:
> +QString ScreenShotter:
> + // First lets look for existing files using our numbering pattern
> instead of this complex numbering pattern, why not just use current date &
> time?
Done.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1289
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
> > Does this actually take screenshot of running applications?
> > ScreenShotter:
> > shell itself, no?
>
> Yes it takes screenshots of whatever is being rendered to the screen by qtmir.
> This is because the shell window will be backed by qtmir's DisplayWindow,
> which is where all the shell and apps surfaces will be rendered into.
Isn't this [ab]using an implementation detail of qtmir/qtubuntu? Reading the documentation of QGuiApplication
I'm fine if we do decide this, but maybe it needs some comment in the code.
Michael Zanetti (mzanetti) wrote : | # |
Albert, the reason why this works is really because application surfaces are just normal QQuickItems inside the shell. It does only screenshot the shell window with whatever the shell paints, in this case also the application surface items. I think this is ok as it really only works inside the shell application but not from other apps etc.
But the other question I have is if we really want to have such a thing in the product. I imagine people hitting up + down accidentally all the time. Do we really want them to make screenshots without even knowing? This doesn't sound like being something I would want to have enabled in a final product. Instead I think this should be done properly through some ui element, maybe in the developer mode options.
Daniel d'Andrada (dandrader) wrote : | # |
> Albert, the reason why this works is really because application surfaces are
> just normal QQuickItems inside the shell. It does only screenshot the shell
> window with whatever the shell paints, in this case also the application
> surface items. I think this is ok as it really only works inside the shell
> application but not from other apps etc.
>
>
> But the other question I have is if we really want to have such a thing in the
> product. I imagine people hitting up + down accidentally all the time. Do we
> really want them to make screenshots without even knowing? This doesn't sound
> like being something I would want to have enabled in a final product. Instead
> I think this should be done properly through some ui element, maybe in the
> developer mode options.
It reminds me that I have a screenshot of my lockscreen in my android phone and I have absolutely no idea how I did it. :-D
Will google it now.
Daniel d'Andrada (dandrader) wrote : | # |
Would it be possible to move the screenshot animation onto a separate QML file? Shell.qml is already quite big as it is.
Alberto Aguirre (albaguirre) wrote : | # |
> Albert, the reason why this works is really because application surfaces are
> just normal QQuickItems inside the shell. It does only screenshot the shell
> window with whatever the shell paints, in this case also the application
> surface items. I think this is ok as it really only works inside the shell
> application but not from other apps etc.
>
Right!
>
> But the other question I have is if we really want to have such a thing in the
> product. I imagine people hitting up + down accidentally all the time. Do we
> really want them to make screenshots without even knowing? This doesn't sound
> like being something I would want to have enabled in a final product. Instead
> I think this should be done properly through some ui element, maybe in the
> developer mode options.
From the bug/feature request I don't think they want a developer option...it's for users to share screenshots of their phone to social media...
As for accidental bumps of the keys...maybe I can just disable screenshotting when screen is off?
Alberto Aguirre (albaguirre) wrote : | # |
> Would it be possible to move the screenshot animation onto a separate QML
> file? Shell.qml is already quite big as it is.
Sure.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1296
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1298
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) : | # |
Albert Astals Cid (aacid) wrote : | # |
How hard would be adding the shutter sound that we use in Camera application be like Vesa suggests in the bug?
Albert Astals Cid (aacid) wrote : | # |
Text conflict in qml/Shell.qml
1 conflicts encountered.
Alberto Aguirre (albaguirre) wrote : | # |
@Albert,
Yes I will add that. I just need to find some time.
Alberto Aguirre (albaguirre) wrote : | # |
@Albert
Ok, fixed conflict and added shutter sounds as requested by design.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1300
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1301. By Alberto Aguirre
-
Clasify shutter sound as alert to avoid pausing other players.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1301
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
FAILURE: http://
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
* saveScreenshot
make QImage and QStrings there const &
* ScreenGrabber:
Make QWindowList windows const so we get the "fast" operator[] when doing windows[0]
* onKeyReleased:
bring the else up to the } line
* screenGrabber.
Looks like this could be a binding instead of a function call?
* There's a few ; missing in the two onStopped functions
* //TODO: This should be configurable (perhaps through gsettings?):
What's the use case/benefit for the user of making this configurable?
* screenshotsDir.
Should we localize this?
Michał Sawicz (saviq) wrote : | # |
> * //TODO: This should be configurable (perhaps through gsettings?):
> What's the use case/benefit for the user of making this configurable?
Yeah, don't think we need to configure this. Why not PNG by default though?
> * screenshotsDir.
> Should we localize this?
No, we decided against localizing folder names because of having to "unlocalize" them everywhere that tries to read them.
Is that folder be picked up by the gallery app already?
Albert Astals Cid (aacid) wrote : | # |
> > * //TODO: This should be configurable (perhaps through gsettings?):
> > What's the use case/benefit for the user of making this configurable?
>
> Yeah, don't think we need to configure this. Why not PNG by default though?
Yeah maybe PNG makes more sense
>
> > * screenshotsDir.
> > Should we localize this?
>
> No, we decided against localizing folder names because of having to
> "unlocalize" them everywhere that tries to read them.
>
> Is that folder be picked up by the gallery app already?
Yes (screenshots look very fuzzy in the gallery app, but when downloaded with adb they look fine so i guess it's a gallery bug)
Alberto Aguirre (albaguirre) wrote : | # |
> > * //TODO: This should be configurable (perhaps through gsettings?):
> > What's the use case/benefit for the user of making this configurable?
>
> Yeah, don't think we need to configure this. Why not PNG by default though?
>
I had it as PNG but other products do jpg too...presumably size?
> > * screenshotsDir.
> > Should we localize this?
>
> No, we decided against localizing folder names because of having to
> "unlocalize" them everywhere that tries to read them.
>
> Is that folder be picked up by the gallery app already?
Yes it is.
Alberto Aguirre (albaguirre) wrote : | # |
> * saveScreenshot
> make QImage and QStrings there const &
>
They need to be copies, because they will be run in a separate thread plus Qt has copy on writing semantics on those.
>
> * ScreenGrabber:
> Make QWindowList windows const so we get the "fast" operator[] when doing
> windows[0]
>
Agree.
>
> * onKeyReleased:
> bring the else up to the } line
>
Sure.
>
> * screenGrabber.
> Looks like this could be a binding instead of a function call?
>
Ok will do.
> * There's a few ; missing in the two onStopped functions
>
Ok I'll fix it.
>
> * //TODO: This should be configurable (perhaps through gsettings?):
> What's the use case/benefit for the user of making this configurable?
>
I guess simply size/quality tradeoff.
- 1302. By Alberto Aguirre
-
Address review feedback
- 1303. By Alberto Aguirre
-
merge lp:unity8
- 1304. By Alberto Aguirre
-
Use binding instead of function call to enable/disable screenshotting according to screen power status.
Alberto Aguirre (albaguirre) wrote : | # |
I've addressed the review comments.
I have left JPG as the format as the size tradeoff is:
For 960x540 screenshot we are talking about 41KB (JPG) vs 1.6MB (PNG).
Let me know if you still want PNG as default.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1304
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alberto Aguirre (albaguirre) wrote : | # |
Actually it looks like QIMage does compress png if we set the quality number to 0 or something low.
So the size is about for a 960x540 screenshot is around 41KB (JPG) vs 330KB (PNG).
- 1305. By Alberto Aguirre
-
Make PNG the default screenshot format
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1305
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1305
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
file://
Albert Astals Cid (aacid) wrote : | # |
i meant needs fixing
Alberto Aguirre (albaguirre) wrote : | # |
Is this not supported in utopic?
https:/
Albert Astals Cid (aacid) wrote : | # |
It is, but we have our own QtMultimedia mock to make testing easier and the role is not available there. Can you define it in the mock? tests/mocks/
- 1306. By Alberto Aguirre
-
Add audioRole to QtMultimedia mock
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1306
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
We should try to eat the key presses, otherwise if i let the button pressed after taking the screenshot it changes my volume that is clearly not what we want, no?
- 1307. By Alberto Aguirre
-
Avoid volume control changes when both volume keys are pressed.
Alberto Aguirre (albaguirre) wrote : | # |
> We should try to eat the key presses, otherwise if i let the button pressed
> after taking the screenshot it changes my volume that is clearly not what we
> want, no?
Fixed.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1307
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1308. By Alberto Aguirre
-
Remove trailing whitespace in comments
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1308
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
* Did you perform an exploratory manual test run of the code change and any related functionality?
Yes
* Did CI run pass? If not, please explain why.
Autopilot is previously borked
* Did you make sure that the branch does not contain spurious tags?
Yes
Preview Diff
1 | === modified file 'debian/unity8-private.install' |
2 | --- debian/unity8-private.install 2014-10-06 15:45:25 +0000 |
3 | +++ debian/unity8-private.install 2014-10-30 02:40:10 +0000 |
4 | @@ -6,6 +6,7 @@ |
5 | usr/lib/*/unity8/qml/Lights |
6 | usr/lib/*/unity8/qml/Powerd |
7 | usr/lib/*/unity8/qml/SessionBroadcast |
8 | +usr/lib/*/unity8/qml/ScreenGrabber |
9 | usr/lib/*/unity8/qml/Ubuntu |
10 | usr/lib/*/unity8/qml/Unity |
11 | usr/lib/*/unity8/qml/Utils |
12 | |
13 | === modified file 'plugins/CMakeLists.txt' |
14 | --- plugins/CMakeLists.txt 2014-09-29 09:43:18 +0000 |
15 | +++ plugins/CMakeLists.txt 2014-10-30 02:40:10 +0000 |
16 | @@ -18,6 +18,7 @@ |
17 | add_subdirectory(Dash) |
18 | add_subdirectory(Powerd) |
19 | add_subdirectory(SessionBroadcast) |
20 | +add_subdirectory(ScreenGrabber) |
21 | add_subdirectory(Ubuntu) |
22 | add_subdirectory(Unity) |
23 | add_subdirectory(Utils) |
24 | |
25 | === added directory 'plugins/ScreenGrabber' |
26 | === added file 'plugins/ScreenGrabber/CMakeLists.txt' |
27 | --- plugins/ScreenGrabber/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
28 | +++ plugins/ScreenGrabber/CMakeLists.txt 2014-10-30 02:40:10 +0000 |
29 | @@ -0,0 +1,13 @@ |
30 | +include_directories( |
31 | + ${CMAKE_CURRENT_BINARY_DIR} |
32 | +) |
33 | + |
34 | +set(SCREENGRABBERSOURCES |
35 | + screengrabber.cpp |
36 | + plugin.cpp |
37 | +) |
38 | + |
39 | +add_library(ScreenGrabber-qml MODULE ${SCREENGRABBERSOURCES}) |
40 | +qt5_use_modules(ScreenGrabber-qml Qml Gui Quick Concurrent) |
41 | + |
42 | +add_unity8_plugin(ScreenGrabber 0.1 ScreenGrabber TARGETS ScreenGrabber-qml) |
43 | |
44 | === added file 'plugins/ScreenGrabber/ScreenGrabber.qmltypes' |
45 | --- plugins/ScreenGrabber/ScreenGrabber.qmltypes 1970-01-01 00:00:00 +0000 |
46 | +++ plugins/ScreenGrabber/ScreenGrabber.qmltypes 2014-10-30 02:40:10 +0000 |
47 | @@ -0,0 +1,17 @@ |
48 | +import QtQuick.tooling 1.1 |
49 | + |
50 | +// This file describes the plugin-supplied types contained in the library. |
51 | +// It is used for QML tooling purposes only. |
52 | +// |
53 | +// This file was auto-generated by: |
54 | +// 'qmlplugindump -nonrelocatable ScreenGrabber 0.1 plugins' |
55 | + |
56 | +Module { |
57 | + Component { |
58 | + name: "ScreenGrabber" |
59 | + prototype: "QObject" |
60 | + exports: ["ScreenGrabber/ScreenGrabber 0.1"] |
61 | + exportMetaObjectRevisions: [0] |
62 | + Method { name: "captureAndSave" } |
63 | + } |
64 | +} |
65 | |
66 | === added file 'plugins/ScreenGrabber/plugin.cpp' |
67 | --- plugins/ScreenGrabber/plugin.cpp 1970-01-01 00:00:00 +0000 |
68 | +++ plugins/ScreenGrabber/plugin.cpp 2014-10-30 02:40:10 +0000 |
69 | @@ -0,0 +1,28 @@ |
70 | +/* |
71 | + * Copyright (C) 2014 Canonical, Ltd. |
72 | + * |
73 | + * This program is free software; you can redistribute it and/or modify |
74 | + * it under the terms of the GNU General Public License as published by |
75 | + * the Free Software Foundation; version 3. |
76 | + * |
77 | + * This program is distributed in the hope that it will be useful, |
78 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
79 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
80 | + * GNU General Public License for more details. |
81 | + * |
82 | + * You should have received a copy of the GNU General Public License |
83 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
84 | + * |
85 | + * Authors: Alberto Aguirre <alberto.aguirre@canonical.com> |
86 | + */ |
87 | + |
88 | +#include "plugin.h" |
89 | +#include "screengrabber.h" |
90 | + |
91 | +#include <QtQml/qqml.h> |
92 | + |
93 | +void ScreenGrabberPlugin::registerTypes(const char *uri) |
94 | +{ |
95 | + Q_ASSERT(uri == QLatin1String("ScreenGrabber")); |
96 | + qmlRegisterType<ScreenGrabber>(uri, 0, 1, "ScreenGrabber"); |
97 | +} |
98 | |
99 | === added file 'plugins/ScreenGrabber/plugin.h' |
100 | --- plugins/ScreenGrabber/plugin.h 1970-01-01 00:00:00 +0000 |
101 | +++ plugins/ScreenGrabber/plugin.h 2014-10-30 02:40:10 +0000 |
102 | @@ -0,0 +1,33 @@ |
103 | +/* |
104 | + * Copyright (C) 2014 Canonical, Ltd. |
105 | + * |
106 | + * This program is free software; you can redistribute it and/or modify |
107 | + * it under the terms of the GNU General Public License as published by |
108 | + * the Free Software Foundation; version 3. |
109 | + * |
110 | + * This program is distributed in the hope that it will be useful, |
111 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
112 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
113 | + * GNU General Public License for more details. |
114 | + * |
115 | + * You should have received a copy of the GNU General Public License |
116 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
117 | + * |
118 | + * Authors: Alberto Aguirre <alberto.aguirre@canonical.com> |
119 | + */ |
120 | + |
121 | +#ifndef SCREENGRABBER_PLUGIN_H |
122 | +#define SCREENGRABBER_PLUGIN_H |
123 | + |
124 | +#include <QtQml/QQmlExtensionPlugin> |
125 | + |
126 | +class ScreenGrabberPlugin : public QQmlExtensionPlugin |
127 | +{ |
128 | + Q_OBJECT |
129 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
130 | + |
131 | +public: |
132 | + void registerTypes(const char *uri); |
133 | +}; |
134 | + |
135 | +#endif // SCREENGRABBER_PLUGIN_H |
136 | |
137 | === added file 'plugins/ScreenGrabber/qmldir' |
138 | --- plugins/ScreenGrabber/qmldir 1970-01-01 00:00:00 +0000 |
139 | +++ plugins/ScreenGrabber/qmldir 2014-10-30 02:40:10 +0000 |
140 | @@ -0,0 +1,3 @@ |
141 | +module ScreenGrabber |
142 | +plugin ScreenGrabber-qml |
143 | +typeinfo ScreenGrabber.qmltypes |
144 | |
145 | === added file 'plugins/ScreenGrabber/screengrabber.cpp' |
146 | --- plugins/ScreenGrabber/screengrabber.cpp 1970-01-01 00:00:00 +0000 |
147 | +++ plugins/ScreenGrabber/screengrabber.cpp 2014-10-30 02:40:10 +0000 |
148 | @@ -0,0 +1,94 @@ |
149 | +/* |
150 | + * Copyright (C) 2014 Canonical, Ltd. |
151 | + * |
152 | + * This program is free software; you can redistribute it and/or modify |
153 | + * it under the terms of the GNU General Public License as published by |
154 | + * the Free Software Foundation; version 3. |
155 | + * |
156 | + * This program is distributed in the hope that it will be useful, |
157 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
158 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
159 | + * GNU General Public License for more details. |
160 | + * |
161 | + * You should have received a copy of the GNU General Public License |
162 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
163 | + * |
164 | + * Authors: Alberto Aguirre <alberto.aguirre@canonical.com> |
165 | + */ |
166 | + |
167 | +#include "screengrabber.h" |
168 | + |
169 | +#include <QDir> |
170 | +#include <QDateTime> |
171 | +#include <QStandardPaths> |
172 | +#include <QtGui/QImage> |
173 | +#include <QtGui/QGuiApplication> |
174 | +#include <QtQuick/QQuickWindow> |
175 | +#include <QtConcurrent/QtConcurrentRun> |
176 | + |
177 | +#include <QDebug> |
178 | + |
179 | +void saveScreenshot(QImage screenshot, QString filename, QString format, int quality) |
180 | +{ |
181 | + if (!screenshot.save(filename, format.toLatin1().data(), quality)) |
182 | + qWarning() << "ScreenShotter: failed to save snapshot!"; |
183 | +} |
184 | + |
185 | +ScreenGrabber::ScreenGrabber(QObject *parent) |
186 | + : QObject(parent), |
187 | + screenshotQuality(0) |
188 | +{ |
189 | + QDir screenshotsDir(QStandardPaths::displayName(QStandardPaths::PicturesLocation)); |
190 | + screenshotsDir.mkdir("Screenshots"); |
191 | + screenshotsDir.cd("Screenshots"); |
192 | + if (screenshotsDir.exists()) |
193 | + { |
194 | + fileNamePrefix = screenshotsDir.absolutePath(); |
195 | + fileNamePrefix.append("/screenshot"); |
196 | + } |
197 | + else |
198 | + { |
199 | + qWarning() << "ScreenShotter: failed to create directory at: " << screenshotsDir.absolutePath(); |
200 | + } |
201 | +} |
202 | + |
203 | +void ScreenGrabber::captureAndSave() |
204 | +{ |
205 | + if (fileNamePrefix.isEmpty()) |
206 | + { |
207 | + qWarning() << "ScreenShotter: no directory to save screenshot"; |
208 | + return; |
209 | + } |
210 | + |
211 | + const QWindowList windows = QGuiApplication::topLevelWindows(); |
212 | + if (windows.empty()) |
213 | + { |
214 | + qWarning() << "ScreenShotter: no top level windows found!"; |
215 | + return; |
216 | + } |
217 | + |
218 | + QQuickWindow *main_window = qobject_cast<QQuickWindow *>(windows[0]); |
219 | + if (!main_window) |
220 | + { |
221 | + qWarning() << "ScreenShotter: can only take screenshots of QQuickWindows"; |
222 | + return; |
223 | + } |
224 | + |
225 | + QImage screenshot = main_window->grabWindow(); |
226 | + QtConcurrent::run(saveScreenshot, screenshot, makeFileName(), getFormat(), screenshotQuality); |
227 | +} |
228 | + |
229 | +QString ScreenGrabber::makeFileName() |
230 | +{ |
231 | + QString fileName(fileNamePrefix); |
232 | + fileName.append(QDateTime::currentDateTime().toString("yyyymmdd_hhmmsszzz")); |
233 | + fileName.append("."); |
234 | + fileName.append(getFormat()); |
235 | + return fileName; |
236 | +} |
237 | + |
238 | +QString ScreenGrabber::getFormat() |
239 | +{ |
240 | + //TODO: This should be configurable (perhaps through gsettings?) |
241 | + return "png"; |
242 | +} |
243 | |
244 | === added file 'plugins/ScreenGrabber/screengrabber.h' |
245 | --- plugins/ScreenGrabber/screengrabber.h 1970-01-01 00:00:00 +0000 |
246 | +++ plugins/ScreenGrabber/screengrabber.h 2014-10-30 02:40:10 +0000 |
247 | @@ -0,0 +1,42 @@ |
248 | +/* |
249 | + * Copyright (C) 2014 Canonical, Ltd. |
250 | + * |
251 | + * This program is free software; you can redistribute it and/or modify |
252 | + * it under the terms of the GNU General Public License as published by |
253 | + * the Free Software Foundation; version 3. |
254 | + * |
255 | + * This program is distributed in the hope that it will be useful, |
256 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
257 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
258 | + * GNU General Public License for more details. |
259 | + * |
260 | + * You should have received a copy of the GNU General Public License |
261 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
262 | + * |
263 | + * Authors: Alberto Aguirre <alberto.aguirre@canonical.com> |
264 | + */ |
265 | + |
266 | +#ifndef SNAPSHOTTER_H |
267 | +#define SNAPSHOTTER_H |
268 | + |
269 | +#include <QObject> |
270 | +#include <QString> |
271 | + |
272 | +class ScreenGrabber: public QObject |
273 | +{ |
274 | + Q_OBJECT |
275 | + |
276 | +public: |
277 | + explicit ScreenGrabber(QObject *parent = 0); |
278 | + |
279 | +public Q_SLOTS: |
280 | + void captureAndSave(); |
281 | + |
282 | +private: |
283 | + QString makeFileName(); |
284 | + QString getFormat(); |
285 | + QString fileNamePrefix; |
286 | + int screenshotQuality; |
287 | +}; |
288 | + |
289 | +#endif |
290 | |
291 | === added file 'qml/Components/ScreenGrabber.qml' |
292 | --- qml/Components/ScreenGrabber.qml 1970-01-01 00:00:00 +0000 |
293 | +++ qml/Components/ScreenGrabber.qml 2014-10-30 02:40:10 +0000 |
294 | @@ -0,0 +1,72 @@ |
295 | +/* |
296 | + * Copyright (C) 2014 Canonical, Ltd. |
297 | + * |
298 | + * This program is free software; you can redistribute it and/or modify |
299 | + * it under the terms of the GNU General Public License as published by |
300 | + * the Free Software Foundation; version 3. |
301 | + * |
302 | + * This program is distributed in the hope that it will be useful, |
303 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
304 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
305 | + * GNU General Public License for more details. |
306 | + * |
307 | + * You should have received a copy of the GNU General Public License |
308 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
309 | + */ |
310 | + |
311 | +import QtQuick 2.0 |
312 | +import QtMultimedia 5.0 |
313 | +import ScreenGrabber 0.1 |
314 | + |
315 | +Rectangle { |
316 | + id: root |
317 | + enabled: true |
318 | + visible: false |
319 | + color: "white" |
320 | + anchors.fill: parent |
321 | + opacity: 0.0 |
322 | + |
323 | + ScreenGrabber { |
324 | + id: screenGrabber |
325 | + objectName: "screenGrabber" |
326 | + } |
327 | + |
328 | + Audio { |
329 | + id: shutterSound |
330 | + audioRole: MediaPlayer.alert |
331 | + source: "/system/media/audio/ui/camera_click.ogg" |
332 | + } |
333 | + |
334 | + function capture() { |
335 | + if (!enabled) |
336 | + return; |
337 | + |
338 | + visible = true; |
339 | + shutterSound.stop(); |
340 | + shutterSound.play(); |
341 | + fadeIn.start(); |
342 | + } |
343 | + |
344 | + NumberAnimation on opacity { |
345 | + id: fadeIn |
346 | + from: 0.0 |
347 | + to: 1.0 |
348 | + onStopped: { |
349 | + if (visible) { |
350 | + fadeOut.start(); |
351 | + } |
352 | + } |
353 | + } |
354 | + |
355 | + NumberAnimation on opacity { |
356 | + id: fadeOut |
357 | + from: 1.0 |
358 | + to: 0.0 |
359 | + onStopped: { |
360 | + if (visible) { |
361 | + screenGrabber.captureAndSave(); |
362 | + visible = false; |
363 | + } |
364 | + } |
365 | + } |
366 | +} |
367 | |
368 | === added file 'qml/Components/VolumeKeyFilter.qml' |
369 | --- qml/Components/VolumeKeyFilter.qml 1970-01-01 00:00:00 +0000 |
370 | +++ qml/Components/VolumeKeyFilter.qml 2014-10-30 02:40:10 +0000 |
371 | @@ -0,0 +1,63 @@ |
372 | +/* |
373 | + * Copyright (C) 2014 Canonical, Ltd. |
374 | + * |
375 | + * This program is free software; you can redistribute it and/or modify |
376 | + * it under the terms of the GNU General Public License as published by |
377 | + * the Free Software Foundation; version 3. |
378 | + * |
379 | + * This program is distributed in the hope that it will be useful, |
380 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
381 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
382 | + * GNU General Public License for more details. |
383 | + * |
384 | + * You should have received a copy of the GNU General Public License |
385 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
386 | + */ |
387 | + |
388 | +import QtQuick 2.0 |
389 | +/*! |
390 | + \brief A filter for volume keys |
391 | + |
392 | +A filter which treats volume keys as single tri-state key with the states: |
393 | +VolumeUp Pressed, VolumeDown Pressed or Volume Up+Down pressed |
394 | +*/ |
395 | +QtObject { |
396 | + id: root |
397 | + |
398 | + signal volumeUpPressed() |
399 | + signal volumeDownPressed() |
400 | + signal bothVolumeKeysPressed() |
401 | + |
402 | + property bool volumeUpKeyPressed: false |
403 | + property bool volumeDownKeyPressed: false |
404 | + property bool aVolumeKeyWasReleased: true |
405 | + |
406 | + function onKeyPressed(key) { |
407 | + if (key == Qt.Key_VolumeUp) |
408 | + volumeUpKeyPressed = true; |
409 | + else if (key == Qt.Key_VolumeDown) |
410 | + volumeDownKeyPressed = true; |
411 | + |
412 | + if (volumeDownKeyPressed && volumeUpKeyPressed) { |
413 | + //avoids sending a signal repeatedly if both keys are held |
414 | + //instead one of the keys must have been previously released |
415 | + if (aVolumeKeyWasReleased) |
416 | + bothVolumeKeysPressed(); |
417 | + aVolumeKeyWasReleased = false; |
418 | + } else if (volumeDownKeyPressed) { |
419 | + volumeDownPressed(); |
420 | + } else if (volumeUpKeyPressed) { |
421 | + volumeUpPressed(); |
422 | + } |
423 | + } |
424 | + |
425 | + function onKeyReleased(key) { |
426 | + if (key == Qt.Key_VolumeUp) { |
427 | + volumeUpKeyPressed = false; |
428 | + aVolumeKeyWasReleased = true; |
429 | + } else if (key == Qt.Key_VolumeDown) { |
430 | + volumeDownKeyPressed = false; |
431 | + aVolumeKeyWasReleased = true; |
432 | + } |
433 | + } |
434 | +} |
435 | |
436 | === modified file 'qml/Shell.qml' |
437 | --- qml/Shell.qml 2014-10-13 15:41:29 +0000 |
438 | +++ qml/Shell.qml 2014-10-30 02:40:10 +0000 |
439 | @@ -132,23 +132,32 @@ |
440 | objectName: "dashCommunicator" |
441 | } |
442 | |
443 | + ScreenGrabber { |
444 | + id: screenGrabber |
445 | + z: edgeDemo.z + 10 |
446 | + enabled: Powerd.status === Powerd.On |
447 | + } |
448 | + |
449 | Binding { |
450 | target: ApplicationManager |
451 | property: "forceDashActive" |
452 | value: launcher.shown || launcher.dashSwipe |
453 | } |
454 | |
455 | + VolumeKeyFilter { |
456 | + id: volumeKeyFilter |
457 | + onVolumeDownPressed: volumeControl.volumeDown() |
458 | + onVolumeUpPressed: volumeControl.volumeUp() |
459 | + onBothVolumeKeysPressed: screenGrabber.capture() |
460 | + } |
461 | |
462 | WindowKeysFilter { |
463 | - // Handle but do not filter out volume keys |
464 | - Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; } |
465 | - Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; } |
466 | - |
467 | Keys.onPressed: { |
468 | if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) { |
469 | dialogs.onPowerKeyPressed(); |
470 | event.accepted = true; |
471 | } else { |
472 | + volumeKeyFilter.onKeyPressed(event.key); |
473 | event.accepted = false; |
474 | } |
475 | } |
476 | @@ -158,6 +167,7 @@ |
477 | dialogs.onPowerKeyReleased(); |
478 | event.accepted = true; |
479 | } else { |
480 | + volumeKeyFilter.onKeyReleased(event.key); |
481 | event.accepted = false; |
482 | } |
483 | } |
484 | |
485 | === modified file 'tests/mocks/QtMultimedia/QtMultimedia.qmltypes' |
486 | --- tests/mocks/QtMultimedia/QtMultimedia.qmltypes 2014-06-26 07:47:57 +0000 |
487 | +++ tests/mocks/QtMultimedia/QtMultimedia.qmltypes 2014-10-30 02:40:10 +0000 |
488 | @@ -20,11 +20,21 @@ |
489 | "StoppedState": 2 |
490 | } |
491 | } |
492 | + Enum { |
493 | + name: "AudioRole" |
494 | + values: { |
495 | + "AlarmRole": 0, |
496 | + "AlertRole": 1, |
497 | + "MultimediaRole": 2, |
498 | + "PhoneRole": 3 |
499 | + } |
500 | + } |
501 | Property { name: "source"; type: "QUrl" } |
502 | Property { name: "playbackState"; type: "PlaybackState"; isReadonly: true } |
503 | Property { name: "position"; type: "int"; isReadonly: true } |
504 | Property { name: "duration"; type: "int"; isReadonly: true } |
505 | Property { name: "errorString"; type: "string"; isReadonly: true } |
506 | + Property { name: "audioRole"; type: "AudioRole" } |
507 | Signal { |
508 | name: "sourceChanged" |
509 | Parameter { name: "source"; type: "QUrl" } |
510 | |
511 | === modified file 'tests/mocks/QtMultimedia/audio.cpp' |
512 | --- tests/mocks/QtMultimedia/audio.cpp 2014-09-12 14:51:55 +0000 |
513 | +++ tests/mocks/QtMultimedia/audio.cpp 2014-10-30 02:40:10 +0000 |
514 | @@ -105,3 +105,13 @@ |
515 | stop(); |
516 | } |
517 | } |
518 | + |
519 | +Audio::AudioRole Audio::audioRole() const |
520 | +{ |
521 | + return Audio::MultimediaRole; |
522 | +} |
523 | + |
524 | +void Audio::setAudioRole(Audio::AudioRole audioRole) |
525 | +{ |
526 | + Q_UNUSED(audioRole); |
527 | +} |
528 | |
529 | === modified file 'tests/mocks/QtMultimedia/audio.h' |
530 | --- tests/mocks/QtMultimedia/audio.h 2013-11-14 12:12:05 +0000 |
531 | +++ tests/mocks/QtMultimedia/audio.h 2014-10-30 02:40:10 +0000 |
532 | @@ -27,11 +27,13 @@ |
533 | { |
534 | Q_OBJECT |
535 | Q_ENUMS(PlaybackState) |
536 | + Q_ENUMS(AudioRole) |
537 | Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) |
538 | Q_PROPERTY(PlaybackState playbackState READ playbackState NOTIFY playbackStateChanged) |
539 | Q_PROPERTY(int position READ position NOTIFY positionChanged) |
540 | Q_PROPERTY(int duration READ duration NOTIFY durationChanged) |
541 | Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged) |
542 | + Q_PROPERTY(AudioRole audioRole READ audioRole WRITE setAudioRole) |
543 | public: |
544 | enum PlaybackState { |
545 | PlayingState, |
546 | @@ -39,6 +41,13 @@ |
547 | StoppedState |
548 | }; |
549 | |
550 | + enum AudioRole { |
551 | + AlarmRole, |
552 | + AlertRole, |
553 | + MultimediaRole, |
554 | + PhoneRole |
555 | + }; |
556 | + |
557 | explicit Audio(QObject *parent = 0); |
558 | |
559 | QUrl source() const; |
560 | @@ -52,6 +61,9 @@ |
561 | |
562 | QString errorString() const; |
563 | |
564 | + AudioRole audioRole() const; |
565 | + void setAudioRole(AudioRole audioRole); |
566 | + |
567 | public Q_SLOTS: |
568 | void pause(); |
569 | void play(); |
FAILED: Continuous integration, rev:1288 jenkins. qa.ubuntu. com/job/ unity8- ci/4392/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/5150/ console jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- utopic/ 1393 jenkins. qa.ubuntu. com/job/ unity8- utopic- amd64-ci/ 1486 jenkins. qa.ubuntu. com/job/ unity8- utopic- i386-ci/ 1486 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- mako/4896/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/6402 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/6402/ artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 13696
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/4392/ rebuild
http://