Add hint similar to autohide to raise/lower a window

Add action type to screen edge show to allow raise/lower as well as
autohide

Add an action type to screen edge show to allow raise/lower as well as
autohide. This uses the same atom, using a mask to separate type and
location.

The logic for handling geometry changes is moved from the screenedge to
the client so that we can handle both types without screenedge needing
to know what the raise is for.

REVIEW: 124272
master
David Edmundson 9 years ago
parent 78e9a56cd1
commit 04ab8554aa

@ -28,6 +28,7 @@ AbstractClient::AbstractClient(QObject *parent)
, m_screen(0)
, m_fullscreen(false)
, m_hiddenInternal(false)
, m_keepBelow(false)
, m_geometry()
{
}
@ -91,4 +92,15 @@ QRect AbstractClient::geometry() const
return m_geometry;
}
bool AbstractClient::keepBelow() const
{
return m_keepBelow;
}
void AbstractClient::setKeepBelow(bool keepBelow)
{
m_keepBelow = keepBelow;
emit keepBelowChanged();
}
}

@ -39,21 +39,25 @@ public:
bool isFullScreen() const;
bool isHiddenInternal() const;
QRect geometry() const;
bool keepBelow() const;
void setActive(bool active);
void setScreen(int screen);
void setFullScreen(bool set);
void setHiddenInternal(bool set);
void setGeometry(const QRect &rect);
void setKeepBelow(bool);
Q_SIGNALS:
void geometryChanged();
void keepBelowChanged();
private:
bool m_active;
int m_screen;
bool m_fullscreen;
bool m_hiddenInternal;
bool m_keepBelow;
QRect m_geometry;
};

@ -31,6 +31,7 @@ Client::~Client() = default;
void Client::showOnScreenEdge()
{
setKeepBelow(false);
setHiddenInternal(false);
}

@ -749,31 +749,15 @@ void TestScreenEdges::testClientEdge()
s->init();
s->reserve(&client, KWin::ElectricBottom);
QPointer<Edge> edge = s->findChildren<Edge*>().last();
QCOMPARE(&client, edge->client());
QCOMPARE(edge->isScreenEdge(), true);
QCOMPARE(edge->isCorner(), false);
QCOMPARE(edge->isBottom(), true);
QCOMPARE(edge->isReserved(), false);
// reserve again shouldn't change anything
s->reserve(&client, KWin::ElectricBottom);
QCOMPARE(edge.data(), s->findChildren<Edge*>().last());
QCOMPARE(&client, edge->client());
QCOMPARE(edge->isReserved(), false);
// let's set the client to be hidden
client.setHiddenInternal(true);
QPointer<Edge> edge = s->findChildren<Edge*>().last();
s->reserve(&client, KWin::ElectricBottom);
QCOMPARE(edge.data(), s->findChildren<Edge*>().last());
QCOMPARE(edge->isReserved(), true);
// let's change the geometry, which should destroy the edge
QCOMPARE(client.isHiddenInternal(), true);
QCOMPARE(edge.isNull(), false);
client.setGeometry(QRect(2, 2, 20, 20));
QCOMPARE(client.isHiddenInternal(), false);
QCOMPARE(edge.isNull(), true);
// for none of the edges it should be able to be set
for (int i = 0; i < ELECTRIC_COUNT; ++i) {
client.setHiddenInternal(true);
@ -848,6 +832,30 @@ void TestScreenEdges::testClientEdge()
s->check(QPoint(50, 0), QDateTime::currentDateTime());
QCOMPARE(client.isHiddenInternal(), true);
QCOMPARE(Cursor::pos(), QPoint(50, 0));
// set to windows can cover
client.setGeometry(screens()->geometry());
client.setHiddenInternal(false);
client.setKeepBelow(true);
s->reserve(&client, KWin::ElectricLeft);
QCOMPARE(client.keepBelow(), true);
QCOMPARE(client.isHiddenInternal(), false);
xcb_enter_notify_event_t event2;
Cursor::setPos(0, 50);
event2.root_x = 0;
event2.root_y = 50;
event2.event_x = 0;
event2.event_y = 50;
event2.root = XCB_WINDOW_NONE;
event2.child = XCB_WINDOW_NONE;
event2.event = s->windows().first();
event2.same_screen_focus = 1;
event2.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event2));
QCOMPARE(client.keepBelow(), false);
QCOMPARE(client.isHiddenInternal(), false);
QCOMPARE(Cursor::pos(), QPoint(1, 50));
}
QTEST_MAIN(TestScreenEdges)

@ -2142,9 +2142,14 @@ Xcb::Property Client::fetchShowOnScreenEdge() const
void Client::readShowOnScreenEdge(Xcb::Property &property)
{
//value comes in two parts, edge in the lower byte
//then the type in the upper byte
// 0 = autohide
// 1 = raise in front on activate
const uint32_t value = property.value<uint32_t>(ElectricNone);
ElectricBorder border = ElectricNone;
switch (value) {
switch (value & 0xFF) {
case 0:
border = ElectricTop;
break;
@ -2159,8 +2164,32 @@ void Client::readShowOnScreenEdge(Xcb::Property &property)
break;
}
if (border != ElectricNone) {
hideClient(true);
ScreenEdges::self()->reserve(this, border);
disconnect(m_edgeRemoveConnection);
bool successfullyHidden = false;
if (((value >> 8) & 0xFF) == 1) {
setKeepBelow(true);
successfullyHidden = keepBelow(); //request could have failed due to user kwin rules
m_edgeRemoveConnection = connect(this, &AbstractClient::keepBelowChanged, this, [this](){
if (!keepBelow()) {
ScreenEdges::self()->reserve(this, ElectricNone);
}
});
} else {
hideClient(true);
successfullyHidden = isHiddenInternal();
m_edgeRemoveConnection = connect(this, &Client::geometryChanged, this, [this](){
ScreenEdges::self()->reserve(this, ElectricNone);
});
}
if (successfullyHidden) {
ScreenEdges::self()->reserve(this, border);
} else {
ScreenEdges::self()->reserve(this, ElectricNone);
}
} else if (!property.isNull() && property->type != XCB_ATOM_NONE) {
// property value is incorrect, delete the property
// so that the client knows that it is not hidden
@ -2168,8 +2197,9 @@ void Client::readShowOnScreenEdge(Xcb::Property &property)
} else {
// restore
// TODO: add proper unreserve
//this will call showOnScreenEdge to reset the state
ScreenEdges::self()->reserve(this, ElectricNone);
hideClient(false);
}
}
@ -2181,7 +2211,10 @@ void Client::updateShowOnScreenEdge()
void Client::showOnScreenEdge()
{
disconnect(m_edgeRemoveConnection);
hideClient(false);
setKeepBelow(false);
xcb_delete_property(connection(), window(), atoms->kde_screen_edge_show);
}

@ -772,6 +772,8 @@ private:
QList<QMetaObject::Connection> m_connections;
bool m_clientSideDecorated;
QMetaObject::Connection m_edgeRemoveConnection;
};
/**

@ -654,8 +654,6 @@ ScreenEdges::ScreenEdges(QObject *parent)
return;
}
deleteEdgeForClient(client);
QObject::disconnect(client, &Client::geometryChanged,
ScreenEdges::self(), &ScreenEdges::handleClientGeometryChanged);
});
}
@ -1087,7 +1085,7 @@ void ScreenEdges::reserve(Client *client, ElectricBorder border)
if ((*it)->client() == client) {
hadBorder = true;
if ((*it)->border() == border) {
if (client->isHiddenInternal() && !(*it)->isReserved()) {
if (!(*it)->isReserved()) {
(*it)->reserve();
}
return;
@ -1101,10 +1099,8 @@ void ScreenEdges::reserve(Client *client, ElectricBorder border)
}
if (border != ElectricNone) {
connect(client, &Client::geometryChanged, this, &ScreenEdges::handleClientGeometryChanged, Qt::UniqueConnection);
createEdgeForClient(client, border);
} else {
disconnect(client, &Client::geometryChanged, this, &ScreenEdges::handleClientGeometryChanged);
if (hadBorder) // show again
client->showOnScreenEdge();
}
@ -1176,22 +1172,13 @@ void ScreenEdges::createEdgeForClient(Client *client, ElectricBorder border)
Edge *edge = createEdge(border, x, y, width, height, false);
edge->setClient(client);
m_edges.append(edge);
if (client->isHiddenInternal()) {
edge->reserve();
}
edge->reserve();
} else {
// we could not create an edge window, so don't allow the window to hide
client->showOnScreenEdge();
}
}
void ScreenEdges::handleClientGeometryChanged()
{
Client *c = static_cast<Client*>(sender());
deleteEdgeForClient(c);
c->showOnScreenEdge();
}
void ScreenEdges::deleteEdgeForClient(Client* c)
{
auto it = m_edges.begin();

@ -364,7 +364,6 @@ private:
bool handleEnterNotifiy(xcb_window_t window, const QPoint &point, const QDateTime &timestamp);
bool handleDndNotify(xcb_window_t window, const QPoint &point);
void createEdgeForClient(Client *client, ElectricBorder border);
void handleClientGeometryChanged();
void deleteEdgeForClient(Client *client);
bool m_desktopSwitching;
bool m_desktopSwitchingMovingClients;

@ -25,6 +25,7 @@
#include <QTimer>
#include <QToolButton>
#include <QWidget>
#include <QCheckBox>
#include "../xcbutils.h"
int main(int argc, char **argv)
@ -37,15 +38,21 @@ int main(int argc, char **argv)
KWin::Xcb::Atom atom(QByteArrayLiteral("_KDE_NET_WM_SCREEN_EDGE_SHOW"));
uint32_t value = 2;
uint32_t locationValue = 2;
uint32_t actionValue = 0;
QPushButton *hideWindowButton = new QPushButton(QStringLiteral("Hide"), widget.data());
QObject::connect(hideWindowButton, &QPushButton::clicked, [&widget, &atom, &value]() {
QObject::connect(hideWindowButton, &QPushButton::clicked, [&widget, &atom, &locationValue, &actionValue]() {
uint32_t value = locationValue | (actionValue << 8);
xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, widget->winId(), atom, XCB_ATOM_CARDINAL, 32, 1, &value);
});
QPushButton *hideAndRestoreButton = new QPushButton(QStringLiteral("Hide and Restore after 10 sec"), widget.data());
QTimer *restoreTimer = new QTimer(hideAndRestoreButton);
restoreTimer->setSingleShot(true);
QObject::connect(hideAndRestoreButton, &QPushButton::clicked, [&widget, &atom, &value, restoreTimer]() {
QObject::connect(hideAndRestoreButton, &QPushButton::clicked, [&widget, &atom, &locationValue, &actionValue, restoreTimer]() {
uint32_t value = locationValue | (actionValue << 8);
xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, widget->winId(), atom, XCB_ATOM_CARDINAL, 32, 1, &value);
restoreTimer->start(10000);
});
@ -54,34 +61,40 @@ int main(int argc, char **argv)
});
QToolButton *edgeButton = new QToolButton(widget.data());
QCheckBox *raiseCheckBox = new QCheckBox("Raise:", widget.data());
QObject::connect(raiseCheckBox, &QCheckBox::toggled, [&actionValue](bool checked) {
actionValue = checked ? 1: 0;
});
edgeButton->setText(QStringLiteral("Edge"));
edgeButton->setPopupMode(QToolButton::MenuButtonPopup);
QMenu *edgeButtonMenu = new QMenu(edgeButton);
QObject::connect(edgeButtonMenu->addAction("Top"), &QAction::triggered, [&widget, &value]() {
QObject::connect(edgeButtonMenu->addAction("Top"), &QAction::triggered, [&widget, &locationValue]() {
const QRect geo = QGuiApplication::primaryScreen()->geometry();
widget->setGeometry(geo.x(), geo.y(), geo.width(), 100);
value = 0;
locationValue = 0;
});
QObject::connect(edgeButtonMenu->addAction("Right"), &QAction::triggered, [&widget, &value]() {
QObject::connect(edgeButtonMenu->addAction("Right"), &QAction::triggered, [&widget, &locationValue]() {
const QRect geo = QGuiApplication::primaryScreen()->geometry();
widget->setGeometry(geo.x() + geo.width() - 100, geo.y(), 100, geo.height());
value = 1;
locationValue = 1;
});
QObject::connect(edgeButtonMenu->addAction("Bottom"), &QAction::triggered, [&widget, &value]() {
QObject::connect(edgeButtonMenu->addAction("Bottom"), &QAction::triggered, [&widget, &locationValue]() {
const QRect geo = QGuiApplication::primaryScreen()->geometry();
widget->setGeometry(geo.x(), geo.y() + geo.height() - 100, geo.width(), 100);
value = 2;
locationValue = 2;
});
QObject::connect(edgeButtonMenu->addAction("Left"), &QAction::triggered, [&widget, &value]() {
QObject::connect(edgeButtonMenu->addAction("Left"), &QAction::triggered, [&widget, &locationValue]() {
const QRect geo = QGuiApplication::primaryScreen()->geometry();
widget->setGeometry(geo.x(), geo.y(), 100, geo.height());
value = 3;
locationValue = 3;
});
edgeButtonMenu->addSeparator();
QObject::connect(edgeButtonMenu->addAction("Floating"), &QAction::triggered, [&widget, &value]() {
QObject::connect(edgeButtonMenu->addAction("Floating"), &QAction::triggered, [&widget, &locationValue]() {
const QRect geo = QGuiApplication::primaryScreen()->geometry();
widget->setGeometry(QRect(geo.center(), QSize(100, 100)));
value = 4;
locationValue = 4;
});
edgeButton->setMenu(edgeButtonMenu);

Loading…
Cancel
Save