=== modified file 'plugins/WindowManager/Screen.h'
--- plugins/WindowManager/Screen.h 2017-04-06 12:58:36 +0000
+++ plugins/WindowManager/Screen.h 2017-04-06 12:58:37 +0000
@@ -16,7 +16,6 @@
Q_OBJECT
Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
-
Q_PROPERTY(bool used READ used NOTIFY usedChanged)
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(qtmir::OutputTypes outputType READ outputType NOTIFY outputTypeChanged)
=== modified file 'plugins/WindowManager/Screens.cpp'
--- plugins/WindowManager/Screens.cpp 2017-04-06 12:58:36 +0000
+++ plugins/WindowManager/Screens.cpp 2017-04-06 12:58:37 +0000
@@ -67,6 +67,16 @@
return count();
}
+int Screens::indexOf(Screen *screen) const
+{
+ return m_screens.indexOf(screen);
+}
+
+Screen *Screens::get(int index) const
+{
+ return m_screens.at(index);
+}
+
int Screens::count() const
{
return m_screens.size();
=== modified file 'plugins/WindowManager/Screens.h'
--- plugins/WindowManager/Screens.h 2017-04-06 12:58:36 +0000
+++ plugins/WindowManager/Screens.h 2017-04-06 12:58:37 +0000
@@ -49,6 +49,9 @@
QVariant data(const QModelIndex &index, int role = ScreenRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ Q_INVOKABLE int indexOf(Screen*) const;
+ Q_INVOKABLE Screen* get(int index) const;
+
int count() const;
QVariant activeScreen() const;
=== modified file 'plugins/WindowManager/WorkspaceModel.h'
--- plugins/WindowManager/WorkspaceModel.h 2017-04-06 12:58:36 +0000
+++ plugins/WindowManager/WorkspaceModel.h 2017-04-06 12:58:37 +0000
@@ -49,8 +49,8 @@
void remove(Workspace* workspace);
virtual void move(int from, int to);
- int indexOf(Workspace *workspace) const;
- Workspace* get(int index) const;
+ Q_INVOKABLE int indexOf(Workspace *workspace) const;
+ Q_INVOKABLE Workspace* get(int index) const;
// From QAbstractItemModel
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
=== modified file 'qml/Shell.qml'
--- qml/Shell.qml 2017-04-06 12:58:36 +0000
+++ qml/Shell.qml 2017-04-06 12:58:37 +0000
@@ -99,7 +99,7 @@
readonly property var topLevelSurfaceList: {
if (!WMScreen.currentWorkspace) return null;
- return WMScreen.currentWorkspace.windowModel
+ return stage.temporarySelectedWorkspace ? stage.temporarySelectedWorkspace.windowModel : WMScreen.currentWorkspace.windowModel
}
onMainAppChanged: {
@@ -189,11 +189,11 @@
}
function startApp(appId) {
- if (ApplicationManager.findApplication(appId)) {
- ApplicationManager.requestFocusApplication(appId);
- } else {
+ if (!ApplicationManager.findApplication(appId)) {
ApplicationManager.startApplication(appId);
}
+ ApplicationManager.requestFocusApplication(appId);
+ stage.closeSpread();
}
function startLockedApp(app) {
=== modified file 'qml/Stage/ApplicationWindow.qml'
--- qml/Stage/ApplicationWindow.qml 2017-02-24 12:37:14 +0000
+++ qml/Stage/ApplicationWindow.qml 2017-04-06 12:58:37 +0000
@@ -52,13 +52,8 @@
// other instructions.
if (surface) {
surfaceContainer.surface = surface;
- d.liveSurface = surface.live;
- d.hadSurface = false;
surfaceInitTimer.start();
} else {
- if (d.surfaceInitialized) {
- d.hadSurface = true;
- }
d.surfaceInitialized = false;
surfaceContainer.surface = null;
}
@@ -67,21 +62,6 @@
QtObject {
id: d
- property bool liveSurface: false;
- property var con: Connections {
- target: root.surface
- onLiveChanged: d.liveSurface = root.surface.live
- }
- // using liveSurface instead of root.surface.live because with the latter
- // this expression is not reevaluated when root.surface changes
- readonly property bool needToTakeScreenshot: root.surface && d.surfaceInitialized && !d.liveSurface
- && applicationState !== ApplicationInfoInterface.Running
- onNeedToTakeScreenshotChanged: {
- if (needToTakeScreenshot && screenshotImage.status === Image.Null) {
- screenshotImage.take();
- }
- }
-
// helpers so that we don't have to check for the existence of an application everywhere
// (in order to avoid breaking qml binding due to a javascript exception)
readonly property string name: root.application ? root.application.name : ""
@@ -131,34 +111,10 @@
id: surfaceInitTimer
interval: 100
onTriggered: {
- if (root.surface && root.surface.live) {d.surfaceInitialized = true;}
- }
- }
-
- Timer {
- id: surfaceIsOldTimer
- interval: 1000
- onTriggered: { if (stateGroup.state === "surface") { d.surfaceOldEnoughToBeResized = true; } }
- }
-
- Image {
- id: screenshotImage
- objectName: "screenshotImage"
- anchors.fill: parent
- fillMode: Image.PreserveAspectCrop
- horizontalAlignment: Image.AlignLeft
- verticalAlignment: Image.AlignTop
- antialiasing: !root.interactive
- z: 1
-
- function take() {
- // Save memory by using a half-resolution (thus quarter size) screenshot.
- // Do not make this a binding, we can only take the screenshot once!
- surfaceContainer.grabToImage(
- function(result) {
- screenshotImage.source = result.url;
- },
- Qt.size(root.width / 2, root.height / 2));
+ if (root.surface && root.surface.live) {
+ d.surfaceInitialized = true;
+ d.hadSurface = true;
+ }
}
}
@@ -167,7 +123,7 @@
visible: active
active: false
anchors.fill: parent
- z: screenshotImage.z + 1
+ z: 1
sourceComponent: Component {
Splash {
id: splash
@@ -238,167 +194,14 @@
id: stateGroup
objectName: "applicationWindowStateGroup"
states: [
- State {
- name: "void"
- when:
- d.hadSurface && (!root.surface || !d.surfaceInitialized)
- &&
- screenshotImage.status !== Image.Ready
- },
- State {
- name: "splashScreen"
- when:
- !d.hadSurface && (!root.surface || !d.surfaceInitialized)
- &&
- screenshotImage.status !== Image.Ready
- },
- State {
+ State{
name: "surface"
- when:
- (root.surface && d.surfaceInitialized)
- &&
- (d.liveSurface ||
- (d.applicationState !== ApplicationInfoInterface.Running
- && screenshotImage.status !== Image.Ready))
- PropertyChanges {
- target: root
- implicitWidth: surfaceContainer.implicitWidth
- implicitHeight: surfaceContainer.implicitHeight
- }
- },
- State {
- name: "screenshot"
- when:
- screenshotImage.status === Image.Ready
- &&
- (d.applicationState !== ApplicationInfoInterface.Running
- || !root.surface || !d.surfaceInitialized)
- },
- State {
- // This is a dead end. From here we expect the surface to be removed from the model
- // shortly after we stop referencing to it in our SurfaceContainer.
- name: "closed"
- when:
- // The surface died while the application is running. It must have been closed
- // by the shell or the application decided to destroy it by itself
- root.surface && d.surfaceInitialized && !d.liveSurface
- && d.applicationState === ApplicationInfoInterface.Running
- }
- ]
-
- transitions: [
- Transition {
- from: ""; to: "splashScreen"
- PropertyAction { target: splashLoader; property: "active"; value: true }
- PropertyAction { target: surfaceContainer
- property: "visible"; value: false }
- },
- Transition {
- from: "splashScreen"; to: "surface"
- SequentialAnimation {
- PropertyAction { target: surfaceContainer
- property: "opacity"; value: 0.0 }
- PropertyAction { target: surfaceContainer
- property: "visible"; value: true }
- UbuntuNumberAnimation { target: surfaceContainer; property: "opacity";
- from: 0.0; to: 1.0
- duration: UbuntuAnimation.BriskDuration }
- ScriptAction { script: {
- splashLoader.active = false;
- surfaceIsOldTimer.start();
- } }
- }
- },
- Transition {
- from: "surface"; to: "splashScreen"
- SequentialAnimation {
- ScriptAction { script: {
- surfaceIsOldTimer.stop();
- d.surfaceOldEnoughToBeResized = false;
- splashLoader.active = true;
- surfaceContainer.visible = true;
- } }
- UbuntuNumberAnimation { target: splashLoader; property: "opacity";
- from: 0.0; to: 1.0
- duration: UbuntuAnimation.BriskDuration }
- PropertyAction { target: surfaceContainer
- property: "visible"; value: false }
- }
- },
- Transition {
- from: "surface"; to: "screenshot"
- SequentialAnimation {
- ScriptAction { script: {
- surfaceIsOldTimer.stop();
- d.surfaceOldEnoughToBeResized = false;
- screenshotImage.visible = true;
- } }
- UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
- from: 0.0; to: 1.0
- duration: UbuntuAnimation.BriskDuration }
- ScriptAction { script: {
- surfaceContainer.visible = false;
- surfaceContainer.surface = null;
- d.hadSurface = true;
- } }
- }
- },
- Transition {
- from: "screenshot"; to: "surface"
- SequentialAnimation {
- PropertyAction { target: surfaceContainer
- property: "visible"; value: true }
- UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
- from: 1.0; to: 0.0
- duration: UbuntuAnimation.BriskDuration }
- ScriptAction { script: {
- screenshotImage.visible = false;
- screenshotImage.source = "";
- surfaceIsOldTimer.start();
- } }
- }
- },
- Transition {
- from: "splashScreen"; to: "screenshot"
- SequentialAnimation {
- PropertyAction { target: screenshotImage
- property: "visible"; value: true }
- UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
- from: 0.0; to: 1.0
- duration: UbuntuAnimation.BriskDuration }
- PropertyAction { target: splashLoader; property: "active"; value: false }
- }
- },
- Transition {
- from: "surface"; to: "void"
- ScriptAction { script: {
- surfaceIsOldTimer.stop();
- d.surfaceOldEnoughToBeResized = false;
- surfaceContainer.visible = false;
- } }
- },
- Transition {
- from: "void"; to: "surface"
- SequentialAnimation {
- PropertyAction { target: surfaceContainer; property: "opacity"; value: 0.0 }
- PropertyAction { target: surfaceContainer; property: "visible"; value: true }
- UbuntuNumberAnimation { target: surfaceContainer; property: "opacity";
- from: 0.0; to: 1.0
- duration: UbuntuAnimation.BriskDuration }
- ScriptAction { script: {
- surfaceIsOldTimer.start();
- } }
- }
- },
- Transition {
- to: "closed"
- SequentialAnimation {
- ScriptAction { script: {
- surfaceContainer.visible = false;
- surfaceContainer.surface = null;
- d.hadSurface = true;
- } }
- }
+ when: (root.surface && d.surfaceInitialized) || d.hadSurface
+ },
+ State {
+ name: "splash"
+ when: !root.surface && !d.surfaceInitialized && !d.hadSurface
+ PropertyChanges { target: splashLoader; active: true }
}
]
}
=== modified file 'qml/Stage/DecoratedWindow.qml'
--- qml/Stage/DecoratedWindow.qml 2017-04-06 12:58:36 +0000
+++ qml/Stage/DecoratedWindow.qml 2017-04-06 12:58:37 +0000
@@ -126,15 +126,15 @@
name: "preview"; when: root.scaleToPreviewProgress > 0
PropertyChanges {
target: root
- implicitWidth: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedWidth, root.scaleToPreviewSize, root.scaleToPreviewProgress)
- implicitHeight: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedHeight, root.scaleToPreviewSize, root.scaleToPreviewProgress)
+ implicitWidth: MathUtils.linearAnimation(0, 1, applicationWindow.requestedWidth, root.scaleToPreviewSize, root.scaleToPreviewProgress)
+ implicitHeight: MathUtils.linearAnimation(0, 1, applicationWindow.requestedHeight, root.scaleToPreviewSize, root.scaleToPreviewProgress)
}
PropertyChanges {
target: applicationWindow;
- requestedWidth: applicationWindow.oldRequestedWidth
- requestedHeight: applicationWindow.oldRequestedHeight
- width: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedWidth, applicationWindow.minSize, root.scaleToPreviewProgress)
- height: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedHeight, applicationWindow.minSize, root.scaleToPreviewProgress)
+// requestedWidth: applicationWindow.oldRequestedWidth
+// requestedHeight: applicationWindow.oldRequestedHeight
+ width: MathUtils.linearAnimation(0, 1, applicationWindow.requestedWidth, applicationWindow.minSize, root.scaleToPreviewProgress)
+ height: MathUtils.linearAnimation(0, 1, applicationWindow.requestedHeight, applicationWindow.minSize, root.scaleToPreviewProgress)
itemScale: root.implicitWidth / width
}
}
@@ -173,10 +173,10 @@
height: implicitHeight
requestedHeight: !counterRotate ? root.requestedHeight - d.requestedDecorationHeight : root.requestedWidth
requestedWidth: !counterRotate ? root.requestedWidth : root.requestedHeight - d.requestedDecorationHeight
- property int oldRequestedWidth: requestedWidth
- property int oldRequestedHeight: requestedHeight
- onRequestedWidthChanged: oldRequestedWidth = requestedWidth
- onRequestedHeightChanged: oldRequestedHeight = requestedHeight
+// property int oldRequestedWidth: requestedWidth
+// property int oldRequestedHeight: requestedHeight
+// onRequestedWidthChanged: oldRequestedWidth = requestedWidth
+// onRequestedHeightChanged: oldRequestedHeight = requestedHeight
focus: true
property real itemScale: 1
=== added file 'qml/Stage/Spread/ScreensAndWorkspaces.qml'
--- qml/Stage/Spread/ScreensAndWorkspaces.qml 1970-01-01 00:00:00 +0000
+++ qml/Stage/Spread/ScreensAndWorkspaces.qml 2017-04-06 12:58:37 +0000
@@ -0,0 +1,261 @@
+import QtQuick 2.4
+import Ubuntu.Components 1.3
+import Ubuntu.Components.Popups 1.3
+import WindowManager 1.0
+import Unity.Application 0.1
+import ".."
+
+Item {
+ id: root
+
+ property string background
+
+ property var screensProxy: Screens.createProxy();
+
+ property QtObject activeWorkspace: null
+
+ signal closeSpread();
+
+ Row {
+ id: row
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ Behavior on anchors.horizontalCenterOffset { NumberAnimation { duration: UbuntuAnimation.SlowDuration } }
+ spacing: units.gu(1)
+
+ property var selectedIndex: undefined
+
+ Repeater {
+ model: screensProxy
+
+ delegate: Item {
+ height: root.height - units.gu(6)
+ width: workspaces.width
+
+ Item {
+ id: header
+ anchors { left: parent.left; top: parent.top; right: parent.right }
+ height: units.gu(7)
+ z: 1
+
+ property bool isCurrent: {
+ // another screen is selected.
+ if (row.selectedIndex != undefined && row.selectedIndex != index) return false;
+
+ // this screen is active.
+ if (WMScreen.active && WMScreen.isSameAs(model.screen) && WMScreen.currentWorkspace.isSameAs(activeWorkspace)) return true;
+ if (model.screen.workspaces.indexOf(activeWorkspace) >= 0) return true;
+
+ // not active.
+ return false;
+ }
+
+ property bool isSelected: screenMA.containsMouse
+ onIsSelectedChanged: {
+ if (isSelected) {
+ row.selectedIndex = Qt.binding(function() { return index; });
+ } else if (row.selectedIndex === index) {
+ row.selectedIndex = undefined;
+ }
+ }
+
+ UbuntuShape {
+ anchors.fill: parent
+ backgroundColor: "white"
+ opacity: header.isCurrent || header.isSelected ? 1.0 : 0.5
+ }
+
+ DropArea {
+ anchors.fill: parent
+ keys: ["workspace"]
+
+ onEntered: {
+ workspaces.workspaceModel.insert(workspaces.workspaceModel.count, {text: drag.source.text})
+ drag.source.inDropArea = true;
+ }
+
+ onExited: {
+ workspaces.workspaceModel.remove(workspaces.workspaceModel.count - 1, 1)
+ drag.source.inDropArea = false;
+ }
+
+ onDropped: {
+ drag.source.inDropArea = false;
+ }
+ }
+
+ Column {
+ anchors.fill: parent
+ anchors.margins: units.gu(1)
+
+ Label {
+ text: model.screen.name
+ color: header.isCurrent || header.isSelected ? "black" : "white"
+ }
+
+ Label {
+ text: model.screen.outputTypeName
+ color: header.isCurrent || header.isSelected ? "black" : "white"
+ fontSize: "x-small"
+ }
+
+ Label {
+ text: screen.availableModes[screen.currentModeIndex].size.width + "x" + screen.availableModes[screen.currentModeIndex].size.height
+ color: header.isCurrent || header.isSelected ? "black" : "white"
+ fontSize: "x-small"
+ }
+ }
+
+ Icon {
+ anchors {
+ top: parent.top
+ right: parent.right
+ margins: units.gu(1)
+ }
+ width: units.gu(3)
+ height: width
+ source: "image://theme/select"
+ color: header.isCurrent || header.isSelected ? "black" : "white"
+ visible: model.screen.active
+ }
+
+ MouseArea {
+ id: screenMA
+ hoverEnabled: true
+ anchors.fill: parent
+
+ onClicked: {
+ var obj = screensMenuComponent.createObject(header)
+ obj.open(mouseX, mouseY)
+ }
+ }
+
+ Component {
+ id: screensMenuComponent
+ UbuntuShape {
+ id: screensMenu
+ width: units.gu(20)
+ height: contentColumn.childrenRect.height
+ backgroundColor: "white"
+
+ function open(mouseX, mouseY) {
+ x = Math.max(0, Math.min(mouseX - width / 2, parent.width - width))
+ y = mouseY + units.gu(1)
+ }
+
+ InverseMouseArea {
+ anchors.fill: parent
+ onClicked: {
+ screensMenu.destroy()
+ }
+ }
+
+ Column {
+ id: contentColumn
+ width: parent.width
+ ListItem {
+ height: layout.height
+ highlightColor: "transparent"
+ ListItemLayout {
+ id: layout
+ title.text: qsTr("Add workspace")
+ title.color: "black"
+ }
+ onClicked: {
+ screen.workspaces.addWorkspace();
+ Screens.sync(root.screensProxy);
+ screensMenu.destroy();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Workspaces {
+ id: workspaces
+ height: parent.height - header.height - units.gu(2)
+ width: {
+ var width = 0;
+ if (screensProxy.count == 1) {
+ width = Math.min(implicitWidth, root.width - units.gu(8));
+ } else {
+ width = Math.min(implicitWidth, model.screen.active ? root.width - units.gu(48) : units.gu(40))
+ }
+ return Math.max(workspaces.minimumWidth, width);
+ }
+
+ Behavior on width { UbuntuNumberAnimation {} }
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: units.gu(1)
+ anchors.horizontalCenter: parent.horizontalCenter
+ screen: model.screen
+ background: root.background
+
+ workspaceModel: model.screen.workspaces
+ activeWorkspace: root.activeWorkspace
+ readOnly: false
+
+ onCommitScreenSetup: Screens.sync(root.screensProxy)
+ onCloseSpread: root.closeSpread();
+
+ onClicked: {
+ root.activeWorkspace = workspace;
+ }
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ anchors { left: parent.left; top: parent.top; bottom: parent.bottom; topMargin: units.gu(6); bottomMargin: units.gu(1) }
+ width: units.gu(5)
+ color: "#33000000"
+ visible: (row.width - root.width + units.gu(10)) / 2 - row.anchors.horizontalCenterOffset > units.gu(5)
+ MouseArea {
+ id: leftScrollArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onPressed: mouse.accepted = false;
+ }
+ DropArea {
+ id: leftFakeDropArea
+ anchors.fill: parent
+ keys: ["application", "workspace"]
+ }
+ }
+ Rectangle {
+ anchors { right: parent.right; top: parent.top; bottom: parent.bottom; topMargin: units.gu(6); bottomMargin: units.gu(1) }
+ width: units.gu(5)
+ color: "#33000000"
+ visible: (row.width - root.width + units.gu(10)) / 2 + row.anchors.horizontalCenterOffset > units.gu(5)
+ MouseArea {
+ id: rightScrollArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onPressed: mouse.accepted = false;
+ }
+ DropArea {
+ id: rightFakeDropArea
+ anchors.fill: parent
+ keys: ["application", "workspace"]
+ }
+ }
+ Timer {
+ repeat: true
+ running: leftScrollArea.containsMouse || rightScrollArea.containsMouse || leftFakeDropArea.containsDrag || rightFakeDropArea.containsDrag
+ interval: UbuntuAnimation.SlowDuration
+ triggeredOnStart: true
+ onTriggered: {
+ var newOffset = row.anchors.horizontalCenterOffset;
+ var maxOffset = Math.max((row.width - root.width + units.gu(10)) / 2, 0);
+ if (leftScrollArea.containsMouse || leftFakeDropArea.containsDrag) {
+ newOffset += units.gu(20)
+ } else {
+ newOffset -= units.gu(20)
+ }
+ newOffset = Math.max(-maxOffset, Math.min(maxOffset, newOffset));
+ row.anchors.horizontalCenterOffset = newOffset;
+ }
+ }
+}
=== modified file 'qml/Stage/Spread/Spread.qml'
--- qml/Stage/Spread/Spread.qml 2017-03-09 09:31:43 +0000
+++ qml/Stage/Spread/Spread.qml 2017-04-06 12:58:37 +0000
@@ -28,10 +28,10 @@
property var spreadFlickable
// some config options
- property real contentMargin: 0.16 * root.height
- property real contentTopMargin: contentMargin
- property real contentBottomMargin: 0.35 * contentMargin
- property real windowTitleTopMargin: 3/4 * (contentTopMargin - windowTitle.height)
+ property real contentMargin: 0.1 * root.height
+ property real contentTopMargin: contentMargin + root.y + windowTitle.height
+ property real contentBottomMargin: contentMargin
+ property real windowTitleTopMargin: contentMargin - windowTitle.height
property int stackItemCount: 3
property real leftRotationAngle: 22
property real rightRotationAngle: 32
@@ -52,7 +52,7 @@
readonly property real spreadWidth: rightStackXPos - leftStackXPos
readonly property real spreadHeight: root.height
- readonly property real spreadItemHeight: spreadHeight - contentTopMargin - contentBottomMargin
+ readonly property real spreadItemHeight: spreadHeight - contentMargin * 2
readonly property real spreadItemWidth: stackHeight
readonly property real dynamicLeftRotationAngle: leftRotationAngle * rotationAngleFactor
@@ -92,10 +92,9 @@
readonly property real visibleItemCount: (spreadWidth / spreadItemWidth) / (1 - itemOverlap)
- readonly property real spreadTotalWidth: Math.max(2,totalItemCount) * spreadWidth / visibleItemCount
-
- readonly property real centeringOffset: Math.max(spreadWidth - spreadTotalWidth ,0) / (2 * spreadWidth)
-
+ readonly property real spreadTotalWidth: totalItemCount * spreadWidth / visibleItemCount
+
+ readonly property real centeringOffset: Math.max(spreadWidth - spreadTotalWidth + (leftStackXPos - leftMargin) * 2, 0) / (2 * spreadWidth)
readonly property var curve: BezierCurve {
controlPoint2: {'x': 0.19, 'y': 0.00}
=== modified file 'qml/Stage/Spread/SpreadDelegateInputArea.qml'
--- qml/Stage/Spread/SpreadDelegateInputArea.qml 2016-11-07 14:07:45 +0000
+++ qml/Stage/Spread/SpreadDelegateInputArea.qml 2017-04-06 12:58:37 +0000
@@ -28,6 +28,9 @@
readonly property alias distance: d.distance
+ property var stage: null
+ property var dragDelegate: null
+
signal clicked()
signal close()
@@ -84,33 +87,27 @@
}
}
- // Event eater
- MouseArea {
- anchors.fill: parent
- onClicked: root.clicked()
- onWheel: wheel.accepted = true
- }
-
MultiPointTouchArea {
anchors.fill: parent
- mouseEnabled: false
maximumTouchPoints: 1
property int offset: 0
+ // tp.startY seems to be broken for mouse interaction... lets track it ourselves
+ property int startY: 0
+
touchPoints: [
TouchPoint {
id: tp
}
]
- onCanceled: {
- d.moving = false
- animation.animate("center");
+ onPressed: {
+ startY = tp.y
}
onTouchUpdated: {
- if (!d.moving) {
- if (Math.abs(tp.startY - tp.y) > d.threshold) {
+ if (!d.moving || !tp.pressed) {
+ if (Math.abs(startY - tp.y) > d.threshold) {
d.moving = true;
d.dragEvents = []
offset = tp.y - tp.startY;
@@ -119,17 +116,32 @@
}
}
- if (root.closeable) {
- d.distance = tp.y - tp.startY - offset
+
+ var value = tp.y - tp.startY - offset;
+ if (value < 0) {
+ var coords = mapToItem(stage, tp.x, tp.y);
+ dragDelegate.Drag.hotSpot.x = dragDelegate.width / 2
+ dragDelegate.Drag.hotSpot.y = units.gu(2)
+ dragDelegate.x = coords.x - dragDelegate.Drag.hotSpot.x
+ dragDelegate.y = coords.y - dragDelegate.Drag.hotSpot.y
+ dragDelegate.Drag.active = true;
+ dragDelegate.surface = model.window.surface;
+
} else {
- var value = tp.y - tp.startY - offset;
- d.distance = Math.sqrt(Math.abs(value)) * (value < 0 ? -1 : 1) * 3
+ if (root.closeable) {
+ d.distance = value
+ } else {
+ d.distance = Math.sqrt(Math.abs(value)) * (value < 0 ? -1 : 1) * 3
+ }
}
d.pushDragEvent(tp);
}
onReleased: {
+ var result = dragDelegate.Drag.drop();
+ dragDelegate.surface = null;
+
if (!d.moving) {
root.clicked()
}
@@ -149,6 +161,13 @@
animation.animate("center")
}
}
+
+ onCanceled: {
+ dragDelegate.Drag.active = false;
+ dragDelegate.surface = null;
+ d.moving = false
+ animation.animate("center");
+ }
}
UbuntuNumberAnimation {
=== added file 'qml/Stage/Spread/WorkspacePreview.qml'
--- qml/Stage/Spread/WorkspacePreview.qml 1970-01-01 00:00:00 +0000
+++ qml/Stage/Spread/WorkspacePreview.qml 2017-04-06 12:58:37 +0000
@@ -0,0 +1,127 @@
+import QtQuick 2.4
+import Ubuntu.Components 1.3
+import Unity.Application 0.1
+import WindowManager 1.0
+import ".."
+import "../../Components"
+
+Item {
+ id: previewSpace
+ clip: true
+
+ property var workspace
+
+ property string background
+ property int screenHeight
+
+ property real previewScale: previewSpace.height / previewSpace.screenHeight
+
+ property bool containsDragLeft: false
+ property bool containsDragRight: false
+ property bool isActive: false
+ property bool isSelected: false
+
+ Image {
+ source: previewSpace.background
+ anchors.fill: parent
+ sourceSize.width: width
+ sourceSize.height: height
+
+ Repeater {
+ id: topLevelSurfaceRepeater
+ model: visible ? workspace.windowModel : null
+ delegate: Item {
+ width: surfaceItem.width
+ height: surfaceItem.height + decorationHeight * previewScale
+ x: model.window.position.x * previewScale
+ y: (model.window.position.y - decorationHeight) * previewScale
+ z: topLevelSurfaceRepeater.count - index
+ visible: model.window.state !== Mir.MinimizedState && model.window.state !== Mir.HiddenState
+
+ property int decorationHeight: units.gu(3)
+
+ WindowDecoration {
+ width: surfaceItem.implicitWidth
+ height: parent.decorationHeight
+ transform: Scale {
+ origin.x: 0
+ origin.y: 0
+ xScale: previewScale
+ yScale: previewScale
+ }
+ title: model.window && model.window.surface ? model.window.surface.name : ""
+ z: 3
+ }
+
+ MirSurfaceItem {
+ id: surfaceItem
+ y: parent.decorationHeight * previewScale
+ width: implicitWidth * previewScale
+ height: implicitHeight * previewScale
+ surfaceWidth: -1
+ surfaceHeight: -1
+ surface: model.window.surface
+ }
+ }
+ }
+
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ border.color: UbuntuColors.ash
+ border.width: units.gu(.5)
+ color: "transparent"
+ visible: previewSpace.isActive
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ border.color: UbuntuColors.blue
+ border.width: units.gu(.5)
+ color: "transparent"
+ visible: previewSpace.isSelected
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.rightMargin: parent.width / 2
+ color: "#55000000"
+ visible: previewSpace.containsDragLeft
+
+ Column {
+ anchors.centerIn: parent
+ spacing: units.gu(1)
+ Icon {
+ source: "../graphics/multi-monitor_drop-here.png"
+ height: units.gu(4)
+ width: height
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Label {
+ text: qsTr("Drop here")
+ }
+ }
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.leftMargin: parent.width / 2
+ color: "#55000000"
+ visible: previewSpace.containsDragRight
+
+ Column {
+ anchors.centerIn: parent
+ spacing: units.gu(1)
+ Icon {
+ source: "../graphics/multi-monitor_leave.png"
+ height: units.gu(4)
+ width: height
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Label {
+ text: qsTr("Drop and go")
+ }
+ }
+ }
+}
=== added file 'qml/Stage/Spread/Workspaces.qml'
--- qml/Stage/Spread/Workspaces.qml 1970-01-01 00:00:00 +0000
+++ qml/Stage/Spread/Workspaces.qml 2017-04-06 12:58:37 +0000
@@ -0,0 +1,412 @@
+import QtQuick 2.4
+import Ubuntu.Components 1.3
+import WindowManager 1.0
+import "MathUtils.js" as MathUtils
+import "../../Components"
+
+Item {
+ id: root
+ implicitWidth: listView.contentWidth
+ readonly property int minimumWidth: {
+ var count = Math.min(3, listView.count);
+ return listView.itemWidth * count + listView.spacing * (count - 1)
+ }
+
+ property QtObject screen: null
+ property alias workspaceModel: listView.model
+ property var background // TODO: should be stored in the workspace data
+ property int selectedIndex: -1
+ property bool readOnly: true
+ property var activeWorkspace: null
+
+ signal commitScreenSetup();
+ signal closeSpread();
+ signal clicked(var workspace);
+
+ DropArea {
+ anchors.fill: root
+
+ keys: ['workspace']
+
+ onEntered: {
+ var index = listView.getDropIndex(drag);
+ drag.source.workspace.assign(workspaceModel, index)
+ drag.source.inDropArea = true;
+ }
+
+ onPositionChanged: {
+ var index = listView.getDropIndex(drag);
+ if (listView.dropItemIndex == index) return;
+ listView.model.move(listView.dropItemIndex, index, 1);
+ listView.dropItemIndex = index;
+ }
+
+ onExited: {
+ drag.source.workspace.unassign()
+ listView.dropItemIndex = -1;
+ listView.hoveredWorkspaceIndex = -1;
+ drag.source.inDropArea = false;
+ }
+
+ onDropped: {
+ drop.accept(Qt.MoveAction);
+ listView.dropItemIndex = -1;
+ drag.source.inDropArea = false;
+ }
+ }
+ DropArea {
+ anchors.fill: parent
+ keys: ["application"]
+
+ onPositionChanged: {
+ listView.progressiveScroll(drag.x)
+ listView.updateDropProperties(drag)
+ }
+ onExited: {
+ listView.hoveredWorkspaceIndex = -1
+ }
+ onDropped: {
+ var surface = drag.source.surface;
+ drag.source.surface = null;
+ var workspace = listView.model.get(listView.hoveredWorkspaceIndex);
+ WorkspaceManager.moveSurfaceToWorkspace(surface, workspace);
+ drop.accept(Qt.MoveAction)
+ if (listView.hoveredHalf == "right") {
+ root.closeSpread();
+ workspace.activate();
+ }
+ surface.activate();
+ listView.hoveredWorkspaceIndex = -1
+ }
+ }
+
+ onSelectedIndexChanged: {
+ listView.positionViewAtIndex(selectedIndex, ListView.Center);
+ }
+
+ Item {
+ // We need to clip the listview as it has left/right margins and it would
+ // overlap with items next to it and eat mouse input. However, we can't
+ // just clip at the actual bounds as the delegates have the close button
+ // on hover which reaches a bit outside, so lets some margins for the clipping
+ anchors.fill: parent
+ anchors.margins: -units.gu(2)
+ clip: true
+
+
+ ListView {
+ id: listView
+ anchors {
+ fill: parent
+ topMargin: -parent.anchors.margins
+ bottomMargin: -parent.anchors.margins
+ leftMargin: -itemWidth - parent.anchors.margins
+ rightMargin: -itemWidth - parent.anchors.margins
+ }
+ boundsBehavior: Flickable.StopAtBounds
+
+ Behavior on contentX {
+ SmoothedAnimation { duration: 200 }
+ }
+
+ property var clickedWorkspace: null
+
+ orientation: ListView.Horizontal
+ spacing: units.gu(1)
+ leftMargin: itemWidth
+ rightMargin: itemWidth
+
+ property int screenWidth: screen.availableModes[screen.currentModeIndex].size.width
+ property int screenHeight: screen.availableModes[screen.currentModeIndex].size.height
+ property int itemWidth: height * screenWidth / screenHeight
+ property int foldingAreaWidth: itemWidth / 2
+ property int maxAngle: 40
+
+ property real realContentX: contentX - originX + leftMargin
+ property int dropItemIndex: -1
+ property int hoveredWorkspaceIndex: -1
+ property string hoveredHalf: "" // left or right
+
+ function getDropIndex(drag) {
+ var coords = mapToItem(listView.contentItem, drag.x, drag.y)
+ var index = Math.floor((drag.x + listView.realContentX) / (listView.itemWidth + listView.spacing));
+ if (index < 0) index = 0;
+ var upperLimit = dropItemIndex == -1 ? listView.count : listView.count - 1
+ if (index > upperLimit) index = upperLimit;
+ return index;
+ }
+
+ function updateDropProperties(drag) {
+ var coords = mapToItem(listView.contentItem, drag.x, drag.y)
+ var index = Math.floor(drag.x + listView.realContentX) / (listView.itemWidth + listView.spacing);
+ if (index < 0) {
+ listView.hoveredWorkspaceIndex = -1;
+ listView.hoveredHalf = "";
+ return;
+ }
+
+ var upperLimit = dropItemIndex == -1 ? listView.count : listView.count - 1
+ if (index > upperLimit) index = upperLimit;
+ listView.hoveredWorkspaceIndex = index;
+ var pixelsInTile = (drag.x + listView.realContentX) % (listView.itemWidth + listView.spacing);
+ listView.hoveredHalf = (pixelsInTile / listView.itemWidth) < .5 ? "left" : "right";
+ }
+
+ function progressiveScroll(mouseX) {
+ var progress = Math.max(0, Math.min(1, (mouseX - listView.itemWidth) / (width - listView.leftMargin * 2 - listView.itemWidth * 2)))
+ listView.contentX = listView.originX + (listView.contentWidth - listView.width + listView.leftMargin + listView.rightMargin) * progress - listView.leftMargin
+ }
+
+ displaced: Transition { UbuntuNumberAnimation { properties: "x" } }
+
+ delegate: Item {
+ id: workspaceDelegate
+ objectName: "delegate" + index
+ height: parent.height
+ width: listView.itemWidth
+ Behavior on width { UbuntuNumberAnimation {} }
+ visible: listView.dropItemIndex !== index
+
+ property int itemX: -listView.realContentX + index * (listView.itemWidth + listView.spacing)
+ property int distanceFromLeft: itemX //- listView.leftMargin
+ property int distanceFromRight: listView.width - listView.leftMargin - listView.rightMargin - itemX - listView.itemWidth
+
+ property int itemAngle: {
+ if (index == 0) {
+ if (distanceFromLeft < 0) {
+ var progress = (distanceFromLeft + listView.foldingAreaWidth) / listView.foldingAreaWidth
+ return MathUtils.linearAnimation(1, -1, 0, listView.maxAngle, Math.max(-1, Math.min(1, progress)));
+ }
+ return 0
+ }
+ if (index == listView.count - 1) {
+ if (distanceFromRight < 0) {
+ var progress = (distanceFromRight + listView.foldingAreaWidth) / listView.foldingAreaWidth
+ return MathUtils.linearAnimation(1, -1, 0, -listView.maxAngle, Math.max(-1, Math.min(1, progress)));
+ }
+ return 0
+ }
+
+ if (distanceFromLeft < listView.foldingAreaWidth) {
+ // itemX : 10gu = p : 100
+ var progress = distanceFromLeft / listView.foldingAreaWidth
+ return MathUtils.linearAnimation(1, -1, 0, listView.maxAngle, Math.max(-1, Math.min(1, progress)));
+ }
+ if (distanceFromRight < listView.foldingAreaWidth) {
+ var progress = distanceFromRight / listView.foldingAreaWidth
+ return MathUtils.linearAnimation(1, -1, 0, -listView.maxAngle, Math.max(-1, Math.min(1, progress)));
+ }
+ return 0
+ }
+
+ property int itemOffset: {
+ if (index == 0) {
+ if (distanceFromLeft < 0) {
+ return -distanceFromLeft
+ }
+ return 0
+ }
+ if (index == listView.count - 1) {
+ if (distanceFromRight < 0) {
+ return distanceFromRight
+ }
+ return 0
+ }
+
+ if (itemX < -listView.foldingAreaWidth) {
+ return -itemX
+ }
+ if (distanceFromLeft < listView.foldingAreaWidth) {
+ return (listView.foldingAreaWidth - distanceFromLeft) / 2
+ }
+
+ if (distanceFromRight < -listView.foldingAreaWidth) {
+ return distanceFromRight
+ }
+
+ if (distanceFromRight < listView.foldingAreaWidth) {
+ return -(listView.foldingAreaWidth - distanceFromRight) / 2
+ }
+
+ return 0
+ }
+
+ z: itemOffset < 0 ? itemOffset : -itemOffset
+ transform: [
+ Rotation {
+ angle: itemAngle
+ axis { x: 0; y: 1; z: 0 }
+ origin { x: itemAngle < 0 ? listView.itemWidth : 0; y: height / 2 }
+ },
+ Translate {
+ x: itemOffset
+ }
+ ]
+
+ WorkspacePreview {
+ id: workspacePreview
+ height: listView.height
+ width: listView.itemWidth
+ background: root.background
+ screenHeight: listView.screenHeight
+ containsDragLeft: listView.hoveredWorkspaceIndex == index && listView.hoveredHalf == "left"
+ containsDragRight: listView.hoveredWorkspaceIndex == index && listView.hoveredHalf == "right"
+ isActive: workspace.isSameAs(root.activeWorkspace)
+ isSelected: index === root.selectedIndex
+ workspace: model.workspace
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ root.clicked(model.workspace)
+ }
+ onDoubleClicked: {
+ model.workspace.activate();
+ root.closeSpread();
+ }
+ }
+
+ MouseArea {
+ id: closeMouseArea
+ objectName: "closeMouseArea"
+ anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 }
+ hoverEnabled: true
+ height: units.gu(4)
+ width: height
+ visible: !root.readOnly && listView.count > 1
+
+ onClicked: {
+ model.workspace.unassign();
+ root.commitScreenSetup();
+ }
+ Image {
+ id: closeImage
+ source: "../graphics/window-close.svg"
+ anchors.fill: closeMouseArea
+ anchors.margins: units.gu(1)
+ sourceSize.width: width
+ sourceSize.height: height
+ readonly property var mousePos: hoverMouseArea.mapToItem(workspaceDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
+ readonly property bool shown: (hoverMouseArea.containsMouse || parent.containsMouse)
+ && mousePos.y < workspaceDelegate.width / 4
+ && mousePos.y > -units.gu(2)
+ && mousePos.x > -units.gu(2)
+ && mousePos.x < workspaceDelegate.height / 4
+ opacity: shown ? 1 : 0
+ visible: opacity > 0
+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
+
+ }
+ }
+ }
+
+ MouseArea {
+ id: hoverMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ propagateComposedEvents: true
+ anchors.leftMargin: listView.leftMargin
+ anchors.rightMargin: listView.rightMargin
+ enabled: !root.readOnly
+
+ property int draggedIndex: -1
+
+ property int startX: 0
+ property int startY: 0
+
+ onMouseXChanged: {
+ if (!pressed || dragging) {
+ listView.progressiveScroll(mouseX)
+ }
+ }
+ onMouseYChanged: {
+ if (Math.abs(mouseY - startY) > units.gu(3)) {
+ drag.axis = Drag.XAndYAxis;
+ }
+ }
+
+ onReleased: {
+ var result = fakeDragItem.Drag.drop();
+ // if (result == Qt.IgnoreAction) {
+ // WorkspaceManager.destroyWorkspace(fakeDragItem.workspace);
+ // }
+ root.commitScreenSetup();
+ drag.target = null;
+ }
+
+ property bool dragging: drag.active
+ onDraggingChanged: {
+ if (drag.active) {
+ var ws = listView.model.get(draggedIndex);
+ if (ws) ws.unassign();
+ }
+ }
+
+ onPressed: {
+ startX = mouseX;
+ startY = mouseY;
+ if (listView.model.count < 2) return;
+
+ var coords = mapToItem(listView.contentItem, mouseX, mouseY)
+ draggedIndex = listView.indexAt(coords.x, coords.y)
+ var clickedItem = listView.itemAt(coords.x, coords.y)
+
+ var itemCoords = clickedItem.mapToItem(listView, -listView.leftMargin, 0);
+ fakeDragItem.x = itemCoords.x
+ fakeDragItem.y = itemCoords.y
+ fakeDragItem.workspace = listView.model.get(draggedIndex)
+
+ var mouseCoordsInItem = mapToItem(clickedItem, mouseX, mouseY);
+ fakeDragItem.Drag.hotSpot.x = mouseCoordsInItem.x
+ fakeDragItem.Drag.hotSpot.y = mouseCoordsInItem.y
+
+ drag.axis = Drag.YAxis;
+ drag.target = fakeDragItem;
+ }
+
+ WorkspacePreview {
+ id: fakeDragItem
+ height: listView.height
+ width: listView.itemWidth
+ background: root.background
+ screenHeight: screen.availableModes[screen.currentModeIndex].size.height
+ visible: Drag.active
+
+ Drag.active: hoverMouseArea.drag.active
+ Drag.keys: ['workspace']
+
+ property bool inDropArea: false
+
+ Rectangle {
+ anchors.fill: parent
+ color: "#33000000"
+ opacity: parent.inDropArea ? 0 : 1
+ Behavior on opacity { UbuntuNumberAnimation { } }
+ Rectangle {
+ anchors.centerIn: parent
+ width: units.gu(6)
+ height: units.gu(6)
+ radius: width / 2
+ color: "#aa000000"
+ }
+
+ Icon {
+ height: units.gu(3)
+ width: height
+ anchors.centerIn: parent
+ name: "edit-delete"
+ color: "white"
+ }
+ }
+
+ states: [
+ State {
+ when: fakeDragItem.Drag.active
+ ParentChange { target: fakeDragItem; parent: shell }
+ }
+ ]
+ }
+ }
+ }
+ }
+}
=== modified file 'qml/Stage/Stage.qml'
--- qml/Stage/Stage.qml 2017-04-06 12:58:36 +0000
+++ qml/Stage/Stage.qml 2017-04-06 12:58:37 +0000
@@ -50,6 +50,8 @@
property Item availableDesktopArea
property PanelState panelState
+ readonly property var temporarySelectedWorkspace: state == "spread" ? screensAndWorkspaces.activeWorkspace : null
+
// Configuration
property string mode: "staged"
@@ -138,6 +140,7 @@
function updateFocusedAppOrientationAnimated() { /* TODO */}
function closeSpread() {
+ spreadItem.highlightedIndex = -1;
priv.goneToSpread = false;
}
@@ -244,6 +247,43 @@
}
}
+ GlobalShortcut {
+ id: showWorkspaceSwitcherShortcutLeft
+ shortcut: Qt.AltModifier|Qt.ControlModifier|Qt.Key_Left
+ active: !workspaceSwitcher.active
+ onTriggered: {
+ root.focus = true;
+ workspaceSwitcher.showLeft()
+ }
+ }
+ GlobalShortcut {
+ id: showWorkspaceSwitcherShortcutRight
+ shortcut: Qt.AltModifier|Qt.ControlModifier|Qt.Key_Right
+ active: !workspaceSwitcher.active
+ onTriggered: {
+ root.focus = true;
+ workspaceSwitcher.showRight()
+ }
+ }
+ GlobalShortcut {
+ id: showWorkspaceSwitcherShortcutUp
+ shortcut: Qt.AltModifier|Qt.ControlModifier|Qt.Key_Up
+ active: !workspaceSwitcher.active
+ onTriggered: {
+ root.focus = true;
+ workspaceSwitcher.showUp()
+ }
+ }
+ GlobalShortcut {
+ id: showWorkspaceSwitcherShortcutDown
+ shortcut: Qt.AltModifier|Qt.ControlModifier|Qt.Key_Down
+ active: !workspaceSwitcher.active
+ onTriggered: {
+ root.focus = true;
+ workspaceSwitcher.showDown()
+ }
+ }
+
QtObject {
id: priv
objectName: "DesktopStagePrivate"
@@ -379,7 +419,7 @@
readonly property real windowDecorationHeight: units.gu(3)
}
- Component.onCompleted: priv.updateMainAndSideStageIndexes();
+ Component.onCompleted: priv.updateMainAndSideStageIndexes()
Connections {
target: panelState
@@ -484,6 +524,7 @@
PropertyChanges { target: cancelSpreadMouseArea; enabled: true }
PropertyChanges { target: blurLayer; visible: true; blurRadius: 32; brightness: .65; opacity: 1 }
PropertyChanges { target: wallpaper; visible: false }
+ PropertyChanges { target: screensAndWorkspaces; opacity: 1 }
},
State {
name: "stagedRightEdge"; when: root.spreadEnabled && (rightEdgeDragArea.dragging || rightEdgePushProgress > 0) && root.mode == "staged"
@@ -531,11 +572,16 @@
Transition {
from: "stagedRightEdge,sideStagedRightEdge,windowedRightEdge"; to: "spread"
PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
+ PropertyAction { target: screensAndWorkspaces; property: "activeWorkspace"; value: WMScreen.currentWorkspace }
PropertyAnimation { target: blurLayer; properties: "brightness,blurRadius"; duration: priv.animationDuration }
+ UbuntuNumberAnimation { target: screensAndWorkspaces; property: "opacity"; duration: priv.animationDuration }
},
Transition {
to: "spread"
+ PropertyAction { target: screensAndWorkspaces; property: "activeWorkspace"; value: WMScreen.currentWorkspace }
PropertyAction { target: spreadItem; property: "highlightedIndex"; value: appRepeater.count > 1 ? 1 : 0 }
+ PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
+ UbuntuNumberAnimation { target: screensAndWorkspaces; property: "opacity"; duration: priv.animationDuration }
},
Transition {
from: "spread"
@@ -593,10 +639,20 @@
visible: false
}
+ ScreensAndWorkspaces {
+ id: screensAndWorkspaces
+ anchors { left: parent.left; top: parent.top; right: parent.right; leftMargin: root.leftMargin }
+ height: Math.max(units.gu(30), parent.height * .3)
+ background: root.background
+ opacity: 0
+ visible: opacity > 0
+ onCloseSpread: priv.goneToSpread = false;
+ }
+
Spread {
id: spreadItem
objectName: "spreadItem"
- anchors.fill: appContainer
+ anchors { left: parent.left; bottom: parent.bottom; right: parent.right; top: screensAndWorkspaces.bottom }
leftMargin: root.availableDesktopArea.x
model: root.topLevelSurfaceList
spreadFlickable: floatingFlickable
@@ -611,6 +667,83 @@
appRepeater.itemAt(highlightedIndex).close();
}
}
+
+ FloatingFlickable {
+ id: floatingFlickable
+ objectName: "spreadFlickable"
+ anchors.fill: parent
+ enabled: false
+ contentWidth: spreadItem.spreadTotalWidth
+
+ function snap(toIndex) {
+ var delegate = appRepeater.itemAt(toIndex)
+ var targetContentX = floatingFlickable.contentWidth / spreadItem.totalItemCount * toIndex;
+ if (targetContentX - floatingFlickable.contentX > spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) {
+ var offset = (spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) - (targetContentX - floatingFlickable.contentX)
+ snapAnimation.to = floatingFlickable.contentX - offset;
+ snapAnimation.start();
+ } else if (targetContentX - floatingFlickable.contentX < spreadItem.leftStackXPos + units.gu(1)) {
+ var offset = (spreadItem.leftStackXPos + units.gu(1)) - (targetContentX - floatingFlickable.contentX);
+ snapAnimation.to = floatingFlickable.contentX - offset;
+ snapAnimation.start();
+ }
+ }
+ UbuntuNumberAnimation {id: snapAnimation; target: floatingFlickable; property: "contentX"}
+ }
+
+ MouseArea {
+ id: hoverMouseArea
+ objectName: "hoverMouseArea"
+ anchors.fill: parent
+ propagateComposedEvents: true
+ hoverEnabled: true
+ enabled: false
+ visible: enabled
+
+ property int scrollAreaWidth: width / 3
+ property bool progressiveScrollingEnabled: false
+
+ onPressed: mouse.accepted = false
+
+ onMouseXChanged: {
+ mouse.accepted = false
+
+ if (hoverMouseArea.pressed) {
+ return;
+ }
+
+ // Find the hovered item and mark it active
+ for (var i = appRepeater.count - 1; i >= 0; i--) {
+ var appDelegate = appRepeater.itemAt(i);
+ var mapped = mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
+ var itemUnder = appDelegate.childAt(mapped.x, mapped.y);
+ if (itemUnder && (itemUnder.objectName === "dragArea" || itemUnder.objectName === "windowInfoItem" || itemUnder.objectName == "closeMouseArea")) {
+ spreadItem.highlightedIndex = i;
+ break;
+ }
+ }
+
+ if (floatingFlickable.contentWidth > floatingFlickable.width) {
+ var margins = floatingFlickable.width * 0.05;
+
+ if (!progressiveScrollingEnabled && mouseX < floatingFlickable.width - scrollAreaWidth) {
+ progressiveScrollingEnabled = true
+ }
+
+ // do we need to scroll?
+ if (mouseX < scrollAreaWidth + margins) {
+ var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
+ var contentX = (1 - progress) * (floatingFlickable.contentWidth - floatingFlickable.width)
+ floatingFlickable.contentX = Math.max(0, Math.min(floatingFlickable.contentX, contentX))
+ }
+ if (mouseX > floatingFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
+ var progress = Math.min(1, (mouseX - (floatingFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
+ var contentX = progress * (floatingFlickable.contentWidth - floatingFlickable.width)
+ floatingFlickable.contentX = Math.min(floatingFlickable.contentWidth - floatingFlickable.width, Math.max(floatingFlickable.contentX, contentX))
+ }
+ }
+ }
+ }
}
Connections {
@@ -705,6 +838,24 @@
}
}
+ MirSurfaceItem {
+ id: fakeDragItem
+ property real previewScale: .5
+ height: (screensAndWorkspaces.height - units.gu(8)) / 2
+ // w : h = iw : ih
+ width: implicitWidth * height / implicitHeight
+ surfaceWidth: -1
+ surfaceHeight: -1
+ opacity: surface != null ? 1 : 0
+ Behavior on opacity { UbuntuNumberAnimation {} }
+ visible: opacity > 0
+
+ Drag.active: surface != null
+ Drag.keys: ["application"]
+
+ z: 1000
+ }
+
Repeater {
id: appRepeater
model: topLevelSurfaceList
@@ -733,6 +884,9 @@
}
z: normalZ
+ opacity: fakeDragItem.surface == model.window.surface && fakeDragItem.Drag.active ? 0 : 1
+ Behavior on opacity { UbuntuNumberAnimation {} }
+
// Normally we want x/y where the surface thinks it is. Width/height of our delegate will
// match what the actual surface size is.
// Don't write to those, they will be set by states
@@ -913,7 +1067,6 @@
function claimFocus() {
if (root.state == "spread") {
spreadItem.highlightedIndex = index
- priv.goneToSpread = false;
}
if (root.mode == "stagedWithSideStage") {
if (appDelegate.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
@@ -1247,8 +1400,6 @@
y: spreadMaths.targetY
z: index
height: spreadItem.spreadItemHeight
- requestedWidth: decoratedWindow.oldRequestedWidth
- requestedHeight: decoratedWindow.oldRequestedHeight
visible: spreadMaths.itemVisible
}
PropertyChanges { target: dragArea; enabled: true }
@@ -1268,8 +1419,6 @@
y: stagedRightEdgeMaths.animatedY
z: stagedRightEdgeMaths.animatedZ
height: stagedRightEdgeMaths.animatedHeight
- requestedWidth: decoratedWindow.oldRequestedWidth
- requestedHeight: decoratedWindow.oldRequestedHeight
visible: appDelegate.x < root.width
}
PropertyChanges {
@@ -1299,8 +1448,6 @@
y: windowedRightEdgeMaths.animatedY
z: windowedRightEdgeMaths.animatedZ
height: stagedRightEdgeMaths.animatedHeight
- requestedWidth: decoratedWindow.oldRequestedWidth
- requestedHeight: decoratedWindow.oldRequestedHeight
}
PropertyChanges {
target: decoratedWindow
@@ -1323,10 +1470,14 @@
target: appDelegate
x: stageMaths.itemX
y: root.availableDesktopArea.y
+ visuallyMaximized: true
+ visible: appDelegate.x < root.width
+ }
+ PropertyChanges {
+ target: appDelegate
requestedWidth: appContainer.width
requestedHeight: root.availableDesktopArea.height
- visuallyMaximized: true
- visible: appDelegate.x < root.width
+ restoreEntryValues: false
}
PropertyChanges {
target: decoratedWindow
@@ -1356,10 +1507,14 @@
x: stageMaths.itemX
y: root.availableDesktopArea.y
z: stageMaths.itemZ
+ visuallyMaximized: true
+ visible: appDelegate.x < root.width
+ }
+ PropertyChanges {
+ target: appDelegate
requestedWidth: stageMaths.itemWidth
requestedHeight: root.availableDesktopArea.height
- visuallyMaximized: true
- visible: appDelegate.x < root.width
+ restoreEntryValues: false
}
PropertyChanges {
target: decoratedWindow
@@ -1382,8 +1537,12 @@
requestedY: 0;
visuallyMinimized: false;
visuallyMaximized: true
+ }
+ PropertyChanges {
+ target: appDelegate
requestedWidth: root.availableDesktopArea.width;
requestedHeight: appContainer.height;
+ restoreEntryValues: false
}
PropertyChanges { target: touchControls; enabled: true }
},
@@ -1393,8 +1552,12 @@
target: appDelegate;
requestedX: 0
requestedY: 0
- requestedWidth: appContainer.width;
- requestedHeight: appContainer.height;
+ }
+ PropertyChanges {
+ target: appDelegate
+ requestedWidth: appContainer.width
+ requestedHeight: appContainer.height
+ restoreEntryValues: false
}
PropertyChanges { target: decoratedWindow; hasDecoration: false }
},
@@ -1409,6 +1572,12 @@
PropertyChanges { target: touchControls; enabled: true }
PropertyChanges { target: resizeArea; enabled: true }
PropertyChanges { target: decoratedWindow; shadowOpacity: .3}
+ PropertyChanges {
+ target: appDelegate
+ requestedWidth: windowedWidth
+ requestedHeight: windowedHeight
+ restoreEntryValues: false
+ }
},
State {
name: "restored";
@@ -1509,6 +1678,7 @@
}
}
]
+
transitions: [
Transition {
from: "staged,stagedWithSideStage"
@@ -1522,6 +1692,7 @@
UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,requestedWidth,requestedHeight"; duration: priv.animationDuration}
},
Transition {
+ from: "normal,restored,maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight,staged,stagedWithSideStage,windowedRightEdge,stagedRightEdge";
to: "spread"
// DecoratedWindow wants the scaleToPreviewSize set before enabling scaleToPreview
PropertyAction { target: appDelegate; properties: "z,visible" }
@@ -1628,6 +1799,7 @@
borderThickness: units.gu(2)
enabled: false
visible: enabled
+ readyToAssesBounds: !appDelegate._constructing
onPressed: {
appDelegate.activate();
@@ -1651,19 +1823,13 @@
width: implicitWidth
height: implicitHeight
highlightSize: windowInfoItem.iconMargin / 2
+ boundsItem: root.availableDesktopArea
+ panelState: root.panelState
altDragEnabled: root.mode == "windowed"
- boundsItem: root.availableDesktopArea
- panelState: root.panelState
requestedWidth: appDelegate.requestedWidth
requestedHeight: appDelegate.requestedHeight
- property int oldRequestedWidth: -1
- property int oldRequestedHeight: -1
-
- onRequestedWidthChanged: oldRequestedWidth = requestedWidth
- onRequestedHeightChanged: oldRequestedHeight = requestedHeight
-
onCloseClicked: { appDelegate.close(); }
onMaximizeClicked: {
if (appDelegate.canBeMaximized) {
@@ -1744,6 +1910,8 @@
anchors.fill: decoratedWindow
enabled: false
closeable: !appDelegate.isDash
+ stage: root
+ dragDelegate: fakeDragItem
onClicked: {
spreadItem.highlightedIndex = index;
@@ -1786,12 +1954,15 @@
objectName: "closeMouseArea"
anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset }
readonly property var mousePos: hoverMouseArea.mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
- visible: !appDelegate.isDash && dragArea.distance == 0
+ readonly property bool shown: !appDelegate.isDash && dragArea.distance == 0
&& index == spreadItem.highlightedIndex
&& mousePos.y < (decoratedWindow.height / 3)
&& mousePos.y > -units.gu(4)
&& mousePos.x > -units.gu(4)
&& mousePos.x < (decoratedWindow.width * 2 / 3)
+ opacity: shown ? 1 : 0
+ visible: opacity > 0
+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
height: units.gu(6)
width: height
@@ -1865,81 +2036,17 @@
panelState: root.panelState
}
- MouseArea {
- id: hoverMouseArea
- objectName: "hoverMouseArea"
- anchors.fill: appContainer
- propagateComposedEvents: true
- hoverEnabled: true
- enabled: false
- visible: enabled
-
- property int scrollAreaWidth: width / 3
- property bool progressiveScrollingEnabled: false
-
- onMouseXChanged: {
- mouse.accepted = false
-
- if (hoverMouseArea.pressed) {
- return;
- }
-
- // Find the hovered item and mark it active
- for (var i = appRepeater.count - 1; i >= 0; i--) {
- var appDelegate = appRepeater.itemAt(i);
- var mapped = mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
- var itemUnder = appDelegate.childAt(mapped.x, mapped.y);
- if (itemUnder && (itemUnder.objectName === "dragArea" || itemUnder.objectName === "windowInfoItem" || itemUnder.objectName == "closeMouseArea")) {
- spreadItem.highlightedIndex = i;
- break;
- }
- }
-
- if (floatingFlickable.contentWidth > floatingFlickable.width) {
- var margins = floatingFlickable.width * 0.05;
-
- if (!progressiveScrollingEnabled && mouseX < floatingFlickable.width - scrollAreaWidth) {
- progressiveScrollingEnabled = true
- }
-
- // do we need to scroll?
- if (mouseX < scrollAreaWidth + margins) {
- var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
- var contentX = (1 - progress) * (floatingFlickable.contentWidth - floatingFlickable.width)
- floatingFlickable.contentX = Math.max(0, Math.min(floatingFlickable.contentX, contentX))
- }
- if (mouseX > floatingFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
- var progress = Math.min(1, (mouseX - (floatingFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
- var contentX = progress * (floatingFlickable.contentWidth - floatingFlickable.width)
- floatingFlickable.contentX = Math.min(floatingFlickable.contentWidth - floatingFlickable.width, Math.max(floatingFlickable.contentX, contentX))
- }
- }
- }
-
- onPressed: mouse.accepted = false
- }
-
- FloatingFlickable {
- id: floatingFlickable
- objectName: "spreadFlickable"
- anchors.fill: appContainer
- enabled: false
- contentWidth: spreadItem.spreadTotalWidth
-
- function snap(toIndex) {
- var delegate = appRepeater.itemAt(toIndex)
- var targetContentX = floatingFlickable.contentWidth / spreadItem.totalItemCount * toIndex;
- if (targetContentX - floatingFlickable.contentX > spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) {
- var offset = (spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) - (targetContentX - floatingFlickable.contentX)
- snapAnimation.to = Math.max(0, floatingFlickable.contentX - offset);
- snapAnimation.start();
- } else if (targetContentX - floatingFlickable.contentX < spreadItem.leftStackXPos + units.gu(1)) {
- var offset = (spreadItem.leftStackXPos + units.gu(1)) - (targetContentX - floatingFlickable.contentX);
- snapAnimation.to = Math.max(0, floatingFlickable.contentX - offset);
- snapAnimation.start();
- }
- }
- UbuntuNumberAnimation {id: snapAnimation; target: floatingFlickable; property: "contentX"}
+ WorkspaceSwitcher {
+ id: workspaceSwitcher
+ anchors.centerIn: parent
+ height: units.gu(20)
+ width: root.width - units.gu(8)
+ background: root.background
+ onActiveChanged: {
+ if (!active) {
+ appContainer.focus = true;
+ }
+ }
}
PropertyAnimation {
=== modified file 'qml/Stage/WindowResizeArea.qml'
--- qml/Stage/WindowResizeArea.qml 2017-02-21 15:19:01 +0000
+++ qml/Stage/WindowResizeArea.qml 2017-04-06 12:58:37 +0000
@@ -36,35 +36,58 @@
property int minWidth: 0
property int minHeight: 0
+ property bool readyToAssesBounds: false
+ onReadyToAssesBoundsChanged: d.reassesBounds()
+
QtObject {
id: d
readonly property int maxSafeInt: 2147483647
readonly property int maxSizeIncrement: units.gu(40)
+ function reassesBounds() {
+ if (!readyToAssesBounds) return;
+
+ if (target.windowedWidth < minimumWidth) {
+ target.windowedWidth = minimumWidth;
+ }
+ if (target.windowedHeight < minimumHeight) {
+ target.windowedHeight = minimumHeight;
+ }
+ if (target.windowedHeight < minimumHeight) {
+ target.windowedHeight = minimumHeight;
+ }
+ if (target.windowedWidth > maximumWidth) {
+ target.windowedWidth = maximumWidth;
+ }
+ if (target.windowedHeight > maximumHeight) {
+ target.windowedHeight = maximumHeight;
+ }
+ }
+
readonly property int minimumWidth: root.target ? Math.max(root.minWidth, root.target.minimumWidth) : root.minWidth
onMinimumWidthChanged: {
- if (target.windowedWidth < minimumWidth) {
+ if (readyToAssesBounds && target.windowedWidth < minimumWidth) {
target.windowedWidth = minimumWidth;
}
}
readonly property int minimumHeight: root.target ? Math.max(root.minHeight, root.target.minimumHeight) : root.minHeight
onMinimumHeightChanged: {
- if (target.windowedHeight < minimumHeight) {
+ if (readyToAssesBounds && target.windowedHeight < minimumHeight) {
target.windowedHeight = minimumHeight;
}
}
readonly property int maximumWidth: root.target && root.target.maximumWidth >= minimumWidth && root.target.maximumWidth > 0
? root.target.maximumWidth : maxSafeInt
onMaximumWidthChanged: {
- if (target.windowedWidth > maximumWidth) {
+ if (readyToAssesBounds && target.windowedWidth > maximumWidth) {
target.windowedWidth = maximumWidth;
}
}
readonly property int maximumHeight: root.target && root.target.maximumHeight >= minimumHeight && root.target.maximumHeight > 0
? root.target.maximumHeight : maxSafeInt
onMaximumHeightChanged: {
- if (target.windowedHeight > maximumHeight) {
+ if (readyToAssesBounds && target.windowedHeight > maximumHeight) {
target.windowedHeight = maximumHeight;
}
}
=== modified file 'qml/Stage/WindowStateSaver.qml'
--- qml/Stage/WindowStateSaver.qml 2017-02-24 12:54:39 +0000
+++ qml/Stage/WindowStateSaver.qml 2017-04-06 12:58:37 +0000
@@ -43,7 +43,10 @@
(target.fullscreen ? 0 : root.leftMargin)); });
target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, screenHeight - target.windowedHeight), minimumY); });
- target.updateNormalGeometry();
+ target.normalWidth = target.windowedWidth;
+ target.normalHeight = target.windowedHeight;
+ target.normalX = target.windowedX;
+ target.normalY = target.windowedY;
// initialize the x/y to restore to
target.restoredX = target.normalX;
=== added file 'qml/Stage/WorkspaceSwitcher.qml'
--- qml/Stage/WorkspaceSwitcher.qml 1970-01-01 00:00:00 +0000
+++ qml/Stage/WorkspaceSwitcher.qml 2017-04-06 12:58:37 +0000
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2014-2016 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 .
+ */
+
+import QtQuick 2.4
+import Ubuntu.Components 1.3
+import "Spread"
+import WindowManager 1.0
+import Unity.Application 0.1
+
+Item {
+ id: root
+
+ opacity: d.shown ? 1 : 0
+ visible: opacity > 0
+ Behavior on opacity { UbuntuNumberAnimation {} }
+
+ property var screensProxy: Screens.createProxy();
+ property string background
+
+ readonly property alias active: d.active
+
+ function showLeft() {
+ show();
+ d.previousWorkspace();
+ }
+ function showRight() {
+ show();
+ d.nextWorkspace();
+ }
+ function showUp() {
+ show();
+ d.previousScreen();
+ }
+ function showDown() {
+ show();
+ d.nextScreen();
+ }
+
+ function show() {
+ hideTimer.stop();
+ d.altPressed = true;
+ d.ctrlPressed = true;
+ d.active = true;
+ d.shown = true;
+ focus = true;
+
+ d.highlightedScreenIndex = screensProxy.activeScreen;
+ var activeScreen = screensProxy.get(screensProxy.activeScreen);
+ d.highlightedWorkspaceIndex = activeScreen.workspaces.indexOf(activeScreen.currentWorkspace)
+ }
+
+ QtObject {
+ id: d
+
+ property bool active: false
+ property bool shown: false
+ property bool altPressed: false
+ property bool ctrlPressed: false
+
+ property int rowHeight: root.height - units.gu(4)
+
+ property int highlightedScreenIndex: -1
+ property int highlightedWorkspaceIndex: -1
+
+ function previousWorkspace() {
+ highlightedWorkspaceIndex = Math.max(highlightedWorkspaceIndex - 1, 0);
+ }
+ function nextWorkspace() {
+ var screen = screensProxy.get(highlightedScreenIndex);
+ highlightedWorkspaceIndex = Math.min(highlightedWorkspaceIndex + 1, screen.workspaces.count - 1);
+ }
+ function previousScreen() {
+ highlightedScreenIndex = Math.max(highlightedScreenIndex - 1, 0);
+ var screen = screensProxy.get(highlightedScreenIndex);
+ highlightedWorkspaceIndex = Math.min(highlightedWorkspaceIndex, screen.workspaces.count - 1)
+ }
+ function nextScreen() {
+ highlightedScreenIndex = Math.min(highlightedScreenIndex + 1, screensProxy.count - 1);
+ var screen = screensProxy.get(highlightedScreenIndex);
+ highlightedWorkspaceIndex = Math.min(highlightedWorkspaceIndex, screen.workspaces.count - 1)
+ }
+ }
+
+ Timer {
+ id: hideTimer
+ interval: 300
+ onTriggered: d.shown = false;
+ }
+
+ Keys.onPressed: {
+ switch (event.key) {
+ case Qt.Key_Left:
+ d.previousWorkspace();
+ break;
+ case Qt.Key_Right:
+ d.nextWorkspace()
+ break;
+ case Qt.Key_Up:
+ d.previousScreen();
+ break;
+ case Qt.Key_Down:
+ d.nextScreen();
+ }
+ }
+ Keys.onReleased: {
+ switch (event.key) {
+ case Qt.Key_Alt:
+ d.altPressed = false;
+ break;
+ case Qt.Key_Control:
+ d.ctrlPressed = false;
+ break;
+ }
+
+ if (!d.altPressed && !d.ctrlPressed) {
+ d.active = false;
+ hideTimer.start();
+ focus = false;
+ screensProxy.get(d.highlightedScreenIndex).workspaces.get(d.highlightedWorkspaceIndex).activate();
+ }
+ }
+
+ UbuntuShape {
+ backgroundColor: "#F2111111"
+ clip: true
+ width: Math.min(parent.width, screensColumn.width + units.gu(4))
+ anchors.horizontalCenter: parent.horizontalCenter
+ height: parent.height
+
+ Column {
+ id: screensColumn
+ anchors {
+ top: parent.top; topMargin: units.gu(2) - d.highlightedScreenIndex * (d.rowHeight + screensColumn.spacing)
+ left: parent.left; leftMargin: units.gu(2)
+ }
+ width: screensRepeater.itemAt(d.highlightedScreenIndex).width
+ spacing: units.gu(2)
+ Behavior on anchors.topMargin { UbuntuNumberAnimation {} }
+ Behavior on width { UbuntuNumberAnimation {} }
+
+ Repeater {
+ id: screensRepeater
+ model: screensProxy
+
+ delegate: Item {
+ height: d.rowHeight
+ width: workspaces.width
+ anchors.horizontalCenter: parent.horizontalCenter
+ opacity: d.highlightedScreenIndex == index ? 1 : 0
+ Behavior on opacity { UbuntuNumberAnimation {} }
+
+ UbuntuShape {
+ id: header
+ anchors { left: parent.left; top: parent.top; right: parent.right }
+ height: units.gu(4)
+ backgroundColor: "white"
+
+ Label {
+ anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(1) }
+ text: model.screen.name
+ color: UbuntuColors.ash
+ }
+ }
+
+ Workspaces {
+ id: workspaces
+ height: parent.height - header.height - units.gu(2)
+ width: Math.min(implicitWidth, root.width - units.gu(4))
+
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: units.gu(1)
+ anchors.horizontalCenter: parent.horizontalCenter
+ screen: model.screen
+ background: root.background
+ selectedIndex: d.highlightedScreenIndex == index ? d.highlightedWorkspaceIndex : -1
+
+ workspaceModel: model.screen.workspaces
+ }
+ }
+ }
+ }
+ }
+}
=== added file 'qml/Stage/graphics/multi-monitor_drop-here.png'
Binary files qml/Stage/graphics/multi-monitor_drop-here.png 1970-01-01 00:00:00 +0000 and qml/Stage/graphics/multi-monitor_drop-here.png 2017-04-06 12:58:37 +0000 differ
=== added file 'qml/Stage/graphics/multi-monitor_leave.png'
Binary files qml/Stage/graphics/multi-monitor_leave.png 1970-01-01 00:00:00 +0000 and qml/Stage/graphics/multi-monitor_leave.png 2017-04-06 12:58:37 +0000 differ
=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.cpp'
--- tests/mocks/Unity/Application/MirSurfaceItem.cpp 2017-01-26 11:10:01 +0000
+++ tests/mocks/Unity/Application/MirSurfaceItem.cpp 2017-04-06 12:58:37 +0000
@@ -189,11 +189,13 @@
m_qmlItem = qobject_cast(m_qmlContentComponent->create());
m_qmlItem->setParentItem(this);
- m_qmlItem->setWidth(m_surfaceWidth);
- m_qmlItem->setHeight(m_surfaceHeight);
-
- setImplicitWidth(m_qmlItem->implicitWidth());
- setImplicitHeight(m_qmlItem->implicitHeight());
+ if (m_fillMode == FillMode::Stretch && width() != 0 && height() != 0) {
+ m_qmlItem->setSize(QSize(this->width(), this->height()));
+ } else {
+ m_qmlItem->setSize(m_qmlSurface->size());
+ }
+ setImplicitWidth(m_qmlItem->width());
+ setImplicitHeight(m_qmlItem->height());
{
QQmlProperty screenshotSource(m_qmlItem, "screenshotSource");
@@ -308,6 +310,16 @@
connect(m_qmlSurface, &MirSurface::screenshotUrlChanged, this, &MirSurfaceItem::updateScreenshot);
connect(m_qmlSurface, &MirSurface::liveChanged, this, &MirSurfaceItem::liveChanged);
connect(m_qmlSurface, &MirSurface::stateChanged, this, &MirSurfaceItem::surfaceStateChanged);
+ connect(m_qmlSurface, &MirSurface::sizeChanged, this, [this] () {
+ setImplicitSize(m_qmlSurface->width(), m_qmlSurface->height());
+ if (m_fillMode == FillMode::Stretch) {
+ m_qmlItem->setSize(QSize(this->width(), this->height()));
+ } else {
+ m_qmlItem->setSize(m_qmlSurface->size());
+ }
+ });
+ m_surfaceWidth = surface->size().width();
+ m_surfaceHeight = surface->size().height();
QUrl qmlComponentFilePath;
if (!m_qmlSurface->qmlFilePath().isEmpty()) {
@@ -321,6 +333,7 @@
switch (m_qmlContentComponent->status()) {
case QQmlComponent::Ready:
createQmlContentItem();
+ qDebug() << "content created" << m_surfaceWidth << implicitWidth() << width();
break;
case QQmlComponent::Loading:
connect(m_qmlContentComponent, &QQmlComponent::statusChanged,
@@ -399,9 +412,15 @@
if (m_qmlSurface && m_surfaceWidth > 0 && m_surfaceHeight > 0) {
m_qmlSurface->resize(m_surfaceWidth, m_surfaceHeight);
if (m_qmlItem) {
- m_qmlItem->setWidth(m_surfaceWidth);
- m_qmlItem->setHeight(m_surfaceHeight);
+ if (m_fillMode == FillMode::Stretch) {
+ m_qmlItem->setWidth(width());
+ m_qmlItem->setHeight(height());
+ } else {
+ m_qmlItem->setWidth(m_surfaceWidth);
+ m_qmlItem->setHeight(m_surfaceHeight);
+ }
}
+ qDebug() << this << "setting implicitsize" << m_surfaceWidth << m_surfaceHeight;
setImplicitSize(m_surfaceWidth, m_surfaceHeight);
}
}
=== modified file 'tests/mocks/Unity/Application/resources/MirSurfaceItem.qml'
--- tests/mocks/Unity/Application/resources/MirSurfaceItem.qml 2016-07-01 15:32:37 +0000
+++ tests/mocks/Unity/Application/resources/MirSurfaceItem.qml 2017-04-06 12:58:37 +0000
@@ -20,9 +20,6 @@
id: root
color: "pink"
- implicitWidth: width
- implicitHeight: height
-
property alias screenshotSource: screenshotImage.source
property int orientationAngle
=== modified file 'tests/mocks/WindowManager/MockScreens.cpp'
--- tests/mocks/WindowManager/MockScreens.cpp 2017-04-06 12:58:36 +0000
+++ tests/mocks/WindowManager/MockScreens.cpp 2017-04-06 12:58:37 +0000
@@ -31,10 +31,11 @@
class MockScreen : public qtmir::Screen
{
Q_OBJECT
+ Q_PROPERTY(QString outputTypeName READ outputTypeName NOTIFY outputTypeNameChanged)
public:
MockScreen()
{
- m_sizes.append(new qtmir::ScreenMode(50, QSize(640,480)));
+ m_sizes.append(new qtmir::ScreenMode(50, QSize(800,568)));
m_sizes.append(new qtmir::ScreenMode(60, QSize(1280,1024)));
m_sizes.append(new qtmir::ScreenMode(60, QSize(1440,900)));
m_sizes.append(new qtmir::ScreenMode(60, QSize(1920,1080)));
@@ -51,7 +52,6 @@
if (m_connectedWindow) {
disconnect(m_connectedWindow.data());
- m_sizes.takeFirst()->deleteLater();
}
m_connectedWindow = w;
@@ -77,7 +77,6 @@
});
if (w->isActive()) setActive(true);
- m_sizes.push_front(new qtmir::ScreenMode(50, w->size()));
Q_EMIT availableModesChanged();
}
@@ -90,6 +89,7 @@
QSizeF physicalSize() const override { return m_physicalSize; }
qtmir::FormFactor formFactor() const override { return m_formFactor; }
qtmir::OutputTypes outputType() const override { return m_outputType; }
+ QString outputTypeName() const { return QStringLiteral("Internal"); }
MirPowerMode powerMode() const override { return m_powerMode; }
Qt::ScreenOrientation orientation() const override { return m_orientation; }
QPoint position() const override { return m_position; }
@@ -137,6 +137,9 @@
return true;
}
+Q_SIGNALS:
+ void outputTypeNameChanged();
+
public:
miral::DisplayId m_id;
bool m_active{false};
@@ -168,7 +171,7 @@
screen->m_active = i == 0;
screen->m_name = QString("Monitor %1").arg(i);
screen->m_position = QPoint(lastPoint.x(), lastPoint.y());
- screen->m_currentModeIndex = 3;
+ screen->m_currentModeIndex = 0;
m_mocks.append(screen);
lastPoint.rx() += screen->m_sizes[screen->m_currentModeIndex]->size.width();
=== modified file 'tests/qmltests/Stage/tst_ApplicationWindow.qml'
--- tests/qmltests/Stage/tst_ApplicationWindow.qml 2017-04-06 12:58:36 +0000
+++ tests/qmltests/Stage/tst_ApplicationWindow.qml 2017-04-06 12:58:37 +0000
@@ -245,13 +245,12 @@
function test_showSplashUntilAppFullyInit_data() {
return [
{tag: "state=Running then create surface", swapInitOrder: false},
-
{tag: "create surface then state=Running", swapInitOrder: true},
]
}
function test_showSplashUntilAppFullyInit() {
- verify(stateGroup.state === "splashScreen");
+ verify(stateGroup.state === "splash");
if (data.swapInitOrder) {
surfaceCheckbox.checked = true;
@@ -259,7 +258,7 @@
setApplicationState(appRunning);
}
- verify(stateGroup.state === "splashScreen");
+ verify(stateGroup.state === "splash");
if (data.swapInitOrder) {
setApplicationState(appRunning);
@@ -284,27 +283,8 @@
waitUntilTransitionsEnd(stateGroup);
}
- function test_killedAppShowsScreenshot() {
- surfaceCheckbox.checked = true;
- setApplicationState(appRunning);
- tryCompare(stateGroup, "state", "surface");
-
- setApplicationState(appSuspended);
-
- verify(stateGroup.state === "surface");
- verify(fakeApplication.surface !== null);
-
- // kill it!
- surfaceCheckbox.checked = false;
- setApplicationState(appStopped);
-
- tryCompare(stateGroup, "state", "screenshot");
- tryCompare(fakeApplication.surfaceList, "count", 0);
- }
-
function test_restartApp() {
- var screenshotImage = findChild(applicationWindow, "screenshotImage");
-
+ tryCompare(stateGroup, "state", "splash");
surfaceCheckbox.checked = true;
setApplicationState(appRunning);
tryCompare(stateGroup, "state", "surface");
@@ -316,26 +296,23 @@
surfaceCheckbox.checked = false;
setApplicationState(appStopped);
- tryCompare(stateGroup, "state", "screenshot");
waitUntilTransitionsEnd(stateGroup);
- tryCompare(applicationWindow, "surface", null);
+ tryCompare(stateGroup, "state", "surface");
// and restart it
setApplicationState(appStarting);
waitUntilTransitionsEnd(stateGroup);
- verify(stateGroup.state === "screenshot");
- verify(applicationWindow.surface === null);
+ verify(stateGroup.state === "surface");
setApplicationState(appRunning);
waitUntilTransitionsEnd(stateGroup);
- verify(stateGroup.state === "screenshot");
+ verify(stateGroup.state === "surface");
surfaceCheckbox.checked = true;
tryCompare(stateGroup, "state", "surface");
- tryCompare(screenshotImage, "status", Image.Null);
}
function test_appCrashed() {
@@ -343,13 +320,15 @@
setApplicationState(appRunning);
tryCompare(stateGroup, "state", "surface");
waitUntilTransitionsEnd(stateGroup);
+ var surface = applicationWindow.surface;
// oh, it crashed...
surfaceCheckbox.checked = false;
setApplicationState(appStopped);
- tryCompare(stateGroup, "state", "screenshot");
- tryCompare(applicationWindow, "surface", null);
+ waitUntilTransitionsEnd(stateGroup);
+ tryCompare(stateGroup, "state", "surface");
+ tryCompare(applicationWindow, "surface", surface);
}
function test_keepSurfaceWhileInvisible() {
@@ -393,17 +372,6 @@
verify(surfaceItem.touchReleaseCount === 1);
}
- function test_showNothingOnSuddenSurfaceLoss() {
- surfaceCheckbox.checked = true;
- setApplicationState(appRunning);
- tryCompare(stateGroup, "state", "surface");
- waitUntilTransitionsEnd(stateGroup);
-
- applicationWindow.surface = null;
-
- tryCompare(stateGroup, "state", "void");
- }
-
function test_surfaceActiveFocusFollowsAppWindowInterative() {
applicationWindow.interactive = false;
applicationWindow.interactive = true;
=== modified file 'tests/qmltests/Stage/tst_DesktopStage.qml'
--- tests/qmltests/Stage/tst_DesktopStage.qml 2017-04-06 12:58:36 +0000
+++ tests/qmltests/Stage/tst_DesktopStage.qml 2017-04-06 12:58:37 +0000
@@ -558,8 +558,6 @@
var gmailDelegate = startApplication("gmail-webapp");
verify(gmailDelegate);
- wait(2000)
-
var gmailMaximizeButton = findChild(gmailDelegate, "maximizeWindowButton");
verify(gmailMaximizeButton);
mouseClick(gmailMaximizeButton);
=== modified file 'tests/qmltests/Stage/tst_PhoneStage.qml'
--- tests/qmltests/Stage/tst_PhoneStage.qml 2017-04-06 12:58:36 +0000
+++ tests/qmltests/Stage/tst_PhoneStage.qml 2017-04-06 12:58:37 +0000
@@ -304,7 +304,6 @@
performEdgeSwipeToShowAppSpread();
- print("tapping", selectedAppDeleage.appId, selectedAppDeleage.visible)
if (selectedAppDeleage.x > stage.width - units.gu(5)) {
touchFlick(stage, stage.width - units.gu(2), stage.height / 2, units.gu(2), stage.height / 2, true, true, units.gu(2), 10)
}
=== modified file 'tests/qmltests/Stage/tst_TabletStage.qml'
--- tests/qmltests/Stage/tst_TabletStage.qml 2017-04-06 12:58:36 +0000
+++ tests/qmltests/Stage/tst_TabletStage.qml 2017-04-06 12:58:37 +0000
@@ -66,7 +66,6 @@
}
Component.onCompleted: {
- print("starting dash")
ApplicationManager.startApplication("unity8-dash");
}
}
@@ -138,7 +137,6 @@
name: "TabletStage"
when: windowShown
- readonly property alias topLevelSurfaceList: root.topLevelSurfaceList
property Item sideStage: stage ? findChild(stage, "sideStage") : null
function init() {
@@ -167,6 +165,7 @@
waitUntilAppSurfaceShowsUp(topLevelSurfaceList.idAt(0));
sideStage.hideNow()
tryCompare(sideStage, "x", stage.width)
+
}
function cleanup() {
@@ -228,7 +227,7 @@
tryCompare(stage, "state", "spread");
}
- function swipeSurfaceUpwards(surfaceId) {
+ function swipeSurfaceDownwards(surfaceId) {
var appWindow = findAppWindowForSurfaceId(surfaceId);
verify(appWindow);
@@ -236,7 +235,7 @@
// to not be covered by other surfaces when they're all being shown in the spread
touchFlick(appWindow,
appWindow.width * 0.1, appWindow.height / 2,
- appWindow.width * 0.1, -appWindow.height / 2);
+ appWindow.width * 0.1, appWindow.height * 1.5);
}
function dragToSideStage(surfaceId) {
@@ -334,7 +333,7 @@
compare(appDelegate.stage, ApplicationInfoInterface.SideStage);
tryCompare(dragArea, "closeable", true);
- swipeSurfaceUpwards(dialerSurfaceId);
+ swipeSurfaceDownwards(dialerSurfaceId);
// Check that dialer-app has been closed
@@ -345,6 +344,8 @@
tryCompareFunction(function() {
return ApplicationManager.findApplication(dialerCheckBox.appId);
}, null);
+
+ stage.closeSpread();
}
function test_suspendsAndResumesAppsInMainStage() {
@@ -597,7 +598,6 @@
function test_loadSideStageByDraggingFromMainStage() {
sideStage.showNow();
- print("sidestage now shown. launching browser")
var webbrowserSurfaceId = topLevelSurfaceList.nextId;
webbrowserCheckBox.checked = true;
waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
@@ -662,10 +662,6 @@
// simulate the suspended app being killed by the out-of-memory daemon
webbrowserApp.surfaceList.get(0).setLive(false);
- // wait until the surface is gone
- tryCompare(webbrowserApp.surfaceList, "count", 0);
- compare(topLevelSurfaceList.surfaceAt(topLevelSurfaceList.indexForId(webbrowserSurfaceId)), null);
-
switchToSurface(webbrowserSurfaceId);
// webbrowser should have been brought to front
=== modified file 'tests/qmltests/tst_OrientedShell.qml'
--- tests/qmltests/tst_OrientedShell.qml 2017-04-06 12:58:36 +0000
+++ tests/qmltests/tst_OrientedShell.qml 2017-04-06 12:58:37 +0000
@@ -1521,7 +1521,6 @@
}
var point = surfaceItem.mapToItem(orientedShell, 0, 0);
- print("exptectedAngle", expectedAngle, point.x, point.y)
switch (expectedAngle) {
case 0:
return point.x === 0 && point.y === panelState.panelHeight;
=== modified file 'tests/qmltests/tst_Shell.qml'
--- tests/qmltests/tst_Shell.qml 2017-04-06 12:58:36 +0000
+++ tests/qmltests/tst_Shell.qml 2017-04-06 12:58:37 +0000
@@ -265,6 +265,7 @@
anchors { left: parent.left; right: parent.right }
activeFocusOnPress: false
model: ["phone", "tablet", "desktop"]
+ selectedIndex: 2
onSelectedIndexChanged: {
shellLoader.state = model[selectedIndex];
}
@@ -278,6 +279,7 @@
anchors { left: parent.left; right: parent.right }
activeFocusOnPress: false
model: ["phone", "tablet", "desktop"]
+ selectedIndex: 0
}
MouseTouchEmulationCheckbox {
id: mouseEmulation
@@ -1710,9 +1712,9 @@
var spreadDelegate2 = appRepeater.itemAt(2);
var closeMouseArea = findChild(spreadDelegate2, "closeMouseArea");
- // Move the mosue over tile 2 and verify the close button becomes visible
+ // Move the mouse over tile 2 and verify the close button becomes visible
var x = 0;
- var y = shell.height * .5;
+ var y = shell.height * .6;
mouseMove(shell, x, y)
while (spreadItem.highlightedIndex !== 2 && x <= 4000) {
x+=10;
@@ -1720,6 +1722,7 @@
wait(0); // spin the loop so bindings get evaluated
}
tryCompare(closeMouseArea, "enabled", true)
+ waitForRendering(shell)
var countBeforeClickingCloseButton = topLevelSurfaceList.count;
verify(topLevelSurfaceList.indexForId(surfaceId) === 2);
@@ -1761,7 +1764,7 @@
// Move the mouse over tile 2 and verify the highlight becomes visible
var x = 0;
- var y = shell.height * (data.tileInfo ? .9 : 0.5)
+ var y = shell.height * (data.tileInfo ? .9 : 0.7)
mouseMove(shell, x, y)
while (spreadItem.highlightedIndex !== 2 && x <= 4000) {
x+=10;
@@ -1783,6 +1786,15 @@
function test_progressiveAutoScrolling() {
loadDesktopShellWithApps()
+ // load some more apps
+ ApplicationManager.startApplication("twitter-webapp")
+ ApplicationManager.startApplication("ubuntu-weather-app")
+ ApplicationManager.startApplication("notes-app")
+ for (var i = 0; i < topLevelSurfaceList.count; ++i) {
+ waitUntilAppWindowIsFullyLoaded(topLevelSurfaceList.idAt(i));
+ }
+
+
var appRepeater = findInvisibleChild(shell, "appRepeater");
verify(appRepeater !== null);
@@ -1795,7 +1807,7 @@
// Move the mouse to the right and make sure it scrolls the Flickable
var x = 0;
- var y = shell.height * .5
+ var y = shell.height * .7
mouseMove(shell, x, y)
while (x <= shell.width) {
x+=10;
@@ -2696,7 +2708,6 @@
dashAppDelegate.windowedY = data.windowY;
topLevelSurfaceList.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
var initialY = dashAppDelegate.y;
- print("intial", initialY, "panel", panelState.panelHeight);
verify(initialY > panelState.panelHeight);
topLevelSurfaceList.inputMethodSurface.setInputBounds(Qt.rect(0, root.height / 2, root.width, root.height / 2));