2
* This file is part of unity-2d
4
* Copyright 2010-2011 Canonical Ltd.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; version 3.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21
import "utils.js" as Utils
28
property int columns: desktop.workspaces.columns
29
property int rows: desktop.workspaces.rows
31
property int margin: 35
32
property int spacing: 4
34
/* Effective area available for laying out the workspaces after considering
35
inter-workspace spaces */
36
property int availableWidth: switcher.width - (columns * spacing)
37
property int availableHeight: switcher.height - (rows * spacing)
39
property int maxCellWidth: Math.floor(availableWidth / columns)
40
property int maxCellHeight: Math.floor(availableHeight / rows)
41
/* Depending on the aspect ratio of the final workspaces layout, we will
42
have either vertical or horizontal margins. That is, we will either:
43
- use maxCellWidth as base cell width and compute the height based on the
45
- use maxCellHeight for the base cell height and compute the width based
47
To figure out which way to go, compute the other size and see how things
48
would fit inside the screen. */
49
property int computedCellHeight: maxCellWidth * switcher.height / switcher.width
50
property int computedCellWidth: maxCellHeight * switcher.width / switcher.height
52
property bool useWidth: (computedCellHeight + spacing) * rows <= switcher.height
54
property int cellWidth: useWidth ? maxCellWidth : computedCellWidth
55
property int cellHeight: useWidth ? computedCellHeight : maxCellHeight
56
property real cellScale: cellWidth / switcher.width
58
/* Scale of a workspace when the user zooms on it (fills most of the switcher, leaving a margin to see
59
the corners of the other workspaces below it) */
60
property bool isDesktopHorizontal: declarativeView.screen.panelsFreeGeometry.width > declarativeView.screen.panelsFreeGeometry.height
61
property real zoomedScale: (isDesktopHorizontal) ? ((width - 2*margin) / switcher.width) :
62
((height - 2*margin) / switcher.height)
64
/* When this is set, it is used to filter the global list of windows to limit it to
65
a single application. See the SortFilterProxyModel used in Spread.qml */
66
property string applicationFilter
68
/* The number of the currently zoomed workspace (-1 means no workspace)
69
Use workspaceForNumber to find the actual Workspace component. */
70
property int zoomedWorkspace: -1
72
/* This is the master model containing all the windows recognized by bamf for the entire
73
screen. Each workspace will individually filter them to select only those that
75
property variant allWindows: WindowsList { }
77
/* Group all Workspace elements into a single Item to help workspaceByNumber
78
iterate over less items than it would need to if the Repeater was adding children
79
to the switcher itself. */
82
anchors.centerIn: parent
84
width: cellWidth * columns
85
height: cellHeight * rows
87
model: desktop.workspaces.count
88
cellWidth: parent.cellWidth + spacing
89
cellHeight: parent.cellHeight + spacing
90
keyNavigationWraps: true
91
property string windowFocus
93
if (event.key == Qt.Key_Left || event.key == Qt.Key_Up) {
95
} else if (event.key == Qt.Key_Right || event.key == Qt.Key_Down) {
100
highlight: Rectangle {
102
x: workspaces.currentItem.x
103
y: workspaces.currentItem.y
105
width: workspaces.cellWidth
106
height: workspaces.cellHeight
107
visible: workspaces.currentItem.state == "unzoomed"
109
highlightFollowsCurrentItem: false
111
delegate: Workspace {
114
property int workspaceNumber: index
116
width: workspaces.cellWidth
117
height: workspaces.cellHeight
119
unzoomedScale: switcher.cellScale
121
/* Center the workspace in 'zoomed' state */
122
zoomedX: switcher.width * (1 - zoomedScale) / 2
123
zoomedY: switcher.height * (1 - zoomedScale) / 2
124
zoomedScale: switcher.zoomedScale
128
onCurrentIndexChanged: {
129
if (workspaces.windowFocus == "first") {
130
setFocusOnFirstWindow()
131
} else if (workspaces.windowFocus == "last") {
132
setFocusOnLastWindow()
138
if (desktop.workspaces.current == workspaceNumber) {
144
if (zoomedWorkspace == workspaceNumber) {
153
if (zoomedWorkspace == -1) {
154
workspaces.currentIndex = index
159
if (zoomedWorkspace == workspaceNumber) {
160
activateWorkspace(workspaceNumber)
161
} else if (zoomedWorkspace == -1) {
162
if (windowCount <= 1) {
163
activateWorkspace(workspaceNumber)
165
workspaces.currentIndex = index
166
zoomedWorkspace = workspaceNumber
169
workspaces.currentIndex = index
175
onCurrentIndexChanged: {
180
/* FIXME: bad naming. Ideas: screenModeActivated, initialState */
181
property bool initial: true
183
/* This connection receives all commands from the DBUS API */
187
onShowCurrentWorkspace: {
188
/* Setup application pre-filtering and initially zoomed desktop, if any
189
were specified as arguments */
190
applicationFilter = applicationDesktopFile
191
zoomedWorkspace = desktop.workspaces.current
195
onShowAllWorkspaces: {
196
if (desktop.workspaces.count > 1) {
197
applicationFilter = applicationDesktopFile
201
control.showCurrentWorkspace(applicationDesktopFile)
205
onHide: cancelAndExit()
207
onFilterByApplication: applicationFilter = applicationDesktopFile
214
spreadView.forceActivateWindow()
215
workspaces.currentIndex = desktop.workspaces.current
216
/* This is necessary otherwise we don't get keypresses until the user does a
217
mouse over on a window */
218
workspaces.forceActiveFocus()
222
/* This controls the exit from the switcher.
223
Note that we can't just hide the workspaces switcher immediately when the user
224
wants to activate a window or cancel the switching process. We first want any
225
transitions to complete, so we need to start this timer, and when it's triggered
226
it will actually do all that is necessary to hide the switcher and cleanup */
228
id: exitTransitionTimer
229
interval: Utils.transitionDuration
233
/* Nothing should be allowed to touch the windows anymore here, so it should
234
be safe to unload them all to save memory.
235
NOTE: i'm not exactly sure any memory will actually be saved since the biggest
236
usage is the window screenshots, and Qt is caching them (see SpreadWindow.qml
237
for the trick I use to force them to refresh and more info on this cache)
245
/* Handle both the ESC keypress and any click on the area outside of the
246
switcher in the same way: maximize the currently active workspace to screen
247
size and hide the switcher (effectively canceling the switching operation).
248
If another workspace was zoomed unzoom it first. */
253
event.accepted = true
256
if (event.modifiers & Qt.MetaModifier) {
258
event.accepted = true
267
onOutsideClick: cancelAndExit()
270
function cancelAndExit() {
273
/* Let the transition finish and then hide the switcher and perform cleanup */
274
exitTransitionTimer.start()
277
function activateWindow(windowInfo) {
278
desktop.workspaces.changeCurrent(zoomedWorkspace)
279
windowInfo.activate()
283
function activateWorkspace(workspaceNumber) {
284
desktop.workspaces.changeCurrent(workspaceNumber)