Merge lp:~unity-2d-team/unity-2d/launcher-layout into lp:unity-2d/3.0

Proposed by Ugo Riboni
Status: Merged
Approved by: Florian Boucault
Approved revision: 395
Merged at revision: 388
Proposed branch: lp:~unity-2d-team/unity-2d/launcher-layout
Merge into: lp:unity-2d/3.0
Diff against target: 1074 lines (+394/-278)
19 files modified
launcher/Launcher.qml (+31/-22)
launcher/LauncherItem.qml (+180/-167)
launcher/UnityApplications/iconimageprovider.cpp (+29/-19)
launcher/UnityApplications/launcherapplication.cpp (+19/-0)
launcher/UnityApplications/launcherapplication.h (+2/-0)
launcher/UnityApplications/launcherdevice.cpp (+6/-0)
launcher/UnityApplications/launcherdevice.h (+1/-0)
launcher/UnityApplications/launcheritem.h (+3/-0)
launcher/UnityApplications/placeentry.cpp (+6/-0)
launcher/UnityApplications/placeentry.h (+1/-0)
launcher/UnityApplications/trash.cpp (+7/-1)
launcher/UnityApplications/trash.h (+1/-0)
launcher/UnityApplications/workspaces.cpp (+6/-0)
launcher/UnityApplications/workspaces.h (+1/-0)
launcher/app/launcher.cpp (+8/-1)
launcher/app/launcherview.cpp (+39/-51)
launcher/app/launcherview.h (+2/-1)
libunity-2d-private/Unity2d/blendedimageprovider.cpp (+51/-15)
panel/applets/homebutton/homebuttonapplet.cpp (+1/-1)
To merge this branch: bzr merge lp:~unity-2d-team/unity-2d/launcher-layout
Reviewer Review Type Date Requested Status
Florian Boucault (community) Approve
Review via email: mp+49368@code.launchpad.net

Description of the change

[launcher] Implement various look and feel changes in the launcher to match the launcher design on Natty.
The only functional change is the "pips" on the right side of the window to indicate the number of open windows.
There are also changes to the icon and blended image providers, to correctly handle scaling if requested in the former and to use the right compositing mode for the latter. Both also have more warnings and safer code.
Everything else is visual changes and code cleaning.

To post a comment you must log in.
Revision history for this message
Florian Boucault (fboucault) wrote :

The launcher width is only 65 pixels in the mockups, not 66.

review: Needs Fixing
Revision history for this message
Florian Boucault (fboucault) wrote :

launcher/UnityApplications/iconimageprovider.cpp:

QDebug include is in the middle of the file.

review: Needs Fixing
Revision history for this message
Ugo Riboni (uriboni) wrote :

Fixed the QDebug. Regarding the 66 vs. 65 pixels: it's 66 in the current natty implementation, 65 in the mockup. I didn't fix it for now, and you will figure it out with Otto later as agreed.

387. By Ugo Riboni

Move QDebug include to the top of the file

Revision history for this message
Florian Boucault (fboucault) wrote :

=== modified file 'launcher/Launcher.qml'

@@ -44,11 +53,7 @@
                     list.visibleMenu.hide()
                 }
                 list.visibleMenu = item.menu
-
- /* The menu needs to never overlap with the MouseArea of
- item otherwise flickering happens when the mouse is on
- an overlapping pixel (hence the -4). */
- item.menu.show(width-4, y+height/2-list.contentY+panel.y)
+ item.menu.show(width, y + height / 2 - list.contentY + panel.y)

The contextual menu's vertical position is slightly off, it should be around 3 pixels below. The point of the arrow of the contextual menu should be at the same height as the point of the arrow showing that the application is focused.

review: Needs Fixing
Revision history for this message
Florian Boucault (fboucault) wrote :

Can you add an unexpected change to that merge request? The width of the ubuntu circle of friends button in the panel has to coincide with the width of the launcher so that the line of the button and the border line of the launcher match perfectly and form only one continuous vertical line.

Thanks.

Revision history for this message
Florian Boucault (fboucault) wrote :

=== modified file 'launcher/LauncherItem.qml'

+ It is tile composed by a colored background layer, an icon (with 'icon' as source),
+ and a shine layer on top.

does not make sense.

review: Needs Fixing
Revision history for this message
Florian Boucault (fboucault) wrote :

=== modified file 'launcher/UnityApplications/launcherapplication.cpp'

@@ -394,6 +404,8 @@
     }
     if (m_has_visible_window != prev)
         emit hasVisibleWindowChanged(m_has_visible_window);
+
+ Q_EMIT windowCountChanged(windowCount());
 }

This is a hack taking advantage of the fact that LauncherApplication::updateHasVisibleWindow is called at the right time.

Instead you need to define a slot that will do Q_EMIT windowCountChanged(windowCount()); and connect it to BamfApplication::WindowAdded and BamfApplication::WindowRemoved signals.

review: Needs Fixing (code)
Revision history for this message
Florian Boucault (fboucault) wrote :

> === modified file 'launcher/UnityApplications/launcherapplication.cpp'
>
> @@ -394,6 +404,8 @@
> }
> if (m_has_visible_window != prev)
> emit hasVisibleWindowChanged(m_has_visible_window);
> +
> + Q_EMIT windowCountChanged(windowCount());
> }
>
>
> This is a hack taking advantage of the fact that
> LauncherApplication::updateHasVisibleWindow is called at the right time.
>
> Instead you need to define a slot that will do Q_EMIT
> windowCountChanged(windowCount()); and connect it to
> BamfApplication::WindowAdded and BamfApplication::WindowRemoved signals.

I suggest calling the slot 'updateWindowCount'.

Revision history for this message
Florian Boucault (fboucault) wrote :

=== modified file 'launcher/app/launcherview.cpp'

@@ -32,6 +32,9 @@
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>

+#define MAX(a,b) ((a >= b) ? a : b)
+#define MIN(a,b) ((a <= b) ? a : b)
+

Remove and replace with Qt's qMax and qMin.

(http://doc.qt.nokia.com/latest/qtglobal.html#qMax)

review: Needs Fixing
Revision history for this message
Florian Boucault (fboucault) wrote :

=== modified file 'launcher/app/launcher.cpp'
--- launcher/app/launcher.cpp 2011-02-08 10:41:55 +0000
+++ launcher/app/launcher.cpp 2011-02-11 11:57:46 +0000
@@ -76,12 +76,15 @@
     launcherView->setFocus();

     launcherView->engine()->addImportPath(unity2dImportPath());
+ launcherView->engine()->addImportPath(unity2dDirectory() + "/libunity-2d-private/");

This should _only_ be done when running un-installed. Please take example from places/app/places.cpp:

    if (!isRunningInstalled()) {
        [...]
        /* Place.qml imports Unity2d */
        view.engine()->addImportPath(unity2dDirectory() + "/libunity-2d-private/");
    }

review: Needs Fixing
Revision history for this message
Florian Boucault (fboucault) wrote :

=== modified file 'launcher/app/launcher.cpp'

     launcherView->rootContext()->setContextProperty("launcherView", launcherView);
     launcherView->rootContext()->setContextProperty("panel", &panel);
+ launcherView->rootContext()->setContextProperty("engineBaseUrl",
+ launcherView->engine()->baseUrl().toLocalFile());

This looks like a workaround for the lack of support of images in path relative to the launcher binary in BlendedImageProvider. Let's document it quickly for now.

Revision history for this message
Florian Boucault (fboucault) wrote :

=== added file 'launcher/artwork/launcher_arrow_ltr.png'
=== added file 'launcher/artwork/launcher_arrow_rtl.png'
=== added file 'launcher/artwork/launcher_pip_ltr.png'

No abbreviations. Replace 'ltr' with 'left' and 'rtl' with 'right'.

review: Needs Fixing
Revision history for this message
Florian Boucault (fboucault) wrote :

I sometimes get a WARNING (hopefully not important):

LauncherItem.qml:89 Unable to assign undefined value

Revision history for this message
Florian Boucault (fboucault) wrote :

=== modified file 'libunity-2d-private/Unity2d/blendedimageprovider.cpp'

        qWarning() << "BlendedImageProvider: faile to match id:" << id;
should read
        qWarning() << "BlendedImageProvider: failed to match id:" << id;

"[...] when a sting isn't an SVG color name"
should read
"[...] when a string is not a SVG color name (eg. "red", "yellow", etc.)

review: Needs Fixing
Revision history for this message
Florian Boucault (fboucault) wrote :

Only 'launcher/LauncherItem.qml' left to do and the review should be complete.

388. By Ugo Riboni

Make sure the panel home button is aligned with the new launcher size

389. By Ugo Riboni

Make sure the menu is aligned with the center of tha active app arrow

390. By Ugo Riboni

Fix typos in comment

391. By Ugo Riboni

Fix to prevent some harmless warnings

392. By Ugo Riboni

Separate the code path for updating windowCount from that of hasVisibleWindow

393. By Ugo Riboni

Use qMin and qMax instead of local defines

394. By Ugo Riboni

Make sure to correctly add import paths based on installed/uninstalled status. Document a workaround.

395. By Ugo Riboni

Fix typos and docs

Revision history for this message
Ugo Riboni (uriboni) wrote :

Fixed pretty much everything, except the renaming of the icons which stay as they are since they were copied from Unity.

Also please check my fix in commit 391 for the following warning:
"LauncherItem.qml:89 Unable to assign undefined value"
and let me know if you have a better workaround.

Revision history for this message
Florian Boucault (fboucault) wrote :

Sounds good to me, ship that good job!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'launcher/Launcher.qml'
2--- launcher/Launcher.qml 2011-02-10 08:24:27 +0000
3+++ launcher/Launcher.qml 2011-02-15 13:21:38 +0000
4@@ -2,39 +2,48 @@
5 import UnityApplications 1.0
6
7 Item {
8- width: 58
9- height: 1024
10+ id: launcher
11
12 Image {
13 id: background
14
15 anchors.fill: parent
16 fillMode: Image.TileVertically
17- source: "/usr/share/unity/themes/launcher_background_middle.png"
18+ source: "artwork/background.png"
19 }
20
21 ListView {
22 id: list
23+ spacing: 5
24+ anchors.topMargin: 5
25+ anchors.fill: parent
26+ focus: true
27
28 /* Keep a reference to the currently visible contextual menu */
29 property variant visibleMenu
30
31- anchors.fill: parent
32- focus: true
33-
34 model: ListAggregatorModel {
35 id: items
36 }
37
38 delegate: LauncherItem {
39- id: wrapper
40-
41- width: 58; height: 54
42- icon: "image://icons/"+item.icon
43+ id: launcherItem
44+
45+ width: launcher.width
46+ height: tileSize
47+
48+ icon: "image://icons/" + item.icon
49 running: item.running
50 active: item.active
51 urgent: item.urgent
52 launching: item.launching
53+ pips: Math.min(item.windowCount, 3)
54+ tileSize: 54
55+
56+ /* Best way I could find to check if the item is an application or the
57+ workspaces switcher. There may be something cleaner and better. */
58+ backgroundFromIcon: item.toString().indexOf("LauncherApplication") == 0 ||
59+ item.toString().indexOf("Workspaces") == 0
60
61 Binding { target: item.menu; property: "title"; value: item.name }
62
63@@ -44,11 +53,9 @@
64 list.visibleMenu.hide()
65 }
66 list.visibleMenu = item.menu
67-
68- /* The menu needs to never overlap with the MouseArea of
69- item otherwise flickering happens when the mouse is on
70- an overlapping pixel (hence the -4). */
71- item.menu.show(width-4, y+height/2-list.contentY+panel.y)
72+ // The extra 4 pixels are needed to center exactly with the arrow
73+ // that indicated the active tile.
74+ item.menu.show(width, y + height / 2 - list.contentY + panel.y + 4)
75 }
76
77 onClicked: {
78@@ -75,6 +82,7 @@
79 else
80 item.menu.hide()
81 }
82+
83 Connections {
84 target: list
85 onMovementStarted: item.menu.hide()
86@@ -87,16 +95,17 @@
87 }
88
89 ListView.onAdd: SequentialAnimation {
90- PropertyAction { target: wrapper; property: "scale"; value: 0 }
91- NumberAnimation { target: wrapper; property: "height"; from: 0; to: 54; duration: 250; easing.type: Easing.InOutQuad }
92- NumberAnimation { target: wrapper; property: "scale"; to: 1; duration: 250; easing.type: Easing.InOutQuad }
93+ PropertyAction { target: launcherItem; property: "scale"; value: 0 }
94+ NumberAnimation { target: launcherItem; property: "height";
95+ from: 0; to: launcherItem.tileSize; duration: 250; easing.type: Easing.InOutQuad }
96+ NumberAnimation { target: launcherItem; property: "scale"; to: 1; duration: 250; easing.type: Easing.InOutQuad }
97 }
98
99 ListView.onRemove: SequentialAnimation {
100- PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true }
101- NumberAnimation { target: wrapper; property: "scale"; to: 0; duration: 250; easing.type: Easing.InOutQuad }
102- NumberAnimation { target: wrapper; property: "height"; to: 0; duration: 250; easing.type: Easing.InOutQuad }
103- PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
104+ PropertyAction { target: launcherItem; property: "ListView.delayRemove"; value: true }
105+ NumberAnimation { target: launcherItem; property: "scale"; to: 0; duration: 250; easing.type: Easing.InOutQuad }
106+ NumberAnimation { target: launcherItem; property: "height"; to: 0; duration: 250; easing.type: Easing.InOutQuad }
107+ PropertyAction { target: launcherItem; property: "ListView.delayRemove"; value: false }
108 }
109
110 onRunningChanged: setIconGeometry()
111
112=== modified file 'launcher/LauncherItem.qml'
113--- launcher/LauncherItem.qml 2011-01-17 19:17:00 +0000
114+++ launcher/LauncherItem.qml 2011-02-15 13:21:38 +0000
115@@ -1,201 +1,214 @@
116 import Qt 4.7
117-
118-/* Item displaying a launcher item.
119-
120- It contains:
121- - a generic bordered background image
122- - an icon representing the item
123- - a text describing the item
124-
125- When an application is launched, the border changes appearance.
126- It supports mouse hover by changing the appearance of the background image.
127-
128- The 'icon' property holds the source of the image to load as an icon.
129- The 'label' property holds the text to display.
130- The 'running' property is a boolean indicating whether or not the
131- application is launched.
132-
133- The 'clicked' signal is emitted upon clicking on the item.
134+import Unity2d 1.0
135+
136+/* This component represents a single "tile" in the launcher and the surrounding
137+ indicator icons.
138+
139+ The tile is square in size, with a side determined by the 'tileSize' property,
140+ and rounded borders.
141+ It is composed by a colored background layer, an icon (with 'icon' as source),
142+ and a layer on top that provides a "shine" effect.
143+ The main color of the background layer may be calculated based on the icon color
144+ or may be fixed (depending on the 'backgroundFromIcon' property).
145+
146+ There's also an additional layer which contains only the outline of the tile
147+ that is only appearing during the launching animation (when the 'launching' property is
148+ true). During this animation the background fades out and the outline fades in,
149+ giving a "pulsing" appearance to the tile.
150+
151+ Around the tile we may have on the left a number of "pips" between zero and three.
152+ Pips are small icons used to indicate how many windows we have open for the current tile
153+ (based on the 'windowCount' property).
154+ The rule is: if there's only one window, we just display an arrow. If there are
155+ two we display 2 pips, if there are 3 or more display 3 pips.
156+
157+ On the right of the tile there's an arrow that appears if the tile is currently 'active'.
158+
159+ Additionally, when the tile is marked as 'urgent' it will start an animation where the
160+ rotation is changed so that it appears to be "shaking".
161 */
162 Item {
163- id: launcherItem
164+ id: item
165+ anchors.horizontalCenter: parent.horizontalCenter
166
167+ property int tileSize
168 property alias icon: icon.source
169- property alias label: label.text
170 property bool running: false
171 property bool active: false
172 property bool urgent: false
173 property bool launching: false
174+ property bool backgroundFromIcon
175+ property color defaultBackgroundColor: "#333333"
176+
177+ property int pips: 0
178+ property string pipSource: engineBaseUrl + "artwork/launcher_" +
179+ ((pips <= 1) ? "arrow" : "pip") + "_ltr.png"
180+ function getPipOffset(index) {
181+ /* Pips need to always be centered, regardless if they are an even or odd
182+ number. The following simple conditional code works and is less
183+ convoluted than a generic formula. It's ok since we always work with at
184+ most three pips anyway. */
185+ if (pips == 1) return 0;
186+ if (pips == 2) return (index == 0) ? -2 : +2
187+ else return (index == 0) ? 0 : (index == 1) ? -4 : +4
188+ }
189
190 signal clicked(variant mouse)
191 signal entered
192 signal exited
193
194- Keys.onPressed: {
195- if (event.key == Qt.Key_Return) {
196- clicked()
197- event.accepted = true;
198- }
199- }
200-
201- Image {
202- id: shadow
203-
204- source: "artwork/shadow.png"
205- asynchronous: true
206- }
207-
208- Image {
209- id: glow
210-
211- anchors.horizontalCenter: parent.horizontalCenter
212+ /* This is the arrow shown at the right of the tile when the application is
213+ the active one */
214+ Image {
215+ anchors.right: parent.right
216 anchors.verticalCenter: parent.verticalCenter
217-
218- source: "artwork/glow.png"
219- asynchronous: true
220- opacity: 0.0
221-
222- SequentialAnimation on opacity {
223- loops: Animation.Infinite
224- alwaysRunToEnd: true
225- running: launching
226- NumberAnimation { to: 1.0; duration: 1000; easing.type: Easing.InOutQuad }
227- NumberAnimation { to: 0.0; duration: 1000; easing.type: Easing.InOutQuad }
228+ source: "image://blended/%1color=%2alpha=%3"
229+ .arg(engineBaseUrl + "artwork/launcher_arrow_rtl.png")
230+ .arg("lightgrey")
231+ .arg(1.0)
232+
233+ /* This extra shift is necessary (as is for the pips below)
234+ since we are vertically centering in a parent with even height, so
235+ there's one pixel offset that need to be assigned arbitrarily.
236+ Unity chose to add it, QML to subtract it. So we adjust for that. */
237+ transform: Translate { y: 1 }
238+
239+ visible: active
240+ }
241+
242+ /* This is the area on the left of the tile where the pips/arrow end up.
243+
244+ I'd rather use a Column here, but the pip images have an halo
245+ around them, so they are pretty tall and would mess up the column.
246+ As a workaround I center all of them, then shift up or down
247+ depending on the index. */
248+ Repeater {
249+ model: item.pips
250+ delegate: Image {
251+ /* FIXME: It seems that when the image is created (or re-used) by the Repeater
252+ for a moment it doesn't have any parent, and therefore warnings are
253+ printed for the following two anchor assignements. This fixes the
254+ problem, but I'm not sure if it should happen in the first place. */
255+ anchors.left: (parent) ? parent.left : undefined
256+ anchors.verticalCenter: (parent) ? parent.verticalCenter : undefined
257+
258+ source: "image://blended/%1color=%2alpha=%3"
259+ .arg(pipSource).arg("lightgrey").arg(1.0)
260+
261+ transform: Translate { y: getPipOffset(index) + 1 }
262 }
263 }
264
265+ /* This is the for centering the actual tile in the launcher */
266 Item {
267- id: container
268-
269- width: 50
270- height: 50
271- anchors.horizontalCenter: parent.horizontalCenter
272- anchors.verticalCenter: parent.verticalCenter
273-
274- MouseArea {
275- id: mouse
276-
277- acceptedButtons: Qt.LeftButton | Qt.RightButton
278- hoverEnabled: true
279- anchors.fill: parent
280- onClicked: launcherItem.clicked(mouse)
281- onEntered: launcherItem.entered()
282- onExited: launcherItem.exited()
283- }
284-
285- Rectangle {
286- id: background
287-
288- opacity: mouse.containsMouse ? 1.0 : 0.9
289- anchors.fill: parent
290- anchors.margins: 1
291- anchors.horizontalCenter: parent.horizontalCenter
292- anchors.verticalCenter: parent.verticalCenter
293- smooth: true
294- color: if(icon.source != "")
295- return launcherView.iconAverageColor(icon.source,
296- Qt.size(icon.width, icon.height))
297- radius: 5
298- }
299-
300+ id: tile
301+ anchors.centerIn: parent
302+ width: item.tileSize
303+ height: parent.height
304+
305+ /* This is the image providing the background image. The
306+ color blended with this image is obtained from the color of the icon when it's
307+ loaded.
308+ While the application is launching, this will fade out and in. */
309+ Image {
310+ id: tileBackground
311+ property color color: defaultBackgroundColor
312+ anchors.fill: parent
313+
314+ SequentialAnimation on opacity {
315+ NumberAnimation { to: 0.0; duration: 1000; easing.type: Easing.InOutQuad }
316+ NumberAnimation { to: 1.0; duration: 1000; easing.type: Easing.InOutQuad }
317+
318+ loops: Animation.Infinite
319+ alwaysRunToEnd: true
320+ running: launching
321+ }
322+
323+ sourceSize.width: item.tileSize
324+ sourceSize.height: item.tileSize
325+ source: "image://blended/%1color=%2alpha=%3"
326+ .arg(engineBaseUrl + "artwork/round_corner_54x54.png")
327+ .arg(color.toString().replace("#", ""))
328+ .arg(1.0)
329+ }
330+
331+ /* This image appears only while launching, and pulses in and out in counterpoint
332+ to the background, so that the outline of the tile is always visible. */
333+ Image {
334+ id: tileOutline
335+ anchors.fill: parent
336+
337+ sourceSize.width: item.tileSize
338+ sourceSize.height: item.tileSize
339+ source: "artwork/round_outline_54x54.png"
340+
341+ opacity: 0
342+
343+ SequentialAnimation on opacity {
344+ NumberAnimation { to: 1.0; duration: 1000; easing.type: Easing.InOutQuad }
345+ NumberAnimation { to: 0.0; duration: 1000; easing.type: Easing.InOutQuad }
346+
347+ loops: Animation.Infinite
348+ alwaysRunToEnd: true
349+ running: launching
350+ }
351+ }
352+
353+ /* This is just the main icon of the tile */
354 Image {
355 id: icon
356-
357- width: 32
358- height: 32
359- anchors.horizontalCenter: parent.horizontalCenter
360- anchors.verticalCenter: parent.verticalCenter
361- fillMode: Image.PreserveAspectFit
362- sourceSize.width: width
363- sourceSize.height: height
364- smooth: true
365-
366- asynchronous: true
367- opacity: status == Image.Ready ? 1 : 0
368- Behavior on opacity {NumberAnimation {duration: 200; easing.type: Easing.InOutQuad}}
369+ anchors.centerIn: parent
370+
371+ sourceSize.width: 48
372+ sourceSize.height: 48
373+
374+ /* Whenever one of the parameters used in calculating the background color of
375+ the icon changes, recalculate its value */
376+ onWidthChanged: updateColors()
377+ onHeightChanged: updateColors()
378+ onSourceChanged: updateColors()
379+
380+ function updateColors() {
381+ if (!item.backgroundFromIcon) return;
382+
383+ var colors = launcherView.getColorsFromIcon(icon.source, icon.sourceSize)
384+ if (colors && colors.length > 0) tileBackground.color = colors[0]
385+ }
386 }
387
388+ /* This just adds some shiny effect to the tile */
389 Image {
390- id: foreground
391-
392+ id: tileShine
393 anchors.fill: parent
394- anchors.horizontalCenter: parent.horizontalCenter
395- anchors.verticalCenter: parent.verticalCenter
396- fillMode: Image.PreserveAspectFit
397- sourceSize.width: width
398- sourceSize.height: height
399- smooth: true
400-
401- source: "/usr/share/unity/themes/prism_icon_foreground.png"
402-
403- asynchronous: true
404- opacity: status == Image.Ready ? 1 : 0
405- Behavior on opacity {NumberAnimation {duration: 200; easing.type: Easing.InOutQuad}}
406+
407+ source: "artwork/round_shine_54x54.png"
408+ sourceSize.width: item.tileSize
409+ sourceSize.height: item.tileSize
410 }
411
412+ /* The entire tile will "shake" when the window is marked as "urgent", to attract
413+ the user's attention */
414 SequentialAnimation {
415- id: nudging
416 running: urgent
417+ alwaysRunToEnd: true
418+
419 SequentialAnimation {
420 loops: 30
421- NumberAnimation { target: container; property: "rotation"; to: 15; duration: 150 }
422- NumberAnimation { target: container; property: "rotation"; to: -15; duration: 150 }
423+ NumberAnimation { target: tile; property: "rotation"; to: 15; duration: 150 }
424+ NumberAnimation { target: tile; property: "rotation"; to: -15; duration: 150 }
425 }
426- NumberAnimation { target: container; property: "rotation"; to: 0; duration: 75 }
427- }
428-
429- NumberAnimation {
430- id: end_nudging
431- running: !urgent
432- target: container
433- property: "rotation"
434- to: 0
435- duration: 75
436- }
437-
438- }
439-
440- Image {
441- id: running_arrow
442-
443- z: -1
444- width: sourceSize.width
445- height: sourceSize.height
446- anchors.rightMargin: -2
447- anchors.right: container.left
448- anchors.verticalCenter: container.verticalCenter
449- opacity: running ? 1.0 : 0.0
450- source: urgent ? "/usr/share/unity/themes/application-running-notify.png" : "/usr/share/unity/themes/application-running.png"
451-
452- Behavior on opacity {NumberAnimation {duration: 200; easing.type: Easing.InOutQuad}}
453- }
454-
455- Image {
456- id: active_arrow
457-
458- z: -1
459- width: sourceSize.width
460- height: sourceSize.height
461- anchors.leftMargin: -2
462- anchors.left: container.right
463- anchors.verticalCenter: container.verticalCenter
464- opacity: active ? 1.0 : 0.0
465- source: "/usr/share/unity/themes/application-selected.png"
466-
467- Behavior on opacity {NumberAnimation {duration: 200; easing.type: Easing.InOutQuad}}
468- }
469-
470- Text {
471- id: label
472-
473- font.pointSize: 10
474- wrapMode: Text.WordWrap
475- horizontalAlignment: Text.AlignHCenter
476- anchors.top: parent.bottom
477- anchors.topMargin: 7
478- anchors.right: parent.right
479- anchors.bottom: parent.bottom
480- anchors.left: parent.left
481- font.underline: parent.focus
482+ NumberAnimation { target: tile; property: "rotation"; to: 0; duration: 75 }
483+ }
484+ }
485+
486+ MouseArea {
487+ id: mouse
488+ anchors.fill: parent
489+
490+ hoverEnabled: true
491+ acceptedButtons: Qt.LeftButton | Qt.RightButton
492+ onClicked: item.clicked(mouse)
493+ onEntered: item.entered()
494+ onExited: item.exited()
495 }
496 }
497
498=== modified file 'launcher/UnityApplications/iconimageprovider.cpp'
499--- launcher/UnityApplications/iconimageprovider.cpp 2011-01-15 01:41:03 +0000
500+++ launcher/UnityApplications/iconimageprovider.cpp 2011-02-15 13:21:38 +0000
501@@ -21,6 +21,7 @@
502 #include "config.h"
503
504 #include <QFile>
505+#include <QDebug>
506
507
508 static const char* UNITY_RES_PATH = "/usr/share/unity/";
509@@ -46,25 +47,34 @@
510 to do so was a failure due to the fragility of the code path. For example
511 it is very easy to break the entire mechanism by adding or forgetting a
512 slash in any of the paths. */
513- if (id.startsWith(UNITY_RES_PATH))
514- {
515- if (QFile::exists(id))
516- {
517- return QImage(id);
518- }
519- else
520- {
521- QString rid(id);
522- rid.replace(UNITY_RES_PATH, INSTALL_PREFIX "/share/unity-2d/");
523- /* No need to check whether the file exists, we don’t have a
524- fallback anyway. */
525- return QImage(rid);
526- }
527- }
528-
529- /* Dealing with case where id is an absolute path to the icon file */
530- if(id.startsWith("/"))
531- return QImage(id);
532+ QString iconFilePath;
533+ if (id.startsWith(UNITY_RES_PATH)) {
534+ iconFilePath = id;
535+ if (!QFile::exists(iconFilePath)) {
536+ iconFilePath.replace(UNITY_RES_PATH, INSTALL_PREFIX "/share/unity-2d/");
537+ }
538+ } else if (id.startsWith("/")) {
539+ iconFilePath = id;
540+ }
541+
542+ /* We have a direct path to the icon file. Let's load it, scale it if required and
543+ we are done */
544+ if (!iconFilePath.isEmpty()) {
545+ QImage icon(iconFilePath);
546+ if (icon.isNull()) {
547+ qWarning() << "Failed to directly load icon at path:" << iconFilePath;
548+ return QImage();
549+ }
550+
551+ if (requestedSize.isValid()) {
552+ icon = icon.scaled(requestedSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
553+ }
554+
555+ if (size) {
556+ *size = icon.size();
557+ }
558+ return icon;
559+ }
560
561 /* if id is of the form theme_name/icon_name then lookup the icon in the
562 specified theme otherwise in the default theme */
563
564=== modified file 'launcher/UnityApplications/launcherapplication.cpp'
565--- launcher/UnityApplications/launcherapplication.cpp 2011-02-10 08:24:27 +0000
566+++ launcher/UnityApplications/launcherapplication.cpp 2011-02-15 13:21:38 +0000
567@@ -109,6 +109,16 @@
568 return false;
569 }
570
571+int
572+LauncherApplication::windowCount() const
573+{
574+ if (m_application == NULL) {
575+ return 0;
576+ }
577+
578+ return m_application->windows()->size();
579+}
580+
581 bool
582 LauncherApplication::urgent() const
583 {
584@@ -297,6 +307,8 @@
585 QObject::connect(application, SIGNAL(UrgentChanged(bool)), this, SIGNAL(urgentChanged(bool)));
586 QObject::connect(application, SIGNAL(WindowAdded(BamfWindow*)), this, SLOT(updateHasVisibleWindow()));
587 QObject::connect(application, SIGNAL(WindowRemoved(BamfWindow*)), this, SLOT(updateHasVisibleWindow()));
588+ QObject::connect(application, SIGNAL(WindowAdded(BamfWindow*)), this, SLOT(updateWindowCount()));
589+ QObject::connect(application, SIGNAL(WindowRemoved(BamfWindow*)), this, SLOT(updateWindowCount()));
590 connect(application, SIGNAL(ChildAdded(BamfView*)), SLOT(slotChildAdded(BamfView*)));
591 connect(application, SIGNAL(ChildRemoved(BamfView*)), SLOT(slotChildRemoved(BamfView*)));
592
593@@ -318,6 +330,7 @@
594 m_launching_timer.stop();
595 emit launchingChanged(launching());
596 updateHasVisibleWindow();
597+ updateWindowCount();
598 fetchIndicatorMenus();
599 }
600
601@@ -396,6 +409,12 @@
602 emit hasVisibleWindowChanged(m_has_visible_window);
603 }
604
605+void
606+LauncherApplication::updateWindowCount()
607+{
608+ Q_EMIT windowCountChanged(windowCount());
609+}
610+
611 bool
612 LauncherApplication::has_visible_window() const
613 {
614
615=== modified file 'launcher/UnityApplications/launcherapplication.h'
616--- launcher/UnityApplications/launcherapplication.h 2011-02-10 08:24:27 +0000
617+++ launcher/UnityApplications/launcherapplication.h 2011-02-15 13:21:38 +0000
618@@ -52,6 +52,7 @@
619 /* getters */
620 virtual bool active() const;
621 virtual bool running() const;
622+ virtual int windowCount() const;
623 virtual bool urgent() const;
624 bool sticky() const;
625 virtual QString name() const;
626@@ -93,6 +94,7 @@
627 void onBamfApplicationClosed(bool running);
628 void onLaunchingTimeouted();
629 void updateHasVisibleWindow();
630+ void updateWindowCount();
631
632 bool launch();
633 void show();
634
635=== modified file 'launcher/UnityApplications/launcherdevice.cpp'
636--- launcher/UnityApplications/launcherdevice.cpp 2011-01-14 20:41:34 +0000
637+++ launcher/UnityApplications/launcherdevice.cpp 2011-02-15 13:21:38 +0000
638@@ -54,6 +54,12 @@
639 return false;
640 }
641
642+int
643+LauncherDevice::windowCount() const
644+{
645+ return 0;
646+}
647+
648 bool
649 LauncherDevice::urgent() const
650 {
651
652=== modified file 'launcher/UnityApplications/launcherdevice.h'
653--- launcher/UnityApplications/launcherdevice.h 2010-11-04 19:50:22 +0000
654+++ launcher/UnityApplications/launcherdevice.h 2011-02-15 13:21:38 +0000
655@@ -40,6 +40,7 @@
656 /* getters */
657 virtual bool active() const;
658 virtual bool running() const;
659+ virtual int windowCount() const;
660 virtual bool urgent() const;
661 virtual QString name() const;
662 virtual QString icon() const;
663
664=== modified file 'launcher/UnityApplications/launcheritem.h'
665--- launcher/UnityApplications/launcheritem.h 2010-12-16 11:07:52 +0000
666+++ launcher/UnityApplications/launcheritem.h 2011-02-15 13:21:38 +0000
667@@ -31,6 +31,7 @@
668
669 Q_PROPERTY(bool active READ active NOTIFY activeChanged)
670 Q_PROPERTY(bool running READ running NOTIFY runningChanged)
671+ Q_PROPERTY(int windowCount READ windowCount NOTIFY windowCountChanged)
672 Q_PROPERTY(bool urgent READ urgent NOTIFY urgentChanged)
673 Q_PROPERTY(QString name READ name NOTIFY nameChanged)
674 Q_PROPERTY(QString icon READ icon NOTIFY iconChanged)
675@@ -45,6 +46,7 @@
676 /* getters */
677 virtual bool active() const = 0;
678 virtual bool running() const = 0;
679+ virtual int windowCount() const = 0;
680 virtual bool urgent() const = 0;
681 virtual QString name() const = 0;
682 virtual QString icon() const = 0;
683@@ -61,6 +63,7 @@
684 signals:
685 void activeChanged(bool);
686 void runningChanged(bool);
687+ void windowCountChanged(int);
688 void urgentChanged(bool);
689 void nameChanged(QString);
690 void iconChanged(QString);
691
692=== modified file 'launcher/UnityApplications/placeentry.cpp'
693--- launcher/UnityApplications/placeentry.cpp 2011-02-07 15:41:35 +0000
694+++ launcher/UnityApplications/placeentry.cpp 2011-02-15 13:21:38 +0000
695@@ -234,6 +234,12 @@
696 return false;
697 }
698
699+int
700+PlaceEntry::windowCount() const
701+{
702+ return 0;
703+}
704+
705 bool
706 PlaceEntry::urgent() const
707 {
708
709=== modified file 'launcher/UnityApplications/placeentry.h'
710--- launcher/UnityApplications/placeentry.h 2011-02-01 18:03:11 +0000
711+++ launcher/UnityApplications/placeentry.h 2011-02-15 13:21:38 +0000
712@@ -109,6 +109,7 @@
713 /* getters */
714 virtual bool active() const;
715 virtual bool running() const;
716+ virtual int windowCount() const;
717 virtual bool urgent() const;
718 virtual QString name() const;
719 virtual QString icon() const;
720
721=== modified file 'launcher/UnityApplications/trash.cpp'
722--- launcher/UnityApplications/trash.cpp 2011-01-14 20:41:34 +0000
723+++ launcher/UnityApplications/trash.cpp 2011-02-15 13:21:38 +0000
724@@ -53,6 +53,12 @@
725 return false;
726 }
727
728+int
729+Trash::windowCount() const
730+{
731+ return 0;
732+}
733+
734 bool
735 Trash::urgent() const
736 {
737@@ -68,7 +74,7 @@
738 QString
739 Trash::icon() const
740 {
741- return QString(unity2dDirectory() + "/launcher/artwork/trash.png");
742+ return "user-trash";
743 }
744
745 bool
746
747=== modified file 'launcher/UnityApplications/trash.h'
748--- launcher/UnityApplications/trash.h 2010-11-09 10:52:04 +0000
749+++ launcher/UnityApplications/trash.h 2011-02-15 13:21:38 +0000
750@@ -39,6 +39,7 @@
751 /* getters */
752 virtual bool active() const;
753 virtual bool running() const;
754+ virtual int windowCount() const;
755 virtual bool urgent() const;
756 virtual QString name() const;
757 virtual QString icon() const;
758
759=== modified file 'launcher/UnityApplications/workspaces.cpp'
760--- launcher/UnityApplications/workspaces.cpp 2011-02-03 20:31:40 +0000
761+++ launcher/UnityApplications/workspaces.cpp 2011-02-15 13:21:38 +0000
762@@ -48,6 +48,12 @@
763 return false;
764 }
765
766+int
767+Workspaces::windowCount() const
768+{
769+ return 0;
770+}
771+
772 bool
773 Workspaces::urgent() const
774 {
775
776=== modified file 'launcher/UnityApplications/workspaces.h'
777--- launcher/UnityApplications/workspaces.h 2011-02-02 22:45:59 +0000
778+++ launcher/UnityApplications/workspaces.h 2011-02-15 13:21:38 +0000
779@@ -39,6 +39,7 @@
780 /* getters */
781 virtual bool active() const;
782 virtual bool running() const;
783+ virtual int windowCount() const;
784 virtual bool urgent() const;
785 virtual QString name() const;
786 virtual QString icon() const;
787
788=== modified file 'launcher/app/launcher.cpp'
789--- launcher/app/launcher.cpp 2011-02-08 10:41:55 +0000
790+++ launcher/app/launcher.cpp 2011-02-15 13:21:38 +0000
791@@ -64,7 +64,7 @@
792 /* Panel containing the QML declarative view */
793 Unity2dPanel panel;
794 panel.setEdge(Unity2dPanel::LeftEdge);
795- panel.setFixedWidth(58);
796+ panel.setFixedWidth(66);
797
798 /* QML declarative view */
799 LauncherView *launcherView = new LauncherView;
800@@ -79,10 +79,17 @@
801 /* Note: baseUrl seems to be picky: if it does not end with a slash,
802 setSource() will fail */
803 launcherView->engine()->setBaseUrl(QUrl::fromLocalFile(unity2dDirectory() + "/launcher/"));
804+ if (!isRunningInstalled()) {
805+ launcherView->engine()->addImportPath(unity2dDirectory() + "/libunity-2d-private/");
806+ }
807
808 launcherView->rootContext()->setContextProperty("launcherView", launcherView);
809 launcherView->rootContext()->setContextProperty("panel", &panel);
810
811+ /* FIXME: this is needed since the blended image provider doesn't support relative paths yet */
812+ launcherView->rootContext()->setContextProperty("engineBaseUrl",
813+ launcherView->engine()->baseUrl().toLocalFile());
814+
815 LauncherControl control;
816 launcherView->rootContext()->setContextProperty("launcherControl", &control);
817 control.connectToBus();
818
819=== modified file 'launcher/app/launcherview.cpp'
820--- launcher/app/launcherview.cpp 2011-02-07 17:21:35 +0000
821+++ launcher/app/launcherview.cpp 2011-02-15 13:21:38 +0000
822@@ -110,65 +110,53 @@
823 if (accepted) event->accept();
824 }
825
826-QColor
827-LauncherView::iconAverageColor(QUrl source, QSize size)
828+/* Calculates both the background color and the glow color of a launcher tile
829+ based on the colors in the specified icon (using the same algorithm as Unity).
830+ The values are returned as list where the first item is the background color
831+ and the second one is the glow color.
832+*/
833+QList<QVariant>
834+LauncherView::getColorsFromIcon(QUrl source, QSize size) const
835 {
836- /* FIXME: we are loading again an icon that was already loaded */
837+ QList<QVariant> colors;
838+
839+ // FIXME: we should find a way to avoid reloading the icon
840 QImage icon = engine()->imageProvider("icons")->requestImage(source.path().mid(1), &size, size);
841-
842- if (icon.width() == 0 || icon.height() == 0)
843- {
844- qWarning() << "Unable to load icon at" << source;
845- return QColor();
846+ if (icon.width() == 0 || icon.height() == 0) {
847+ qWarning() << "Unable to load icon in getColorsFromIcon from" << source;
848+ return colors;
849 }
850
851- int total_r = 0, total_g = 0, total_b = 0;
852- int select_r = 0, select_g = 0, select_b = 0;
853- int selected_pixels = 0;
854+ long int rtotal = 0, gtotal = 0, btotal = 0;
855+ float total = 0.0f;
856
857- for (int y=0; y<icon.height(); ++y)
858- {
859- for (int x=0; x<icon.width(); ++x)
860- {
861+ for (int y = 0; y < icon.height(); ++y) {
862+ for (int x = 0; x < icon.width(); ++x) {
863 QColor color = QColor::fromRgba(icon.pixel(x, y));
864
865- if (color.alphaF() < 0.5)
866- continue;
867-
868- total_r += color.red();
869- total_g += color.green();
870- total_b += color.blue();
871-
872- if (color.saturationF() <= 0.33)
873- continue;
874-
875- select_r += color.red();
876- select_g += color.green();
877- select_b += color.blue();
878-
879- selected_pixels++;
880+ float saturation = (qMax (color.red(), qMax (color.green(), color.blue())) -
881+ qMin (color.red(), qMin (color.green(), color.blue()))) / 255.0f;
882+ float relevance = .1 + .9 * (color.alpha() / 255.0f) * saturation;
883+
884+ rtotal += (unsigned char) (color.red() * relevance);
885+ gtotal += (unsigned char) (color.green() * relevance);
886+ btotal += (unsigned char) (color.blue() * relevance);
887+
888+ total += relevance * 255;
889 }
890 }
891
892- QColor color;
893-
894- if (selected_pixels <= 20)
895- {
896- int total_pixels = icon.width()*icon.height();
897- color = QColor::fromRgb(total_r/total_pixels,
898- total_g/total_pixels,
899- total_b/total_pixels);
900- color.setHsv(color.hue(), 0, color.value());
901- }
902- else
903- {
904- color = QColor::fromRgb(select_r/selected_pixels,
905- select_g/selected_pixels,
906- select_b/selected_pixels);
907- float saturation = qMin(color.saturationF()*0.7, 1.0);
908- float value = qMin(color.valueF()*1.4, 1.0);
909- color.setHsvF(color.hueF(), saturation, value);
910- }
911-
912- return color;
913+ QColor hsv = QColor::fromRgbF(rtotal / total, gtotal / total, btotal / total).toHsv();
914+
915+ /* Background color is the base color with 0.90f HSV value */
916+ hsv.setHsvF(hsv.hueF(),
917+ (hsv.saturationF() > .15f) ? 0.65f : hsv.saturationF(),
918+ 0.90f);
919+ colors.append(QVariant::fromValue(hsv.toRgb()));
920+
921+ /* Glow color is the base color with 1.0f HSV value */
922+ hsv.setHsvF(hsv.hueF(), hsv.saturationF(), 1.0f);
923+ colors.append(QVariant::fromValue(hsv.toRgb()));
924+
925+ return colors;
926 }
927
928=== modified file 'launcher/app/launcherview.h'
929--- launcher/app/launcherview.h 2011-02-07 17:21:35 +0000
930+++ launcher/app/launcherview.h 2011-02-15 13:21:38 +0000
931@@ -23,6 +23,7 @@
932 #include <QDeclarativeView>
933 #include <QUrl>
934 #include <QDragEnterEvent>
935+#include <QList>
936
937 class LauncherView : public QDeclarativeView
938 {
939@@ -30,7 +31,7 @@
940
941 public:
942 explicit LauncherView();
943- Q_INVOKABLE QColor iconAverageColor(QUrl source, QSize size);
944+ Q_INVOKABLE QList<QVariant> getColorsFromIcon(QUrl source, QSize size) const;
945
946 signals:
947 void desktopFileDropped(QString path);
948
949=== added file 'launcher/artwork/background.png'
950Binary files launcher/artwork/background.png 1970-01-01 00:00:00 +0000 and launcher/artwork/background.png 2011-02-15 13:21:38 +0000 differ
951=== removed file 'launcher/artwork/glow.png'
952Binary files launcher/artwork/glow.png 2011-01-28 14:43:29 +0000 and launcher/artwork/glow.png 1970-01-01 00:00:00 +0000 differ
953=== added file 'launcher/artwork/launcher_arrow_ltr.png'
954Binary files launcher/artwork/launcher_arrow_ltr.png 1970-01-01 00:00:00 +0000 and launcher/artwork/launcher_arrow_ltr.png 2011-02-15 13:21:38 +0000 differ
955=== added file 'launcher/artwork/launcher_arrow_rtl.png'
956Binary files launcher/artwork/launcher_arrow_rtl.png 1970-01-01 00:00:00 +0000 and launcher/artwork/launcher_arrow_rtl.png 2011-02-15 13:21:38 +0000 differ
957=== added file 'launcher/artwork/launcher_pip_ltr.png'
958Binary files launcher/artwork/launcher_pip_ltr.png 1970-01-01 00:00:00 +0000 and launcher/artwork/launcher_pip_ltr.png 2011-02-15 13:21:38 +0000 differ
959=== added file 'launcher/artwork/round_corner_54x54.png'
960Binary files launcher/artwork/round_corner_54x54.png 1970-01-01 00:00:00 +0000 and launcher/artwork/round_corner_54x54.png 2011-02-15 13:21:38 +0000 differ
961=== added file 'launcher/artwork/round_outline_54x54.png'
962Binary files launcher/artwork/round_outline_54x54.png 1970-01-01 00:00:00 +0000 and launcher/artwork/round_outline_54x54.png 2011-02-15 13:21:38 +0000 differ
963=== added file 'launcher/artwork/round_shine_54x54.png'
964Binary files launcher/artwork/round_shine_54x54.png 1970-01-01 00:00:00 +0000 and launcher/artwork/round_shine_54x54.png 2011-02-15 13:21:38 +0000 differ
965=== removed file 'launcher/artwork/shadow.png'
966Binary files launcher/artwork/shadow.png 2010-09-13 15:52:34 +0000 and launcher/artwork/shadow.png 1970-01-01 00:00:00 +0000 differ
967=== removed file 'launcher/artwork/trash.png'
968Binary files launcher/artwork/trash.png 2010-11-09 10:52:04 +0000 and launcher/artwork/trash.png 1970-01-01 00:00:00 +0000 differ
969=== modified file 'libunity-2d-private/Unity2d/blendedimageprovider.cpp'
970--- libunity-2d-private/Unity2d/blendedimageprovider.cpp 2011-02-07 15:32:51 +0000
971+++ libunity-2d-private/Unity2d/blendedimageprovider.cpp 2011-02-15 13:21:38 +0000
972@@ -16,6 +16,7 @@
973
974 #include "blendedimageprovider.h"
975 #include <QPainter>
976+#include <QDebug>
977
978 BlendedImageProvider::BlendedImageProvider() : QDeclarativeImageProvider(QDeclarativeImageProvider::Image)
979 {
980@@ -28,31 +29,66 @@
981 QImage BlendedImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
982 {
983 /* id is of the form [FILENAME]color=[COLORNAME]alpha=[FLOAT] */
984- QRegExp rx("(.+)color=(.+)alpha=(\\d+(?:\.\\d+)?)");
985- rx.indexIn(id);
986+ QRegExp rx("^(.+)color=(.+)alpha=(\\d+(?:\\.\\d+)?)$");
987+ if (rx.indexIn(id)) {
988+ qWarning() << "BlendedImageProvider: failed to match id:" << id;
989+ return QImage();
990+ }
991 QStringList list = rx.capturedTexts();
992- if(list.size() != 4)
993- return QImage();
994-
995- QString filename = list[1];
996- QColor color;
997- color.setNamedColor(list[2]);
998- float alpha = list[3].toFloat();
999+
1000+ QString fileName = list[1];
1001+ if (fileName.isEmpty()) {
1002+ qWarning() << "BlendedImageProvider: filename can't be empty.";
1003+ return QImage();
1004+ }
1005+
1006+ QString colorName = list[2];
1007+ if (!QColor::isValidColor(colorName)) {
1008+ /* Passing a named color of the form #RRGGBB is impossible
1009+ due to the fact that QML Image considers the source an URL and strips any anchor
1010+ from the string it passes to this method (i.e. everything after the #).
1011+ As a workaround we allow passing the color as RRGGBB and when a sting is not an
1012+ SVG color name (e.g. "blue", "yellow" etc.) we try interpreting it as an RRGGBB
1013+ color by adding back the #.
1014+ */
1015+ colorName.prepend("#");
1016+ if (!QColor::isValidColor(colorName)) {
1017+ qWarning() << "BlendedImageProvider: invalid color name:" << list[2];
1018+ return QImage();
1019+ }
1020+ }
1021+ QColor color(colorName);
1022+
1023+ bool valid = false;
1024+ float alpha = list[3].toFloat(&valid);
1025+ if (!valid) {
1026+ qWarning() << "BlendedImageProvider: can't convert alpha to floating point:" << list[3];
1027+ return QImage();
1028+ }
1029 color.setAlphaF(alpha);
1030
1031- QImage image(filename);
1032- if(requestedSize.width() == 0 && requestedSize.height() != 0)
1033+ QImage image(fileName);
1034+ if (image.isNull()) {
1035+ qWarning() << "BlendedImageProvider: failed to load image from file:" << fileName;
1036+ return QImage();
1037+ }
1038+
1039+ if (requestedSize.width() == 0 && requestedSize.height() != 0) {
1040 image = image.scaledToHeight(requestedSize.height(), Qt::SmoothTransformation);
1041- else if(requestedSize.width() != 0 && requestedSize.height() == 0)
1042+ } else if (requestedSize.width() != 0 && requestedSize.height() == 0) {
1043 image = image.scaledToWidth(requestedSize.width(), Qt::SmoothTransformation);
1044- else if(requestedSize.isValid())
1045+ } else if (requestedSize.isValid()) {
1046 image = image.scaled(requestedSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1047+ }
1048
1049- if(size)
1050+ if (size) {
1051 *size = image.size();
1052+ }
1053
1054+ /* We use SourceAtop as the composition mode since we want any area that is fully transparent
1055+ in the source image to be fully transparent also in the result. */
1056 QPainter painter(&image);
1057- painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
1058+ painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
1059 painter.fillRect(image.rect(), color);
1060 painter.end();
1061
1062
1063=== modified file 'panel/applets/homebutton/homebuttonapplet.cpp'
1064--- panel/applets/homebutton/homebuttonapplet.cpp 2011-01-22 03:52:17 +0000
1065+++ panel/applets/homebutton/homebuttonapplet.cpp 2011-02-15 13:21:38 +0000
1066@@ -49,7 +49,7 @@
1067 connect(m_button, SIGNAL(clicked()), SLOT(toggleDash()));
1068
1069 m_button->setStyleSheet(
1070- "QToolButton { border: none; margin: 0; padding: 0; width: 54 }"
1071+ "QToolButton { border: none; margin: 0; padding: 0; width: 61 }"
1072 "QToolButton:checked, QToolButton:pressed {"
1073 // Use border-image here, not background-image, because bfb_bg_active.png is 56px wide
1074 " border-image: url(theme:/bfb_bg_active.png);"

Subscribers

People subscribed via source and target branches

to all changes: