This file is indexed.

/usr/share/unity-2d/shell/launcher/LauncherItem.qml is in unity-2d-shell 5.10.0-0ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
/*
 * This file is part of unity-2d
 *
 * Copyright 2010-2011 Canonical Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import QtQuick 1.1
import Unity2d 1.0
import "../common"
import "../common/utils.js" as Utils

/* This component represents a single "tile" in the launcher and the surrounding
   indicator icons.

   The tile is square in size, with a side determined by the 'tileSize' property,
   and rounded borders.
   It is composed by a colored background layer, an icon (with 'icon' as source),
   and a layer on top that provides a "shine" effect.
   The main color of the background layer may be calculated based on the icon color
   or may be fixed (depending on the 'backgroundFromIcon' property).

   There's also an additional layer which contains only the outline of the tile
   that is only appearing during the launching animation (when the 'launching' property is
   true). During this animation the background fades out and the outline fades in,
   giving a "pulsing" appearance to the tile.

   Around the tile we may have on the left a number of "pips" between zero and three.
   Pips are small icons used to indicate how many windows we have open for the current tile
   (based on the 'windowCount' property).
   The rule is: if there's only one window, we just display an arrow. If there are
   two we display 2 pips, if there are 3 or more display 3 pips.

   On the right of the tile there's an arrow that appears if the tile is currently 'active'.

   Additionally, when the tile is marked as 'urgent' it will start an animation where the
   rotation is changed so that it appears to be "shaking".
*/
DropItem {
    id: item

    Accessible.role: Accessible.PushButton

    anchors.horizontalCenter: parent.horizontalCenter

    height: selectionOutlineSize

    property bool isBfb: false
    property int tileSize
    property int selectionOutlineSize
    property alias name: looseItem.objectName
    property string desktopFile: ""
    property string icon: "image://icons/unknown"
    property alias urgentAnimation: urgentAnimation
    property bool running: false
    property bool active: false
    property bool activeOnThisScreen: false
    property bool urgent: false
    property bool launching: false
    property alias interactive: mouse.enabled

    property int counter: 0
    property bool counterVisible: false
    property real progress: 0.0
    property bool progressBarVisible: false
    property alias emblem: emblemIcon.source
    property bool emblemVisible: false

    property bool backgroundFromIcon
    property color defaultBackgroundColor: "#333333"
    property color selectedBackgroundColor: "#dddddd"

    property alias shortcutVisible: shortcut.visible
    property alias shortcutText: shortcutText.text

    property bool beHudItem: shellManager.hudActive && shellManager.hudShell == declarativeView
                             && isBfb && launcher2dConfiguration.hideMode == 0

    property bool isBeingDragged: false
    property int dragPosition

    property int pips: 0
    property string pipSource: "launcher/artwork/launcher_" +
                               ((pips <= 1) ? "arrow" : "pip") + "_ltr.png"
    function getPipOffset(index) {
        /* Pips need to always be centered, regardless if they are an even or odd
           number. The following simple conditional code works and is less
           convoluted than a generic formula. It's ok since we always work with at
           most three pips anyway. */
        if (pips == 1) return 0
        if (pips == 2) return (index == 0) ? -2 : +2
        else return (index == 0) ? 0 : (index == 1) ? -4 : +4
    }

    signal clicked(variant mouse)
    signal pressed(variant mouse)
    signal entered
    signal exited

    Item {
        /* The actual item, reparented so its y coordinate can be animated. */
        id: looseItem
        LayoutMirroring.enabled: Utils.isRightToLeft()
        LayoutMirroring.childrenInherit: true
        parent: list
        width: item.width
        height: item.height
        x: item.x
        y: -item.ListView.view.contentY + item.y
        /* The item is above the list's contentItem.
           Top and bottom gradients, ListViewDragAndDrop and autoscroll areas
           are above the item */
        z: list.contentItem.z + 1

        /* Bind to the scale of the delegate so that it is animated upon insertion/removal */
        scale: item.scale

        /* The y coordinate is initially not animated, as it would result in an
           unwanted effect of every single item popping out from the top of the
           launcher (even when they are supposed to be coming from the bottom).
           This property is later set to true once the item has taken its
           initial position. */
        property bool animateY: false

        /* This is the arrow shown at the right of the tile when the application is
           the active one */
        Image {
            objectName: "active"
            anchors.right: parent.right
            y: item.height - item.selectionOutlineSize / 2 - height / 2
            mirror: Utils.isRightToLeft()

            source: "image://blended/%1color=%2alpha=%3"
                  .arg("launcher/artwork/launcher_arrow_" 
                       + (activeOnThisScreen || beHudItem ? "" : "outline_" ) 
                       + "rtl.png")
                  .arg("lightgrey")
                  .arg(1.0)

            visible: (active && (looseItem.state != "beingDragged")) || beHudItem
        }

        /* This is the area on the left of the tile where the pips/arrow end up.

           I'd rather use a Column here, but the pip images have an halo
           around them, so they are pretty tall and would mess up the column.
           As a workaround I center all of them, then shift up or down
           depending on the index. */
        Repeater {
            model: item.pips
            delegate: Image {
                objectName: "pips-" + index
                /* FIXME: It seems that when the image is created (or re-used) by the Repeater
                   for a moment it doesn't have any parent, and therefore warnings are
                   printed for the following two anchor assignements. This fixes the
                   problem, but I'm not sure if it should happen in the first place. */
                anchors.left: (parent) ? parent.left : undefined
                y: item.height - item.selectionOutlineSize / 2 - height / 2 + getPipOffset(index)
                mirror: Utils.isRightToLeft()

                source: "image://blended/%1color=%2alpha=%3"
                        .arg(pipSource).arg("lightgrey").arg(1.0)

                visible: looseItem.state != "beingDragged"
            }
        }

        MouseArea {
            id: mouse
            anchors.fill: parent
            hoverEnabled: true
            acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MidButton

            onClicked: item.clicked(mouse)
            onEntered: item.entered()
            onExited: item.exited()
            onPressed: item.pressed(mouse)
        }

        /* This is the for centering the actual tile in the launcher */
        Item {
            id: tile
            width: item.tileSize
            height: item.tileSize
            anchors.centerIn: parent

            /* This draws the icon, the tile background and the sheen on top */
            IconTile {
                id: icon
                width: item.tileSize
                height: item.tileSize
                anchors.centerIn: parent

                activeFocus: item.activeFocus
                backgroundFromIcon: item.backgroundFromIcon

                source: (beHudItem && hudLoader) ? hudLoader.item.appIcon : item.icon
                tileBackgroundImage: (item.isBfb) ? "../launcher/artwork/squircle_base_54.png" : ""
                tileShineImage: (item.isBfb) ? "../launcher/artwork/squircle_shine_54.png" : ""
                selectedTileBackgroundImage: (item.isBfb) ? "../launcher/artwork/squircle_base_selected_54.png" : ""

                /* tile background fade in/out animation */
                SequentialAnimation on backgroundOpacity {
                    NumberAnimation { to: 0.0; duration: 1000; easing.type: Easing.InOutQuad }
                    NumberAnimation { to: 1.0; duration: 1000; easing.type: Easing.InOutQuad }

                    loops: Animation.Infinite
                    alwaysRunToEnd: true
                    running: launching
                }
            }

            /* This image appears only while launching, and pulses in and out in counterpoint
               to the background, so that the outline of the tile is always visible. */
            Image {
                id: tileOutline
                anchors.fill: parent
                smooth: true

                sourceSize.width: item.tileSize
                sourceSize.height: item.tileSize
                source: "artwork/round_outline_54x54.png"

                opacity: 0

                SequentialAnimation on opacity {
                    NumberAnimation { to: 1.0; duration: 1000; easing.type: Easing.InOutQuad }
                    NumberAnimation { to: 0.0; duration: 1000; easing.type: Easing.InOutQuad }

                    loops: Animation.Infinite
                    alwaysRunToEnd: true
                    running: launching
                }
            }

            Image {
                id: selectionOutline
                objectName: "selectionOutline"
                anchors.centerIn: parent
                smooth: true
                source: isBfb ? "artwork/squircle_glow_54.png" : "artwork/round_selected_66x66.png"
                visible: declarativeView.focus && item.activeFocus
            }

            Rectangle {
                id: counter
                height: 16 - border.width
                width: 32
                // Using anchors the item will be 1 pixel off with respect to Unity
                y: 1
                x: 1
                radius: height / 2 - 1
                smooth: true
                border.width: 2
                border.color: "white"
                color: "#595959"
                visible: launcherItem.counterVisible

                Text {
                    anchors.centerIn: parent
                    font.pixelSize: parent.height - 3
                    width: parent.width - 5
                    smooth: true
                    elide: Text.ElideRight
                    horizontalAlignment: Text.AlignHCenter
                    color: "white"
                    text: launcherItem.counter
                }
            }

            Image {
                id: progressBar
                objectName: "progressBar"
                source: "artwork/progress_bar_trough.png"
                anchors.verticalCenter: parent.verticalCenter
                anchors.left: parent.left
                width: tile.width
                smooth: true
                state: launcherItem.progressBarVisible ? "" : "hidden"

                Image {
                    id: progressFill
                    source: "artwork/progress_bar_fill.png"
                    anchors.verticalCenter: parent.verticalCenter
                    x: 6
                    width: sourceSize.width * launcherItem.progress
                    smooth: true

                    Behavior on width {
                       NumberAnimation { duration: 200; easing.type: Easing.InOutSine }
                    }
                }

                Behavior on width {
                    NumberAnimation { duration: 200; easing.type: Easing.InOutSine }
                }

                states: State {
                    name: "hidden"
                    PropertyChanges {
                        target: progressBar
                        width: 0
                    }
                    // This, combined with anchors.left: parent.left in the default state
                    // makes the bar seem to come in from the left and go away at the right
                    AnchorChanges {
                        target: progressBar
                        anchors.left: undefined
                        anchors.right: tile.right
                    }
                }
            }

            Rectangle {
                id: shortcut
                anchors.centerIn: parent
                color: "#B3000000" // 0.7 opacity on black
                radius: 2
                width: 22
                height: 22
                smooth: true

                Text {
                    id: shortcutText
                    anchors.centerIn: parent
                    color: "white"
                    smooth: true
                }
            }

            Image {
                id: emblemIcon
                anchors.left: parent.left
                anchors.top: parent.top
                visible: launcherItem.emblemVisible && !counter.visible
                smooth: true
            }


            /* The entire tile will "shake" when the window is marked as "urgent", to attract
               the user's attention */
            SequentialAnimation {
                id: urgentAnimation
                running: urgent
                alwaysRunToEnd: true

                SequentialAnimation {
                    loops: (urgent) ? 30 : 0
                    NumberAnimation { target: tile; property: "rotation"; to: 15; duration: 150 }
                    NumberAnimation { target: tile; property: "rotation"; to: -15; duration: 150 }
                }
                NumberAnimation { target: tile; property: "rotation"; to: 0; duration: 75 }
            }
        }

        states: State {
            name: "beingDragged"
            when: item.isBeingDragged
            PropertyChanges {
                target: looseItem
                y: item.dragPosition - tile.height / 2
                /* When dragging an item, stack it on top of all its siblings */
                z: list.contentItem.z + 2
            }
        }
        Behavior on y {
            enabled: /* do not animate during initial positioning */
                     looseItem.animateY
                     /* do not animate while dragging to re-order applications */
                     && (looseItem.state != "beingDragged")
                     /* do not animate during insertion/removal */
                     && (looseItem.scale == 1)
                     /* do not animate while flicking the list */
                     && !item.ListView.view.moving
                     && !item.ListView.view.autoScrolling
            NumberAnimation {
                duration: 250
                easing.type: Easing.OutBack
            }
        }

        /* Delay the animation on y to when the item has been initially positioned. */
        Timer {
            id: canAnimateY
            /* This ensures that the trigger will be executed in the next
               iteration of the event loop, at which point the item will have
               taken its initial position. */
            triggeredOnStart: true
            onTriggered: {
                stop()
                looseItem.animateY = true
            }
        }
        Component.onCompleted: canAnimateY.start()
    }
}