diff --git a/geometry.cpp b/geometry.cpp --- a/geometry.cpp +++ b/geometry.cpp @@ -3254,7 +3254,7 @@ { m_electricMaximizing = maximizing; if (maximizing) - outline()->show(electricBorderMaximizeGeometry(Cursor::pos(), desktop())); + outline()->show(electricBorderMaximizeGeometry(Cursor::pos(), desktop()), moveResizeGeometry()); else outline()->hide(); elevate(maximizing); diff --git a/outline.h b/outline.h --- a/outline.h +++ b/outline.h @@ -45,6 +45,8 @@ class Outline : public QObject { Q_OBJECT Q_PROPERTY(QRect geometry READ geometry NOTIFY geometryChanged) + Q_PROPERTY(QRect visualParentGeometry READ visualParentGeometry NOTIFY visualParentGeometryChanged) + Q_PROPERTY(QRect unifiedGeometry READ unifiedGeometry NOTIFY unifiedGeometryChanged) Q_PROPERTY(bool active READ isActive NOTIFY activeChanged) public: ~Outline(); @@ -58,6 +60,14 @@ void setGeometry(const QRect &outlineGeometry); /** + * Set the visual parent geometry. + * This is the geometry from which the will emerge. + * @param visualParentGeometry The visual geometry of the visual parent + * @see showOutline + */ + void setVisualParentGeometry(const QRect &visualParentGeometry); + + /** * Shows the outline of a window using either an effect or the X implementation. * To stop the outline process use @link hideOutline. * @see hideOutline @@ -74,12 +84,26 @@ void show(const QRect &outlineGeometry); /** + * Shows the outline for the given @p outlineGeometry animated from @p visualParentGeometry. + * This is the same as setOutlineGeometry followed by setVisualParentGeometry + * and then showOutline. + * To stop the outline process use @link hideOutline. + * @param outlineGeometry The geometry of the outline to be shown + * @param visualParentGeometry The geometry from where the outline should emerge + * @see hideOutline + * @since 5.10 + */ + void show(const QRect &outlineGeometry, const QRect &visualParentGeometry); + + /** * Hides shown outline. * @see showOutline */ void hide(); const QRect &geometry() const; + const QRect &visualParentGeometry() const; + QRect unifiedGeometry() const; bool isActive() const; @@ -89,11 +113,14 @@ Q_SIGNALS: void activeChanged(); void geometryChanged(); + void unifiedGeometryChanged(); + void visualParentGeometryChanged(); private: void createHelper(); QScopedPointer m_visual; QRect m_outlineGeometry; + QRect m_visualParentGeometry; bool m_active; KWIN_SINGLETON(Outline) }; @@ -157,6 +184,12 @@ } inline +const QRect &Outline::visualParentGeometry() const +{ + return m_visualParentGeometry; +} + +inline Outline *OutlineVisual::outline() { return m_outline; diff --git a/outline.cpp b/outline.cpp --- a/outline.cpp +++ b/outline.cpp @@ -55,16 +55,16 @@ void Outline::show() { - m_active = true; - emit activeChanged(); if (m_visual.isNull()) { createHelper(); } if (m_visual.isNull()) { // something went wrong return; } m_visual->show(); + m_active = true; + emit activeChanged(); } void Outline::hide() @@ -82,7 +82,13 @@ void Outline::show(const QRect& outlineGeometry) { + show(outlineGeometry, QRect()); +} + +void Outline::show(const QRect &outlineGeometry, const QRect &visualParentGeometry) +{ setGeometry(outlineGeometry); + setVisualParentGeometry(visualParentGeometry); show(); } @@ -93,6 +99,22 @@ } m_outlineGeometry = outlineGeometry; emit geometryChanged(); + emit unifiedGeometryChanged(); +} + +void Outline::setVisualParentGeometry(const QRect &visualParentGeometry) +{ + if (m_visualParentGeometry == visualParentGeometry) { + return; + } + m_visualParentGeometry = visualParentGeometry; + emit visualParentGeometryChanged(); + emit unifiedGeometryChanged(); +} + +QRect Outline::unifiedGeometry() const +{ + return m_outlineGeometry | m_visualParentGeometry; } void Outline::createHelper() diff --git a/qml/outline/plasma/outline.qml b/qml/outline/plasma/outline.qml --- a/qml/outline/plasma/outline.qml +++ b/qml/outline/plasma/outline.qml @@ -1,5 +1,6 @@ /* * Copyright 2014 Martin Gräßlin + * Copyright 2017 Kai Uwe Broulik * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,41 +18,84 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -import QtQuick 2.1; -import QtQuick.Window 2.1; -import org.kde.plasma.core 2.0 as PlasmaCore; +import QtQuick 2.1 +import QtQuick.Window 2.1 +import org.kde.plasma.core 2.0 as PlasmaCore Window { id: window + + readonly property int animationDuration: units.longDuration + property bool animationEnabled: false + flags: Qt.BypassWindowManagerHint | Qt.FramelessWindowHint color: "transparent" // outline is a context property - x: outline.geometry.x - y: outline.geometry.y - width: outline.geometry.width - height: outline.geometry.height + x: outline.unifiedGeometry.x + y: outline.unifiedGeometry.y + width: outline.unifiedGeometry.width + height: outline.unifiedGeometry.height + visible: outline.active - PlasmaCore.FrameSvgItem { - function updateBorders() { - var maximizedArea = workspace.clientArea(workspace.MaximizeArea, Qt.point(outline.geometry.x, outline.geometry.y), workspace.currentDesktop); - var left = false; - var right = false; - var top = false; - var bottom = false; - if (outline.geometry.x == maximizedArea.x) { - left = true; - } - if (outline.geometry.y == maximizedArea.y) { - top = true; + onVisibleChanged: { + if (visible) { + if (outline.visualParentGeometry.width > 0 && outline.visualParentGeometry.height > 0) { + window.animationEnabled = false + // move our frame to the visual parent geometry + svg.setGeometry(outline.visualParentGeometry) + window.animationEnabled = true + // and then animate it nicely to its destination + svg.setGeometry(outline.geometry) + } else { + // no visual parent? just move it to its destination right away + window.animationEnabled = false + svg.setGeometry(outline.geometry) + window.animationEnabled = true } - if (outline.geometry.x + outline.geometry.width == maximizedArea.x + maximizedArea.width) { - right = true; - } - if (outline.geometry.y + outline.geometry.height == maximizedArea.y + maximizedArea.height) { - bottom = true; + } + } + + Connections { + target: outline + // when unified geometry changes, this means our window position changed and any + // animation will potentially be offset and/or cut off, skip the animation in this case + onUnifiedGeometryChanged: { + if (window.visible) { + window.animationEnabled = false + svg.setGeometry(outline.geometry) + window.animationEnabled = true } + } + } + + PlasmaCore.FrameSvgItem { + id: svg + + // takes into account the offset inside unified geometry + function setGeometry(geometry) { + x = geometry.x - outline.unifiedGeometry.x + y = geometry.y - outline.unifiedGeometry.y + width = geometry.width + height = geometry.height + } + + imagePath: "widgets/translucentbackground" + + x: 0 + y: 0 + width: 0 + height: 0 + + enabledBorders: { + var maximizedArea = workspace.clientArea(workspace.MaximizeArea, Qt.point(outline.geometry.x, outline.geometry.y), workspace.currentDesktop); + + var left = outline.geometry.x === maximizedArea.x; + var right = outline.geometry.x + outline.geometry.width === maximizedArea.x + maximizedArea.width; + var top = outline.geometry.y === maximizedArea.y; + var bottom = outline.geometry.y + outline.geometry.height === maximizedArea.y + maximizedArea.height; + var borders = PlasmaCore.FrameSvgItem.AllBorders; if (left) { borders = borders & ~PlasmaCore.FrameSvgItem.LeftBorder; @@ -68,15 +112,24 @@ if (left && right && bottom && top) { borders = PlasmaCore.FrameSvgItem.AllBorders; } - svg.enabledBorders = borders; + return borders; } - id: svg - imagePath: "widgets/translucentbackground" - anchors.fill: parent - Connections { - target: outline - onGeometryChanged: svg.updateBorders() + + Behavior on x { + NumberAnimation { duration: window.animationDuration; easing.type: Easing.InOutQuad; } + enabled: window.animationEnabled + } + Behavior on y { + NumberAnimation { duration: window.animationDuration; easing.type: Easing.InOutQuad; } + enabled: window.animationEnabled + } + Behavior on width { + NumberAnimation { duration: window.animationDuration; easing.type: Easing.InOutQuad; } + enabled: window.animationEnabled + } + Behavior on height { + NumberAnimation { duration: window.animationDuration; easing.type: Easing.InOutQuad; } + enabled: window.animationEnabled } - Component.onCompleted: svg.updateBorders() } }