Merge lp:~unity-2d-team/unity-2d/unity-2d-shell-shaped-testability-shapetests into lp:~unity-2d-team/unity-2d/unity-2d-shell
- unity-2d-shell-shaped-testability-shapetests
- Merge into unity-2d-shell
Status: | Merged |
---|---|
Approved by: | Michał Sawicz |
Approved revision: | 937 |
Merged at revision: | 921 |
Proposed branch: | lp:~unity-2d-team/unity-2d/unity-2d-shell-shaped-testability-shapetests |
Merge into: | lp:~unity-2d-team/unity-2d/unity-2d-shell |
Diff against target: |
1073 lines (+812/-51) 20 files modified
CMakeLists.txt (+1/-0) libunity-2d-private/Unity2d/plugin.cpp (+10/-0) libunity-2d-private/src/CMakeLists.txt (+3/-0) libunity-2d-private/src/inputshapemanager.cpp (+87/-0) libunity-2d-private/src/inputshapemanager.h (+38/-0) libunity-2d-private/src/inputshapemask.cpp (+88/-0) libunity-2d-private/src/inputshapemask.h (+48/-0) libunity-2d-private/src/inputshaperectangle.cpp (+86/-0) libunity-2d-private/src/inputshaperectangle.h (+49/-0) libunity-2d-private/src/unity2ddeclarativeview.cpp (+6/-0) libunity-2d-private/src/unity2ddeclarativeview.h (+2/-0) shell/MERGE-TODO (+0/-2) shell/Shell.qml (+27/-1) shell/app/shelldeclarativeview.cpp (+1/-46) shell/app/shelldeclarativeview.h (+1/-1) shell/dash/Home.qml (+1/-0) tests/getshape/CMakeLists.txt (+22/-0) tests/getshape/getshape.cpp (+102/-0) tests/run-tests.rb (+1/-1) tests/shell/input_shaping.rb (+239/-0) |
To merge this branch: | bzr merge lp:~unity-2d-team/unity-2d/unity-2d-shell-shaped-testability-shapetests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michał Sawicz | Approve | ||
Review via email: mp+89236@code.launchpad.net |
Commit message
Description of the change
[shell] Shape the shell window input according to what components are visible
Michał Sawicz (saviq) wrote : | # |
- 927. By Michał Sawicz
-
Merge from shell
Michał Sawicz (saviq) wrote : | # |
* getshape.cpp:72 unnecessary space before semicolon
* getshape.cpp maybe use QUrl::fromLocalFile / toLocalFile to handle things like ~?
* getshape.cpp doesn't seem to handle masks, just rectangles?
* input_shaping.rb:9 I'm sure Gerry will be pleased ;)
* input_shaping.rb:35 open_window_at has been refactored into a separate TmpWindow class, see autohide_
* input_shaping.rb:68 maybe use a constant like other UNITY_2D_* do?, especially if #{pwd} is really $PWD
* input_shaping.rb:92 says "Launcher Autohide and Show Tests"
* input_shaping.rb:92 maybe abstract the constants to run-tests.rb? we do have the launcher width in launcher tests, too, might make sense to only have them in one place
* input_shaping.rb:94 DASH_HEIGHT_
* input_shaping.
* input_shaping.
- 928. By Ugo Riboni
-
Fix minor style issue and make use of unity2dDirectory more robust
- 929. By Ugo Riboni
-
Don't animate the shape of the launcher
- 930. By Ugo Riboni
-
Add missing verification image
Gerry Boland (gerboland) wrote : | # |
Please can you add a comment of the following form to each test case?:
# Test case objectives:
# * Check the Launcher position on Empty desktop
# Pre-conditions
# * Desktop with no running applications
# Test steps
# * Verify something
# * Click a button
# * Verify this happens
# Post-conditions
# * What non-unity2d thing should exist at test end
# References
# * None (lp bug number?)
This helps show what test cases need to be altered for future changes, and lets non-experts analyse the coverage of our test-suite.
And one more thing: "desktop_geometry" could be added to the Ruby XDo library
- 931. By Ugo Riboni
-
Fix style issues, use verify in tests and not assert, remove dead code, include shell tests in the global test run
- 932. By Ugo Riboni
-
Put back asserts in the utility functions as verify seems to work inside tests only
- 933. By Ugo Riboni
-
Ensure we're running a panel before the test battery starts. Fix some style issues.
- 934. By Ugo Riboni
-
Remove the test for same size before comparing images, and add return code check instead
- 935. By Ugo Riboni
-
Tap the button to close shortcuts instead of fiddling with internal variables
- 936. By Ugo Riboni
-
Put back the image size tests as they never hurt, and use verify_true to check the return of the compare_images
- 937. By Ugo Riboni
-
Wait a bit after simulating taps and keystrokes, to ensure everything settles before getting shapes
Michał Sawicz (saviq) : | # |
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2012-01-10 16:41:53 +0000 |
3 | +++ CMakeLists.txt 2012-01-20 13:41:29 +0000 |
4 | @@ -97,6 +97,7 @@ |
5 | add_subdirectory(spread) |
6 | add_subdirectory(shell) |
7 | add_subdirectory(po) |
8 | +add_subdirectory(tests/getshape) |
9 | |
10 | # uninstall target |
11 | configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) |
12 | |
13 | === modified file 'libunity-2d-private/Unity2d/plugin.cpp' |
14 | --- libunity-2d-private/Unity2d/plugin.cpp 2012-01-20 10:19:06 +0000 |
15 | +++ libunity-2d-private/Unity2d/plugin.cpp 2012-01-20 13:41:29 +0000 |
16 | @@ -69,6 +69,11 @@ |
17 | #include "spreadmonitor.h" |
18 | #include "focuspath.h" |
19 | |
20 | +#include "unity2ddeclarativeview.h" |
21 | +#include "inputshapemanager.h" |
22 | +#include "inputshaperectangle.h" |
23 | +#include "inputshapemask.h" |
24 | + |
25 | #include <QtDeclarative/qdeclarative.h> |
26 | #include <QDeclarativeEngine> |
27 | #include <QDeclarativeContext> |
28 | @@ -161,6 +166,11 @@ |
29 | qmlRegisterType<GestureHandler>(uri, 0, 1, "GestureHandler"); |
30 | qmlRegisterType<WindowsIntersectMonitor>(uri, 0, 1, "WindowsIntersectMonitor"); |
31 | qmlRegisterType<SpreadMonitor>(uri, 0, 1, "SpreadMonitor"); |
32 | + |
33 | + qmlRegisterType<InputShapeManager>(uri, 0, 1, "InputShapeManager"); |
34 | + qmlRegisterType<InputShapeRectangle>(uri, 0, 1, "InputShapeRectangle"); |
35 | + qmlRegisterType<InputShapeMask>(uri, 0, 1, "InputShapeMask"); |
36 | + qmlRegisterType<Unity2DDeclarativeView>(); |
37 | } |
38 | |
39 | void Unity2dPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri) |
40 | |
41 | === modified file 'libunity-2d-private/src/CMakeLists.txt' |
42 | --- libunity-2d-private/src/CMakeLists.txt 2012-01-20 10:19:06 +0000 |
43 | +++ libunity-2d-private/src/CMakeLists.txt 2012-01-20 13:41:29 +0000 |
44 | @@ -73,6 +73,9 @@ |
45 | abstractdbusservicemonitor.cpp |
46 | spreadmonitor.cpp |
47 | focuspath.cpp |
48 | + inputshapemanager.cpp |
49 | + inputshaperectangle.cpp |
50 | + inputshapemask.cpp |
51 | ) |
52 | |
53 | # Build |
54 | |
55 | === added file 'libunity-2d-private/src/inputshapemanager.cpp' |
56 | --- libunity-2d-private/src/inputshapemanager.cpp 1970-01-01 00:00:00 +0000 |
57 | +++ libunity-2d-private/src/inputshapemanager.cpp 2012-01-20 13:41:29 +0000 |
58 | @@ -0,0 +1,87 @@ |
59 | +#include <QDebug> |
60 | +#include <QRect> |
61 | +#include <QX11Info> |
62 | +#include <QRegion> |
63 | + |
64 | +#include "inputshapemanager.h" |
65 | +#include "unity2ddeclarativeview.h" |
66 | +#include "screeninfo.h" |
67 | + |
68 | +// X11 |
69 | +#include <X11/Xlib.h> |
70 | +#include <X11/Xregion.h> |
71 | +#include <X11/extensions/shape.h> |
72 | + |
73 | +InputShapeManager::InputShapeManager(QObject *parent) : |
74 | + QObject(parent), |
75 | + m_target(0) |
76 | +{ |
77 | +} |
78 | + |
79 | +void InputShapeManager::updateManagedShape() |
80 | +{ |
81 | + if (m_target == NULL || !m_target->isVisible()) { |
82 | + return; |
83 | + } |
84 | + |
85 | + QBitmap inputShape(m_target->width(), m_target->height()); |
86 | + inputShape.fill(Qt::color0); |
87 | + QPainter painter(&inputShape); |
88 | + |
89 | + Q_FOREACH(InputShapeRectangle* shape, m_shapes) { |
90 | + if (shape->enabled()) { |
91 | + painter.drawPixmap(shape->rectangle().x(), shape->rectangle().y(), |
92 | + shape->shape()); |
93 | + } |
94 | + } |
95 | + |
96 | + // FIXME: A more efficient way of doing this would be to call XShapeCombineMask passing an X11 |
97 | + // pixmap created from the mask bitmap. However for some reason I wasn't able to figure out yet |
98 | + // I get a lot of warnings when calling QBitmap::handle, so for now I'm passing a region as a |
99 | + // workaround. |
100 | + XShapeCombineRegion(QX11Info::display(), m_target->effectiveWinId(), ShapeInput, |
101 | + 0, 0, QRegion(inputShape).handle(), ShapeSet); |
102 | +} |
103 | + |
104 | +Unity2DDeclarativeView* InputShapeManager::target() const |
105 | +{ |
106 | + return m_target; |
107 | +} |
108 | + |
109 | +void InputShapeManager::setTarget(Unity2DDeclarativeView *target) |
110 | +{ |
111 | + if (m_target != target) { |
112 | + if (m_target != NULL) m_target->disconnect(this); |
113 | + |
114 | + //TODO: de-shape the current target view, if any, before shaping the new one. not used now |
115 | + // as we never change the view anyway. |
116 | + |
117 | + m_target = target; |
118 | + if (m_target != NULL) { |
119 | + // due to the way xshape works we need to re-apply the shaping every time the target window |
120 | + // is mapped again. |
121 | + connect(m_target, SIGNAL(shown()), SLOT(updateManagedShape())); |
122 | + connect(m_target, SIGNAL(sceneResized(QSize)), SLOT(updateManagedShape())); |
123 | + } |
124 | + Q_EMIT targetChanged(); |
125 | + updateManagedShape(); |
126 | + } |
127 | +} |
128 | + |
129 | +QDeclarativeListProperty<InputShapeRectangle> InputShapeManager::shapes() |
130 | +{ |
131 | + return QDeclarativeListProperty<InputShapeRectangle>(this, this, &InputShapeManager::appendShape); |
132 | +} |
133 | + |
134 | +void InputShapeManager::appendShape(QDeclarativeListProperty<InputShapeRectangle> *list, InputShapeRectangle *shape) |
135 | +{ |
136 | + InputShapeManager* instance = qobject_cast<InputShapeManager*>(list->object); |
137 | + if (instance != NULL) { |
138 | + instance->m_shapes.append(shape); |
139 | + instance->connect(shape, SIGNAL(shapeChanged()), SLOT(updateManagedShape())); |
140 | + instance->connect(shape, SIGNAL(enabledChanged()), SLOT(updateManagedShape())); |
141 | + instance->updateManagedShape(); |
142 | + } |
143 | +} |
144 | + |
145 | +#include "inputshapemanager.moc" |
146 | |
147 | === added file 'libunity-2d-private/src/inputshapemanager.h' |
148 | --- libunity-2d-private/src/inputshapemanager.h 1970-01-01 00:00:00 +0000 |
149 | +++ libunity-2d-private/src/inputshapemanager.h 2012-01-20 13:41:29 +0000 |
150 | @@ -0,0 +1,38 @@ |
151 | +#ifndef INPUTSHAPEMANAGER_H |
152 | +#define INPUTSHAPEMANAGER_H |
153 | + |
154 | +#include <QObject> |
155 | +#include <QDeclarativeListProperty> |
156 | + |
157 | +#include "inputshaperectangle.h" |
158 | + |
159 | +class Unity2DDeclarativeView; |
160 | + |
161 | +class InputShapeManager : public QObject |
162 | +{ |
163 | + Q_OBJECT |
164 | + Q_PROPERTY(Unity2DDeclarativeView* target READ target WRITE setTarget NOTIFY targetChanged) |
165 | + Q_PROPERTY(QDeclarativeListProperty<InputShapeRectangle> shapes READ shapes) |
166 | + Q_CLASSINFO("DefaultProperty", "shapes") |
167 | + |
168 | +public: |
169 | + explicit InputShapeManager(QObject *parent = 0); |
170 | + Unity2DDeclarativeView* target() const; |
171 | + void setTarget(Unity2DDeclarativeView* target); |
172 | + QDeclarativeListProperty<InputShapeRectangle> shapes(); |
173 | + |
174 | +Q_SIGNALS: |
175 | + void targetChanged(); |
176 | + |
177 | +public Q_SLOTS: |
178 | + void updateManagedShape(); |
179 | + |
180 | +protected: |
181 | + static void appendShape(QDeclarativeListProperty<InputShapeRectangle> *property, InputShapeRectangle *value); |
182 | + |
183 | +private: |
184 | + Unity2DDeclarativeView* m_target; |
185 | + QList<InputShapeRectangle*> m_shapes; |
186 | +}; |
187 | + |
188 | +#endif // INPUTSHAPEMANAGER_H |
189 | |
190 | === added file 'libunity-2d-private/src/inputshapemask.cpp' |
191 | --- libunity-2d-private/src/inputshapemask.cpp 1970-01-01 00:00:00 +0000 |
192 | +++ libunity-2d-private/src/inputshapemask.cpp 2012-01-20 13:41:29 +0000 |
193 | @@ -0,0 +1,88 @@ |
194 | +#include "inputshapemask.h" |
195 | +#include "config.h" |
196 | + |
197 | +#include <QBitmap> |
198 | +#include <QDebug> |
199 | + |
200 | +InputShapeMask::InputShapeMask(QObject *parent) : |
201 | + QObject(parent), |
202 | + m_enabled(true) |
203 | +{ |
204 | +} |
205 | + |
206 | +void InputShapeMask::updateShape() |
207 | +{ |
208 | + QBitmap newShape; |
209 | + |
210 | + if (!m_source.isEmpty() && m_color.isValid()) { |
211 | + QPixmap image; |
212 | + QString path = unity2dDirectory() + "/" + m_source; |
213 | + if (image.load(path)) { |
214 | + newShape = image.createMaskFromColor(m_color.rgb(), Qt::MaskInColor); |
215 | + } else { |
216 | + qWarning() << "Failed to load input shape mask image from" << path; |
217 | + } |
218 | + } |
219 | + |
220 | + m_shape = newShape; |
221 | + Q_EMIT shapeChanged(); |
222 | +} |
223 | + |
224 | +QString InputShapeMask::source() const |
225 | +{ |
226 | + return m_source; |
227 | +} |
228 | + |
229 | +QColor InputShapeMask::color() const |
230 | +{ |
231 | + return m_color; |
232 | +} |
233 | + |
234 | +QPoint InputShapeMask::position() const |
235 | +{ |
236 | + return m_position; |
237 | +} |
238 | + |
239 | +bool InputShapeMask::enabled() const |
240 | +{ |
241 | + return m_enabled; |
242 | +} |
243 | + |
244 | +QBitmap InputShapeMask::shape() const |
245 | +{ |
246 | + return m_shape; |
247 | +} |
248 | + |
249 | +void InputShapeMask::setSource(const QString &source) |
250 | +{ |
251 | + if (m_source != source) { |
252 | + m_source = source; |
253 | + updateShape(); |
254 | + } |
255 | +} |
256 | + |
257 | +void InputShapeMask::setColor(const QColor &color) |
258 | +{ |
259 | + if (m_color != color) { |
260 | + m_color = color; |
261 | + updateShape(); |
262 | + } |
263 | +} |
264 | + |
265 | +void InputShapeMask::setPosition(const QPoint &position) |
266 | +{ |
267 | + if (m_position != position) { |
268 | + m_position = position; |
269 | + Q_EMIT positionChanged(); |
270 | + } |
271 | +} |
272 | + |
273 | +void InputShapeMask::setEnabled(bool enabled) |
274 | +{ |
275 | + if (m_enabled != enabled) { |
276 | + m_enabled = enabled; |
277 | + Q_EMIT enabledChanged(); |
278 | + } |
279 | +} |
280 | + |
281 | +#include "inputshapemask.moc" |
282 | |
283 | === added file 'libunity-2d-private/src/inputshapemask.h' |
284 | --- libunity-2d-private/src/inputshapemask.h 1970-01-01 00:00:00 +0000 |
285 | +++ libunity-2d-private/src/inputshapemask.h 2012-01-20 13:41:29 +0000 |
286 | @@ -0,0 +1,48 @@ |
287 | +#ifndef INPUTSHAPEMASK_H |
288 | +#define INPUTSHAPEMASK_H |
289 | + |
290 | +#include <QObject> |
291 | +#include <QColor> |
292 | +#include <QPoint> |
293 | +#include <QBitmap> |
294 | + |
295 | +class InputShapeMask : public QObject |
296 | +{ |
297 | + Q_OBJECT |
298 | + Q_PROPERTY(QString source READ source WRITE setSource) |
299 | + Q_PROPERTY(QColor color READ color WRITE setColor) |
300 | + Q_PROPERTY(QPoint position READ position WRITE setPosition NOTIFY positionChanged) |
301 | + Q_PROPERTY(QBitmap shape READ shape NOTIFY shapeChanged) |
302 | + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) |
303 | + |
304 | +public: |
305 | + explicit InputShapeMask(QObject *parent = 0); |
306 | + |
307 | + QString source() const; |
308 | + QColor color() const; |
309 | + QPoint position() const; |
310 | + bool enabled() const; |
311 | + QBitmap shape() const; |
312 | + |
313 | + void setSource(const QString& source); |
314 | + void setColor(const QColor& color); |
315 | + void setPosition(const QPoint& position); |
316 | + void setEnabled(bool enabled); |
317 | + |
318 | +Q_SIGNALS: |
319 | + void enabledChanged(); |
320 | + void shapeChanged(); |
321 | + void positionChanged(); |
322 | + |
323 | +protected: |
324 | + void updateShape(); |
325 | + |
326 | +private: |
327 | + QString m_source; |
328 | + QColor m_color; |
329 | + QPoint m_position; |
330 | + bool m_enabled; |
331 | + QBitmap m_shape; |
332 | +}; |
333 | + |
334 | +#endif // INPUTSHAPEMASK_H |
335 | |
336 | === added file 'libunity-2d-private/src/inputshaperectangle.cpp' |
337 | --- libunity-2d-private/src/inputshaperectangle.cpp 1970-01-01 00:00:00 +0000 |
338 | +++ libunity-2d-private/src/inputshaperectangle.cpp 2012-01-20 13:41:29 +0000 |
339 | @@ -0,0 +1,86 @@ |
340 | +#include "inputshaperectangle.h" |
341 | +#include "inputshapemask.h" |
342 | + |
343 | +#include <QBitmap> |
344 | +#include <QPainter> |
345 | +#include <QPainterPath> |
346 | +#include <QDebug> |
347 | +#include <QRect> |
348 | + |
349 | +InputShapeRectangle::InputShapeRectangle(QObject *parent) : |
350 | + QObject(parent), |
351 | + m_enabled(true) |
352 | +{ |
353 | +} |
354 | + |
355 | +void InputShapeRectangle::updateShape() |
356 | +{ |
357 | + QBitmap newShape(m_rectangle.width(), m_rectangle.height()); |
358 | + newShape.fill(Qt::color1); |
359 | + |
360 | + if (!m_rectangle.isEmpty() && m_masks.count() > 0) { |
361 | + QPainter painter(&newShape); |
362 | + painter.setBackgroundMode(Qt::OpaqueMode); |
363 | + |
364 | + Q_FOREACH (InputShapeMask* mask, m_masks) { |
365 | + if (mask->enabled()) { |
366 | + painter.drawPixmap(mask->position(), mask->shape()); |
367 | + } |
368 | + } |
369 | + } |
370 | + |
371 | + m_shape = newShape; |
372 | + Q_EMIT shapeChanged(); |
373 | +} |
374 | + |
375 | +QRect InputShapeRectangle::rectangle() const |
376 | +{ |
377 | + return m_rectangle; |
378 | +} |
379 | + |
380 | +void InputShapeRectangle::setRectangle(QRect rectangle) |
381 | +{ |
382 | + if (rectangle != m_rectangle) { |
383 | + m_rectangle = rectangle; |
384 | + updateShape(); |
385 | + Q_EMIT rectangleChanged(); |
386 | + } |
387 | +} |
388 | + |
389 | +bool InputShapeRectangle::enabled() const |
390 | +{ |
391 | + return m_enabled; |
392 | +} |
393 | + |
394 | +void InputShapeRectangle::setEnabled(bool enabled) |
395 | +{ |
396 | + if (enabled != m_enabled) { |
397 | + m_enabled = enabled; |
398 | + Q_EMIT enabledChanged(); |
399 | + |
400 | + } |
401 | +} |
402 | + |
403 | +QBitmap InputShapeRectangle::shape() const |
404 | +{ |
405 | + return m_shape; |
406 | +} |
407 | + |
408 | +QDeclarativeListProperty<InputShapeMask> InputShapeRectangle::masks() |
409 | +{ |
410 | + return QDeclarativeListProperty<InputShapeMask>(this, this, &InputShapeRectangle::appendMask); |
411 | +} |
412 | + |
413 | +void InputShapeRectangle::appendMask(QDeclarativeListProperty<InputShapeMask> *list, InputShapeMask *mask) |
414 | +{ |
415 | + InputShapeRectangle* instance = qobject_cast<InputShapeRectangle*>(list->object); |
416 | + if (instance != NULL) { |
417 | + instance->m_masks.append(mask); |
418 | + instance->connect(mask, SIGNAL(enabledChanged()), SLOT(updateShape())); |
419 | + instance->connect(mask, SIGNAL(shapeChanged()), SLOT(updateShape())); |
420 | + instance->connect(mask, SIGNAL(positionChanged()), SLOT(updateShape())); |
421 | + instance->updateShape(); |
422 | + } |
423 | +} |
424 | + |
425 | +#include "inputshaperectangle.moc" |
426 | |
427 | === added file 'libunity-2d-private/src/inputshaperectangle.h' |
428 | --- libunity-2d-private/src/inputshaperectangle.h 1970-01-01 00:00:00 +0000 |
429 | +++ libunity-2d-private/src/inputshaperectangle.h 2012-01-20 13:41:29 +0000 |
430 | @@ -0,0 +1,49 @@ |
431 | +#ifndef INPUTSHAPERECTANGLE_H |
432 | +#define INPUTSHAPERECTANGLE_H |
433 | + |
434 | +#include <QObject> |
435 | +#include <QRect> |
436 | +#include <QBitmap> |
437 | +#include <QDeclarativeListProperty> |
438 | +#include <QList> |
439 | + |
440 | +class InputShapeMask; |
441 | + |
442 | +class InputShapeRectangle : public QObject |
443 | +{ |
444 | + Q_OBJECT |
445 | + Q_PROPERTY(QRect rectangle READ rectangle WRITE setRectangle NOTIFY rectangleChanged) |
446 | + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) |
447 | + Q_PROPERTY(QBitmap shape READ shape NOTIFY shapeChanged) |
448 | + Q_PROPERTY(QDeclarativeListProperty<InputShapeMask> masks READ masks) |
449 | + Q_CLASSINFO("DefaultProperty", "masks") |
450 | + |
451 | +public: |
452 | + explicit InputShapeRectangle(QObject *parent = 0); |
453 | + |
454 | + QRect rectangle() const; |
455 | + void setRectangle(QRect rectangle); |
456 | + bool enabled() const; |
457 | + void setEnabled(bool enabled); |
458 | + QBitmap shape() const; |
459 | + QDeclarativeListProperty<InputShapeMask> masks(); |
460 | + |
461 | +protected: |
462 | + static void appendMask(QDeclarativeListProperty<InputShapeMask> *list, InputShapeMask *mask); |
463 | + |
464 | +protected Q_SLOTS: |
465 | + void updateShape(); |
466 | + |
467 | +Q_SIGNALS: |
468 | + void rectangleChanged(); |
469 | + void enabledChanged(); |
470 | + void shapeChanged(); |
471 | + |
472 | +private: |
473 | + QRect m_rectangle; |
474 | + bool m_enabled; |
475 | + QBitmap m_shape; |
476 | + QList<InputShapeMask*> m_masks; |
477 | +}; |
478 | + |
479 | +#endif // INPUTSHAPERECTANGLE_H |
480 | |
481 | === modified file 'libunity-2d-private/src/unity2ddeclarativeview.cpp' |
482 | --- libunity-2d-private/src/unity2ddeclarativeview.cpp 2011-12-08 19:41:38 +0000 |
483 | +++ libunity-2d-private/src/unity2ddeclarativeview.cpp 2012-01-20 13:41:29 +0000 |
484 | @@ -21,6 +21,7 @@ |
485 | #include <QVariant> |
486 | #include <QX11Info> |
487 | #include <QFileInfo> |
488 | +#include <QShowEvent> |
489 | |
490 | #include <X11/Xlib.h> |
491 | #include <X11/Xatom.h> |
492 | @@ -158,6 +159,11 @@ |
493 | Q_EMIT globalPositionChanged(globalPosition()); |
494 | } |
495 | |
496 | +void Unity2DDeclarativeView::showEvent(QShowEvent *event) |
497 | +{ |
498 | + Q_EMIT shown(); |
499 | +} |
500 | + |
501 | |
502 | /* Obtaining & Discarding Keyboard Focus for Window on Demand |
503 | * |
504 | |
505 | === modified file 'libunity-2d-private/src/unity2ddeclarativeview.h' |
506 | --- libunity-2d-private/src/unity2ddeclarativeview.h 2011-12-08 19:41:38 +0000 |
507 | +++ libunity-2d-private/src/unity2ddeclarativeview.h 2012-01-20 13:41:29 +0000 |
508 | @@ -44,10 +44,12 @@ |
509 | void useOpenGLChanged(bool); |
510 | void transparentBackgroundChanged(bool); |
511 | void globalPositionChanged(QPoint); |
512 | + void shown(); |
513 | |
514 | protected: |
515 | void setupViewport(); |
516 | virtual void moveEvent(QMoveEvent* event); |
517 | + virtual void showEvent(QShowEvent *event); |
518 | |
519 | protected Q_SLOTS: |
520 | void forceActivateWindow(); |
521 | |
522 | === modified file 'shell/MERGE-TODO' |
523 | --- shell/MERGE-TODO 2012-01-10 16:41:53 +0000 |
524 | +++ shell/MERGE-TODO 2012-01-20 13:41:29 +0000 |
525 | @@ -3,8 +3,6 @@ |
526 | |
527 | = High = |
528 | |
529 | -* Shell window should be input-shaped so that the part that belongs to neither dash nor launcher does not receive input |
530 | - - This should also work correctly with the dash bottom-right corner which is already input shaped. |
531 | * The panel now has window buttons to close, minimize, maximize the dash. Make these work with the shell and remove the |
532 | bottom-right maximize button we have now. |
533 | * Add back this Launcher feature: when alt+f1 is pressed and launcher already has focus, the shell window should be deactivated |
534 | |
535 | === modified file 'shell/Shell.qml' |
536 | --- shell/Shell.qml 2012-01-17 11:25:08 +0000 |
537 | +++ shell/Shell.qml 2012-01-20 13:41:29 +0000 |
538 | @@ -23,7 +23,7 @@ |
539 | Item { |
540 | id: shell |
541 | height: screen.availableGeometry.height |
542 | - width: shell.childrenRect.width |
543 | + width: screen.availableGeometry.width |
544 | |
545 | Accessible.name: "shell" |
546 | |
547 | @@ -114,4 +114,30 @@ |
548 | declarativeView.forceDeactivateWindow() |
549 | } |
550 | } |
551 | + |
552 | + InputShapeManager { |
553 | + target: declarativeView |
554 | + |
555 | + InputShapeRectangle { |
556 | + // Prevent the launcher mask to ever go to negative values or be less than 1 pixel |
557 | + // (to preserve the autohide/intellihide edge detection) |
558 | + rectangle: Qt.rect(0, launcherLoader.y, |
559 | + launcherLoader.visibilityController.shown ? launcherLoader.width : 1, |
560 | + launcherLoader.height) |
561 | + enabled: launcherLoader.status == Loader.Ready |
562 | + } |
563 | + |
564 | + InputShapeRectangle { |
565 | + rectangle: Qt.rect(dashLoader.x, dashLoader.y, dashLoader.width, dashLoader.height) |
566 | + enabled: dashLoader.status == Loader.Ready && dashLoader.item.active |
567 | + |
568 | + InputShapeMask { |
569 | + id: shape1 |
570 | + source: "shell/dash/artwork/desktop_dash_background_no_transparency.png" |
571 | + color: "red" |
572 | + position: Qt.point(dashLoader.width - 50, dashLoader.height - 49) |
573 | + enabled: declarativeView.dashMode == ShellDeclarativeView.DesktopMode |
574 | + } |
575 | + } |
576 | + } |
577 | } |
578 | |
579 | === modified file 'shell/app/shelldeclarativeview.cpp' |
580 | --- shell/app/shelldeclarativeview.cpp 2012-01-17 13:59:13 +0000 |
581 | +++ shell/app/shelldeclarativeview.cpp 2012-01-20 13:41:29 +0000 |
582 | @@ -166,7 +166,7 @@ |
583 | void |
584 | ShellDeclarativeView::showEvent(QShowEvent *event) |
585 | { |
586 | - QDeclarativeView::showEvent(event); |
587 | + Unity2DDeclarativeView::showEvent(event); |
588 | /* Note that this has to be called everytime the window is shown, as the WM |
589 | will remove the flags when the window is hidden */ |
590 | setWMFlags(); |
591 | @@ -254,51 +254,6 @@ |
592 | } |
593 | |
594 | void |
595 | -ShellDeclarativeView::resizeEvent(QResizeEvent* event) |
596 | -{ |
597 | - if (!QX11Info::isCompositingManagerRunning()) { |
598 | - updateMask(); |
599 | - } |
600 | - QDeclarativeView::resizeEvent(event); |
601 | -} |
602 | - |
603 | -static QBitmap |
604 | -createCornerMask() |
605 | -{ |
606 | - QPixmap pix(unity2dDirectory() + "/shell/dash/artwork/desktop_dash_background_no_transparency.png"); |
607 | - return pix.createMaskFromColor(Qt::red, Qt::MaskOutColor); |
608 | -} |
609 | - |
610 | -void |
611 | -ShellDeclarativeView::updateMask() |
612 | -{ |
613 | - if (m_mode == FullScreenMode) { |
614 | - clearMask(); |
615 | - return; |
616 | - } |
617 | - QBitmap bmp(size()); |
618 | - { |
619 | - static QBitmap corner = createCornerMask(); |
620 | - static QBitmap top = corner.copy(0, 0, corner.width(), 1); |
621 | - static QBitmap left = corner.copy(0, 0, 1, corner.height()); |
622 | - |
623 | - const int cornerX = bmp.width() - corner.width(); |
624 | - const int cornerY = bmp.height() - corner.height(); |
625 | - |
626 | - QPainter painter(&bmp); |
627 | - painter.fillRect(bmp.rect(), Qt::color1); |
628 | - painter.setBackgroundMode(Qt::OpaqueMode); |
629 | - painter.setBackground(Qt::color1); |
630 | - painter.setPen(Qt::color0); |
631 | - painter.drawPixmap(cornerX, cornerY, corner); |
632 | - |
633 | - painter.drawTiledPixmap(cornerX, 0, top.width(), cornerY, top); |
634 | - painter.drawTiledPixmap(0, cornerY, cornerX, left.height(), left); |
635 | - } |
636 | - setMask(bmp); |
637 | -} |
638 | - |
639 | -void |
640 | ShellDeclarativeView::toggleDash() |
641 | { |
642 | if (dashActive()) { |
643 | |
644 | === modified file 'shell/app/shelldeclarativeview.h' |
645 | --- shell/app/shelldeclarativeview.h 2011-12-21 18:42:06 +0000 |
646 | +++ shell/app/shelldeclarativeview.h 2012-01-20 13:41:29 +0000 |
647 | @@ -104,7 +104,6 @@ |
648 | void onAltF1Pressed(); |
649 | |
650 | protected: |
651 | - void resizeEvent(QResizeEvent*); |
652 | virtual void showEvent(QShowEvent *event); |
653 | virtual void mouseMoveEvent(QMouseEvent *event); |
654 | virtual void leaveEvent(QEvent *event); |
655 | @@ -118,6 +117,7 @@ |
656 | void updateMask(); |
657 | void setWMFlags(); |
658 | bool isSpreadActive(); |
659 | + void updateInputShape(); |
660 | |
661 | DashMode m_mode; |
662 | bool m_expanded; |
663 | |
664 | === modified file 'shell/dash/Home.qml' |
665 | --- shell/dash/Home.qml 2012-01-10 10:42:46 +0000 |
666 | +++ shell/dash/Home.qml 2012-01-20 13:41:29 +0000 |
667 | @@ -155,6 +155,7 @@ |
668 | |
669 | AbstractButton { |
670 | id: closeShortcutsButton |
671 | + objectName: "closeShortcutsButton" |
672 | |
673 | anchors.left: parent.left |
674 | anchors.top: parent.top |
675 | |
676 | === added directory 'tests/getshape' |
677 | === added file 'tests/getshape/CMakeLists.txt' |
678 | --- tests/getshape/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
679 | +++ tests/getshape/CMakeLists.txt 2012-01-20 13:41:29 +0000 |
680 | @@ -0,0 +1,22 @@ |
681 | +# Sources |
682 | +set(shell_SRCS |
683 | + getshape.cpp |
684 | + ) |
685 | + |
686 | +qt4_wrap_cpp(shell_MOC_SRCS ${shell_MOC_HDRS}) |
687 | + |
688 | +# Build |
689 | + |
690 | +add_executable(getshape ${shell_SRCS} ${shell_MOC_SRCS}) |
691 | + |
692 | +include_directories( |
693 | + ${CMAKE_CURRENT_SOURCE_DIR} |
694 | + ${CMAKE_CURRENT_BINARY_DIR} |
695 | + ) |
696 | + |
697 | +target_link_libraries(getshape |
698 | + ${QT_QTCORE_LIBRARIES} |
699 | + ${QT_QTGUI_LIBRARIES} |
700 | + ${X11_Xext_LIB} |
701 | + ${X11_X11_LIB} |
702 | + ) |
703 | |
704 | === added file 'tests/getshape/getshape.cpp' |
705 | --- tests/getshape/getshape.cpp 1970-01-01 00:00:00 +0000 |
706 | +++ tests/getshape/getshape.cpp 2012-01-20 13:41:29 +0000 |
707 | @@ -0,0 +1,102 @@ |
708 | +/* |
709 | + * Copyright (C) 2010 Canonical, Ltd. |
710 | + * |
711 | + * Authors: |
712 | + * Florian Boucault <florian.boucault@canonical.com> |
713 | + * Ugo Riboni <ugo.riboni@canonical.com> |
714 | + * |
715 | + * This program is free software; you can redistribute it and/or modify |
716 | + * it under the terms of the GNU General Public License as published by |
717 | + * the Free Software Foundation; version 3. |
718 | + * |
719 | + * This program is distributed in the hope that it will be useful, |
720 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
721 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
722 | + * GNU General Public License for more details. |
723 | + * |
724 | + * You should have received a copy of the GNU General Public License |
725 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
726 | + */ |
727 | + |
728 | +// QT |
729 | +#include <QApplication> |
730 | +#include <QX11Info> |
731 | +#include <QDebug> |
732 | +#include <QStringList> |
733 | + |
734 | +#include <QBitmap> |
735 | +#include <QRegion> |
736 | +#include <QPainter> |
737 | +#include <QPainterPath> |
738 | + |
739 | +// X11 |
740 | +#include <X11/Xlib.h> |
741 | +#include <X11/extensions/shape.h> |
742 | + |
743 | +void printUsage() |
744 | +{ |
745 | + qDebug() << "ARGUMENTS: window_id [output_file]"; |
746 | +} |
747 | + |
748 | +int handle_x11_errors(Display *display, XErrorEvent *theEvent) |
749 | +{ |
750 | + qWarning() << "Failed to call X11 function XShapeGetRectangles."; |
751 | + qWarning() << "The window ID that was passed to it was probably not valid anymore."; |
752 | + qWarning() << "X error code:" << theEvent->error_code; |
753 | + qWarning() << "X Request code" << theEvent->request_code; |
754 | + exit(4); |
755 | +} |
756 | + |
757 | +int main(int argc, char *argv[]) |
758 | +{ |
759 | + QApplication application(argc, argv); |
760 | + QStringList arguments = application.arguments(); |
761 | + |
762 | + if (arguments.length() < 2) { |
763 | + printUsage(); |
764 | + return 1; |
765 | + } |
766 | + |
767 | + bool ok; |
768 | + Window windowId = arguments.at(1).toLongLong(&ok, 0); |
769 | + if (!ok) { |
770 | + qWarning() << "Window ID is not a valid integer:" << arguments.at(1); |
771 | + return 2; |
772 | + } |
773 | + |
774 | + QString outputFile; |
775 | + if (arguments.length() > 2) { |
776 | + outputFile = arguments.at(2); |
777 | + } |
778 | + |
779 | + XErrorHandler old_handler = XSetErrorHandler(handle_x11_errors); |
780 | + |
781 | + QRegion region; |
782 | + int count, ordering; |
783 | + XRectangle *rects = XShapeGetRectangles(QX11Info::display(), windowId, |
784 | + ShapeInput, &count, &ordering); |
785 | + XSync(QX11Info::display(), False); |
786 | + XSetErrorHandler(old_handler); |
787 | + |
788 | + for (int i = 0; i < count; i++) { |
789 | + region = region.united(QRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height)); |
790 | + |
791 | + printf("%dx%d@%d,%d", rects[i].width, rects[i].height, rects[i].x, rects[i].y); |
792 | + } |
793 | + |
794 | + if (!outputFile.isEmpty()) { |
795 | + QBitmap bitmap(region.boundingRect().width(), region.boundingRect().height()); |
796 | + bitmap.fill(Qt::color0); |
797 | + QPainter painter(&bitmap); |
798 | + QPainterPath path; |
799 | + path.addRegion(region); |
800 | + painter.fillPath(path, Qt::color1); |
801 | + painter.end(); |
802 | + if (!bitmap.save(outputFile)) { |
803 | + qWarning() << "Failed to save file with path:" << outputFile; |
804 | + return 3; |
805 | + } |
806 | + } |
807 | + |
808 | + return 0; |
809 | +} |
810 | |
811 | === modified file 'tests/run-tests.rb' |
812 | --- tests/run-tests.rb 2012-01-18 12:18:20 +0000 |
813 | +++ tests/run-tests.rb 2012-01-20 13:41:29 +0000 |
814 | @@ -62,7 +62,7 @@ |
815 | require 'testhelper' |
816 | |
817 | # List of directories in which to search for test cases |
818 | -test_directories = ['launcher', 'panel', 'places', 'spread', 'window-manager', 'other'] |
819 | +test_directories = ['launcher', 'panel', 'places', 'spread', 'shell', 'window-manager', 'other'] |
820 | |
821 | # Only run scan for tests if this script is directly called |
822 | if __FILE__ == $0 |
823 | |
824 | === added directory 'tests/shell' |
825 | === added file 'tests/shell/input_shaping.rb' |
826 | --- tests/shell/input_shaping.rb 1970-01-01 00:00:00 +0000 |
827 | +++ tests/shell/input_shaping.rb 2012-01-20 13:41:29 +0000 |
828 | @@ -0,0 +1,239 @@ |
829 | +#!/usr/bin/env ruby1.8 |
830 | +=begin |
831 | +/* |
832 | + * This file is part of unity-2d |
833 | + * |
834 | + * Copyright 2011 Canonical Ltd. |
835 | + * |
836 | + * Authors: |
837 | + * - Ugo Riboni <ugo.riboni@canonical.com> |
838 | + * - Gerry Boland <gerry.boland@canonical.com> |
839 | + * |
840 | + * This program is free software; you can redistribute it and/or modify |
841 | + * it under the terms of the GNU General Public License as published by |
842 | + * the Free Software Foundation; version 3. |
843 | + * |
844 | + * This program is distributed in the hope that it will be useful, |
845 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
846 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
847 | + * GNU General Public License for more details. |
848 | + * |
849 | + * You should have received a copy of the GNU General Public License |
850 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
851 | + */ |
852 | +=end |
853 | + |
854 | +require '../run-tests.rb' unless $INIT_COMPLETED |
855 | +require 'xdo/xwindow' |
856 | +require 'xdo/keyboard' |
857 | +require 'xdo/mouse' |
858 | +require 'timeout' |
859 | +require 'tmpdir' |
860 | +require 'tempfile' |
861 | +include TDriverVerify |
862 | + |
863 | +def desktop_geometry |
864 | + out = %x{xdotool getdisplaygeometry} |
865 | + return out.split.collect { |coord| coord.to_i } |
866 | +end |
867 | + |
868 | +# We just need a temp file name but ruby insist on creating it, so we just delete it first. |
869 | +def tempfilename(base, extension = ".tmp") |
870 | + maskfile = Tempfile.new([base, extension]) |
871 | + maskpath = maskfile.path |
872 | + maskfile.close |
873 | + maskfile.unlink |
874 | + return maskpath |
875 | +end |
876 | + |
877 | +def get_shell_shape |
878 | + pwd = File.expand_path(File.dirname(__FILE__)) |
879 | + |
880 | + # Try to find the shell window |
881 | + shell_ids = XDo::XWindow::search('unity-2d-shell') |
882 | + assert(!shell_ids.empty?, "Failed to retrieve the shell window id") |
883 | + shell_id = shell_ids[0] |
884 | + |
885 | + # Get the shape of the shell window using our custom tool |
886 | + maskpath = tempfilename('shape', '.png') |
887 | + out = %x{#{pwd}/../getshape/getshape #{shell_id} #{maskpath}} |
888 | + assert($?.exitstatus == 0, "Failed to call getshape to get the shape of the window") |
889 | + return maskpath |
890 | +end |
891 | + |
892 | +# Compare two images using ImageMagick. Perform a pixel-by-pixel comparison and return true |
893 | +# only if all the pixels are identical. |
894 | +def compare_images(image1, image2) |
895 | + # Before checking the pixels make sure the two images are the same size, otherwise some times |
896 | + # IM will hang for a long time (probably trying to do some super clever subimage matching). |
897 | + size1 = %x{identify -format '%wx%h' #{image1}} |
898 | + size2 = %x{identify -format '%wx%h' #{image2}} |
899 | + return false if size1 != size2 |
900 | + |
901 | + # Discard the difference image and redirect stderr to stdout as IM will output the number of |
902 | + # different pixels there for some reason. |
903 | + difference = %x{compare #{image1} #{image2} -metric AE /dev/null 2>&1}.chop.to_i |
904 | + |
905 | + # If the images are too different or have different sizes IM will exit with return code 1. |
906 | + # Unfortunately it's the same code we have when there is any error (like a wrong filename), |
907 | + # so the best we can do is just return false |
908 | + return false if $?.exitstatus != 0 |
909 | + |
910 | + return difference == 0 |
911 | +end |
912 | + |
913 | +############################# Test Suite ############################# |
914 | +context "Shell input shape tests" do |
915 | + pwd = File.expand_path(File.dirname(__FILE__)) + '/' |
916 | + |
917 | + PANEL_HEIGHT = 24 |
918 | + LAUNCHER_WIDTH = 65 |
919 | + |
920 | + # Run once at the beginning of this test suite |
921 | + startup do |
922 | + system 'killall unity-2d-shell > /dev/null 2>&1' |
923 | + system 'killall unity-2d-shell > /dev/null 2>&1' |
924 | + system 'killall unity-2d-panel > /dev/null 2>&1' |
925 | + |
926 | + # Need panel running as position of shell depends on it |
927 | + @@sut = TDriver.sut(:Id => "sut_qt") |
928 | + @@panel = @@sut.run(:name => UNITY_2D_PANEL, |
929 | + :arguments => "-testability" ) |
930 | + |
931 | + # Minimize all windows |
932 | + XDo::XWindow.toggle_minimize_all |
933 | + end |
934 | + |
935 | + # Run once at the end of this test suite |
936 | + shutdown do |
937 | + end |
938 | + |
939 | + # Run before each test case begins |
940 | + setup do |
941 | + #Ensure mouse out of the way |
942 | + XDo::Mouse.move(200,200,10,true) |
943 | + |
944 | + # Execute the application |
945 | + @sut = TDriver.sut(:Id => "sut_qt") |
946 | + @app = @sut.run(:name => UNITY_2D_SHELL, |
947 | + :arguments => "-testability", |
948 | + :sleeptime => 2) |
949 | + # Make certain application is ready for testing |
950 | + verify(10){ @app.Launcher() } |
951 | + end |
952 | + |
953 | + # Run after each test case completes |
954 | + teardown do |
955 | + system "pkill -nf unity-2d-shell" |
956 | + end |
957 | + |
958 | + ##################################################################################### |
959 | + # Test cases |
960 | + |
961 | + test "Shape of launcher alone" do |
962 | + XDo::Keyboard.alt_F1 |
963 | + maskpath = get_shell_shape() |
964 | + |
965 | + # Since the shape of the launcher is dependent on screen geometry, calculate what it should be |
966 | + # then use imagemagick to create an image that contains only a black rectangle where the |
967 | + # launcher should be. |
968 | + screen_width, screen_height = desktop_geometry() |
969 | + screen_height -= PANEL_HEIGHT |
970 | + comparepath = tempfilename('shape', '.png') |
971 | + %x{convert xc:black -background black -extent #{LAUNCHER_WIDTH}x#{screen_height} #{comparepath}} |
972 | + |
973 | + identical = compare_images(maskpath, comparepath) |
974 | + |
975 | + File.unlink(maskpath) |
976 | + File.unlink(comparepath) |
977 | + |
978 | + verify_true(10, "The actual shape does not match the expected shape") { identical } |
979 | + end |
980 | + |
981 | + test "Shape of launcher and desktop mode dash" do |
982 | + XDo::Keyboard.simulate('{SUPER}') |
983 | + sleep 1 |
984 | + maskpath = get_shell_shape() |
985 | + |
986 | + # Since the shape of the launcher is dependent on screen geometry, calculate what it should be, |
987 | + # then draw a black rectangle and compose it at the left side of the dash verification image. |
988 | + |
989 | + screen_width, screen_height = desktop_geometry() |
990 | + screen_height -= PANEL_HEIGHT |
991 | + |
992 | + verifypath = "#{pwd}/verification/dash_desktop.png" |
993 | + out = %x{identify -format "%wx%h" #{verifypath}} |
994 | + verify_width = out.split("x")[0].to_i |
995 | + verify_width += LAUNCHER_WIDTH |
996 | + |
997 | + comparepath = tempfilename('shape', '.png') |
998 | + |
999 | + %x{convert #{verifypath} \ |
1000 | + -gravity northeast -extent #{verify_width}x#{screen_height}! \ |
1001 | + \\( xc:black -background black -extent #{LAUNCHER_WIDTH}x#{screen_height} \\) \ |
1002 | + -gravity northwest -compose over -composite #{comparepath}} |
1003 | + |
1004 | + identical = compare_images(maskpath, comparepath) |
1005 | + |
1006 | + File.unlink(maskpath) |
1007 | + File.unlink(comparepath) |
1008 | + |
1009 | + verify_true(10, "The actual shape does not match the expected shape") { identical } |
1010 | + end |
1011 | + |
1012 | + test "Shape of launcher and fullscreen mode dash" do |
1013 | + XDo::Keyboard.simulate('{SUPER}') |
1014 | + sleep 1 |
1015 | + @app.ShellDeclarativeView()['dashMode'] = 'FullScreenMode' |
1016 | + sleep 1 |
1017 | + |
1018 | + maskpath = get_shell_shape() |
1019 | + |
1020 | + # Compare with just one big rectangle filling the entire screen minus the panel area |
1021 | + screen_width, screen_height = desktop_geometry() |
1022 | + screen_height -= PANEL_HEIGHT |
1023 | + comparepath = tempfilename('shape', '.png') |
1024 | + %x{convert xc:black -background black -extent #{screen_width}x#{screen_height} #{comparepath}} |
1025 | + |
1026 | + identical = compare_images(maskpath, comparepath) |
1027 | + |
1028 | + File.unlink(maskpath) |
1029 | + File.unlink(comparepath) |
1030 | + |
1031 | + verify_true(10, "The actual shape does not match the expected shape") { identical } |
1032 | + end |
1033 | + |
1034 | + test "Shape of launcher and collapsed desktop mode dash" do |
1035 | + XDo::Keyboard.simulate('{SUPER}') |
1036 | + sleep 1 |
1037 | + @app.AbstractButton(:name => 'closeShortcutsButton').tap |
1038 | + sleep 1 |
1039 | + |
1040 | + maskpath = get_shell_shape() |
1041 | + |
1042 | + # Since the shape of the launcher is dependent on screen geometry, calculate what it should be, |
1043 | + # then draw a black rectangle and compose it at the left side of the dash verification image. |
1044 | + |
1045 | + screen_width, screen_height = desktop_geometry() |
1046 | + screen_height -= PANEL_HEIGHT |
1047 | + |
1048 | + verifypath = "#{pwd}/verification/dash_collapsed.png" |
1049 | + out = %x{identify -format "%wx%h" #{verifypath}} |
1050 | + verify_width = out.split("x")[0].to_i |
1051 | + verify_width += LAUNCHER_WIDTH |
1052 | + |
1053 | + comparepath = tempfilename('shape', '.png') |
1054 | + |
1055 | + %x{convert #{verifypath} \ |
1056 | + -gravity northeast -extent #{verify_width}x#{screen_height}! \ |
1057 | + \\( xc:black -background black -extent #{LAUNCHER_WIDTH}x#{screen_height} \\) \ |
1058 | + -gravity northwest -compose over -composite #{comparepath}} |
1059 | + |
1060 | + identical = compare_images(maskpath, comparepath) |
1061 | + |
1062 | + File.unlink(maskpath) |
1063 | + File.unlink(comparepath) |
1064 | + |
1065 | + verify_true(10, "The actual shape does not match the expected shape") { identical } |
1066 | + end |
1067 | +end |
1068 | |
1069 | === added directory 'tests/shell/verification' |
1070 | === added file 'tests/shell/verification/dash_collapsed.png' |
1071 | Binary files tests/shell/verification/dash_collapsed.png 1970-01-01 00:00:00 +0000 and tests/shell/verification/dash_collapsed.png 2012-01-20 13:41:29 +0000 differ |
1072 | === added file 'tests/shell/verification/dash_desktop.png' |
1073 | Binary files tests/shell/verification/dash_desktop.png 1970-01-01 00:00:00 +0000 and tests/shell/verification/dash_desktop.png 2012-01-20 13:41:29 +0000 differ |
* inputshapemask. cpp:19 always add a trailing slash to unity2dDirectory() as it doesn't do that internally (see bug 918669) iveview. cpp:161 any reason for the #include there?
* one thing I'm afraid of: animating the launcher shape looks unnecessary and a resource drain, could we have just the "fully-on-screen" shape, enabled or disabled as soon as the launcher is supposed to be shown?
* unity2ddeclarat