Created
July 29, 2018 16:40
-
-
Save Zren/7b72293743f39b2b2ebac3d11f3ad59b to your computer and use it in GitHub Desktop.
KDE5 Locally Integrated Menu
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/plugins/kdecorations/aurorae/src/aurorae.cpp b/plugins/kdecorations/aurorae/src/aurorae.cpp | |
index 4c5879b..ff00e22 100644 | |
--- a/plugins/kdecorations/aurorae/src/aurorae.cpp | |
+++ b/plugins/kdecorations/aurorae/src/aurorae.cpp | |
@@ -448,6 +448,11 @@ QVariant Decoration::readConfig(const QString &key, const QVariant &defaultValue | |
return config->group(m_themeName).readEntry(key, defaultValue); | |
} | |
+qulonglong Decoration::windowIdAsLong() const | |
+{ | |
+ return (qulonglong)(client().data()->windowId()); | |
+} | |
+ | |
void Decoration::setupBorders(QQuickItem *item) | |
{ | |
m_borders = item->findChild<KWin::Borders*>(QStringLiteral("borders")); | |
diff --git a/plugins/kdecorations/aurorae/src/aurorae.h b/plugins/kdecorations/aurorae/src/aurorae.h | |
index 3b28099..db42453 100644 | |
--- a/plugins/kdecorations/aurorae/src/aurorae.h | |
+++ b/plugins/kdecorations/aurorae/src/aurorae.h | |
@@ -56,6 +56,8 @@ public: | |
KDecoration2::DecoratedClient *clientPointer() const; | |
+ Q_INVOKABLE qulonglong windowIdAsLong() const; | |
+ | |
public Q_SLOTS: | |
void init() override; | |
void installTitleItem(QQuickItem *item); | |
diff --git a/plugins/kdecorations/aurorae/src/qml/aurorae.qml b/plugins/kdecorations/aurorae/src/qml/aurorae.qml | |
index 5b81241..d866526 100644 | |
--- a/plugins/kdecorations/aurorae/src/qml/aurorae.qml | |
+++ b/plugins/kdecorations/aurorae/src/qml/aurorae.qml | |
@@ -15,8 +15,12 @@ You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*********************************************************************/ | |
import QtQuick 2.0 | |
+import QtQuick.Layouts 1.1 | |
+import QtGraphicalEffects 1.0 | |
import org.kde.kwin.decoration 0.1 | |
import org.kde.plasma.core 2.0 as PlasmaCore | |
+import org.kde.plasma.components 2.0 as PlasmaComponents | |
+import org.kde.plasma.private.appmenu 1.0 as AppMenuPrivate | |
Decoration { | |
id: root | |
@@ -155,6 +159,7 @@ Decoration { | |
} | |
Text { | |
id: caption | |
+ visible: false | |
text: decoration.client.caption | |
textFormat: Text.PlainText | |
horizontalAlignment: auroraeTheme.horizontalAlignment | |
@@ -178,7 +183,117 @@ Decoration { | |
duration: auroraeTheme.animationTime | |
} | |
} | |
+ | |
+ // opacity: appMenuArea.shown ? 0.3 : 1 | |
+ // Behavior on opacity { | |
+ // enabled: root.animate | |
+ // NumberAnimation { | |
+ // duration: appMenuArea.showDuration | |
+ // } | |
+ // } | |
+ | |
+ onHeightChanged: console.log('caption.height', height, 'implicitHeight', implicitHeight) | |
+ } | |
+ | |
+ LinearGradient { | |
+ id: captionMask | |
+ anchors.fill: caption | |
+ source: caption | |
+ start: Qt.point(0, 0) | |
+ end: Qt.point(width, 0) | |
+ | |
+ readonly property real appMenuRight: Math.max(0, appMenuButtonsLayout.implicitWidth - (caption.anchors.leftMargin - appMenuArea.anchors.leftMargin)) | |
+ readonly property real fadeInWidth: 10 // * dpi | |
+ readonly property real appMenuRatio: appMenuRight / width | |
+ readonly property real fadeInEndRatio: (appMenuRight + fadeInWidth) / width | |
+ | |
+ gradient: Gradient { | |
+ GradientStop { position: 0; color: "transparent" } | |
+ GradientStop { position: captionMask.appMenuRatio; color: "transparent" } | |
+ GradientStop { position: captionMask.fadeInEndRatio; color: "white" } | |
+ GradientStop { position: 1; color: "white" } | |
+ } | |
+ } | |
+ | |
+ // Rectangle { | |
+ // anchors.fill: captionMask | |
+ // color: "transparent" | |
+ // border.width: 1 | |
+ // border.color: "#f00" | |
+ // } | |
+ | |
+ Item { | |
+ id: appMenuArea | |
+ anchors.top: caption.top | |
+ anchors.bottom: caption.bottom | |
+ anchors.left: leftButtonGroup.right | |
+ anchors.leftMargin: auroraeTheme.buttonSpacing * auroraeTheme.buttonSizeFactor | |
+ | |
+ readonly property int showDuration: 200 | |
+ readonly property bool shown: decoration.client.active | |
+ | |
+ AppMenuPrivate.AppMenuModel { | |
+ id: appMenuModel | |
+ // onRequestActivateIndex: plasmoid.nativeInterface.requestActivateIndex(index) | |
+ useActiveWindowId: false | |
+ // windowId: decoration.client.windowId | |
+ | |
+ Component.onCompleted: { | |
+ // console.log('C decoration.client.windowId', decoration.client.windowId()) | |
+ console.log('C decoration.windowIdAsLong', decoration.windowIdAsLong()) | |
+ appMenuModel.setWindowIdByLong(decoration.windowIdAsLong()) | |
+ | |
+ // decoration.client.windowIdChanged.connect(function(){ | |
+ // // console.log('S decoration.client.windowId', decoration.client.windowId()) | |
+ // console.log('S decoration.windowIdAsLong', decoration.windowIdAsLong()) | |
+ // // appMenuModel.setWindowId(decoration.client.windowId()) | |
+ // // appMenuModel.setWindowId(decoration.client.windowId()) | |
+ // }) | |
+ } | |
+ } | |
+ | |
+ RowLayout { | |
+ id: appMenuButtonsLayout | |
+ anchors.fill: parent | |
+ spacing: 0 | |
+ | |
+ Repeater { | |
+ id: buttonRepeater | |
+ // model: [ | |
+ // { activeMenu: '&File' }, | |
+ // { activeMenu: '&View' }, | |
+ // { activeMenu: '&Help' } | |
+ // ] | |
+ model: appMenuModel | |
+ | |
+ PlasmaComponents.ToolButton { | |
+ id: appMenuButton | |
+ readonly property int buttonIndex: index | |
+ Layout.preferredWidth: minimumWidth | |
+ Layout.fillHeight: true | |
+ // text: modelData.activeMenu | |
+ text: model.activeMenu | |
+ onClicked: { | |
+ // app menu | |
+ var pos = appMenuButton.mapToItem(null, 0, 0); // null = "map to scene" | |
+ var rect = Qt.rect(pos.x, pos.y, appMenuButton.width, appMenuButton.height); | |
+ var actionId = model.actionId; // 0 = root | |
+ decoration.requestShowApplicationMenu(rect, actionId); | |
+ console.log('index', index) | |
+ console.log('model.activeMenu', model.activeMenu) | |
+ console.log('model.activeActions', model.activeActions) | |
+ console.log('model.index', model.index) | |
+ console.log('model.actionId', model.actionId) | |
+ } | |
+ } | |
+ } | |
+ | |
+ Item { | |
+ Layout.fillWidth: true | |
+ } | |
+ } | |
} | |
+ | |
PlasmaCore.FrameSvgItem { | |
id: innerBorder | |
anchors { |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/applets/appmenu/plugin/appmenumodel.cpp b/applets/appmenu/plugin/appmenumodel.cpp | |
index 1b5dc7b..049405a 100644 | |
--- a/applets/appmenu/plugin/appmenumodel.cpp | |
+++ b/applets/appmenu/plugin/appmenumodel.cpp | |
@@ -68,14 +68,16 @@ AppMenuModel::AppMenuModel(QObject *parent) | |
: QAbstractListModel(parent), | |
m_serviceWatcher(new QDBusServiceWatcher(this)) | |
{ | |
- connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &AppMenuModel::onActiveWindowChanged); | |
connect(this, &AppMenuModel::modelNeedsUpdate, this, [this] { | |
if (!m_updatePending) { | |
m_updatePending = true; | |
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); | |
} | |
}); | |
- onActiveWindowChanged(KWindowSystem::activeWindow()); | |
+ if (m_useActiveWindowId) { | |
+ connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &AppMenuModel::onActiveWindowChanged); | |
+ onActiveWindowChanged(KWindowSystem::activeWindow()); | |
+ } | |
m_serviceWatcher->setConnection(QDBusConnection::sessionBus()); | |
//if our current DBus connection gets lost, close the menu | |
@@ -121,10 +123,47 @@ void AppMenuModel::update() | |
m_updatePending = false; | |
} | |
+bool AppMenuModel::useActiveWindowId() const | |
+{ | |
+ return m_useActiveWindowId; | |
+} | |
+ | |
+void AppMenuModel::setUseActiveWindowId(bool set) | |
+{ | |
+ if (m_useActiveWindowId != set) { | |
+ if (set) { | |
+ connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &AppMenuModel::onActiveWindowChanged); | |
+ onActiveWindowChanged(KWindowSystem::activeWindow()); | |
+ } else { | |
+ disconnect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &AppMenuModel::onActiveWindowChanged); | |
+ } | |
+ m_useActiveWindowId = set; | |
+ emit useActiveWindowIdChanged(); | |
+ } | |
+} | |
+ | |
void AppMenuModel::onActiveWindowChanged(WId id) | |
{ | |
- qApp->removeNativeEventFilter(this); | |
+ setWindowId(id); | |
+} | |
+ | |
+WId AppMenuModel::windowId() const | |
+{ | |
+ return m_currentWindowId; | |
+} | |
+ | |
+ | |
+void AppMenuModel::setWindowIdByLong(qulonglong id) | |
+{ | |
+ setWindowId((WId)id); | |
+} | |
+ | |
+void AppMenuModel::setWindowId(WId id) | |
+{ | |
+ if (m_useActiveWindowId) { | |
+ qApp->removeNativeEventFilter(this); | |
+ } | |
if (!id) { | |
setMenuAvailable(false); | |
@@ -202,8 +241,11 @@ void AppMenuModel::onActiveWindowChanged(WId id) | |
// monitor whether an app menu becomes available later | |
// this can happen when an app starts, shows its window, and only later announces global menu (e.g. Firefox) | |
- qApp->installNativeEventFilter(this); | |
+ if (m_useActiveWindowId) { | |
+ qApp->installNativeEventFilter(this); | |
+ } | |
m_currentWindowId = id; | |
+ emit windowIdChanged(); | |
//no menu found, set it to unavailable | |
setMenuAvailable(false); | |
@@ -219,9 +261,12 @@ QHash<int, QByteArray> AppMenuModel::roleNames() const | |
QHash<int, QByteArray> roleNames; | |
roleNames[MenuRole] = QByteArrayLiteral("activeMenu"); | |
roleNames[ActionRole] = QByteArrayLiteral("activeActions"); | |
+ roleNames[ActionIdRole] = QByteArrayLiteral("actionId"); | |
return roleNames; | |
} | |
+static const char *DBUSMENU_PROPERTY_ID = "_dbusmenu_id"; // From libdbusmenuqt/dbusmenuimporter.cpp | |
+ | |
QVariant AppMenuModel::data(const QModelIndex &index, int role) const | |
{ | |
const int row = index.row(); | |
@@ -238,6 +283,8 @@ QVariant AppMenuModel::data(const QModelIndex &index, int role) const | |
return actions.at(row)->text(); | |
} else if (role == ActionRole) { | |
return qVariantFromValue((void *) actions.at(row)); | |
+ } else if (role == ActionIdRole) { | |
+ return actions.at(row)->property(DBUSMENU_PROPERTY_ID).toInt(); | |
} | |
return QVariant(); | |
diff --git a/applets/appmenu/plugin/appmenumodel.h b/applets/appmenu/plugin/appmenumodel.h | |
index 7bd35fc..5632e29 100644 | |
--- a/applets/appmenu/plugin/appmenumodel.h | |
+++ b/applets/appmenu/plugin/appmenumodel.h | |
@@ -36,6 +36,8 @@ class AppMenuModel : public QAbstractListModel, public QAbstractNativeEventFilte | |
Q_OBJECT | |
Q_PROPERTY(bool menuAvailable READ menuAvailable WRITE setMenuAvailable NOTIFY menuAvailableChanged) | |
+ Q_PROPERTY(bool useActiveWindowId READ useActiveWindowId WRITE setUseActiveWindowId NOTIFY useActiveWindowIdChanged) | |
+ // Q_PROPERTY(int windowId READ windowId WRITE setWindowId NOTIFY windowIdChanged) | |
public: | |
explicit AppMenuModel(QObject *parent = nullptr); | |
@@ -43,7 +45,8 @@ public: | |
enum AppMenuRole { | |
MenuRole = Qt::UserRole+1, // TODO this should be Qt::DisplayRole | |
- ActionRole | |
+ ActionRole, | |
+ ActionIdRole | |
}; | |
QVariant data(const QModelIndex &index, int role) const override; | |
@@ -55,6 +58,15 @@ public: | |
bool menuAvailable() const; | |
void setMenuAvailable(bool set); | |
+ bool useActiveWindowId() const; | |
+ void setUseActiveWindowId(bool set); | |
+ | |
+ WId windowId() const; | |
+ Q_INVOKABLE void setWindowIdByLong(qulonglong set); | |
+ void setWindowId(WId set); | |
+ | |
+ void setWindowIdByDecoration(WId set); | |
+ | |
signals: | |
void requestActivateIndex(int index); | |
@@ -68,10 +80,13 @@ private Q_SLOTS: | |
signals: | |
void menuAvailableChanged(); | |
void modelNeedsUpdate(); | |
+ void useActiveWindowIdChanged(); | |
+ void windowIdChanged(); | |
private: | |
bool m_menuAvailable; | |
bool m_updatePending = false; | |
+ bool m_useActiveWindowId = true; | |
WId m_currentWindowId = 0; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment