diff --git a/applets/pager/CMakeLists.txt b/applets/pager/CMakeLists.txt --- a/applets/pager/CMakeLists.txt +++ b/applets/pager/CMakeLists.txt @@ -2,9 +2,9 @@ plasma_install_package(package org.kde.plasma.pager) set(pager_SRCS - plugin/model.cpp - plugin/pager.cpp - plugin/pagerplugin.cpp) + plugin/pagermodel.cpp + plugin/pagerplugin.cpp + plugin/windowmodel.cpp) add_library(pagerplugin SHARED ${pager_SRCS}) @@ -14,13 +14,14 @@ KF5::Plasma KF5::Activities KF5::KDELibs4Support + PW::LibTaskManager Qt5::Core Qt5::Qml Qt5::Quick Qt5::DBus) if (X11_FOUND) - target_link_libraries(pagerplugin Qt5::X11Extras PW::LibTaskManager) + target_link_libraries(pagerplugin Qt5::X11Extras) endif() install(TARGETS pagerplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/plasma/private/pager) diff --git a/applets/pager/package/contents/ui/configGeneral.qml b/applets/pager/package/contents/ui/configGeneral.qml --- a/applets/pager/package/contents/ui/configGeneral.qml +++ b/applets/pager/package/contents/ui/configGeneral.qml @@ -1,5 +1,6 @@ /* * Copyright 2013 David Edmundson + * Copyright 2016 Eike Hein * * 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 @@ -32,6 +33,8 @@ // flat: true // title: i18n("Appearance") + property bool isActivityPager: (plasmoid.pluginName == "org.kde.plasma.activitypager") + property int cfg_displayedText property alias cfg_showWindowIcons: showWindowIcons.checked property int cfg_currentDesktopSelected @@ -85,7 +88,7 @@ QtControls.RadioButton { id: desktopNumberRadio exclusiveGroup: displayedTextGroup - text: i18n("Desktop number") + text: isActivityPager ? i18n("Activity number") : i18n("Desktop number") onCheckedChanged: if (checked) cfg_displayedText = 0; } Item { @@ -96,7 +99,7 @@ QtControls.RadioButton { id: desktopNameRadio exclusiveGroup: displayedTextGroup - text: i18n("Desktop name") + text: isActivityPager ? i18n("Activity name") : i18n("Desktop name") onCheckedChanged: if (checked) cfg_displayedText = 1; } QtControls.RadioButton { diff --git a/applets/pager/package/contents/ui/main.qml b/applets/pager/package/contents/ui/main.qml --- a/applets/pager/package/contents/ui/main.qml +++ b/applets/pager/package/contents/ui/main.qml @@ -1,6 +1,7 @@ /* * Copyright 2012 Luís Gabriel Lima * Copyright 2016 Kai Uwe Broulik + * Copyright 2016 Eike Hein * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -29,16 +30,18 @@ MouseArea { id: root + property bool isActivityPager: (plasmoid.pluginName == "org.kde.plasma.activitypager") property bool vertical: (plasmoid.formFactor == PlasmaCore.Types.Vertical) + property var activityDataSource: null - Layout.minimumWidth: !root.vertical ? pager.preferredSize.width : 1 - Layout.minimumHeight: root.vertical ? pager.preferredSize.height : 1 + Layout.minimumWidth: !root.vertical ? pagerItemFlow.preferredWidth : 1 + Layout.minimumHeight: root.vertical ? pagerItemFlow.preferredHeight : 1 - Layout.maximumWidth: !root.vertical ? pager.preferredSize.width : Infinity - Layout.maximumHeight: root.vertical ? pager.preferredSize.height : Infinity + Layout.maximumWidth: !root.vertical ? pagerItemFlow.preferredWidth : Infinity + Layout.maximumHeight: root.vertical ? pagerItemFlow.preferredHeight : Infinity Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation - Plasmoid.status: pager.desktopCount > 1 ? PlasmaCore.Types.ActiveStatus : PlasmaCore.Types.HiddenStatus + Plasmoid.status: pagerModel.count > 1 ? PlasmaCore.Types.ActiveStatus : PlasmaCore.Types.HiddenStatus Layout.fillWidth: root.vertical Layout.fillHeight: !root.vertical @@ -63,310 +66,381 @@ readonly property color windowInactiveBorderColor: colorWithAlpha(theme.textColor, 0.5) function action_addDesktop() { - pager.slotAddDesktop(); + pagerModel.addDesktop(); } function action_removeDesktop() { - pager.slotRemoveDesktop(); + pagerModel.removeDesktop(); } function action_openKCM() { - KQuickControlsAddonsComponents.KCMShell.open("desktop") + KQuickControlsAddonsComponents.KCMShell.open("desktop"); + } + + function action_showActivityManager() { + if (!activityDataSource) { + activityDataSource = Qt.createQmlObject('import org.kde.plasma.core 2.0 as PlasmaCore; \ + PlasmaCore.DataSource { id: dataSource; engine: "org.kde.activities"; \ + connectedSources: ["Status"] }', root); + } + + var service = activityDataSource.serviceForSource("Status") + var operation = service.operationDescription("toggleActivityManager") + service.startOperationCall(operation) } onWheel: { if (wheel.angleDelta.y > 0 || wheel.angleDelta.x > 0) { - pager.changeDesktop((repeater.count + pager.currentDesktop - 2) % repeater.count) + pagerModel.changePage((repeater.count + pagerModel.currentPage - 2) % repeater.count); } else { - pager.changeDesktop(pager.currentDesktop % repeater.count) + pagerModel.changePage(pagerModel.currentPage % repeater.count); } } - Component.onCompleted: { - if (KQuickControlsAddonsComponents.KCMShell.authorize("desktop.desktop").length > 0) { - plasmoid.setAction("addDesktop", i18n("Add Virtual Desktop"), "list-add"); - plasmoid.setAction("removeDesktop", i18n("Remove Virtual Desktop"), "list-remove"); - plasmoid.action("removeDesktop").enabled = Qt.binding(function() { - return repeater.count > 1; - }); - - plasmoid.setAction("openKCM", i18n("Configure Desktops..."), "configure"); + PagerModel { + id: pagerModel + + enabled: root.visible + + showDesktop: (plasmoid.configuration.currentDesktopSelected == 1) + + pagerType: isActivityPager ? PagerModel.Activities : PagerModel.VirtualDesktops + } + + Connections { + target: plasmoid.configuration + + onShowWindowIconsChanged: { + // Causes the model to reset; Component.onCompleted in the + // window delegate now gets a chance to create the icon item, + // which it otherwise will not do. + pagerModel.refresh(); + } + + onDisplayedTextChanged: { + // Causes the model to reset; Component.onCompleted in the + // desktop delegate now gets a chance to create the label item, + // which it otherwise will not do. + pagerModel.refresh(); } } - Pager { - id: pager - // don't bother updating the models when we're not visible - enabled: root.visible - orientation: plasmoid.formFactor == PlasmaCore.Types.Vertical ? Qt.Vertical : Qt.Horizontal - size: Qt.size(root.width, root.height) - showWindowIcons: plasmoid.configuration.showWindowIcons - currentDesktopSelected: plasmoid.configuration.currentDesktopSelected - displayedText: plasmoid.configuration.displayedText + Component { + id: desktopLabelComponent + + PlasmaComponents.Label { + anchors.centerIn: parent + + property int index: 0 + property var model: null + + text: plasmoid.configuration.displayedText ? model.display : index + 1 + } + } + + Component { + id: windowIconComponent + + PlasmaCore.IconItem { + anchors.centerIn: parent + + height: parent.width / 2 + width: parent.height / 2 + + property var model: null + + source: model ? model.decoration : undefined + usesPlasmaTheme: false + animated: false + } } Timer { id: dragTimer interval: 1000 onTriggered: { - if (dragSwitchDesktopId != -1 && dragSwitchDesktopId !== pager.currentDesktop-1) { - pager.changeDesktop(dragSwitchDesktopId); + if (dragSwitchDesktopId != -1 && dragSwitchDesktopId !== pagerModel.currentPage - 1) { + pagerModel.changePage(dragSwitchDesktopId); } } } - Repeater { - id: repeater - model: pager.model + Flow { + id: pagerItemFlow - PlasmaCore.ToolTipArea { - id: desktop + anchors.fill: parent - property int desktopId: index - property string desktopName: model.desktopName ? model.desktopName : "" - property bool active: (desktopId === pager.currentDesktop-1) + spacing: units.devicePixelRatio - mainText: desktopName - // our ToolTip has maximumLineCount of 8 which doesn't fit but QML doesn't - // respect that in RichText so we effectively can put in as much as we like :) - // it also gives us more flexibility when it comes to styling the
  • - textFormat: Text.RichText + property int effectiveRows: { + var columns = Math.floor(repeater.count / pagerModel.layoutRows); - function updateSubText() { - var generateWindowList = function windowList(windows) { - // if we have 5 windows, we would show "4 and another one" with the - // hint that there's 1 more taking the same amount of space than just showing it - var maximum = windows.length === 5 ? 5 : 4 + if (repeater.count % pagerModel.layoutRows > 0) { + columns += 1; + } - var text = "
    • " - + windows.slice(0, maximum).join("
    • ") - + "
    " + var rows = Math.floor(repeater.count / columns); - if (windows.length > maximum) { - text += i18np("...and %1 other window", "...and %1 other windows", windows.length - maximum) - } + if (repeater.count % columns > 0) { + rows += 1; + } - return text - } + return rows; + } - var text = "" - var visibleWindows = [] - var minimizedWindows = [] - - for (var i = 0, length = windowRectRepeater.count; i < length; ++i) { - var window = windowRectRepeater.itemAt(i) - if (window) { - if (window.minimized) { - minimizedWindows.push(window.visibleName) - } else { - visibleWindows.push(window.visibleName) - } - } - } + readonly property int effectiveColumns: Math.ceil(repeater.count / effectiveRows) - if (visibleWindows.length) { - text += i18np("%1 Window:", "%1 Windows:", visibleWindows.length) - + generateWindowList(visibleWindows) - } + readonly property real pagerItemSizeRatio: pagerModel.pagerItemSize.width / pagerModel.pagerItemSize.height + readonly property real widthScaleFactor: columnWidth / pagerModel.pagerItemSize.width + readonly property real heightScaleFactor: rowHeight / pagerModel.pagerItemSize.height - if (visibleWindows.length && minimizedWindows.length) { - text += "
    " - } + readonly property int innerSpacing: ((vertical ? effectiveColumns : effectiveRows) - 1) * spacing + readonly property int rowHeight: vertical ? Math.floor(columnWidth / pagerItemSizeRatio) : Math.floor((root.height - innerSpacing) / effectiveRows) + readonly property int columnWidth: vertical ? Math.floor((root.width - innerSpacing) / effectiveColumns) : Math.floor(rowHeight * pagerItemSizeRatio) - if (minimizedWindows.length > 0) { - text += i18np("%1 Minimized Window:", "%1 Minimized Windows:", minimizedWindows.length) - + generateWindowList(minimizedWindows) - } + readonly property int preferredWidth: vertical ? width : (effectiveColumns * columnWidth) + ((effectiveColumns - 1) * spacing) + readonly property int preferredHeight: vertical ? (effectiveRows * rowHeight) + ((effectiveRows - 1) * spacing) : height - if (text.length) { - // Get rid of the spacing
      would cause - text = "" + text - } + Repeater { + id: repeater + model: pagerModel - subText = text - } + PlasmaCore.ToolTipArea { + id: desktop - x: model.x - y: model.y - width: model.width - height: model.height - - PlasmaCore.FrameSvgItem { - anchors.fill: parent - z: 1 // to make sure that the FrameSvg will be placed on top of the windows - imagePath: "widgets/pager" - prefix: (desktopMouseArea.enabled && desktopMouseArea.containsMouse) || (root.dragging && root.dragId == desktopId) ? - "hover" : (desktop.active ? "active" : "normal") - } + property int desktopId: index + property bool active: isActivityPager ? (index == pagerModel.currentPage) : (index + 1 == pagerModel.currentPage) - DropArea { - id: droparea - anchors.fill: parent - preventStealing: true + mainText: model.display + // our ToolTip has maximumLineCount of 8 which doesn't fit but QML doesn't + // respect that in RichText so we effectively can put in as much as we like :) + // it also gives us more flexibility when it comes to styling the
    • + textFormat: Text.RichText - onDragEnter: { - root.dragSwitchDesktopId = desktop.desktopId; - dragTimer.start(); - } - onDragLeave: { - root.dragSwitchDesktopId = -1; - dragTimer.stop(); - } - onDrop: { - pager.dropMimeData(event.mimeData, desktop.desktopId); - root.dragSwitchDesktopId = -1; - dragTimer.stop(); - } - } + function updateSubText() { + var generateWindowList = function windowList(windows) { + // if we have 5 windows, we would show "4 and another one" with the + // hint that there's 1 more taking the same amount of space than just showing it + var maximum = windows.length === 5 ? 5 : 4 - MouseArea { - id: desktopMouseArea - anchors.fill: parent - hoverEnabled : true - onClicked: pager.changeDesktop(desktopId); - } + var text = "
      • " + + windows.slice(0, maximum).join("
      • ") + + "
      " - Item { - id: clipRect - x: Math.round(units.devicePixelRatio) - y: Math.round(units.devicePixelRatio) - width: desktop.width - 2 * x - height: desktop.height - 2 * y - clip: true - - PlasmaComponents.Label { - id: desktopText - anchors.centerIn: parent - text: pager.displayedText == Pager.Name ? desktop.desktopName - : (pager.displayedText == Pager.Number ? desktop.desktopId+1 : "") - - } + if (windows.length > maximum) { + text += i18np("...and %1 other window", "...and %1 other windows", windows.length - maximum) + } + + return text + } + + var text = "" + var visibleWindows = [] + var minimizedWindows = [] - Repeater { - id: windowRectRepeater - model: windows - onCountChanged: desktop.updateSubText() - - Rectangle { - id: windowRect - - property int windowId: model.windowId - property string visibleName: model.visibleName - property bool minimized: model.minimized - onMinimizedChanged: desktop.updateSubText() - - /* since we move clipRect with 1, move it back */ - x: model.x - Math.round(units.devicePixelRatio) - y: model.y - Math.round(units.devicePixelRatio) - width: model.width - height: model.height - visible: !model.visible && !minimized - color: { - if (desktop.active) { - if (model.active) - return windowActiveOnActiveDesktopColor; - else - return windowInactiveOnActiveDesktopColor; + for (var i = 0, length = windowRectRepeater.count; i < length; ++i) { + var window = windowRectRepeater.itemAt(i) + if (window) { + if (window.minimized) { + minimizedWindows.push(window.visibleName) } else { - if (model.active) - return windowActiveColor; - else - return windowInactiveColor; + visibleWindows.push(window.visibleName) } } + } - border.width: Math.round(units.devicePixelRatio) - border.color: model.active ? windowActiveBorderColor - : windowInactiveBorderColor - - KQuickControlsAddonsComponents.QPixmapItem { - id: icon - anchors.centerIn: parent - pixmap: model.icon - height: nativeHeight - width: nativeWidth - visible: pager.showWindowIcons - } + if (visibleWindows.length) { + text += i18np("%1 Window:", "%1 Windows:", visibleWindows.length) + + generateWindowList(visibleWindows) + } - MouseArea { - id: windowMouseArea - anchors.fill: parent - drag.target: windowRect - drag.axis: Drag.XandYAxis - drag.minimumX: -windowRect.width/2 - drag.maximumX: root.width - windowRect.width/2 - drag.minimumY: -windowRect.height/2 - drag.maximumY: root.height - windowRect.height/2 - - // used to save the state of some properties before the dragging - QtObject { - id: saveState - property int x: -1 - property int y: -1 - property variant parent - property int desktop: -1 - property int mouseX: -1 - property int mouseY: -1 - } + if (visibleWindows.length && minimizedWindows.length) { + text += "
      " + } - drag.onActiveChanged: { - root.dragging = drag.active; - desktopMouseArea.enabled = !drag.active; - } + if (minimizedWindows.length > 0) { + text += i18np("%1 Minimized Window:", "%1 Minimized Windows:", minimizedWindows.length) + + generateWindowList(minimizedWindows) + } - // reparent windowRect to enable the dragging for other desktops - onPressed: { - if (windowRect.parent == root) - return; - - saveState.x = windowRect.x; - saveState.y = windowRect.y - saveState.parent = windowRect.parent; - saveState.desktop = desktop.desktopId; - saveState.mouseX = mouseX; - saveState.mouseY = mouseY; - - var value = root.mapFromItem(clipRect, windowRect.x, windowRect.y); - windowRect.x = value.x; - windowRect.y = value.y - windowRect.parent = root; - } + if (text.length) { + // Get rid of the spacing
        would cause + text = "" + text + } + + subText = text + } + + width: pagerItemFlow.columnWidth + height: pagerItemFlow.rowHeight + + PlasmaCore.FrameSvgItem { + anchors.fill: parent + z: 1 // to make sure that the FrameSvg will be placed on top of the windows + imagePath: "widgets/pager" + prefix: (desktopMouseArea.enabled && desktopMouseArea.containsMouse) || (root.dragging && root.dragId == desktopId) ? + "hover" : (desktop.active ? "active" : "normal") + } + + DropArea { + id: droparea + anchors.fill: parent + preventStealing: true + + onDragEnter: { + root.dragSwitchDesktopId = desktop.desktopId; + dragTimer.start(); + } + onDragLeave: { + root.dragSwitchDesktopId = -1; + dragTimer.stop(); + } + onDrop: { + pagerModel.drop(event.mimeData, desktop.desktopId); + root.dragSwitchDesktopId = -1; + dragTimer.stop(); + } + } + + MouseArea { + id: desktopMouseArea + anchors.fill: parent + hoverEnabled : true + onClicked: pagerModel.changePage(desktopId); + } - onReleased: { - if (root.dragging) { - pager.moveWindow(windowRect.windowId, windowRect.x, windowRect.y, - root.dragId, saveState.desktop); + Item { + id: clipRect + x: Math.round(units.devicePixelRatio) + y: Math.round(units.devicePixelRatio) + width: desktop.width - 2 * x + height: desktop.height - 2 * y + clip: true + + + Repeater { + id: windowRectRepeater + + model: TasksModel + + onCountChanged: desktop.updateSubText() + + Rectangle { + id: windowRect + + z: model.StackingOrder + + property rect geometry: model.Geometry + property int windowId: model.LegacyWinIdList[0] + property string visibleName: model.display + property bool minimized: (model.IsMinimized === true) + onMinimizedChanged: desktop.updateSubText() + + /* since we move clipRect with 1, move it back */ + x: (geometry.x * pagerItemFlow.widthScaleFactor) - Math.round(units.devicePixelRatio) + y: (geometry.y * pagerItemFlow.heightScaleFactor) - Math.round(units.devicePixelRatio) + width: geometry.width * pagerItemFlow.widthScaleFactor + height: geometry.height * pagerItemFlow.heightScaleFactor + visible: model.IsMinimized !== true + color: { + if (desktop.active) { + if (model.IsActive === true) + return windowActiveOnActiveDesktopColor; + else + return windowInactiveOnActiveDesktopColor; } else { - // when there is no dragging (just a click), the event is passed - // to the desktop mousearea - desktopMouseArea.clicked(mouse); + if (model.IsActive === true) + return windowActiveColor; + else + return windowInactiveColor; } - - windowRect.x = saveState.x; - windowRect.y = saveState.y; - windowRect.parent = saveState.parent; } - } - function checkDesktopHover() { - if (!windowMouseArea.drag.active) - return; + border.width: Math.round(units.devicePixelRatio) + border.color: (model.IsActive === true) ? windowActiveBorderColor + : windowInactiveBorderColor + + MouseArea { + id: windowMouseArea + anchors.fill: parent + + drag.target: windowRect + drag.axis: Drag.XandYAxis + drag.minimumX: -windowRect.width/2 + drag.maximumX: root.width - windowRect.width/2 + drag.minimumY: -windowRect.height/2 + drag.maximumY: root.height - windowRect.height/2 + + drag.onActiveChanged: { + root.dragging = drag.active; + root.dragId = desktop.desktopId; + desktopMouseArea.enabled = !drag.active; + } + + onPressed: { + // Reparent to allow drags outside of this desktop. + var value = root.mapFromItem(clipRect, windowRect.x, windowRect.y); + windowRect.x = value.x; + windowRect.y = value.y + windowRect.parent = root; + } + + onReleased: { + if (root.dragging) { + windowRect.visible = false; + var windowCenter = Qt.point(windowRect.x + windowRect.width / 2, windowRect.y + windowRect.height / 2); + var pagerItem = pagerItemFlow.childAt(windowCenter.x, windowCenter.y); + + if (pagerItem) { + var relativeTopLeft = root.mapToItem(pagerItem, windowRect.x, windowRect.y); + + pagerModel.moveWindow(windowRect.windowId, relativeTopLeft.x, relativeTopLeft.y, + pagerItem.desktopId, root.dragId, + pagerItemFlow.widthScaleFactor, pagerItemFlow.heightScaleFactor); + } + + // Will reset the model, destroying the reparented drag delegate that + // is no longer bound to model.Geometry. + pagerModel.refresh(); + } else { + // When there is no dragging (just a click), the event is passed + // to the desktop MouseArea. + desktopMouseArea.clicked(mouse); + } + } + } - var mouse = root.mapFromItem(windowRect, saveState.mouseX, saveState.mouseY); - for (var i = 0; i < root.children.length; i++) { - var item = root.children[i]; - if (item.desktopId != undefined && Utils.contains(item, mouse)) { - root.dragId = item.desktopId; - return; + Component.onCompleted: { + if (plasmoid.configuration.showWindowIcons) { + windowIconComponent.createObject(windowRect, {"model": model}); } } } + } + } - onXChanged: checkDesktopHover(); - onYChanged: checkDesktopHover(); + Component.onCompleted: { + if (plasmoid.configuration.displayedText < 2) { + desktopLabelComponent.createObject(desktop, {"index": index, "model": model}); } } } } } + + Component.onCompleted: { + if (isActivityPager) { + plasmoid.setAction("showActivityManager", i18n("Show Activity Manager..."), "preferences-activities"); + } else { + if (KQuickControlsAddonsComponents.KCMShell.authorize("desktop.desktop").length > 0) { + plasmoid.setAction("addDesktop", i18n("Add Virtual Desktop"), "list-add"); + plasmoid.setAction("removeDesktop", i18n("Remove Virtual Desktop"), "list-remove"); + plasmoid.action("removeDesktop").enabled = Qt.binding(function() { + return repeater.count > 1; + }); + + plasmoid.setAction("openKCM", i18n("Configure Desktops..."), "configure"); + } + } + } } diff --git a/applets/pager/package/metadata.desktop b/applets/pager/package/metadata.desktop --- a/applets/pager/package/metadata.desktop +++ b/applets/pager/package/metadata.desktop @@ -163,7 +163,7 @@ X-KDE-PluginInfo-Author=The Plasma Team X-KDE-PluginInfo-Email=plasma-devel@kde.org X-KDE-PluginInfo-Name=org.kde.plasma.pager -X-KDE-PluginInfo-Version=3.0 +X-KDE-PluginInfo-Version=4.0 X-KDE-PluginInfo-Website=http://userbase.kde.org/Plasma/Pager X-KDE-PluginInfo-Category=Windows and Tasks X-KDE-PluginInfo-Depends= diff --git a/applets/pager/plugin/model.h b/applets/pager/plugin/model.h deleted file mode 100644 --- a/applets/pager/plugin/model.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2012 Luís Gabriel Lima - * - * 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; either version 2 of - * the License, or (at your option) any later version. - * - * 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 . - */ - -#ifndef MODEL_H -#define MODEL_H - -#include -#include -#include // For WId -#include - -class RectangleModel : public QAbstractListModel -{ - Q_OBJECT -public: - enum RectangleRoles { - WidthRole = Qt::UserRole + 1, - HeightRole, - XRole, - YRole - }; - - RectangleModel(QObject *parent = 0); - - virtual QHash roleNames() const; - virtual void clear(); - void append(const QRectF &rect); - QRectF &rectAt(int index); - - int rowCount(const QModelIndex &parent = QModelIndex()) const; - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - -private: - QList m_rects; -}; - - -class WindowModel : public RectangleModel -{ - Q_OBJECT -public: - enum WindowRole { - IdRole = RectangleModel::YRole + 1, - ActiveRole, - IconRole, - VisibleNameRole, - MinimizedRole - }; - - WindowModel(QObject *parent = 0); - - QHash roleNames() const; - void clear(); - void append(WId, const QRectF &, bool active, const QPixmap &icon, const QString &name, bool minimized); - WId idAt(int index) const; - QString visibleNameAt(int index) const; - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - -private: - QList m_ids; - QList m_active; - QList m_icons; - QStringList m_visibleNames; - QVector m_minimized; -}; - - -class PagerModel : public QAbstractListModel -{ - Q_OBJECT -public: - enum PagerRoles { - WindowsRole = RectangleModel::YRole + 1, - DesktopNameRole - }; - - PagerModel(QObject *parent = 0); - - QHash roleNames() const; - - void clearDesktopRects(); - void appendDesktopRect(const QRectF &rect, const QString &name); - QRectF &desktopRectAt(int index); - - void clearWindowRects(); - void appendWindowRect(int desktopId, WId, const QRectF &, bool active, - const QPixmap &icon, const QString &name, bool minimized); - WindowModel *windowsAt(int index) const; - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - int rowCount(const QModelIndex &parent = QModelIndex()) const; - -private: - RectangleModel m_desktops; - QList m_windows; - QStringList m_names; -}; - -#endif // MODEL_H diff --git a/applets/pager/plugin/model.cpp b/applets/pager/plugin/model.cpp deleted file mode 100644 --- a/applets/pager/plugin/model.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright 2012 Luís Gabriel Lima - * - * 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; either version 2 of - * the License, or (at your option) any later version. - * - * 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 . - */ - -#include "model.h" - -RectangleModel::RectangleModel(QObject *parent) - : QAbstractListModel(parent) -{ -} - -QHash RectangleModel::roleNames() const -{ - QHash rectRoles; - rectRoles[WidthRole] = "width"; - rectRoles[HeightRole] = "height"; - rectRoles[XRole] = "x"; - rectRoles[YRole] = "y"; - return rectRoles; -} - -void RectangleModel::clear() -{ - m_rects.clear(); -} - -void RectangleModel::append(const QRectF &rect) -{ - m_rects.append(rect); -} - -QRectF &RectangleModel::rectAt(int index) -{ - return m_rects[index]; -} - -int RectangleModel::rowCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return m_rects.count(); -} - -QVariant RectangleModel::data(const QModelIndex &index, int role) const -{ - if (index.row() < 0 || index.row() > m_rects.count()) - return QVariant(); - - const QRectF &rect = m_rects[index.row()]; - switch(role) { - case WidthRole: - return rect.width(); - case HeightRole: - return rect.height(); - case XRole: - return rect.x(); - case YRole: - return rect.y(); - default: - return QVariant(); - } -} - - -WindowModel::WindowModel(QObject *parent) - : RectangleModel(parent) -{ -} - -QHash WindowModel::roleNames() const -{ - QHash rectRoles = RectangleModel::roleNames(); - rectRoles[IdRole] = "windowId"; - rectRoles[ActiveRole] = "active"; - rectRoles[IconRole] = "icon"; - rectRoles[VisibleNameRole] = "visibleName"; - rectRoles[MinimizedRole] = "minimized"; - return rectRoles; -} - -void WindowModel::clear() -{ - beginResetModel(); - RectangleModel::clear(); - m_ids.clear(); - m_active.clear(); - m_icons.clear(); - m_visibleNames.clear(); - m_minimized.clear(); - endResetModel(); -} - -void WindowModel::append(WId windowId, const QRectF &rect, bool active, - const QPixmap &icon, const QString &name, bool minimized) -{ - beginInsertRows(QModelIndex(), rowCount(), rowCount()); - m_ids.append(windowId); - RectangleModel::append(rect); - m_active.append(active); - m_icons.append(icon); - m_visibleNames.append(name); - m_minimized.append(minimized); - endInsertRows(); -} - -WId WindowModel::idAt(int index) const -{ - return m_ids[index]; -} - -QString WindowModel::visibleNameAt(int index) const -{ - return m_visibleNames[index]; -} - -QVariant WindowModel::data(const QModelIndex &index, int role) const -{ - if (index.row() < 0 || index.row() >= rowCount()) - return QVariant(); - - if (role >= RectangleModel::WidthRole && role < IdRole) - return RectangleModel::data(index, role); - - switch (role) { - case IdRole: - return int(m_ids[index.row()]); - case ActiveRole: - return m_active[index.row()]; - case IconRole: - return m_icons[index.row()]; - case VisibleNameRole: - return m_visibleNames[index.row()]; - case MinimizedRole: - return m_minimized.value(index.row()); - default: - return QVariant(); - } -} - - -PagerModel::PagerModel(QObject *parent) - : QAbstractListModel(parent) -{ -} - -WindowModel *PagerModel::windowsAt(int index) const -{ - if (index < 0 || index >= m_windows.count()) - return 0; - - return qobject_cast(m_windows[index]); -} - -QHash PagerModel::roleNames() const -{ - QHash rectRoles = m_desktops.roleNames(); - rectRoles[WindowsRole] = "windows"; - rectRoles[DesktopNameRole] = "desktopName"; - return rectRoles; -} - -void PagerModel::clearDesktopRects() -{ - beginResetModel(); - m_desktops.clear(); - m_names.clear(); - endResetModel(); -} - -void PagerModel::appendDesktopRect(const QRectF &rect, const QString &name) -{ - beginInsertRows(QModelIndex(), rowCount(), rowCount()); - m_desktops.append(rect); - m_names.append(name); - endInsertRows(); -} - -QRectF& PagerModel::desktopRectAt(int index) -{ - return m_desktops.rectAt(index); -} - -void PagerModel::clearWindowRects() -{ - int removeIndex = -1; - for (int i = 0; i < m_windows.count(); i++) { - windowsAt(i)->clear(); - - if (i >= rowCount()) - removeIndex = (removeIndex == -1) ? i : -1; - } - - if (removeIndex != -1) { - // remove the windows model if the number of desktop has decreased - for (int i = m_windows.count()-1; i >= removeIndex; i--) { - windowsAt(i)->deleteLater(); - m_windows.removeAt(i); - } - } - - // append more windows model if the number of desktop has increased - for (int i = m_windows.count(); i < rowCount(); i++) - m_windows.append(new WindowModel(this)); -} - -void PagerModel::appendWindowRect(int desktopId, WId windowId, const QRectF &rect, bool active, - const QPixmap &icon, const QString &name, bool minimized) -{ - WindowModel *windows = windowsAt(desktopId); - if (!windows) - return; - - windows->append(windowId, rect, active, icon, name, minimized); - - QModelIndex i = index(desktopId); - emit dataChanged(i, i); -} - -QVariant PagerModel::data(const QModelIndex &index, int role) const -{ - if (role >= RectangleModel::WidthRole && role < WindowsRole) - return m_desktops.data(index, role); - - if (index.row() < 0 || index.row() >= m_windows.count()) - return QVariant(); - - switch (role) { - case WindowsRole: - return QVariant::fromValue(m_windows[index.row()]); - case DesktopNameRole: - return m_names[index.row()]; - default: - return QVariant(); - } -} - -int PagerModel::rowCount(const QModelIndex &index) const -{ - return m_desktops.rowCount(index); -} diff --git a/applets/pager/plugin/pager.h b/applets/pager/plugin/pager.h deleted file mode 100644 --- a/applets/pager/plugin/pager.h +++ /dev/null @@ -1,167 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Daniel Laidig * - * Copyright (C) 2012 by Luís Gabriel Lima * - * * - * 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; either version 2 of the License, or * - * (at your option) any later version. * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * - ***************************************************************************/ - -#ifndef PAGER_H -#define PAGER_H - -#include -#include - -#include - -#include "model.h" -#include - -class QDesktopWidget; - -class KColorScheme; -class KWindowInfo; - -namespace Plasma -{ - class FrameSvg; -} - -class Pager : public QObject -{ - Q_OBJECT - Q_PROPERTY(QObject* model READ model CONSTANT) - Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) - Q_PROPERTY(int currentDesktop READ currentDesktop NOTIFY currentDesktopChanged) - Q_PROPERTY(int desktopCount READ desktopCount NOTIFY desktopCountChanged) - Q_PROPERTY(bool showWindowIcons READ showWindowIcons WRITE setShowWindowIcons NOTIFY showWindowIconsChanged) - Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged) - Q_PROPERTY(QSizeF size READ size WRITE setSize NOTIFY sizeChanged) - Q_PROPERTY(QSize preferredSize READ preferredSize NOTIFY preferredSizeChanged) - Q_PROPERTY(Pager::CurrentDesktopSelected currentDesktopSelected READ currentDesktopSelected WRITE setCurrentDesktopSelected NOTIFY currentDesktopSelectedChanged) - Q_PROPERTY(Pager::DisplayedText displayedText READ displayedText WRITE setDisplayedText NOTIFY displayedTextChanged) - - public: - enum CurrentDesktopSelected { - DoNothing = 0, - ShowDesktop - }; - Q_ENUMS(CurrentDesktopSelected) - - enum DisplayedText { - Number = 0, - Name, - None - }; - Q_ENUMS(DisplayedText) - - Pager(QObject *parent = 0); - ~Pager(); - - QObject *model() const { return m_pagerModel; } - - bool enabled() const { return m_enabled; } - void setEnabled(bool enabled); - - int currentDesktop() const { return m_currentDesktop; } - void setCurrentDesktop(int desktop); - - int desktopCount() const; - - bool showWindowIcons() const { return m_showWindowIcons; } - void setShowWindowIcons(bool show); - - Qt::Orientation orientation() const; - void setOrientation(Qt::Orientation orientation); - - QSizeF size() const; - void setSize(const QSizeF &size); - - QSize preferredSize() const; - - CurrentDesktopSelected currentDesktopSelected() const; - void setCurrentDesktopSelected(CurrentDesktopSelected cur); - - DisplayedText displayedText() const; - void setDisplayedText(DisplayedText disp); - - Q_INVOKABLE void moveWindow(int, double, double, int, int); - Q_INVOKABLE void changeDesktop(int desktopId); - Q_INVOKABLE void dropMimeData(QMimeData *mimeData, int desktopId); - - Q_SIGNALS: - void enabledChanged(); - void currentDesktopChanged(); - void desktopCountChanged(); - void showWindowIconsChanged(); - void orientationChanged(); - void sizeChanged(); - void preferredSizeChanged(); - void currentDesktopSelectedChanged(); - void displayedTextChanged(); - - public Q_SLOTS: - void recalculateGridSizes(int rows); - void updateSizes(); - void recalculateWindowRects(); - - protected Q_SLOTS: - void currentDesktopChanged(int desktop); - void currentActivityChanged(const QString &activity); - void desktopsSizeChanged(); - void numberOfDesktopsChanged(int num); - void desktopNamesChanged(); - void windowChanged(WId id, const unsigned long *dirty); - void startTimer(); - void startTimerFast(); -#if HAVE_X11 - void slotAddDesktop(); - void slotRemoveDesktop(); -#endif - - protected: - void createMenu(); - QRect fixViewportPosition( const QRect& r ); - - private: - - PagerModel *m_pagerModel; - - QTimer* m_timer; - - - DisplayedText m_displayedText; - CurrentDesktopSelected m_currentDesktopSelected; - int m_rows; - int m_columns; - int m_desktopCount; - int m_currentDesktop; - QString m_currentActivity; - qreal m_widthScaleFactor; - qreal m_heightScaleFactor; - QSizeF m_size; - QSize m_preferredSize; - Qt::Orientation m_orientation; - - bool m_showWindowIcons : 1; - bool m_desktopDown : 1; - bool m_validSizes : 1; - bool m_enabled : 1; - - QDesktopWidget *m_desktopWidget; - bool m_isX11; - }; - -#endif diff --git a/applets/pager/plugin/pager.cpp b/applets/pager/plugin/pager.cpp deleted file mode 100644 --- a/applets/pager/plugin/pager.cpp +++ /dev/null @@ -1,637 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Daniel Laidig * - * Copyright (C) 2012 by Luís Gabriel Lima * - * * - * 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; either version 2 of the License, or * - * (at your option) any later version. * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * - ***************************************************************************/ - -#include "pager.h" - -#include - -#include -#include -#include -#include -#if HAVE_X11 -#include -#endif -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#if HAVE_X11 -#include -#include -#endif - -#include -#include - -#include - -const int FAST_UPDATE_DELAY = 100; -const int UPDATE_DELAY = 500; -const int MAXDESKTOPS = 20; -// random(), find a less magic one if you can. -sreich -const qreal MAX_TEXT_WIDTH = 800; - -Pager::Pager(QObject *parent) - : QObject(parent), - m_displayedText(None), - m_currentDesktopSelected(DoNothing), - m_columns(0), - m_currentDesktop(0), - m_orientation(Qt::Horizontal), - m_showWindowIcons(false), - m_desktopDown(false), - m_validSizes(false), - m_enabled(true), - m_desktopWidget(QApplication::desktop()) -#if HAVE_X11 - , m_isX11(QX11Info::isPlatformX11()) -#else - , m_isX11(false) -#endif -{ - //give rows the minimum default for non X11 systems - m_rows = 1; -#if HAVE_X11 - if (m_isX11) { - NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops | NET::DesktopNames, NET::WM2DesktopLayout); - m_rows = info.desktopLayoutColumnsRows().height(); - } -#endif - // initialize with a decent default - m_desktopCount = qMax(1, KWindowSystem::numberOfDesktops()); - - m_pagerModel = new PagerModel(this); - - m_timer = new QTimer(this); - m_timer->setSingleShot(true); - connect(m_timer, &QTimer::timeout, this, &Pager::recalculateWindowRects); - - connect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)), this, SLOT(currentDesktopChanged(int))); - connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, &Pager::startTimerFast); - connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, this, &Pager::startTimerFast); - connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &Pager::startTimerFast); - connect(KWindowSystem::self(), &KWindowSystem::numberOfDesktopsChanged, this, &Pager::numberOfDesktopsChanged); - connect(KWindowSystem::self(), &KWindowSystem::desktopNamesChanged, this, &Pager::desktopNamesChanged); - connect(KWindowSystem::self(), &KWindowSystem::stackingOrderChanged, this, &Pager::startTimerFast); - connect(KWindowSystem::self(), SIGNAL(windowChanged(WId,const ulong*)), this, SLOT(windowChanged(WId,const ulong*))); - connect(KWindowSystem::self(), SIGNAL(showingDesktopChanged(bool)), this, SLOT(startTimer())); - connect(m_desktopWidget, &QDesktopWidget::screenCountChanged, this, &Pager::desktopsSizeChanged); - connect(m_desktopWidget, &QDesktopWidget::resized, this, &Pager::desktopsSizeChanged); - - // connect to KWin's reloadConfig signal to get updates on the desktop layout - QDBusConnection dbus = QDBusConnection::sessionBus(); - dbus.connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"), - this, SLOT(desktopsSizeChanged())); - - recalculateGridSizes(m_rows); - - setCurrentDesktop(KWindowSystem::currentDesktop()); - - KActivities::Consumer *act = new KActivities::Consumer(this); - connect(act, &KActivities::Consumer::currentActivityChanged, this, &Pager::currentActivityChanged); - m_currentActivity = act->currentActivity(); -} - -Pager::~Pager() -{ -} - -void Pager::setEnabled(bool enabled) -{ - if (m_enabled != enabled) { - m_enabled = enabled; - emit enabledChanged(); - - if (enabled) { - startTimerFast(); - } - } -} - -int Pager::desktopCount() const -{ - return m_desktopCount; -} - - -void Pager::setCurrentDesktop(int desktop) -{ - if (m_currentDesktop != desktop) { - m_currentDesktop = desktop; - emit currentDesktopChanged(); - } -} - -void Pager::setShowWindowIcons(bool show) -{ - if (m_showWindowIcons != show) { - m_showWindowIcons = show; - emit showWindowIconsChanged(); - } -} - -Qt::Orientation Pager::orientation() const -{ - return m_orientation; -} - -void Pager::setOrientation(Qt::Orientation orientation) -{ - if (m_orientation == orientation) { - return; - } - - m_orientation = orientation; - emit orientationChanged(); - - // whenever we switch to/from vertical form factor, swap the rows and columns around - if (m_columns != m_rows) { - // pass in columns as the new rows - recalculateGridSizes(m_columns); - recalculateWindowRects(); - } -} - -QSizeF Pager::size() const -{ - return m_size; -} - -QSize Pager::preferredSize() const -{ - return m_preferredSize; -} - -void Pager::setSize(const QSizeF &size) -{ - if (m_size == size) { - return; - } - - m_size = size; - emit sizeChanged(); - - m_validSizes = false; - - startTimer(); -} - -Pager::CurrentDesktopSelected Pager::currentDesktopSelected() const -{ - return m_currentDesktopSelected; -} - -void Pager::setCurrentDesktopSelected(CurrentDesktopSelected cur) -{ - if (m_currentDesktopSelected == cur) { - return; - } - - m_currentDesktopSelected = cur; - emit currentDesktopSelectedChanged(); -} - -Pager::DisplayedText Pager::displayedText() const -{ - return m_displayedText; -} - -void Pager::setDisplayedText(Pager::DisplayedText disp) -{ - if (m_displayedText == disp) { - return; - } - - m_displayedText = disp; - emit displayedTextChanged(); -} - -#if HAVE_X11 -void Pager::slotAddDesktop() -{ - if (!m_isX11) { - return; - } - NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops); - info.setNumberOfDesktops(info.numberOfDesktops() + 1); -} - -void Pager::slotRemoveDesktop() -{ - if (!m_isX11) { - return; - } - NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops); - int desktops = info.numberOfDesktops(); - if (desktops > 1) { - info.setNumberOfDesktops(info.numberOfDesktops() - 1); - } -} -#endif - -void Pager::recalculateGridSizes(int rows) -{ - // recalculate the number of rows and columns in the grid - rows = qBound(1, rows, m_desktopCount); - // avoid weird cases like having 3 rows for 4 desktops, where the last row is unused - int columns = m_desktopCount / rows; - if (m_desktopCount % rows > 0) { - columns++; - } - - rows = m_desktopCount / columns; - if (m_desktopCount % columns > 0) { - rows++; - } - - // update the grid size - m_rows = rows; - m_columns = columns; - - updateSizes(); -} - -void Pager::updateSizes() -{ - const int padding = 2; // Space between miniatures of desktops - const int textMargin = 3; // Space between name of desktop and border - - const qreal leftMargin = 0; - const qreal topMargin = 0; - const qreal rightMargin = 0; - const qreal bottomMargin = 0; - - QRect totalRect; - for (int x = 0; x < m_desktopWidget->screenCount(); x++) { - totalRect |= m_desktopWidget->screenGeometry(x); - } - - const qreal ratio = (qreal) totalRect.width() / - (qreal) totalRect.height(); - - - qreal itemHeight; - qreal itemWidth; - qreal preferredItemHeight; - qreal preferredItemWidth; - - if (orientation() == Qt::Vertical) { - - itemWidth = (m_size.width() - leftMargin - rightMargin - - padding * (m_columns - 1)) / m_columns; - - itemHeight = itemWidth / ratio; - - } else { - // work out the preferred size based on the height of the geometry - preferredItemHeight = (m_size.height() - topMargin - bottomMargin - - padding * (m_rows - 1)) / m_rows; - preferredItemWidth = preferredItemHeight * ratio; - - if (m_displayedText == Name) { - // When containment is in this position we are not limited by low width and we can - // afford increasing width of applet to be able to display every name of desktops - for (int i = 0; i < m_desktopCount; i++) { - QFontMetricsF metrics(KGlobalSettings::taskbarFont()); - QSizeF textSize = metrics.size(Qt::TextSingleLine, KWindowSystem::desktopName(i+1)); - if (textSize.width() + textMargin * 2 > preferredItemWidth) { - preferredItemWidth = textSize.width() + textMargin * 2; - } - } - } - - itemWidth = (m_size.width() - leftMargin - rightMargin - - padding * (m_columns - 1)) / m_columns; - if (itemWidth > preferredItemWidth) { - itemWidth = preferredItemWidth; - } - itemHeight = preferredItemHeight; - if (itemWidth < itemHeight * ratio) { - itemWidth = itemHeight * ratio; - } - } - - m_widthScaleFactor = itemWidth / totalRect.width(); - m_heightScaleFactor = itemHeight / totalRect.height(); - - m_pagerModel->clearDesktopRects(); - - int pw = (int)(leftMargin + (itemWidth + padding) * m_columns + rightMargin); - int ph = (int)(topMargin + (itemHeight + padding) * m_rows + bottomMargin); - - if (orientation() == Qt::Vertical) { - pw = m_size.width(); - } else { - ph = m_size.height(); - } - - m_preferredSize = QSize(pw, ph); - emit preferredSizeChanged(); - - QRectF itemRect(QPointF(leftMargin, topMargin) , QSizeF(itemWidth, itemHeight)); - for (int i = 0; i < m_desktopCount; i++) { - itemRect.moveLeft(leftMargin + (i % m_columns) * (itemWidth + padding)); - itemRect.moveTop(topMargin + (i / m_columns) * (itemHeight + padding)); - - QString name = KWindowSystem::desktopName(i + 1); - m_pagerModel->appendDesktopRect(itemRect, name); - } - - m_validSizes = true; -} - -void Pager::recalculateWindowRects() -{ - if (!m_enabled) { - return; - } - - if (!m_isX11) { - return; - } -#if HAVE_X11 - NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops | NET::DesktopNames, NET::WM2DesktopLayout); - m_rows = info.desktopLayoutColumnsRows().height(); - - if (!m_validSizes) { - recalculateGridSizes(m_rows); - updateSizes(); - } - - QList windows = KWindowSystem::stackingOrder(); - m_pagerModel->clearWindowRects(); - - foreach (WId window, windows) { - KWindowInfo info = KWindowSystem::windowInfo(window, NET::WMGeometry | NET::WMFrameExtents | - NET::WMWindowType | NET::WMDesktop | - NET::WMState | NET::XAWMState | NET::WMVisibleName); - NET::WindowType type = info.windowType(NET::NormalMask | NET::DialogMask | NET::OverrideMask | - NET::UtilityMask | NET::DesktopMask | NET::DockMask | - NET::TopMenuMask | NET::SplashMask | NET::ToolbarMask | - NET::MenuMask); - - // the reason we don't check for -1 or Net::Unknown here is that legitimate windows, such - // as some java application windows, may not have a type set for them. - // apparently sane defaults on properties is beyond the wisdom of x11. - if (type == NET::Desktop || type == NET::Dock || type == NET::TopMenu || - type == NET::Splash || type == NET::Menu || type == NET::Toolbar || - info.hasState(NET::SkipPager)) { - continue; - } - - //check activity - NETWinInfo netInfo(QX11Info::connection(), window, QX11Info::appRootWindow(), 0, NET::WM2Activities); - QString result(netInfo.activities()); - if (!result.isEmpty() && result != QLatin1String("00000000-0000-0000-0000-000000000000")) { - QStringList activities = result.split(','); - if (!activities.contains(m_currentActivity)) { - continue; - } - } - - for (int i = 0; i < m_desktopCount; i++) { - if (!info.isOnDesktop(i+1)) { - continue; - } - - QRectF windowRect = info.frameGeometry(); - - if (KWindowSystem::mapViewport()) { - windowRect = fixViewportPosition(windowRect.toRect()); - } - - windowRect = QRectF(windowRect.x() * m_widthScaleFactor, - windowRect.y() * m_heightScaleFactor, - windowRect.width() * m_widthScaleFactor, - windowRect.height() * m_heightScaleFactor).toRect(); - - bool active = (window == KWindowSystem::activeWindow()); - int windowIconSize = KIconLoader::global()->currentSize(KIconLoader::Small); - int windowRectSize = qMin(windowRect.width(), windowRect.height()); - windowIconSize = qMax(windowIconSize, windowRectSize / 2); - QPixmap icon = KWindowSystem::icon(info.win(), windowIconSize, windowIconSize, true); - m_pagerModel->appendWindowRect(i, window, windowRect, active, icon, info.visibleName(), info.isMinimized()); - } - } -#endif -} - -void Pager::currentDesktopChanged(int desktop) -{ - if (desktop < 1) { - return; // bogus value, don't accept it - } - - setCurrentDesktop(desktop); - m_desktopDown = false; - startTimerFast(); -} - -void Pager::currentActivityChanged(const QString &activity) -{ - m_currentActivity = activity; - startTimerFast(); -} - -void Pager::numberOfDesktopsChanged(int num) -{ - if (!m_isX11) { - return; - } -#if HAVE_X11 - if (num < 1) { - return; // refuse to update to zero desktops - } - - NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops | NET::DesktopNames, NET::WM2DesktopLayout); - m_rows = info.desktopLayoutColumnsRows().height(); - - if (num != m_desktopCount) { - m_desktopCount = num; - emit desktopCountChanged(); - } - - m_pagerModel->clearDesktopRects(); - recalculateGridSizes(m_rows); - recalculateWindowRects(); -#endif -} - -void Pager::desktopNamesChanged() -{ - m_pagerModel->clearDesktopRects(); - m_validSizes = false; - startTimer(); -} - -void Pager::windowChanged(WId id, const unsigned long* dirty) -{ - if (!m_isX11) { - return; - } - Q_UNUSED(id) -#if HAVE_X11 - - if (dirty[NETWinInfo::PROTOCOLS] & (NET::WMGeometry | NET::WMDesktop) || - dirty[NETWinInfo::PROTOCOLS2] & NET::WM2Activities) { - startTimer(); - } -#endif -} - -void Pager::desktopsSizeChanged() -{ - m_pagerModel->clearDesktopRects(); - m_validSizes = false; - startTimer(); -} - -void Pager::startTimer() -{ - if (!m_timer->isActive()) { - m_timer->start(UPDATE_DELAY); - } -} - -void Pager::startTimerFast() -{ - if (!m_timer->isActive()) { - m_timer->start(FAST_UPDATE_DELAY); - } -} - -void Pager::moveWindow(int window, double x, double y, int targetDesktop, int sourceDesktop) -{ -#if HAVE_X11 - if (!m_isX11) { - return; - } - WId windowId = (WId) window; - - QPointF dest = QPointF(x, y) - m_pagerModel->desktopRectAt(targetDesktop).topLeft(); - - dest = QPointF(dest.x()/m_widthScaleFactor, dest.y()/m_heightScaleFactor); - - // don't move windows to negative positions - dest = QPointF(qMax(dest.x(), qreal(0.0)), qMax(dest.y(), qreal(0.0))); - - // use _NET_MOVERESIZE_WINDOW rather than plain move, so that the WM knows this is a pager request - NETRootInfo info(QX11Info::connection(), 0); - int flags = (0x20 << 12) | (0x03 << 8) | 1; // from tool, x/y, northwest gravity - - if (!KWindowSystem::mapViewport()) { - KWindowInfo windowInfo = KWindowSystem::windowInfo(windowId, NET::WMDesktop | NET::WMState); - - if (!windowInfo.onAllDesktops()) { - KWindowSystem::setOnDesktop(windowId, targetDesktop+1); - } - - // only move the window if it is not full screen and if it is kept within the same desktop - // moving when dropping between desktop is too annoying due to the small drop area. - if (!(windowInfo.state() & NET::FullScreen) && - (targetDesktop == sourceDesktop || windowInfo.onAllDesktops())) { - QPoint d = dest.toPoint(); - info.moveResizeWindowRequest(windowId, flags, d.x(), d.y(), 0, 0); - } - } else { - // setOnDesktop() with viewports is also moving a window, and since it takes a moment - // for the WM to do the move, there's a race condition with figuring out how much to move, - // so do it only as one move - dest += KWindowSystem::desktopToViewport(targetDesktop+1, false); - QPoint d = KWindowSystem::constrainViewportRelativePosition(dest.toPoint()); - info.moveResizeWindowRequest(windowId, flags, d.x(), d.y(), 0, 0); - } - m_timer->start(); -#else - Q_UNUSED(window) - Q_UNUSED(x) - Q_UNUSED(y) - Q_UNUSED(targetDesktop) - Q_UNUSED(sourceDesktop) -#endif -} - -void Pager::changeDesktop(int newDesktop) -{ -#if HAVE_X11 - if (!m_isX11) { - return; - } - if (m_currentDesktop == newDesktop+1) { - // toogle the desktop - if (m_currentDesktopSelected == ShowDesktop) { - NETRootInfo info(QX11Info::connection(), 0); - m_desktopDown = !m_desktopDown; - info.setShowingDesktop(m_desktopDown); - } - } else { - KWindowSystem::setCurrentDesktop(newDesktop + 1); - setCurrentDesktop(newDesktop + 1); - } -#else - Q_UNUSED(newDesktop) -#endif -} - -void Pager::dropMimeData(QMimeData *mimeData, int desktopId) -{ - if (!mimeData) { - return; - } - -#if HAVE_X11 - if (m_isX11) { - bool ok; - const QList &ids = TaskManager::XWindowTasksModel::winIdsFromMimeData(mimeData, &ok); - if (ok) { - foreach (const WId &id, ids) { - KWindowSystem::setOnDesktop(id, desktopId + 1); - } - } - } -#endif -} - -// KWindowSystem does not translate position when mapping viewports -// to virtual desktops (it'd probably break more things than fix), -// so the offscreen coordinates need to be fixed -QRect Pager::fixViewportPosition( const QRect& r ) -{ - QRect desktopGeom = m_desktopWidget->geometry(); - int x = r.center().x() % desktopGeom.width(); - int y = r.center().y() % desktopGeom.height(); - if( x < 0 ) { - x = x + desktopGeom.width(); - } - if( y < 0 ) { - y = y + desktopGeom.height(); - } - return QRect( x - r.width() / 2, y - r.height() / 2, r.width(), r.height()); -} - -#include "moc_pager.cpp" diff --git a/applets/pager/plugin/pagermodel.h b/applets/pager/plugin/pagermodel.h new file mode 100644 --- /dev/null +++ b/applets/pager/plugin/pagermodel.h @@ -0,0 +1,109 @@ +/******************************************************************** +Copyright 2016 Eike Hein + +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; either version 2 of the License, or +(at your option) any later version. + +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, write to the +Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . +*********************************************************************/ + +#ifndef PAGERMODEL_H +#define PAGERMODEL_H + +#include + +#if HAVE_X11 +#include +#include +#endif + +#include + +class QMimeData; + +class PagerModel : public QAbstractListModel +{ + Q_OBJECT + + Q_ENUMS(PagerType) + Q_ENUMS(AdditionalRoles) + + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) + Q_PROPERTY(PagerType pagerType READ pagerType WRITE setPagerType NOTIFY pagerTypeChanged) + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + Q_PROPERTY(bool showDesktop READ showDesktop WRITE setShowDesktop NOTIFY showDesktopChanged) + Q_PROPERTY(int currentPage READ currentPage NOTIFY currentPageChanged) + Q_PROPERTY(int layoutRows READ layoutRows NOTIFY layoutRowsChanged) + Q_PROPERTY(QSize pagerItemSize READ pagerItemSize NOTIFY pagerItemSizeChanged) + +public: + enum PagerType { + VirtualDesktops = 0, + Activities + }; + + enum AdditionalRoles { + TasksModel = Qt::UserRole + 1 + }; + + explicit PagerModel(QObject *parent = nullptr); + virtual ~PagerModel(); + + QHash roleNames() const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role) const override; + + PagerType pagerType() const; + void setPagerType(PagerType type); + + bool enabled() const; + void setEnabled(bool enabled); + + bool showDesktop() const; + void setShowDesktop(bool show); + + int currentPage() const; + + int layoutRows() const; + QSize pagerItemSize() const; + +#if HAVE_X11 + QList stackingOrder() const; +#endif + + Q_INVOKABLE void refresh(); + + Q_INVOKABLE void moveWindow(int window, double x, double y, int targetItemId, int sourceItemId, + qreal widthScaleFactor, qreal heightScaleFactor); + Q_INVOKABLE void changePage(int itemId); + Q_INVOKABLE void drop(QMimeData *mimeData, int itemId); + Q_INVOKABLE void addDesktop(); + Q_INVOKABLE void removeDesktop(); + +Q_SIGNALS: + void countChanged() const; + void pagerTypeChanged() const; + void enabledChanged() const; + void showDesktopChanged() const; + void currentPageChanged() const; + void layoutRowsChanged() const; + void pagerItemSizeChanged() const; + +private: + class Private; + QScopedPointer d; +}; + +#endif diff --git a/applets/pager/plugin/pagermodel.cpp b/applets/pager/plugin/pagermodel.cpp new file mode 100644 --- /dev/null +++ b/applets/pager/plugin/pagermodel.cpp @@ -0,0 +1,526 @@ +/******************************************************************** +Copyright 2007 Daniel Laidig +Copyright 2012 Luís Gabriel Lima +Copyright 2016 Eike Hein + +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; either version 2 of the License, or +(at your option) any later version. + +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, write to the +Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . +*********************************************************************/ + +#include "pagermodel.h" +#include "windowmodel.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +using namespace TaskManager; + +class PagerModel::Private +{ +public: + Private(PagerModel *q); + ~Private(); + + static int instanceCount; + + PagerType pagerType = VirtualDesktops; + bool enabled = false; + bool showDesktop = false; + bool desktopDown = false; + + WindowTasksModel *tasksModel = nullptr; + + static ActivityInfo *activityInfo; + QMetaObject::Connection activityInfoConn; + + static VirtualDesktopInfo *virtualDesktopInfo; + QMetaObject::Connection virtualDesktopInfoConn; + + QDesktopWidget *desktopWidget = QApplication::desktop(); + + QList windowModels; + +#if HAVE_X11 + QList cachedStackingOrder = KWindowSystem::stackingOrder(); +#endif + + void refreshDataSource(); + +private: + PagerModel *q; +}; + +int PagerModel::Private::instanceCount = 0; +ActivityInfo *PagerModel::Private::activityInfo = nullptr; +VirtualDesktopInfo *PagerModel::Private::virtualDesktopInfo = nullptr; + +PagerModel::Private::Private(PagerModel *q) + : q(q) +{ + ++instanceCount; + + if (!activityInfo) { + activityInfo = new ActivityInfo(); + } + + if (!virtualDesktopInfo) { + virtualDesktopInfo = new VirtualDesktopInfo(); + } + + QObject::connect(activityInfo, &ActivityInfo::currentActivityChanged, q, + [this]() { + if (pagerType == VirtualDesktops && windowModels.count()) { + for (auto windowModel : windowModels) { + windowModel->setActivity(activityInfo->currentActivity()); + } + } + } + ); + + QObject::connect(virtualDesktopInfo, &VirtualDesktopInfo::currentDesktopChanged, q, + [this]() { + desktopDown = false; + } + ); + + QObject::connect(virtualDesktopInfo, &VirtualDesktopInfo::desktopLayoutRowsChanged, + q, &PagerModel::layoutRowsChanged); + + QObject::connect(desktopWidget, &QDesktopWidget::screenCountChanged, + q, &PagerModel::pagerItemSizeChanged); + QObject::connect(desktopWidget, &QDesktopWidget::resized, + q, &PagerModel::pagerItemSizeChanged); + +#if HAVE_X11 + QObject::connect(KWindowSystem::self(), &KWindowSystem::stackingOrderChanged, q, + [this]() { + cachedStackingOrder = KWindowSystem::stackingOrder(); + + for (auto windowModel : windowModels) { + windowModel->refreshStackingOrder(); + } + } + ); +#endif +} + +PagerModel::Private::~Private() +{ + --instanceCount; + + if (!instanceCount) { + delete activityInfo; + activityInfo = nullptr; + delete virtualDesktopInfo; + virtualDesktopInfo = nullptr; + } +} + +void PagerModel::Private::refreshDataSource() +{ + if (pagerType == VirtualDesktops) { + virtualDesktopInfoConn = QObject::connect(virtualDesktopInfo, + &VirtualDesktopInfo::numberOfDesktopsChanged, + q, [this]() { q->refresh(); }, Qt::UniqueConnection); + + QObject::disconnect(activityInfoConn); + + QObject::disconnect(activityInfo, &ActivityInfo::currentActivityChanged, + q, &PagerModel::currentPageChanged); + QObject::connect(virtualDesktopInfo, &VirtualDesktopInfo::currentDesktopChanged, + q, &PagerModel::currentPageChanged, Qt::UniqueConnection); + } else { + activityInfoConn = QObject::connect(activityInfo, + &ActivityInfo::numberOfRunningActivitiesChanged, + q, [this]() { q->refresh(); }, Qt::UniqueConnection); + + QObject::disconnect(virtualDesktopInfoConn); + + QObject::disconnect(virtualDesktopInfo, &VirtualDesktopInfo::currentDesktopChanged, + q, &PagerModel::currentPageChanged); + QObject::connect(activityInfo, &ActivityInfo::currentActivityChanged, + q, &PagerModel::currentPageChanged, Qt::UniqueConnection); + } + + emit q->currentPageChanged(); +} + +PagerModel::PagerModel(QObject *parent) + : QAbstractListModel(parent) + , d(new Private(this)) +{ + d->tasksModel = new WindowTasksModel(this); +} + +PagerModel::~PagerModel() +{ +} + +QHash PagerModel::roleNames() const +{ + QHash roles = QAbstractItemModel::roleNames(); + + QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles")); + + for (int i = 0; i < e.keyCount(); ++i) { + roles.insert(e.value(i), e.key(i)); + } + + return roles; +} + +int PagerModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + + return d->windowModels.count(); +} + +QVariant PagerModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= d->windowModels.count()) { + return QVariant(); + } + + if (role == Qt::DisplayRole) { + if (d->pagerType == VirtualDesktops) { + return d->virtualDesktopInfo->desktopNames().at(index.row()); + } else { + QString activityId = d->activityInfo->runningActivities().at(index.row()); + return d->activityInfo->activityName(activityId); + } + } else if (role == TasksModel) { + return QVariant::fromValue(d->windowModels.at(index.row())); + } + + return QVariant(); +} + +PagerModel::PagerType PagerModel::pagerType() const +{ + return d->pagerType; +} + +void PagerModel::setPagerType(PagerType type) +{ + if (d->pagerType != type) { + d->pagerType = type; + + refresh(); + + emit pagerTypeChanged(); + } +} + +bool PagerModel::enabled() const +{ + return d->enabled; +} + +void PagerModel::setEnabled(bool enabled) +{ + if (enabled && !d->enabled) { + refresh(); + d->enabled = true; + emit enabledChanged(); + } else if (!enabled && d->enabled) { + beginResetModel(); + + disconnect(d->activityInfoConn); + disconnect(d->virtualDesktopInfoConn); + + qDeleteAll(d->windowModels); + d->windowModels.clear(); + + endResetModel(); + + d->enabled = false; + emit enabledChanged(); + + emit countChanged(); + } +} + +bool PagerModel::showDesktop() const +{ + return d->showDesktop; +} + +void PagerModel::setShowDesktop(bool show) +{ + if (d->showDesktop != show) { + d->showDesktop = show; + + emit showDesktopChanged(); + } +} + +int PagerModel::currentPage() const +{ + if (d->pagerType == VirtualDesktops) { + return d->virtualDesktopInfo->currentDesktop(); + } else { + return d->activityInfo->runningActivities().indexOf(d->activityInfo->currentActivity()); + } +} + +int PagerModel::layoutRows() const +{ + return qBound(1, d->virtualDesktopInfo->desktopLayoutRows(), + d->virtualDesktopInfo->numberOfDesktops()); +} + +QSize PagerModel::pagerItemSize() const +{ + QRect totalRect; + + for (int i = 0; i < d->desktopWidget->screenCount(); ++i) { + totalRect |= d->desktopWidget->screenGeometry(i); + } + + return totalRect.size(); +} + +#if HAVE_X11 +QList PagerModel::stackingOrder() const +{ + return d->cachedStackingOrder; +} +#endif + +void PagerModel::refresh() +{ + beginResetModel(); + + d->refreshDataSource(); + + int modelCount = d->windowModels.count(); + const int modelsNeeded = ((d->pagerType == VirtualDesktops) + ? d->virtualDesktopInfo->numberOfDesktops() + : d->activityInfo->numberOfRunningActivities()); + + if (modelCount > modelsNeeded) { + while (modelCount != modelsNeeded) { + delete d->windowModels.takeLast(); + --modelCount; + } + } else if (modelsNeeded > modelCount) { + while (modelCount != modelsNeeded) { + WindowModel *windowModel = new WindowModel(this); + windowModel->setFilterSkipPager(true); + windowModel->setFilterByVirtualDesktop(true); + windowModel->setFilterByActivity(true); + windowModel->setSourceModel(d->tasksModel); + d->windowModels.append(windowModel); + ++modelCount; + } + } + + if (d->pagerType == VirtualDesktops) { + int virtualDesktop = 1; + + for (auto windowModel : d->windowModels) { + windowModel->setVirtualDesktop(virtualDesktop); + ++virtualDesktop; + + windowModel->setActivity(d->activityInfo->currentActivity()); + } + } else { + int activityIndex = 0; + const QStringList &runningActivities = d->activityInfo->runningActivities(); + + for (auto windowModel : d->windowModels) { + windowModel->setVirtualDesktop(0); + + windowModel->setActivity(runningActivities.at(activityIndex)); + ++activityIndex; + } + } + + endResetModel(); + + emit countChanged(); +} + +void PagerModel::moveWindow(int window, double x, double y, int targetItemId, int sourceItemId, + qreal widthScaleFactor, qreal heightScaleFactor) +{ +#if HAVE_X11 + if (!KWindowSystem::isPlatformX11()) { + return; + } + + const WId windowId = (WId)window; + + QPointF dest(x / widthScaleFactor, y / heightScaleFactor); + + // Don't move windows to negative positions. + dest = QPointF(qMax(dest.x(), qreal(0.0)), qMax(dest.y(), qreal(0.0))); + + // Use _NET_MOVERESIZE_WINDOW rather than plain move, so that the WM knows this is a pager request. + NETRootInfo info(QX11Info::connection(), 0); + const int flags = (0x20 << 12) | (0x03 << 8) | 1; // From tool, x/y, northwest gravity. + + if (!KWindowSystem::mapViewport()) { + KWindowInfo windowInfo(windowId, NET::WMDesktop | NET::WMState); + + if (d->pagerType == VirtualDesktops) { + if (!windowInfo.onAllDesktops()) { + KWindowSystem::setOnDesktop(windowId, targetItemId + 1); + } + } else { + const QStringList &runningActivities = d->activityInfo->runningActivities(); + + if (targetItemId < runningActivities.length()) { + KActivities::Controller activitiesController; + activitiesController.setCurrentActivity(runningActivities.at(targetItemId)); + } + } + + // Only move the window if it is not full screen and if it is kept within the same desktop. + // Moving when dropping between desktop is too annoying due to the small drop area. + if (!(windowInfo.state() & NET::FullScreen) && + (targetItemId == sourceItemId || windowInfo.onAllDesktops())) { + const QPoint &d = dest.toPoint(); + info.moveResizeWindowRequest(windowId, flags, d.x(), d.y(), 0, 0); + } + } else { + // setOnDesktop() with viewports is also moving a window, and since it takes a moment + // for the WM to do the move, there's a race condition with figuring out how much to move, + // so do it only as one move. + dest += KWindowSystem::desktopToViewport(targetItemId + 1, false); + const QPoint &d = KWindowSystem::constrainViewportRelativePosition(dest.toPoint()); + info.moveResizeWindowRequest(windowId, flags, d.x(), d.y(), 0, 0); + } +#else + Q_UNUSED(window) + Q_UNUSED(x) + Q_UNUSED(y) + Q_UNUSED(targetDesktop) + Q_UNUSED(sourceDesktop) +#endif +} + +void PagerModel::changePage(int itemId) +{ +#if HAVE_X11 + if (!KWindowSystem::isPlatformX11()) { + return; + } + + const int targetId = (d->pagerType == VirtualDesktops) ? itemId + 1 : itemId; + + if (currentPage() == targetId) { + // Toggle the desktop. + if (d->showDesktop) { + NETRootInfo info(QX11Info::connection(), 0); + d->desktopDown = !d->desktopDown; + info.setShowingDesktop(d->desktopDown); + } + } else { + if (d->pagerType == VirtualDesktops) { + KWindowSystem::setCurrentDesktop(targetId); + } else { + const QStringList &runningActivities = d->activityInfo->runningActivities(); + + if (targetId < runningActivities.length()) { + KActivities::Controller activitiesController; + activitiesController.setCurrentActivity(runningActivities.at(targetId)); + } + } + } +#else + Q_UNUSED(itemId) +#endif +} + +void PagerModel::drop(QMimeData *mimeData, int itemId) +{ + if (!mimeData) { + return; + } + +#if HAVE_X11 + if (KWindowSystem::isPlatformX11()) { + bool ok; + + const QList &ids = TaskManager::XWindowTasksModel::winIdsFromMimeData(mimeData, &ok); + + if (!ok) { + return; + } + + if (d->pagerType == VirtualDesktops) { + for (const auto &id : ids) { + KWindowSystem::setOnDesktop(id, itemId + 1); + } + } else { + QString newActivity; + const QStringList &runningActivities = d->activityInfo->runningActivities(); + + if (itemId < runningActivities.length()) { + newActivity = runningActivities.at(itemId); + } + + for (const auto &id : ids) { + KWindowSystem::setOnDesktop(id, itemId + 1); + } + } + } +#else + Q_UNUSED(itemId) +#endif +} + +void PagerModel::addDesktop() +{ +#if HAVE_X11 + if (!KWindowSystem::isPlatformX11()) { + return; + } + + NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops); + info.setNumberOfDesktops(info.numberOfDesktops() + 1); +#endif +} + +void PagerModel::removeDesktop() +{ +#if HAVE_X11 + if (!KWindowSystem::isPlatformX11()) { + return; + } + + NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops); + + if (info.numberOfDesktops() > 1) { + info.setNumberOfDesktops(info.numberOfDesktops() - 1); + } +#endif +} + +#include "moc_pagermodel.cpp" diff --git a/applets/pager/plugin/pagerplugin.cpp b/applets/pager/plugin/pagerplugin.cpp --- a/applets/pager/plugin/pagerplugin.cpp +++ b/applets/pager/plugin/pagerplugin.cpp @@ -1,5 +1,6 @@ /* Copyright (C) 2011 Martin Gräßlin + Copyright (C) 2016 Eike Hein 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 @@ -18,12 +19,13 @@ #include "pagerplugin.h" -#include "pager.h" +#include "pagermodel.h" #include -void KickoffPlugin::registerTypes (const char *uri) +void KickoffPlugin::registerTypes(const char *uri) { Q_ASSERT(uri == QLatin1String("org.kde.plasma.private.pager")); - qmlRegisterType(uri, 2, 0, "Pager"); + + qmlRegisterType(uri, 2, 0, "PagerModel"); } diff --git a/applets/pager/plugin/windowmodel.h b/applets/pager/plugin/windowmodel.h new file mode 100644 --- /dev/null +++ b/applets/pager/plugin/windowmodel.h @@ -0,0 +1,52 @@ +/******************************************************************** +Copyright 2016 Eike Hein + +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; either version 2 of the License, or +(at your option) any later version. + +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, write to the +Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . +*********************************************************************/ + +#ifndef WINDOWMODEL_H +#define WINDOWMODEL_H + +#include "taskfilterproxymodel.h" + +class PagerModel; + +class WindowModel : public TaskManager::TaskFilterProxyModel +{ + Q_OBJECT + + Q_ENUMS(WindowModelRoles) + +public: + enum WindowModelRoles { + StackingOrder = Qt::UserRole + 1 + }; + + explicit WindowModel(PagerModel *parent); + virtual ~WindowModel(); + + QHash roleNames() const override; + + QVariant data(const QModelIndex &index, int role) const override; + + void refreshStackingOrder(); + +private: + class Private; + QScopedPointer d; +}; + +#endif diff --git a/applets/pager/plugin/windowmodel.cpp b/applets/pager/plugin/windowmodel.cpp new file mode 100644 --- /dev/null +++ b/applets/pager/plugin/windowmodel.cpp @@ -0,0 +1,120 @@ +/******************************************************************** +Copyright 2016 Eike Hein + +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; either version 2 of the License, or +(at your option) any later version. + +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, write to the +Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . +*********************************************************************/ + +#include "windowmodel.h" +#include "pagermodel.h" + +#include + +#include +#include +#include + +#include + +using namespace TaskManager; + +class WindowModel::Private +{ +public: + Private(WindowModel *q); + + PagerModel *pagerModel = nullptr; + + QDesktopWidget *desktopWidget = QApplication::desktop(); + +private: + WindowModel *q; +}; + +WindowModel::Private::Private(WindowModel *q) + : q(q) +{ +} + +WindowModel::WindowModel(PagerModel *parent) + : TaskFilterProxyModel(parent) + , d(new Private(this)) +{ + d->pagerModel = parent; +} + +WindowModel::~WindowModel() +{ +} + +QHash WindowModel::roleNames() const +{ + QHash roles = TaskFilterProxyModel::roleNames(); + + QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("WindowModelRoles")); + + for (int i = 0; i < e.keyCount(); ++i) { + roles.insert(e.value(i), e.key(i)); + } + + return roles; +} + +QVariant WindowModel::data(const QModelIndex &index, int role) const +{ + if (role == AbstractTasksModel::Geometry && KWindowSystem::mapViewport()) { + + const QRect &windowGeo = TaskFilterProxyModel::data(index, role).toRect(); + const QRect &desktopGeo = d->desktopWidget->geometry(); + + int x = windowGeo.center().x() % desktopGeo.width(); + int y = windowGeo.center().y() % desktopGeo.height(); + + if (x < 0) { + x = x + desktopGeo.width(); + } + + if (y < 0) { + y = y + desktopGeo.height(); + } + + return QRect(x - windowGeo.width() / 2, y - windowGeo.height() / 2, + windowGeo.width(), windowGeo.height()); + } else if (role == StackingOrder) { +#if HAVE_X11 + const QVariantList &winIds = TaskFilterProxyModel::data(index, AbstractTasksModel::LegacyWinIdList).toList(); + + if (winIds.count()) { + const WId winId = winIds.at(0).toLongLong(); + const int z = d->pagerModel->stackingOrder().indexOf(winId); + + if (z != -1) { + return z; + } + } +#endif + + return 0; + } + + return TaskFilterProxyModel::data(index, role); +} + +void WindowModel::refreshStackingOrder() +{ + if (rowCount()) { + emit dataChanged(index(0, 0), index(rowCount() - 1, 0), QVector{StackingOrder}); + } +}