Merge lp:~unity-2d-team/unity-2d/unity-2d-shell-shaped-testability-shapetests into lp:~unity-2d-team/unity-2d/unity-2d-shell

Proposed by Ugo Riboni
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
Reviewer Review Type Date Requested Status
Michał Sawicz Approve
Review via email: mp+89236@code.launchpad.net

Description of the change

[shell] Shape the shell window input according to what components are visible

To post a comment you must log in.
Revision history for this message
Michał Sawicz (saviq) wrote :

* inputshapemask.cpp:19 always add a trailing slash to unity2dDirectory() as it doesn't do that internally (see bug 918669)
* 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?
* unity2ddeclarativeview.cpp:161 any reason for the #include there?

927. By Michał Sawicz

Merge from shell

Revision history for this message
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_show_tests.rb
* 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_COLLAPSED looks unused?
* input_shaping.rb:128 says Launcher, should be Shell?
* input_shaping.rb:188 why D-Bus? do we actually need / want to expose that over D-Bus?

review: Needs Fixing
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

Revision history for this message
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

Revision history for this message
Michał Sawicz (saviq) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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'
1071Binary 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'
1073Binary 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

Subscribers

People subscribed via source and target branches

to all changes: