Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 3fa1cc6b authored by Michail Vourlakos's avatar Michail Vourlakos

mage global menu screen aware

Summary:
--a new screenGeometry property is added in the
AppMenuModel in order to be used for filtering
windows based on their geometry.

BUG: 384895, 395853

Test Plan:
--validate that when moving a window between different screens the global menu applet is updated accordingly
--checkout that nothing has broke because of this new behavior

Reviewers: #plasma, broulik, davidedmundson

Reviewed By: #plasma, davidedmundson

Subscribers: mart, davidedmundson, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D16768
parent a46179d9
......@@ -104,7 +104,7 @@ Item {
Repeater {
id: buttonRepeater
model: appMenuModel
model: !appMenuModel.menuHidden ? appMenuModel : null
PlasmaComponents.ToolButton {
readonly property int buttonIndex: index
......@@ -148,6 +148,7 @@ Item {
AppMenuPrivate.AppMenuModel {
id: appMenuModel
screenGeometry: plasmoid.screenGeometry
onRequestActivateIndex: plasmoid.nativeInterface.requestActivateIndex(index)
Component.onCompleted: {
plasmoid.nativeInterface.model = appMenuModel
......
......@@ -69,12 +69,22 @@ AppMenuModel::AppMenuModel(QObject *parent)
m_serviceWatcher(new QDBusServiceWatcher(this))
{
connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &AppMenuModel::onActiveWindowChanged);
connect(KWindowSystem::self()
, static_cast<void (KWindowSystem::*)(WId)>(&KWindowSystem::windowChanged)
, this
, &AppMenuModel::onWindowChanged);
connect(this, &AppMenuModel::modelNeedsUpdate, this, [this] {
if (!m_updatePending) {
m_updatePending = true;
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
}
});
connect(this, &AppMenuModel::screenGeometryChanged, this, [this] {
onWindowChanged(m_currentWindowId);
});
onActiveWindowChanged(KWindowSystem::activeWindow());
m_serviceWatcher->setConnection(QDBusConnection::sessionBus());
......@@ -100,10 +110,39 @@ void AppMenuModel::setMenuAvailable(bool set)
{
if (m_menuAvailable != set) {
m_menuAvailable = set;
setMenuHidden(false);
emit menuAvailableChanged();
}
}
bool AppMenuModel::menuHidden() const
{
return m_menuHidden;
}
void AppMenuModel::setMenuHidden(bool hide)
{
if (m_menuHidden != hide) {
m_menuHidden = hide;
emit menuHiddenChanged();
}
}
QRect AppMenuModel::screenGeometry() const
{
return m_screenGeometry;
}
void AppMenuModel::setScreenGeometry(QRect geometry)
{
if (m_screenGeometry == geometry) {
return;
}
m_screenGeometry = geometry;
emit screenGeometryChanged();
}
int AppMenuModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
......@@ -187,23 +226,27 @@ void AppMenuModel::onActiveWindowChanged(WId id)
return;
}
m_currentWindowId = id;
WId transientId = info.transientFor();
// lok at transient windows first
while (transientId) {
if (updateMenuFromWindowIfHasMenu(transientId)) {
setMenuHidden(false);
return;
}
transientId = KWindowInfo(transientId, nullptr, NET::WM2TransientFor).transientFor();
}
if (updateMenuFromWindowIfHasMenu(id)) {
setMenuHidden(false);
return;
}
// 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);
m_currentWindowId = id;
m_delayedMenuWindowId = id;
//no menu found, set it to unavailable
setMenuAvailable(false);
......@@ -213,6 +256,15 @@ void AppMenuModel::onActiveWindowChanged(WId id)
}
void AppMenuModel::onWindowChanged(WId id)
{
if (m_currentWindowId == id) {
KWindowInfo info(id, NET::WMState | NET::WMGeometry);
const bool contained = m_screenGeometry.isNull() || m_screenGeometry.contains(info.geometry().center());
setMenuHidden(info.isMinimized() || !contained);
}
}
QHash<int, QByteArray> AppMenuModel::roleNames() const
{
......@@ -321,7 +373,7 @@ bool AppMenuModel::nativeEventFilter(const QByteArray &eventType, void *message,
const uint8_t type = e->response_type & ~0x80;
if (type == XCB_PROPERTY_NOTIFY) {
auto *event = reinterpret_cast<xcb_property_notify_event_t *>(e);
if (event->window == m_currentWindowId) {
if (event->window == m_delayedMenuWindowId) {
auto serviceNameAtom = s_atoms.value(s_x11AppMenuServiceNamePropertyName);
auto objectPathAtom = s_atoms.value(s_x11AppMenuObjectPathPropertyName);
......
......@@ -27,6 +27,7 @@
#include <QStringList>
#include <KWindowSystem>
#include <QPointer>
#include <QRect>
class QMenu;
class QAction;
......@@ -39,6 +40,9 @@ class AppMenuModel : public QAbstractListModel, public QAbstractNativeEventFilte
Q_OBJECT
Q_PROPERTY(bool menuAvailable READ menuAvailable WRITE setMenuAvailable NOTIFY menuAvailableChanged)
Q_PROPERTY(bool menuHidden READ menuHidden NOTIFY menuHiddenChanged)
Q_PROPERTY(QRect screenGeometry READ screenGeometry WRITE setScreenGeometry NOTIFY screenGeometryChanged)
public:
explicit AppMenuModel(QObject *parent = nullptr);
......@@ -58,6 +62,11 @@ public:
bool menuAvailable() const;
void setMenuAvailable(bool set);
bool menuHidden() const;
QRect screenGeometry() const;
void setScreenGeometry(QRect geometry);
signals:
void requestActivateIndex(int index);
......@@ -66,17 +75,27 @@ protected:
private Q_SLOTS:
void onActiveWindowChanged(WId id);
void onWindowChanged(WId id);
void setMenuHidden(bool hide);
void update();
signals:
void menuAvailableChanged();
void menuHiddenChanged();
void modelNeedsUpdate();
void screenGeometryChanged();
private:
bool m_menuAvailable;
bool m_menuHidden = false;
bool m_updatePending = false;
QRect m_screenGeometry;
//! current active window used
WId m_currentWindowId = 0;
//! window that its menu initialization may be delayed
WId m_delayedMenuWindowId = 0;
QPointer<QMenu> m_menu;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment