2015-03-04 08:21:10 +00:00
|
|
|
/********************************************************************
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
|
|
|
|
|
|
|
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
Copyright (C) 2018 David Edmundson <davidedmundson@kde.org>
|
2015-03-04 08:21:10 +00:00
|
|
|
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
*********************************************************************/
|
|
|
|
#include "shell_client.h"
|
2015-05-27 08:16:46 +00:00
|
|
|
#include "composite.h"
|
2015-10-29 09:41:25 +00:00
|
|
|
#include "cursor.h"
|
2015-03-04 08:21:10 +00:00
|
|
|
#include "deleted.h"
|
2016-08-30 11:16:52 +00:00
|
|
|
#include "placement.h"
|
2016-09-15 19:03:40 +00:00
|
|
|
#include "screenedge.h"
|
2015-05-27 08:16:46 +00:00
|
|
|
#include "screens.h"
|
2019-07-29 18:24:09 +00:00
|
|
|
#ifdef KWIN_BUILD_TABBOX
|
|
|
|
#include "tabbox.h"
|
|
|
|
#endif
|
|
|
|
#include "virtualdesktops.h"
|
2015-03-04 08:21:10 +00:00
|
|
|
#include "wayland_server.h"
|
2015-05-27 08:16:46 +00:00
|
|
|
#include "workspace.h"
|
2015-12-17 14:47:36 +00:00
|
|
|
#include "decorations/decorationbridge.h"
|
|
|
|
#include "decorations/decoratedclient.h"
|
|
|
|
#include <KDecoration2/Decoration>
|
|
|
|
#include <KDecoration2/DecoratedClient>
|
2015-03-04 08:21:10 +00:00
|
|
|
|
2015-05-18 12:51:40 +00:00
|
|
|
#include <KWayland/Client/surface.h>
|
2017-08-24 16:57:30 +00:00
|
|
|
#include <KWayland/Server/display.h>
|
2016-11-15 15:48:20 +00:00
|
|
|
#include <KWayland/Server/clientconnection.h>
|
2015-10-29 09:41:25 +00:00
|
|
|
#include <KWayland/Server/seat_interface.h>
|
2015-03-04 08:21:10 +00:00
|
|
|
#include <KWayland/Server/shell_interface.h>
|
|
|
|
#include <KWayland/Server/surface_interface.h>
|
|
|
|
#include <KWayland/Server/buffer_interface.h>
|
2015-06-09 17:10:56 +00:00
|
|
|
#include <KWayland/Server/plasmashell_interface.h>
|
2015-07-15 09:24:19 +00:00
|
|
|
#include <KWayland/Server/shadow_interface.h>
|
2015-12-17 10:14:54 +00:00
|
|
|
#include <KWayland/Server/server_decoration_interface.h>
|
2015-06-09 22:59:53 +00:00
|
|
|
#include <KWayland/Server/qtsurfaceextension_interface.h>
|
2015-11-05 10:30:02 +00:00
|
|
|
#include <KWayland/Server/plasmawindowmanagement_interface.h>
|
2017-12-22 14:22:24 +00:00
|
|
|
#include <KWayland/Server/appmenu_interface.h>
|
2018-01-04 18:32:18 +00:00
|
|
|
#include <KWayland/Server/server_decoration_palette_interface.h>
|
2019-01-01 17:37:18 +00:00
|
|
|
#include <KWayland/Server/xdgdecoration_interface.h>
|
2017-12-22 14:22:24 +00:00
|
|
|
|
2018-03-04 16:05:46 +00:00
|
|
|
#include <QFileInfo>
|
2015-05-18 12:51:40 +00:00
|
|
|
|
2016-11-15 15:48:20 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
2019-07-09 19:19:26 +00:00
|
|
|
|
|
|
|
#include <csignal>
|
2016-11-15 15:48:20 +00:00
|
|
|
|
2019-01-13 16:50:32 +00:00
|
|
|
Q_DECLARE_METATYPE(NET::WindowType)
|
|
|
|
|
2015-03-04 08:21:10 +00:00
|
|
|
using namespace KWayland::Server;
|
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
|
|
|
ShellClient::ShellClient(ShellSurfaceInterface *surface)
|
2015-03-16 08:14:04 +00:00
|
|
|
: AbstractClient()
|
2015-03-04 08:21:10 +00:00
|
|
|
, m_shellSurface(surface)
|
2016-04-22 12:13:37 +00:00
|
|
|
, m_xdgShellSurface(nullptr)
|
|
|
|
, m_xdgShellPopup(nullptr)
|
|
|
|
, m_internal(surface->client() == waylandServer()->internalConnection())
|
|
|
|
{
|
|
|
|
setSurface(surface->surface());
|
|
|
|
init();
|
[wayland] Apply window rules only to xdg-shell clients
Summary:
There are rules that have to be applied only once, e.g. every Remember
and Apply Initially rule, as well rules that need to configure the client,
e.g. size, etc. In the best scenario the compositor would evaluate such
rules when the client is about to be mapped.
This change limits window rules only to xdg-shell clients because right
now only this protocol lets compositors to intervene in the client
initialization process. Also, it makes things a bit easier for us on the
compositor side.
xdg-shell protocol satisfies most of ours requirements to implement window
rules, but not all of them. If the client is about to be mapped for the
second time and its size is forced by a rule, then compositor may need
to configure it. Currently, xdg-shell protocol doesn't have any mechanism
that a client could use to notify the compositor about its intent to map.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: fmonteiro, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19411
2019-07-09 11:58:57 +00:00
|
|
|
m_isInitialized = true;
|
2016-04-22 12:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ShellClient::ShellClient(XdgShellSurfaceInterface *surface)
|
|
|
|
: AbstractClient()
|
|
|
|
, m_shellSurface(nullptr)
|
|
|
|
, m_xdgShellSurface(surface)
|
|
|
|
, m_xdgShellPopup(nullptr)
|
|
|
|
, m_internal(surface->client() == waylandServer()->internalConnection())
|
|
|
|
{
|
|
|
|
setSurface(surface->surface());
|
2019-02-26 13:41:07 +00:00
|
|
|
m_requestGeometryBlockCounter++;
|
2016-04-22 12:13:37 +00:00
|
|
|
init();
|
2019-02-26 13:41:07 +00:00
|
|
|
connect(surface->surface(), &SurfaceInterface::committed, this, &ShellClient::finishInit);
|
2016-04-22 12:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ShellClient::ShellClient(XdgShellPopupInterface *surface)
|
|
|
|
: AbstractClient()
|
|
|
|
, m_shellSurface(nullptr)
|
|
|
|
, m_xdgShellSurface(nullptr)
|
|
|
|
, m_xdgShellPopup(surface)
|
2015-12-18 16:26:21 +00:00
|
|
|
, m_internal(surface->client() == waylandServer()->internalConnection())
|
2015-03-04 08:21:10 +00:00
|
|
|
{
|
|
|
|
setSurface(surface->surface());
|
2019-02-26 13:41:07 +00:00
|
|
|
m_requestGeometryBlockCounter++;
|
2016-04-18 09:55:40 +00:00
|
|
|
init();
|
2019-02-26 13:41:07 +00:00
|
|
|
connect(surface->surface(), &SurfaceInterface::committed, this, &ShellClient::finishInit);
|
2016-04-18 09:55:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ShellClient::~ShellClient() = default;
|
|
|
|
|
2016-04-22 12:13:37 +00:00
|
|
|
template <class T>
|
|
|
|
void ShellClient::initSurface(T *shellSurface)
|
|
|
|
{
|
2016-10-31 14:56:01 +00:00
|
|
|
m_caption = shellSurface->title().simplified();
|
2017-08-20 06:56:13 +00:00
|
|
|
// delay till end of init
|
|
|
|
QTimer::singleShot(0, this, &ShellClient::updateCaption);
|
2016-04-22 12:13:37 +00:00
|
|
|
connect(shellSurface, &T::destroyed, this, &ShellClient::destroyClient);
|
|
|
|
connect(shellSurface, &T::titleChanged, this,
|
|
|
|
[this] (const QString &s) {
|
2017-08-20 06:56:13 +00:00
|
|
|
const auto oldSuffix = m_captionSuffix;
|
2016-10-31 14:56:01 +00:00
|
|
|
m_caption = s.simplified();
|
2017-08-20 06:56:13 +00:00
|
|
|
updateCaption();
|
|
|
|
if (m_captionSuffix == oldSuffix) {
|
|
|
|
// don't emit caption change twice
|
|
|
|
// it already got emitted by the changing suffix
|
|
|
|
emit captionChanged();
|
|
|
|
}
|
2016-04-22 12:13:37 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
connect(shellSurface, &T::moveRequested, this,
|
|
|
|
[this] {
|
|
|
|
// TODO: check the seat and serial
|
|
|
|
performMouseCommand(Options::MouseMove, Cursor::pos());
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2018-03-04 16:05:46 +00:00
|
|
|
// determine the resource name, this is inspired from ICCCM 4.1.2.5
|
|
|
|
// the binary name of the invoked client
|
|
|
|
QFileInfo info{shellSurface->client()->executablePath()};
|
|
|
|
QByteArray resourceName;
|
|
|
|
if (info.exists()) {
|
|
|
|
resourceName = info.fileName().toUtf8();
|
|
|
|
}
|
|
|
|
setResourceClass(resourceName, shellSurface->windowClass());
|
[wayland] Apply window rules only to xdg-shell clients
Summary:
There are rules that have to be applied only once, e.g. every Remember
and Apply Initially rule, as well rules that need to configure the client,
e.g. size, etc. In the best scenario the compositor would evaluate such
rules when the client is about to be mapped.
This change limits window rules only to xdg-shell clients because right
now only this protocol lets compositors to intervene in the client
initialization process. Also, it makes things a bit easier for us on the
compositor side.
xdg-shell protocol satisfies most of ours requirements to implement window
rules, but not all of them. If the client is about to be mapped for the
second time and its size is forced by a rule, then compositor may need
to configure it. Currently, xdg-shell protocol doesn't have any mechanism
that a client could use to notify the compositor about its intent to map.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: fmonteiro, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19411
2019-07-09 11:58:57 +00:00
|
|
|
setDesktopFileName(shellSurface->windowClass());
|
2016-04-22 12:13:37 +00:00
|
|
|
connect(shellSurface, &T::windowClassChanged, this,
|
2018-03-04 16:05:46 +00:00
|
|
|
[this, resourceName] (const QByteArray &windowClass) {
|
|
|
|
setResourceClass(resourceName, windowClass);
|
[wayland] Apply window rules only to xdg-shell clients
Summary:
There are rules that have to be applied only once, e.g. every Remember
and Apply Initially rule, as well rules that need to configure the client,
e.g. size, etc. In the best scenario the compositor would evaluate such
rules when the client is about to be mapped.
This change limits window rules only to xdg-shell clients because right
now only this protocol lets compositors to intervene in the client
initialization process. Also, it makes things a bit easier for us on the
compositor side.
xdg-shell protocol satisfies most of ours requirements to implement window
rules, but not all of them. If the client is about to be mapped for the
second time and its size is forced by a rule, then compositor may need
to configure it. Currently, xdg-shell protocol doesn't have any mechanism
that a client could use to notify the compositor about its intent to map.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: fmonteiro, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19411
2019-07-09 11:58:57 +00:00
|
|
|
if (m_isInitialized && supportsWindowRules()) {
|
2018-03-12 17:06:33 +00:00
|
|
|
setupWindowRules(true);
|
|
|
|
applyWindowRules();
|
|
|
|
}
|
2016-10-27 13:59:08 +00:00
|
|
|
setDesktopFileName(windowClass);
|
2016-04-22 12:13:37 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
connect(shellSurface, &T::resizeRequested, this,
|
|
|
|
[this] (SeatInterface *seat, quint32 serial, Qt::Edges edges) {
|
|
|
|
// TODO: check the seat and serial
|
|
|
|
Q_UNUSED(seat)
|
|
|
|
Q_UNUSED(serial)
|
|
|
|
if (!isResizable() || isShade()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (isMoveResize()) {
|
|
|
|
finishMoveResize(false);
|
|
|
|
}
|
|
|
|
setMoveResizePointerButtonDown(true);
|
|
|
|
setMoveOffset(Cursor::pos() - pos()); // map from global
|
|
|
|
setInvertedMoveOffset(rect().bottomRight() - moveOffset());
|
|
|
|
setUnrestrictedMoveResize(false);
|
|
|
|
auto toPosition = [edges] {
|
|
|
|
Position pos = PositionCenter;
|
|
|
|
if (edges.testFlag(Qt::TopEdge)) {
|
|
|
|
pos = PositionTop;
|
|
|
|
} else if (edges.testFlag(Qt::BottomEdge)) {
|
|
|
|
pos = PositionBottom;
|
|
|
|
}
|
|
|
|
if (edges.testFlag(Qt::LeftEdge)) {
|
|
|
|
pos = Position(pos | PositionLeft);
|
|
|
|
} else if (edges.testFlag(Qt::RightEdge)) {
|
|
|
|
pos = Position(pos | PositionRight);
|
|
|
|
}
|
|
|
|
return pos;
|
|
|
|
};
|
|
|
|
setMoveResizePointerMode(toPosition());
|
|
|
|
if (!startMoveResize())
|
|
|
|
setMoveResizePointerButtonDown(false);
|
|
|
|
updateCursor();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
connect(shellSurface, &T::maximizedChanged, this,
|
|
|
|
[this] (bool maximized) {
|
2016-09-12 12:41:03 +00:00
|
|
|
if (m_shellSurface && isFullScreen()) {
|
|
|
|
// ignore for wl_shell - there it is mutual exclusive and messes with the geometry
|
|
|
|
return;
|
|
|
|
}
|
2019-07-09 18:07:21 +00:00
|
|
|
|
|
|
|
// If the maximized state of the client hasn't been changed due to a window
|
|
|
|
// rule or because the requested state is the same as the current, then the
|
|
|
|
// compositor still has to send a configure event.
|
|
|
|
RequestGeometryBlocker blocker(this);
|
|
|
|
|
2016-04-22 12:13:37 +00:00
|
|
|
maximize(maximized ? MaximizeFull : MaximizeRestore);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
// TODO: consider output!
|
|
|
|
connect(shellSurface, &T::fullscreenChanged, this, &ShellClient::clientFullScreenChanged);
|
|
|
|
|
|
|
|
connect(shellSurface, &T::transientForChanged, this, &ShellClient::setTransient);
|
2017-08-24 16:57:30 +00:00
|
|
|
|
|
|
|
connect(this, &ShellClient::geometryChanged, this, &ShellClient::updateClientOutputs);
|
|
|
|
connect(screens(), &Screens::changed, this, &ShellClient::updateClientOutputs);
|
2016-04-22 12:13:37 +00:00
|
|
|
}
|
|
|
|
|
2016-04-18 09:55:40 +00:00
|
|
|
void ShellClient::init()
|
|
|
|
{
|
2016-10-27 13:59:08 +00:00
|
|
|
connect(this, &ShellClient::desktopFileNameChanged, this, &ShellClient::updateIcon);
|
2015-05-18 12:51:40 +00:00
|
|
|
createWindowId();
|
2015-03-04 08:21:10 +00:00
|
|
|
setupCompositing();
|
2018-02-04 13:19:23 +00:00
|
|
|
updateIcon();
|
2016-04-18 09:55:40 +00:00
|
|
|
SurfaceInterface *s = surface();
|
|
|
|
Q_ASSERT(s);
|
|
|
|
if (s->buffer()) {
|
2015-03-04 08:21:10 +00:00
|
|
|
setReadyForPainting();
|
2016-06-03 11:37:24 +00:00
|
|
|
if (shouldExposeToWindowManagement()) {
|
|
|
|
setupWindowManagementInterface();
|
|
|
|
}
|
2015-06-03 19:19:00 +00:00
|
|
|
m_unmapped = false;
|
2016-11-04 16:52:49 +00:00
|
|
|
m_clientSize = s->size();
|
2015-03-04 08:21:10 +00:00
|
|
|
} else {
|
|
|
|
ready_for_painting = false;
|
|
|
|
}
|
2019-01-27 19:48:00 +00:00
|
|
|
if (!m_internal) {
|
2015-10-13 08:52:01 +00:00
|
|
|
doSetGeometry(QRect(QPoint(0, 0), m_clientSize));
|
2015-05-18 12:51:40 +00:00
|
|
|
}
|
2016-04-18 09:55:40 +00:00
|
|
|
if (waylandServer()->inputMethodConnection() == s->client()) {
|
2015-06-13 02:06:12 +00:00
|
|
|
m_windowType = NET::OnScreenDisplay;
|
|
|
|
}
|
2015-03-04 08:21:10 +00:00
|
|
|
|
2016-04-18 09:55:40 +00:00
|
|
|
connect(s, &SurfaceInterface::sizeChanged, this,
|
2015-03-04 08:21:10 +00:00
|
|
|
[this] {
|
2016-11-04 16:52:49 +00:00
|
|
|
m_clientSize = surface()->size();
|
2019-08-10 14:31:06 +00:00
|
|
|
doSetGeometry(QRect(pos(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
2015-03-04 08:21:10 +00:00
|
|
|
}
|
|
|
|
);
|
2016-04-18 09:55:40 +00:00
|
|
|
connect(s, &SurfaceInterface::unmapped, this, &ShellClient::unmap);
|
2016-08-24 13:43:02 +00:00
|
|
|
connect(s, &SurfaceInterface::unbound, this, &ShellClient::destroyClient);
|
2016-05-23 06:54:28 +00:00
|
|
|
connect(s, &SurfaceInterface::destroyed, this, &ShellClient::destroyClient);
|
2016-04-18 09:55:40 +00:00
|
|
|
if (m_shellSurface) {
|
2016-04-22 12:13:37 +00:00
|
|
|
initSurface(m_shellSurface);
|
2017-09-25 19:10:41 +00:00
|
|
|
auto setPopup = [this] {
|
|
|
|
// TODO: verify grab serial
|
|
|
|
m_hasPopupGrab = m_shellSurface->isPopup();
|
|
|
|
};
|
|
|
|
connect(m_shellSurface, &ShellSurfaceInterface::popupChanged, this, setPopup);
|
|
|
|
setPopup();
|
2016-04-22 12:13:37 +00:00
|
|
|
} else if (m_xdgShellSurface) {
|
|
|
|
initSurface(m_xdgShellSurface);
|
XdgV6 - Kwin side
Summary:
Adds XDGV6 support for the kwin side.
Popup placement support is limited to the stuff v5 had,
a simple offset, rather than the awesome new positioner.
But Qt doesn't make use of it yet either.
Also ideally we should do all the positioning before sending the first
configure, but again Qt doesn't actually do anything with that anyway.
Also integrate pinging clients
Test Plan: gtk3-demo works nicely.
Reviewers: #plasma, graesslin, mart
Reviewed By: #plasma, graesslin
Subscribers: mart, graesslin, kwin, plasma-devel, #kwin
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D6591
2017-09-25 15:37:59 +00:00
|
|
|
|
|
|
|
auto global = static_cast<XdgShellInterface *>(m_xdgShellSurface->global());
|
|
|
|
connect(global, &XdgShellInterface::pingDelayed,
|
|
|
|
this, [this](qint32 serial) {
|
|
|
|
auto it = m_pingSerials.find(serial);
|
|
|
|
if (it != m_pingSerials.end()) {
|
|
|
|
qCDebug(KWIN_CORE) << "First ping timeout:" << caption();
|
|
|
|
setUnresponsive(true);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-10-05 14:27:05 +00:00
|
|
|
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::configureAcknowledged, this, [this](int serial) {
|
|
|
|
m_lastAckedConfigureRequest = serial;
|
|
|
|
});
|
|
|
|
|
XdgV6 - Kwin side
Summary:
Adds XDGV6 support for the kwin side.
Popup placement support is limited to the stuff v5 had,
a simple offset, rather than the awesome new positioner.
But Qt doesn't make use of it yet either.
Also ideally we should do all the positioning before sending the first
configure, but again Qt doesn't actually do anything with that anyway.
Also integrate pinging clients
Test Plan: gtk3-demo works nicely.
Reviewers: #plasma, graesslin, mart
Reviewed By: #plasma, graesslin
Subscribers: mart, graesslin, kwin, plasma-devel, #kwin
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D6591
2017-09-25 15:37:59 +00:00
|
|
|
connect(global, &XdgShellInterface::pingTimeout,
|
|
|
|
this, [this](qint32 serial) {
|
|
|
|
auto it = m_pingSerials.find(serial);
|
|
|
|
if (it != m_pingSerials.end()) {
|
|
|
|
if (it.value() == PingReason::CloseWindow) {
|
|
|
|
qCDebug(KWIN_CORE) << "Final ping timeout on a close attempt, asking to kill:" << caption();
|
|
|
|
|
|
|
|
//for internal windows, killing the window will delete this
|
|
|
|
QPointer<QObject> guard(this);
|
|
|
|
killWindow();
|
|
|
|
if (!guard) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_pingSerials.erase(it);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
connect(global, &XdgShellInterface::pongReceived,
|
|
|
|
this, [this](qint32 serial){
|
|
|
|
auto it = m_pingSerials.find(serial);
|
|
|
|
if (it != m_pingSerials.end()) {
|
|
|
|
setUnresponsive(false);
|
|
|
|
m_pingSerials.erase(it);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-04-22 12:13:37 +00:00
|
|
|
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::windowMenuRequested, this,
|
|
|
|
[this] (SeatInterface *seat, quint32 serial, const QPoint &surfacePos) {
|
|
|
|
// TODO: check serial on seat
|
|
|
|
Q_UNUSED(seat)
|
|
|
|
Q_UNUSED(serial)
|
|
|
|
performMouseCommand(Options::MouseOperationsMenu, pos() + surfacePos);
|
2016-04-18 09:55:40 +00:00
|
|
|
}
|
|
|
|
);
|
2016-04-22 12:13:37 +00:00
|
|
|
connect(m_xdgShellSurface, &XdgShellSurfaceInterface::minimizeRequested, this,
|
2016-04-18 09:55:40 +00:00
|
|
|
[this] {
|
2016-04-22 12:13:37 +00:00
|
|
|
performMouseCommand(Options::MouseMinimize, Cursor::pos());
|
2016-04-18 09:55:40 +00:00
|
|
|
}
|
|
|
|
);
|
2016-04-22 12:13:37 +00:00
|
|
|
auto configure = [this] {
|
|
|
|
if (m_closing) {
|
|
|
|
return;
|
2016-04-18 09:55:40 +00:00
|
|
|
}
|
2018-01-28 09:33:26 +00:00
|
|
|
if (m_requestGeometryBlockCounter != 0 || areGeometryUpdatesBlocked()) {
|
|
|
|
return;
|
|
|
|
}
|
2018-10-10 11:03:22 +00:00
|
|
|
m_xdgShellSurface->configure(xdgSurfaceStates(), m_requestedClientSize);
|
2016-04-22 12:13:37 +00:00
|
|
|
};
|
|
|
|
connect(this, &AbstractClient::activeChanged, this, configure);
|
|
|
|
connect(this, &AbstractClient::clientStartUserMovedResized, this, configure);
|
|
|
|
connect(this, &AbstractClient::clientFinishUserMovedResized, this, configure);
|
|
|
|
} else if (m_xdgShellPopup) {
|
XdgV6 - Kwin side
Summary:
Adds XDGV6 support for the kwin side.
Popup placement support is limited to the stuff v5 had,
a simple offset, rather than the awesome new positioner.
But Qt doesn't make use of it yet either.
Also ideally we should do all the positioning before sending the first
configure, but again Qt doesn't actually do anything with that anyway.
Also integrate pinging clients
Test Plan: gtk3-demo works nicely.
Reviewers: #plasma, graesslin, mart
Reviewed By: #plasma, graesslin
Subscribers: mart, graesslin, kwin, plasma-devel, #kwin
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D6591
2017-09-25 15:37:59 +00:00
|
|
|
connect(m_xdgShellPopup, &XdgShellPopupInterface::grabRequested, this, [this](SeatInterface *seat, quint32 serial) {
|
|
|
|
Q_UNUSED(seat)
|
|
|
|
Q_UNUSED(serial)
|
|
|
|
//TODO - should check the parent had focus
|
|
|
|
m_hasPopupGrab = true;
|
|
|
|
});
|
|
|
|
|
2018-10-19 22:21:54 +00:00
|
|
|
connect(m_xdgShellPopup, &XdgShellPopupInterface::configureAcknowledged, this, [this](int serial) {
|
2018-10-05 14:27:05 +00:00
|
|
|
m_lastAckedConfigureRequest = serial;
|
|
|
|
});
|
|
|
|
|
2016-04-22 12:13:37 +00:00
|
|
|
connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &ShellClient::destroyClient);
|
2016-04-18 09:55:40 +00:00
|
|
|
}
|
2015-07-15 09:24:19 +00:00
|
|
|
|
2017-10-07 12:09:07 +00:00
|
|
|
// set initial desktop
|
[wayland] Apply window rules only to xdg-shell clients
Summary:
There are rules that have to be applied only once, e.g. every Remember
and Apply Initially rule, as well rules that need to configure the client,
e.g. size, etc. In the best scenario the compositor would evaluate such
rules when the client is about to be mapped.
This change limits window rules only to xdg-shell clients because right
now only this protocol lets compositors to intervene in the client
initialization process. Also, it makes things a bit easier for us on the
compositor side.
xdg-shell protocol satisfies most of ours requirements to implement window
rules, but not all of them. If the client is about to be mapped for the
second time and its size is forced by a rule, then compositor may need
to configure it. Currently, xdg-shell protocol doesn't have any mechanism
that a client could use to notify the compositor about its intent to map.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: fmonteiro, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19411
2019-07-09 11:58:57 +00:00
|
|
|
setDesktop(m_internal ? int(NET::OnAllDesktops) : VirtualDesktopManager::self()->current());
|
2017-10-07 12:09:07 +00:00
|
|
|
|
2015-07-15 09:24:19 +00:00
|
|
|
// setup shadow integration
|
|
|
|
getShadow();
|
2016-04-18 09:55:40 +00:00
|
|
|
connect(s, &SurfaceInterface::shadowChanged, this, &Toplevel::getShadow);
|
2015-09-11 10:11:01 +00:00
|
|
|
|
2017-10-13 09:32:02 +00:00
|
|
|
connect(waylandServer(), &WaylandServer::foreignTransientChanged, this, [this](KWayland::Server::SurfaceInterface *child) {
|
|
|
|
if (child == surface()) {
|
|
|
|
setTransient();
|
|
|
|
}
|
|
|
|
});
|
2015-09-11 10:11:01 +00:00
|
|
|
setTransient();
|
2015-12-17 14:47:36 +00:00
|
|
|
|
2017-10-01 14:38:57 +00:00
|
|
|
AbstractClient::updateColorScheme(QString());
|
2015-03-04 08:21:10 +00:00
|
|
|
}
|
|
|
|
|
2019-02-26 13:41:07 +00:00
|
|
|
void ShellClient::finishInit() {
|
|
|
|
SurfaceInterface *s = surface();
|
|
|
|
disconnect(s, &SurfaceInterface::committed, this, &ShellClient::finishInit);
|
|
|
|
|
2019-07-09 17:28:05 +00:00
|
|
|
bool needsPlacement = !isInitialPositionSet();
|
|
|
|
|
[wayland] Apply window rules only to xdg-shell clients
Summary:
There are rules that have to be applied only once, e.g. every Remember
and Apply Initially rule, as well rules that need to configure the client,
e.g. size, etc. In the best scenario the compositor would evaluate such
rules when the client is about to be mapped.
This change limits window rules only to xdg-shell clients because right
now only this protocol lets compositors to intervene in the client
initialization process. Also, it makes things a bit easier for us on the
compositor side.
xdg-shell protocol satisfies most of ours requirements to implement window
rules, but not all of them. If the client is about to be mapped for the
second time and its size is forced by a rule, then compositor may need
to configure it. Currently, xdg-shell protocol doesn't have any mechanism
that a client could use to notify the compositor about its intent to map.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: fmonteiro, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19411
2019-07-09 11:58:57 +00:00
|
|
|
if (supportsWindowRules()) {
|
|
|
|
setupWindowRules(false);
|
|
|
|
|
2019-07-09 17:28:05 +00:00
|
|
|
const QRect originalGeometry = QRect(pos(), sizeForClientSize(clientSize()));
|
|
|
|
const QRect ruledGeometry = rules()->checkGeometry(originalGeometry, true);
|
|
|
|
if (originalGeometry != ruledGeometry) {
|
|
|
|
setGeometry(ruledGeometry);
|
|
|
|
}
|
|
|
|
|
2019-07-09 18:07:21 +00:00
|
|
|
maximize(rules()->checkMaximize(maximizeMode(), true));
|
|
|
|
|
[wayland] Apply window rules only to xdg-shell clients
Summary:
There are rules that have to be applied only once, e.g. every Remember
and Apply Initially rule, as well rules that need to configure the client,
e.g. size, etc. In the best scenario the compositor would evaluate such
rules when the client is about to be mapped.
This change limits window rules only to xdg-shell clients because right
now only this protocol lets compositors to intervene in the client
initialization process. Also, it makes things a bit easier for us on the
compositor side.
xdg-shell protocol satisfies most of ours requirements to implement window
rules, but not all of them. If the client is about to be mapped for the
second time and its size is forced by a rule, then compositor may need
to configure it. Currently, xdg-shell protocol doesn't have any mechanism
that a client could use to notify the compositor about its intent to map.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: fmonteiro, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19411
2019-07-09 11:58:57 +00:00
|
|
|
setDesktop(rules()->checkDesktop(desktop(), true));
|
|
|
|
setDesktopFileName(rules()->checkDesktopFile(desktopFileName(), true).toUtf8());
|
|
|
|
if (rules()->checkMinimize(isMinimized(), true)) {
|
|
|
|
minimize(true); // No animation.
|
|
|
|
}
|
|
|
|
setSkipTaskbar(rules()->checkSkipTaskbar(skipTaskbar(), true));
|
|
|
|
setSkipPager(rules()->checkSkipPager(skipPager(), true));
|
|
|
|
setSkipSwitcher(rules()->checkSkipSwitcher(skipSwitcher(), true));
|
|
|
|
setKeepAbove(rules()->checkKeepAbove(keepAbove(), true));
|
|
|
|
setKeepBelow(rules()->checkKeepBelow(keepBelow(), true));
|
|
|
|
setShortcut(rules()->checkShortcut(shortcut().toString(), true));
|
|
|
|
updateColorScheme();
|
|
|
|
|
2019-07-09 17:28:05 +00:00
|
|
|
// Don't place the client if its position is set by a rule.
|
|
|
|
if (rules()->checkPosition(invalidPoint, true) != invalidPoint) {
|
|
|
|
needsPlacement = false;
|
|
|
|
}
|
|
|
|
|
2019-07-09 18:07:21 +00:00
|
|
|
// Don't place the client if the maximize state is set by a rule.
|
|
|
|
if (requestedMaximizeMode() != MaximizeRestore) {
|
|
|
|
needsPlacement = false;
|
|
|
|
}
|
|
|
|
|
[wayland] Apply window rules only to xdg-shell clients
Summary:
There are rules that have to be applied only once, e.g. every Remember
and Apply Initially rule, as well rules that need to configure the client,
e.g. size, etc. In the best scenario the compositor would evaluate such
rules when the client is about to be mapped.
This change limits window rules only to xdg-shell clients because right
now only this protocol lets compositors to intervene in the client
initialization process. Also, it makes things a bit easier for us on the
compositor side.
xdg-shell protocol satisfies most of ours requirements to implement window
rules, but not all of them. If the client is about to be mapped for the
second time and its size is forced by a rule, then compositor may need
to configure it. Currently, xdg-shell protocol doesn't have any mechanism
that a client could use to notify the compositor about its intent to map.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: fmonteiro, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19411
2019-07-09 11:58:57 +00:00
|
|
|
discardTemporaryRules();
|
|
|
|
RuleBook::self()->discardUsed(this, false); // Remove Apply Now rules.
|
|
|
|
updateWindowRules(Rules::All);
|
|
|
|
}
|
|
|
|
|
2019-07-09 17:28:05 +00:00
|
|
|
if (needsPlacement) {
|
2019-09-12 14:52:47 +00:00
|
|
|
const QRect area = workspace()->clientArea(PlacementArea, Screens::self()->current(), desktop());
|
2019-02-26 13:41:07 +00:00
|
|
|
placeIn(area);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_requestGeometryBlockCounter--;
|
|
|
|
if (m_requestGeometryBlockCounter == 0) {
|
|
|
|
requestGeometry(m_blockedRequestGeometry);
|
|
|
|
}
|
[wayland] Apply window rules only to xdg-shell clients
Summary:
There are rules that have to be applied only once, e.g. every Remember
and Apply Initially rule, as well rules that need to configure the client,
e.g. size, etc. In the best scenario the compositor would evaluate such
rules when the client is about to be mapped.
This change limits window rules only to xdg-shell clients because right
now only this protocol lets compositors to intervene in the client
initialization process. Also, it makes things a bit easier for us on the
compositor side.
xdg-shell protocol satisfies most of ours requirements to implement window
rules, but not all of them. If the client is about to be mapped for the
second time and its size is forced by a rule, then compositor may need
to configure it. Currently, xdg-shell protocol doesn't have any mechanism
that a client could use to notify the compositor about its intent to map.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: fmonteiro, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19411
2019-07-09 11:58:57 +00:00
|
|
|
|
|
|
|
m_isInitialized = true;
|
2019-02-26 13:41:07 +00:00
|
|
|
}
|
|
|
|
|
2015-03-04 08:21:10 +00:00
|
|
|
void ShellClient::destroyClient()
|
|
|
|
{
|
2015-04-30 11:48:59 +00:00
|
|
|
m_closing = true;
|
2019-07-29 18:24:09 +00:00
|
|
|
#ifdef KWIN_BUILD_TABBOX
|
|
|
|
TabBox::TabBox *tabBox = TabBox::TabBox::self();
|
autotests: Fix zero page access
Relevant output:
==18647==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000048 (pc 0x7fbe27fb2db7 bp 0x7ffdcb6d4030 sp 0x7ffdcb6d4020 T0)
==18647==The signal is caused by a READ memory access.
==18647==Hint: address points to the zero page.
#0 0x7fbe27fb2db6 in KWin::TabBox::TabBox::isDisplayed() const /home/jenkins/workspace/Plasma/kwin/kf5-qt5 SUSEQt5.12/tabbox/tabbox.h:231
#1 0x7fbe286dbb85 in KWin::ShellClient::destroyClient() /home/jenkins/workspace/Plasma/kwin/kf5-qt5 SUSEQt5.12/shell_client.cpp:421
#2 0x7fbe2871f6a2 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (KWin::ShellClient::*)()>::call(void (KWin::ShellClient::*)(), KWin::ShellClient*, void**) /usr/include/qt5/QtCore/qobjectdefs_impl.h:152
#3 0x7fbe2871d43f in void QtPrivate::FunctionPointer<void (KWin::ShellClient::*)()>::call<QtPrivate::List<>, void>(void (KWin::ShellClient::*)(), KWin::ShellClient*, void**) /usr/include/qt5/QtCore/qobjectdefs_impl.h:185
#4 0x7fbe28719d65 in QtPrivate::QSlotObject<void (KWin::ShellClient::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (/home/jenkins/install-prefix/lib64/libkwin.so.5+0x1677d65)
#5 0x7fbe1d7cc357 in QMetaObject::activate(QObject*, int, int, void**) (/usr/lib64/libQt5Core.so.5+0x2b3357)
#6 0x7fbe1fd86970 in KWayland::Server::Resource::unbound() /home/jenkins/workspace/Administration/Dependency Build Plasma kf5-qt5 SUSEQt5.12/kwayland/build/src/server/KF5WaylandServer_autogen/EWIEGA46WW/moc_resource.cpp:142
#7 0x7fbe1ff104b4 in KWayland::Server::Resource::Private::unbind(wl_resource*) /home/jenkins/workspace/Administration/Dependency Build Plasma kf5-qt5 SUSEQt5.12/kwayland/src/server/resource.cpp:68
#8 0x7fbe194812ae (/usr/lib64/libwayland-server.so.0+0x92ae)
#9 0x7fbe1948132f in wl_resource_destroy (/usr/lib64/libwayland-server.so.0+0x932f)
#10 0x7fbe1ff1053f in KWayland::Server::Resource::Private::resourceDestroyedCallback(wl_client*, wl_resource*) /home/jenkins/workspace/Administration/Dependency Build Plasma kf5-qt5 SUSEQt5.12/kwayland/src/server/resource.cpp:76
#11 0x7fbe17d26d8c (/usr/lib64/libffi.so.7+0x6d8c)
#12 0x7fbe17d26179 (/usr/lib64/libffi.so.7+0x6179)
#13 0x7fbe19484a5f (/usr/lib64/libwayland-server.so.0+0xca5f)
#14 0x7fbe194816d1 (/usr/lib64/libwayland-server.so.0+0x96d1)
#15 0x7fbe19482c71 in wl_event_loop_dispatch (/usr/lib64/libwayland-server.so.0+0xac71)
#16 0x7fbe1fde6e50 in KWayland::Server::Display::Private::dispatch() /home/jenkins/workspace/Administration/Dependency Build Plasma kf5-qt5 SUSEQt5.12/kwayland/src/server/display.cpp:148
#17 0x7fbe1fde82de in KWayland::Server::Display::dispatchEvents(int) /home/jenkins/workspace/Administration/Dependency Build Plasma kf5-qt5 SUSEQt5.12/kwayland/src/server/display.cpp:220
#18 0x7fbe2872b446 in KWin::WaylandServer::dispatch() /home/jenkins/workspace/Plasma/kwin/kf5-qt5 SUSEQt5.12/wayland_server.cpp:616
#19 0x457e08 in KWin::WaylandTestApplication::~WaylandTestApplication() /home/jenkins/workspace/Plasma/kwin/kf5-qt5 SUSEQt5.12/autotests/integration/kwin_wayland_test.cpp:91
#20 0x43500b in main /home/jenkins/workspace/Plasma/kwin/kf5-qt5 SUSEQt5.12/autotests/integration/debug_console_test.cpp:530
#21 0x7fbe1d03bbca in __libc_start_main (/lib64/libc.so.6+0x26bca)
#22 0x414ed9 in _start (/home/jenkins/workspace/Plasma/kwin/kf5-qt5 SUSEQt5.12/build/bin/testDebugConsole+0x414ed9)
2019-07-29 20:08:52 +00:00
|
|
|
if (tabBox && tabBox->isDisplayed() && tabBox->currentClient() == this) {
|
2019-07-29 18:24:09 +00:00
|
|
|
tabBox->nextPrev(true);
|
|
|
|
}
|
|
|
|
#endif
|
2019-03-12 09:35:17 +00:00
|
|
|
if (isMoveResize()) {
|
|
|
|
leaveMoveResize();
|
|
|
|
}
|
2019-09-10 07:40:36 +00:00
|
|
|
|
|
|
|
// Replace ShellClient with an instance of Deleted in the stacking order.
|
|
|
|
Deleted *deleted = Deleted::create(this);
|
|
|
|
emit windowClosed(this, deleted);
|
2019-07-09 12:03:39 +00:00
|
|
|
|
|
|
|
// Remove Force Temporarily rules.
|
|
|
|
RuleBook::self()->discardUsed(this, true);
|
|
|
|
|
2016-06-03 14:53:23 +00:00
|
|
|
destroyWindowManagementInterface();
|
2015-12-17 14:47:36 +00:00
|
|
|
destroyDecoration();
|
2015-10-01 12:12:46 +00:00
|
|
|
|
2019-09-10 07:40:36 +00:00
|
|
|
StackingUpdatesBlocker blocker(workspace());
|
|
|
|
if (transientFor()) {
|
|
|
|
transientFor()->removeTransient(this);
|
|
|
|
}
|
|
|
|
for (auto it = transients().constBegin(); it != transients().constEnd();) {
|
|
|
|
if ((*it)->transientFor() == this) {
|
|
|
|
removeTransient(*it);
|
|
|
|
it = transients().constBegin(); // restart, just in case something more has changed with the list
|
|
|
|
} else {
|
|
|
|
++it;
|
2015-10-01 12:12:46 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-10 07:40:36 +00:00
|
|
|
|
2015-03-04 08:21:10 +00:00
|
|
|
waylandServer()->removeClient(this);
|
|
|
|
|
2019-09-10 07:40:36 +00:00
|
|
|
deleted->unrefWindow();
|
|
|
|
|
2015-03-04 08:21:10 +00:00
|
|
|
m_shellSurface = nullptr;
|
2016-04-22 12:13:37 +00:00
|
|
|
m_xdgShellSurface = nullptr;
|
|
|
|
m_xdgShellPopup = nullptr;
|
2015-03-04 08:21:10 +00:00
|
|
|
deleteClient(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::deleteClient(ShellClient *c)
|
|
|
|
{
|
|
|
|
delete c;
|
|
|
|
}
|
|
|
|
|
2019-05-17 14:13:54 +00:00
|
|
|
QSize ShellClient::toWindowGeometry(const QSize &size) const
|
|
|
|
{
|
|
|
|
QSize adjustedSize = size - QSize(borderLeft() + borderRight(), borderTop() + borderBottom());
|
|
|
|
// a client going fullscreen should have the window the contents size of the screen
|
|
|
|
if (!isFullScreen() && requestedMaximizeMode() != MaximizeFull) {
|
|
|
|
adjustedSize -= QSize(m_windowMargins.left() + m_windowMargins.right(), m_windowMargins.top() + m_windowMargins.bottom());
|
|
|
|
}
|
|
|
|
return adjustedSize;
|
|
|
|
}
|
|
|
|
|
2015-03-04 08:21:10 +00:00
|
|
|
QStringList ShellClient::activities() const
|
|
|
|
{
|
|
|
|
// TODO: implement
|
|
|
|
return QStringList();
|
|
|
|
}
|
|
|
|
|
2015-12-08 09:11:26 +00:00
|
|
|
QPoint ShellClient::clientContentPos() const
|
|
|
|
{
|
|
|
|
return -1 * clientPos();
|
|
|
|
}
|
|
|
|
|
2015-03-04 08:21:10 +00:00
|
|
|
QSize ShellClient::clientSize() const
|
|
|
|
{
|
|
|
|
return m_clientSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::debug(QDebug &stream) const
|
|
|
|
{
|
2018-09-16 20:45:17 +00:00
|
|
|
stream.nospace();
|
|
|
|
stream << "\'ShellClient:" << surface() << ";WMCLASS:" << resourceClass() << ":"
|
|
|
|
<< resourceName() << ";Caption:" << caption() << "\'";
|
2015-03-04 08:21:10 +00:00
|
|
|
}
|
|
|
|
|
2019-02-27 10:52:44 +00:00
|
|
|
bool ShellClient::belongsToDesktop() const
|
|
|
|
{
|
|
|
|
const auto clients = waylandServer()->clients();
|
|
|
|
|
|
|
|
return std::any_of(clients.constBegin(), clients.constEnd(),
|
|
|
|
[this](const ShellClient *client) {
|
|
|
|
if (belongsToSameApplication(client, SameApplicationChecks())) {
|
|
|
|
return client->isDesktop();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-09-17 09:06:59 +00:00
|
|
|
Layer ShellClient::layerForDock() const
|
2015-03-04 08:21:10 +00:00
|
|
|
{
|
2015-09-17 09:06:59 +00:00
|
|
|
if (m_plasmaShellSurface) {
|
|
|
|
switch (m_plasmaShellSurface->panelBehavior()) {
|
|
|
|
case PlasmaShellSurfaceInterface::PanelBehavior::WindowsCanCover:
|
2015-06-09 17:10:56 +00:00
|
|
|
return NormalLayer;
|
2015-09-17 09:06:59 +00:00
|
|
|
case PlasmaShellSurfaceInterface::PanelBehavior::AutoHide:
|
2015-06-09 17:10:56 +00:00
|
|
|
return AboveLayer;
|
2015-09-17 09:06:59 +00:00
|
|
|
case PlasmaShellSurfaceInterface::PanelBehavior::WindowsGoBelow:
|
|
|
|
case PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible:
|
|
|
|
return DockLayer;
|
|
|
|
default:
|
|
|
|
Q_UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
2015-06-09 17:10:56 +00:00
|
|
|
}
|
2015-09-17 09:06:59 +00:00
|
|
|
return AbstractClient::layerForDock();
|
2015-03-04 08:21:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QRect ShellClient::transparentRect() const
|
|
|
|
{
|
|
|
|
// TODO: implement
|
|
|
|
return QRect();
|
|
|
|
}
|
|
|
|
|
|
|
|
NET::WindowType ShellClient::windowType(bool direct, int supported_types) const
|
|
|
|
{
|
|
|
|
// TODO: implement
|
|
|
|
Q_UNUSED(direct)
|
|
|
|
Q_UNUSED(supported_types)
|
2015-06-08 19:27:55 +00:00
|
|
|
return m_windowType;
|
2015-03-04 08:21:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double ShellClient::opacity() const
|
|
|
|
{
|
2016-02-18 07:27:02 +00:00
|
|
|
return m_opacity;
|
2015-03-04 08:21:10 +00:00
|
|
|
}
|
|
|
|
|
2015-03-16 08:13:19 +00:00
|
|
|
void ShellClient::setOpacity(double opacity)
|
|
|
|
{
|
2016-02-18 07:27:02 +00:00
|
|
|
const qreal newOpacity = qBound(0.0, opacity, 1.0);
|
|
|
|
if (newOpacity == m_opacity) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const qreal oldOpacity = m_opacity;
|
|
|
|
m_opacity = newOpacity;
|
|
|
|
addRepaintFull();
|
|
|
|
emit opacityChanged(this, oldOpacity);
|
2015-03-16 08:13:19 +00:00
|
|
|
}
|
|
|
|
|
2015-03-04 08:21:10 +00:00
|
|
|
void ShellClient::addDamage(const QRegion &damage)
|
|
|
|
{
|
2016-04-18 11:33:23 +00:00
|
|
|
auto s = surface();
|
2016-11-04 16:52:49 +00:00
|
|
|
if (s->size().isValid()) {
|
|
|
|
m_clientSize = s->size();
|
2019-05-17 14:13:54 +00:00
|
|
|
updateWindowMargins();
|
2018-10-05 14:27:05 +00:00
|
|
|
updatePendingGeometry();
|
2015-03-04 08:21:10 +00:00
|
|
|
}
|
2015-07-22 06:38:00 +00:00
|
|
|
markAsMapped();
|
2016-08-09 11:50:29 +00:00
|
|
|
setDepth((s->buffer()->hasAlphaChannel() && !isDesktop()) ? 32 : 24);
|
2016-03-04 15:33:09 +00:00
|
|
|
repaints_region += damage.translated(clientPos());
|
2015-03-04 08:21:10 +00:00
|
|
|
Toplevel::addDamage(damage);
|
|
|
|
}
|
|
|
|
|
2015-07-22 06:38:00 +00:00
|
|
|
void ShellClient::markAsMapped()
|
2015-07-09 07:10:33 +00:00
|
|
|
{
|
|
|
|
if (!m_unmapped) {
|
|
|
|
return;
|
|
|
|
}
|
2015-12-17 14:47:36 +00:00
|
|
|
|
2015-07-09 07:10:33 +00:00
|
|
|
m_unmapped = false;
|
2016-07-04 13:06:20 +00:00
|
|
|
if (!ready_for_painting) {
|
|
|
|
setReadyForPainting();
|
|
|
|
} else {
|
|
|
|
addRepaintFull();
|
|
|
|
emit windowShown(this);
|
|
|
|
}
|
2016-06-03 11:37:24 +00:00
|
|
|
if (shouldExposeToWindowManagement()) {
|
|
|
|
setupWindowManagementInterface();
|
|
|
|
}
|
2016-09-15 19:03:40 +00:00
|
|
|
updateShowOnScreenEdge();
|
2015-07-09 07:10:33 +00:00
|
|
|
}
|
|
|
|
|
2015-12-17 14:47:36 +00:00
|
|
|
void ShellClient::createDecoration(const QRect &oldGeom)
|
|
|
|
{
|
|
|
|
KDecoration2::Decoration *decoration = Decoration::DecorationBridge::self()->createDecoration(this);
|
|
|
|
if (decoration) {
|
|
|
|
QMetaObject::invokeMethod(decoration, "update", Qt::QueuedConnection);
|
|
|
|
connect(decoration, &KDecoration2::Decoration::shadowChanged, this, &Toplevel::getShadow);
|
|
|
|
connect(decoration, &KDecoration2::Decoration::bordersChanged, this,
|
|
|
|
[this]() {
|
|
|
|
GeometryUpdatesBlocker blocker(this);
|
2016-06-09 14:54:06 +00:00
|
|
|
RequestGeometryBlocker requestBlocker(this);
|
2015-12-17 14:47:36 +00:00
|
|
|
QRect oldgeom = geometry();
|
|
|
|
if (!isShade())
|
|
|
|
checkWorkspacePosition(oldgeom);
|
|
|
|
emit geometryShapeChanged(this, oldgeom);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
setDecoration(decoration);
|
2016-06-10 08:52:41 +00:00
|
|
|
// TODO: ensure the new geometry still fits into the client area (e.g. maximized windows)
|
2016-06-23 09:26:31 +00:00
|
|
|
doSetGeometry(QRect(oldGeom.topLeft(), m_clientSize + (decoration ? QSize(decoration->borderLeft() + decoration->borderRight(),
|
|
|
|
decoration->borderBottom() + decoration->borderTop()) : QSize())));
|
2015-12-17 14:47:36 +00:00
|
|
|
|
|
|
|
emit geometryShapeChanged(this, oldGeom);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::updateDecoration(bool check_workspace_pos, bool force)
|
|
|
|
{
|
|
|
|
if (!force &&
|
|
|
|
((!isDecorated() && noBorder()) || (isDecorated() && !noBorder())))
|
|
|
|
return;
|
|
|
|
QRect oldgeom = geometry();
|
|
|
|
QRect oldClientGeom = oldgeom.adjusted(borderLeft(), borderTop(), -borderRight(), -borderBottom());
|
|
|
|
blockGeometryUpdates(true);
|
|
|
|
if (force)
|
|
|
|
destroyDecoration();
|
|
|
|
if (!noBorder()) {
|
|
|
|
createDecoration(oldgeom);
|
|
|
|
} else
|
|
|
|
destroyDecoration();
|
|
|
|
if (m_serverDecoration && isDecorated()) {
|
|
|
|
m_serverDecoration->setMode(KWayland::Server::ServerSideDecorationManagerInterface::Mode::Server);
|
|
|
|
}
|
2019-01-01 17:37:18 +00:00
|
|
|
if (m_xdgDecoration) {
|
2019-04-01 08:29:45 +00:00
|
|
|
auto mode = isDecorated() || m_userNoBorder ? XdgDecorationInterface::Mode::ServerSide: XdgDecorationInterface::Mode::ClientSide;
|
2019-01-01 17:37:18 +00:00
|
|
|
m_xdgDecoration->configure(mode);
|
2019-06-22 15:13:43 +00:00
|
|
|
if (m_requestGeometryBlockCounter == 0) {
|
|
|
|
m_xdgShellSurface->configure(xdgSurfaceStates(), m_requestedClientSize);
|
|
|
|
}
|
2019-01-01 17:37:18 +00:00
|
|
|
}
|
2015-12-17 14:47:36 +00:00
|
|
|
getShadow();
|
|
|
|
if (check_workspace_pos)
|
|
|
|
checkWorkspacePosition(oldgeom, -2, oldClientGeom);
|
|
|
|
blockGeometryUpdates(false);
|
|
|
|
}
|
|
|
|
|
2015-10-13 08:52:01 +00:00
|
|
|
void ShellClient::setGeometry(int x, int y, int w, int h, ForceGeometry_t force)
|
|
|
|
{
|
2019-07-09 17:28:05 +00:00
|
|
|
const QRect newGeometry = rules()->checkGeometry(QRect(x, y, w, h));
|
|
|
|
|
2017-11-22 16:33:21 +00:00
|
|
|
if (areGeometryUpdatesBlocked()) {
|
|
|
|
// when the GeometryUpdateBlocker exits the current geom is passed to setGeometry
|
|
|
|
// thus we need to set it here.
|
2019-07-09 17:28:05 +00:00
|
|
|
geom = newGeometry;
|
2017-11-22 16:33:21 +00:00
|
|
|
if (pendingGeometryUpdate() == PendingGeometryForced)
|
|
|
|
{} // maximum, nothing needed
|
|
|
|
else if (force == ForceGeometrySet)
|
|
|
|
setPendingGeometryUpdate(PendingGeometryForced);
|
|
|
|
else
|
|
|
|
setPendingGeometryUpdate(PendingGeometryNormal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (pendingGeometryUpdate() != PendingGeometryNone) {
|
|
|
|
// reset geometry to the one before blocking, so that we can compare properly
|
|
|
|
geom = geometryBeforeUpdateBlocking();
|
|
|
|
}
|
2019-07-09 17:28:05 +00:00
|
|
|
const QSize requestedClientSize = newGeometry.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom());
|
|
|
|
const QSize requestedWindowGeometrySize = toWindowGeometry(newGeometry.size());
|
2019-04-09 10:13:38 +00:00
|
|
|
|
|
|
|
if (requestedClientSize == m_clientSize && !isWaitingForMoveResizeSync() &&
|
2019-05-17 14:13:54 +00:00
|
|
|
(m_requestedClientSize.isEmpty() || requestedWindowGeometrySize == m_requestedClientSize)) {
|
2019-04-09 10:13:38 +00:00
|
|
|
// size didn't change, and we don't need to explicitly request a new size
|
2019-07-09 17:28:05 +00:00
|
|
|
doSetGeometry(newGeometry);
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
updateMaximizeMode(m_requestedMaximizeMode);
|
2015-10-14 14:34:19 +00:00
|
|
|
} else {
|
|
|
|
// size did change, Client needs to provide a new buffer
|
2019-07-09 17:28:05 +00:00
|
|
|
requestGeometry(newGeometry);
|
2015-10-14 14:34:19 +00:00
|
|
|
}
|
2015-10-13 08:52:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::doSetGeometry(const QRect &rect)
|
2015-03-04 08:21:10 +00:00
|
|
|
{
|
2017-01-04 16:53:46 +00:00
|
|
|
if (geom == rect && pendingGeometryUpdate() == PendingGeometryNone) {
|
2015-03-04 08:21:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-08-20 07:38:19 +00:00
|
|
|
if (!m_unmapped) {
|
|
|
|
addWorkspaceRepaint(visibleRect());
|
|
|
|
}
|
2019-07-09 17:28:05 +00:00
|
|
|
|
2015-03-04 08:21:10 +00:00
|
|
|
geom = rect;
|
2019-07-09 17:28:05 +00:00
|
|
|
updateWindowRules(Rules::Position | Rules::Size);
|
2015-10-14 10:11:56 +00:00
|
|
|
|
|
|
|
if (m_unmapped && m_geomMaximizeRestore.isEmpty() && !geom.isEmpty()) {
|
|
|
|
// use first valid geometry as restore geometry
|
|
|
|
m_geomMaximizeRestore = geom;
|
|
|
|
}
|
|
|
|
|
2015-08-20 07:38:19 +00:00
|
|
|
if (!m_unmapped) {
|
|
|
|
addWorkspaceRepaint(visibleRect());
|
|
|
|
}
|
2016-06-10 08:50:02 +00:00
|
|
|
if (hasStrut()) {
|
|
|
|
workspace()->updateClientArea();
|
|
|
|
}
|
2017-11-22 16:33:21 +00:00
|
|
|
const auto old = geometryBeforeUpdateBlocking();
|
|
|
|
updateGeometryBeforeUpdateBlocking();
|
2015-03-04 08:21:10 +00:00
|
|
|
emit geometryShapeChanged(this, old);
|
2017-01-29 13:30:43 +00:00
|
|
|
|
|
|
|
if (isResize()) {
|
|
|
|
performMoveResize();
|
|
|
|
}
|
2015-03-04 08:21:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray ShellClient::windowRole() const
|
|
|
|
{
|
|
|
|
return QByteArray();
|
|
|
|
}
|
|
|
|
|
2017-11-05 09:10:17 +00:00
|
|
|
bool ShellClient::belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const
|
2015-03-16 08:14:04 +00:00
|
|
|
{
|
2017-11-05 09:10:17 +00:00
|
|
|
if (checks.testFlag(SameApplicationCheck::AllowCrossProcesses)) {
|
|
|
|
if (other->desktopFileName() == desktopFileName()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2015-03-16 08:14:04 +00:00
|
|
|
if (auto s = other->surface()) {
|
|
|
|
return s->client() == surface()->client();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::blockActivityUpdates(bool b)
|
|
|
|
{
|
|
|
|
Q_UNUSED(b)
|
|
|
|
}
|
|
|
|
|
2017-08-03 05:11:40 +00:00
|
|
|
void ShellClient::updateCaption()
|
|
|
|
{
|
|
|
|
const QString oldSuffix = m_captionSuffix;
|
2017-08-20 06:56:13 +00:00
|
|
|
const auto shortcut = shortcutCaptionSuffix();
|
|
|
|
m_captionSuffix = shortcut;
|
|
|
|
if ((!isSpecialWindow() || isToolbar()) && findClientWithSameCaption()) {
|
|
|
|
int i = 2;
|
|
|
|
do {
|
|
|
|
m_captionSuffix = shortcut + QLatin1String(" <") + QString::number(i) + QLatin1Char('>');
|
|
|
|
i++;
|
|
|
|
} while (findClientWithSameCaption());
|
|
|
|
}
|
2017-08-03 05:11:40 +00:00
|
|
|
if (m_captionSuffix != oldSuffix) {
|
|
|
|
emit captionChanged();
|
|
|
|
}
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::closeWindow()
|
|
|
|
{
|
2016-04-22 12:13:37 +00:00
|
|
|
if (m_xdgShellSurface && isCloseable()) {
|
|
|
|
m_xdgShellSurface->close();
|
XdgV6 - Kwin side
Summary:
Adds XDGV6 support for the kwin side.
Popup placement support is limited to the stuff v5 had,
a simple offset, rather than the awesome new positioner.
But Qt doesn't make use of it yet either.
Also ideally we should do all the positioning before sending the first
configure, but again Qt doesn't actually do anything with that anyway.
Also integrate pinging clients
Test Plan: gtk3-demo works nicely.
Reviewers: #plasma, graesslin, mart
Reviewed By: #plasma, graesslin
Subscribers: mart, graesslin, kwin, plasma-devel, #kwin
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D6591
2017-09-25 15:37:59 +00:00
|
|
|
const qint32 pingSerial = static_cast<XdgShellInterface *>(m_xdgShellSurface->global())->ping(m_xdgShellSurface);
|
|
|
|
m_pingSerials.insert(pingSerial, PingReason::CloseWindow);
|
2016-05-09 12:48:10 +00:00
|
|
|
}
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AbstractClient *ShellClient::findModal(bool allow_itself)
|
|
|
|
{
|
|
|
|
Q_UNUSED(allow_itself)
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::isCloseable() const
|
|
|
|
{
|
2015-06-11 23:20:31 +00:00
|
|
|
if (m_windowType == NET::Desktop || m_windowType == NET::Dock) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-04-22 12:13:37 +00:00
|
|
|
if (m_xdgShellSurface) {
|
|
|
|
return true;
|
|
|
|
}
|
2019-01-30 00:59:32 +00:00
|
|
|
return false;
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::isFullScreen() const
|
|
|
|
{
|
2015-10-08 08:05:40 +00:00
|
|
|
return m_fullScreen;
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::isMaximizable() const
|
|
|
|
{
|
2019-07-09 17:28:05 +00:00
|
|
|
if (!isResizable()) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-07-09 18:07:21 +00:00
|
|
|
if (rules()->checkMaximize(MaximizeRestore) != MaximizeRestore || rules()->checkMaximize(MaximizeFull) != MaximizeFull) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-06-07 01:28:38 +00:00
|
|
|
return true;
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::isMinimizable() const
|
|
|
|
{
|
2019-07-09 12:05:32 +00:00
|
|
|
if (!rules()->checkMinimize(true)) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-29 09:31:23 +00:00
|
|
|
return (!m_plasmaShellSurface || m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal);
|
2015-11-05 10:30:02 +00:00
|
|
|
}
|
|
|
|
|
2015-03-16 08:14:04 +00:00
|
|
|
bool ShellClient::isMovable() const
|
|
|
|
{
|
2019-10-09 11:56:55 +00:00
|
|
|
if (isFullScreen()) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-07-09 17:28:05 +00:00
|
|
|
if (rules()->checkPosition(invalidPoint) != invalidPoint) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-16 14:35:24 +00:00
|
|
|
if (m_plasmaShellSurface) {
|
|
|
|
return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal;
|
|
|
|
}
|
2016-04-22 12:13:37 +00:00
|
|
|
if (m_xdgShellPopup) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-26 08:17:46 +00:00
|
|
|
return true;
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::isMovableAcrossScreens() const
|
|
|
|
{
|
2019-07-09 17:28:05 +00:00
|
|
|
if (rules()->checkPosition(invalidPoint) != invalidPoint) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-16 14:35:24 +00:00
|
|
|
if (m_plasmaShellSurface) {
|
|
|
|
return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal;
|
|
|
|
}
|
2016-04-22 12:13:37 +00:00
|
|
|
if (m_xdgShellPopup) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-26 08:17:46 +00:00
|
|
|
return true;
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::isResizable() const
|
|
|
|
{
|
2019-10-09 11:56:55 +00:00
|
|
|
if (isFullScreen()) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-07-09 17:28:05 +00:00
|
|
|
if (rules()->checkSize(QSize()).isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-16 14:35:24 +00:00
|
|
|
if (m_plasmaShellSurface) {
|
|
|
|
return m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal;
|
|
|
|
}
|
2016-04-22 12:13:37 +00:00
|
|
|
if (m_xdgShellPopup) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-13 14:26:45 +00:00
|
|
|
return true;
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::isShown(bool shaded_is_shown) const
|
|
|
|
{
|
|
|
|
Q_UNUSED(shaded_is_shown)
|
2016-10-11 14:24:10 +00:00
|
|
|
return !m_closing && !m_unmapped && !isMinimized() && !m_hidden;
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
2015-05-23 07:02:11 +00:00
|
|
|
void ShellClient::hideClient(bool hide)
|
|
|
|
{
|
2016-10-11 14:24:10 +00:00
|
|
|
if (m_hidden == hide) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_hidden = hide;
|
|
|
|
if (hide) {
|
|
|
|
addWorkspaceRepaint(visibleRect());
|
|
|
|
workspace()->clientHidden(this);
|
|
|
|
emit windowHidden(this);
|
|
|
|
} else {
|
|
|
|
emit windowShown(this);
|
|
|
|
}
|
2015-05-23 07:02:11 +00:00
|
|
|
}
|
|
|
|
|
2016-06-09 12:37:32 +00:00
|
|
|
static bool changeMaximizeRecursion = false;
|
2015-10-13 08:22:18 +00:00
|
|
|
void ShellClient::changeMaximize(bool horizontal, bool vertical, bool adjust)
|
2015-03-16 08:14:04 +00:00
|
|
|
{
|
2016-06-09 12:37:32 +00:00
|
|
|
if (changeMaximizeRecursion) {
|
|
|
|
return;
|
|
|
|
}
|
2016-09-16 12:27:50 +00:00
|
|
|
|
|
|
|
if (!isResizable()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QRect clientArea = isElectricBorderMaximizing() ?
|
|
|
|
workspace()->clientArea(MaximizeArea, Cursor::pos(), desktop()) :
|
|
|
|
workspace()->clientArea(MaximizeArea, this);
|
|
|
|
|
2018-11-08 10:33:57 +00:00
|
|
|
const MaximizeMode oldMode = m_requestedMaximizeMode;
|
|
|
|
const QRect oldGeometry = geometry();
|
|
|
|
|
2015-10-13 08:22:18 +00:00
|
|
|
// 'adjust == true' means to update the size only, e.g. after changing workspace size
|
|
|
|
if (!adjust) {
|
|
|
|
if (vertical)
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
m_requestedMaximizeMode = MaximizeMode(m_requestedMaximizeMode ^ MaximizeVertical);
|
2015-10-13 08:22:18 +00:00
|
|
|
if (horizontal)
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
m_requestedMaximizeMode = MaximizeMode(m_requestedMaximizeMode ^ MaximizeHorizontal);
|
2015-10-13 08:22:18 +00:00
|
|
|
}
|
2016-06-09 12:37:32 +00:00
|
|
|
|
2019-07-09 18:07:21 +00:00
|
|
|
m_requestedMaximizeMode = rules()->checkMaximize(m_requestedMaximizeMode);
|
|
|
|
if (!adjust && m_requestedMaximizeMode == oldMode) {
|
2019-07-08 09:44:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-07-09 17:28:05 +00:00
|
|
|
StackingUpdatesBlocker blocker(workspace());
|
|
|
|
RequestGeometryBlocker geometryBlocker(this);
|
|
|
|
|
2016-06-09 12:37:32 +00:00
|
|
|
// call into decoration update borders
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
if (isDecorated() && decoration()->client() && !(options->borderlessMaximizedWindows() && m_requestedMaximizeMode == KWin::MaximizeFull)) {
|
2016-06-09 12:37:32 +00:00
|
|
|
changeMaximizeRecursion = true;
|
|
|
|
const auto c = decoration()->client().data();
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
if ((m_requestedMaximizeMode & MaximizeVertical) != (oldMode & MaximizeVertical)) {
|
|
|
|
emit c->maximizedVerticallyChanged(m_requestedMaximizeMode & MaximizeVertical);
|
2016-06-09 12:37:32 +00:00
|
|
|
}
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
if ((m_requestedMaximizeMode & MaximizeHorizontal) != (oldMode & MaximizeHorizontal)) {
|
|
|
|
emit c->maximizedHorizontallyChanged(m_requestedMaximizeMode & MaximizeHorizontal);
|
2016-06-09 12:37:32 +00:00
|
|
|
}
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
if ((m_requestedMaximizeMode == MaximizeFull) != (oldMode == MaximizeFull)) {
|
|
|
|
emit c->maximizedChanged(m_requestedMaximizeMode & MaximizeFull);
|
2016-06-09 12:37:32 +00:00
|
|
|
}
|
|
|
|
changeMaximizeRecursion = false;
|
|
|
|
}
|
2016-06-09 14:50:48 +00:00
|
|
|
|
2016-11-25 15:45:40 +00:00
|
|
|
if (options->borderlessMaximizedWindows()) {
|
|
|
|
// triggers a maximize change.
|
|
|
|
// The next setNoBorder interation will exit since there's no change but the first recursion pullutes the restore geometry
|
|
|
|
changeMaximizeRecursion = true;
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
setNoBorder(rules()->checkNoBorder(m_requestedMaximizeMode == MaximizeFull));
|
2016-11-25 15:45:40 +00:00
|
|
|
changeMaximizeRecursion = false;
|
|
|
|
}
|
2016-09-16 12:27:50 +00:00
|
|
|
|
|
|
|
// Conditional quick tiling exit points
|
|
|
|
const auto oldQuickTileMode = quickTileMode();
|
2017-07-18 19:12:37 +00:00
|
|
|
if (quickTileMode() != QuickTileMode(QuickTileFlag::None)) {
|
2016-09-16 12:27:50 +00:00
|
|
|
if (oldMode == MaximizeFull &&
|
|
|
|
!clientArea.contains(m_geomMaximizeRestore.center())) {
|
|
|
|
// Not restoring on the same screen
|
|
|
|
// TODO: The following doesn't work for some reason
|
|
|
|
//quick_tile_mode = QuickTileNone; // And exit quick tile mode manually
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
} else if ((oldMode == MaximizeVertical && m_requestedMaximizeMode == MaximizeRestore) ||
|
|
|
|
(oldMode == MaximizeFull && m_requestedMaximizeMode == MaximizeHorizontal)) {
|
2016-09-16 12:27:50 +00:00
|
|
|
// Modifying geometry of a tiled window
|
2017-07-18 19:12:37 +00:00
|
|
|
updateQuickTileMode(QuickTileFlag::None); // Exit quick tile mode without restoring geometry
|
2016-09-16 12:27:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
if (m_requestedMaximizeMode == MaximizeFull) {
|
2018-11-08 10:33:57 +00:00
|
|
|
m_geomMaximizeRestore = oldGeometry;
|
2016-09-16 12:27:50 +00:00
|
|
|
// TODO: Client has more checks
|
|
|
|
if (options->electricBorderMaximize()) {
|
2017-07-18 19:12:37 +00:00
|
|
|
updateQuickTileMode(QuickTileFlag::Maximize);
|
2016-09-16 12:27:50 +00:00
|
|
|
} else {
|
2017-07-18 19:12:37 +00:00
|
|
|
updateQuickTileMode(QuickTileFlag::None);
|
2016-09-16 12:27:50 +00:00
|
|
|
}
|
|
|
|
if (quickTileMode() != oldQuickTileMode) {
|
|
|
|
emit quickTileModeChanged();
|
|
|
|
}
|
2017-11-22 16:33:21 +00:00
|
|
|
setGeometry(workspace()->clientArea(MaximizeArea, this));
|
2016-06-09 14:50:48 +00:00
|
|
|
workspace()->raiseClient(this);
|
|
|
|
} else {
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
if (m_requestedMaximizeMode == MaximizeRestore) {
|
2017-07-18 19:12:37 +00:00
|
|
|
updateQuickTileMode(QuickTileFlag::None);
|
2016-09-16 12:27:50 +00:00
|
|
|
}
|
|
|
|
if (quickTileMode() != oldQuickTileMode) {
|
|
|
|
emit quickTileModeChanged();
|
|
|
|
}
|
|
|
|
|
2016-06-09 14:50:48 +00:00
|
|
|
if (m_geomMaximizeRestore.isValid()) {
|
2017-11-22 16:33:21 +00:00
|
|
|
setGeometry(m_geomMaximizeRestore);
|
2016-06-09 14:50:48 +00:00
|
|
|
} else {
|
2017-11-22 16:33:21 +00:00
|
|
|
setGeometry(workspace()->clientArea(PlacementArea, this));
|
2016-06-09 14:50:48 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MaximizeMode ShellClient::maximizeMode() const
|
|
|
|
{
|
2015-06-07 01:28:38 +00:00
|
|
|
return m_maximizeMode;
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
2018-10-07 16:51:42 +00:00
|
|
|
MaximizeMode ShellClient::requestedMaximizeMode() const
|
|
|
|
{
|
|
|
|
return m_requestedMaximizeMode;
|
|
|
|
}
|
|
|
|
|
2015-03-16 08:14:04 +00:00
|
|
|
bool ShellClient::noBorder() const
|
|
|
|
{
|
2015-12-17 14:47:36 +00:00
|
|
|
if (m_serverDecoration) {
|
|
|
|
if (m_serverDecoration->mode() == ServerSideDecorationManagerInterface::Mode::Server) {
|
2016-09-12 12:41:03 +00:00
|
|
|
return m_userNoBorder || isFullScreen();
|
2015-12-17 14:47:36 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-01 17:37:18 +00:00
|
|
|
if (m_xdgDecoration && m_xdgDecoration->requestedMode() != XdgDecorationInterface::Mode::ClientSide) {
|
|
|
|
return m_userNoBorder || isFullScreen();
|
|
|
|
}
|
2015-03-16 08:14:04 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-01-09 14:20:19 +00:00
|
|
|
bool ShellClient::isFullScreenable() const
|
|
|
|
{
|
|
|
|
if (!rules()->checkFullScreen(true)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return !isSpecialWindow();
|
|
|
|
}
|
|
|
|
|
2015-03-16 08:14:04 +00:00
|
|
|
void ShellClient::setFullScreen(bool set, bool user)
|
|
|
|
{
|
2019-01-09 19:49:10 +00:00
|
|
|
set = rules()->checkFullScreen(set);
|
|
|
|
|
|
|
|
const bool wasFullscreen = isFullScreen();
|
|
|
|
if (wasFullscreen == set) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (isSpecialWindow()) {
|
2017-10-07 09:41:17 +00:00
|
|
|
return;
|
2019-01-09 19:49:10 +00:00
|
|
|
}
|
|
|
|
if (user && !userCanSetFullScreen()) {
|
2017-10-07 09:41:17 +00:00
|
|
|
return;
|
2019-01-09 19:49:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (wasFullscreen) {
|
2017-10-07 09:41:17 +00:00
|
|
|
workspace()->updateFocusMousePosition(Cursor::pos()); // may cause leave event
|
2018-11-16 11:59:33 +00:00
|
|
|
} else {
|
|
|
|
// in shell surface, maximise mode and fullscreen are exclusive
|
|
|
|
// fullscreen->toplevel should restore the state we had before maximising
|
|
|
|
if (m_shellSurface && m_maximizeMode == MaximizeMode::MaximizeFull) {
|
|
|
|
m_geomFsRestore = m_geomMaximizeRestore;
|
|
|
|
} else {
|
|
|
|
m_geomFsRestore = geometry();
|
|
|
|
}
|
|
|
|
}
|
2017-10-07 09:41:17 +00:00
|
|
|
m_fullScreen = set;
|
2019-01-09 19:49:10 +00:00
|
|
|
|
2017-10-07 09:41:17 +00:00
|
|
|
if (set) {
|
|
|
|
workspace()->raiseClient(this);
|
|
|
|
}
|
|
|
|
RequestGeometryBlocker requestBlocker(this);
|
|
|
|
StackingUpdatesBlocker blocker1(workspace());
|
2017-11-22 16:33:21 +00:00
|
|
|
GeometryUpdatesBlocker blocker2(this);
|
2019-01-09 19:49:10 +00:00
|
|
|
|
2017-10-07 09:41:17 +00:00
|
|
|
workspace()->updateClientLayer(this); // active fullscreens get different layer
|
|
|
|
updateDecoration(false, false);
|
2019-01-09 19:49:10 +00:00
|
|
|
|
|
|
|
if (set) {
|
2017-10-07 09:41:17 +00:00
|
|
|
setGeometry(workspace()->clientArea(FullScreenArea, this));
|
|
|
|
} else {
|
2019-02-22 18:54:52 +00:00
|
|
|
if (m_geomFsRestore.isValid()) {
|
2017-10-07 09:41:17 +00:00
|
|
|
int currentScreen = screen();
|
|
|
|
setGeometry(QRect(m_geomFsRestore.topLeft(), adjustedSize(m_geomFsRestore.size())));
|
|
|
|
if( currentScreen != screen())
|
|
|
|
workspace()->sendClientToScreen( this, currentScreen );
|
|
|
|
} else {
|
2019-02-22 18:54:52 +00:00
|
|
|
// this can happen when the window was first shown already fullscreen,
|
|
|
|
// so let the client set the size by itself
|
|
|
|
setGeometry(QRect(workspace()->clientArea(PlacementArea, this).topLeft(), QSize(0, 0)));
|
2017-10-07 09:41:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-09 19:49:10 +00:00
|
|
|
updateWindowRules(Rules::Fullscreen|Rules::Position|Rules::Size);
|
|
|
|
emit fullScreenChanged();
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::setNoBorder(bool set)
|
|
|
|
{
|
2015-12-17 14:47:36 +00:00
|
|
|
if (!userCanSetNoBorder()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
set = rules()->checkNoBorder(set);
|
|
|
|
if (m_userNoBorder == set) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_userNoBorder = set;
|
|
|
|
updateDecoration(true, false);
|
|
|
|
updateWindowRules(Rules::NoBorder);
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::setOnAllActivities(bool set)
|
|
|
|
{
|
|
|
|
Q_UNUSED(set)
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::takeFocus()
|
|
|
|
{
|
2015-07-09 18:43:41 +00:00
|
|
|
if (rules()->checkAcceptFocus(wantsInput())) {
|
XdgV6 - Kwin side
Summary:
Adds XDGV6 support for the kwin side.
Popup placement support is limited to the stuff v5 had,
a simple offset, rather than the awesome new positioner.
But Qt doesn't make use of it yet either.
Also ideally we should do all the positioning before sending the first
configure, but again Qt doesn't actually do anything with that anyway.
Also integrate pinging clients
Test Plan: gtk3-demo works nicely.
Reviewers: #plasma, graesslin, mart
Reviewed By: #plasma, graesslin
Subscribers: mart, graesslin, kwin, plasma-devel, #kwin
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D6591
2017-09-25 15:37:59 +00:00
|
|
|
if (m_xdgShellSurface) {
|
|
|
|
const qint32 pingSerial = static_cast<XdgShellInterface *>(m_xdgShellSurface->global())->ping(m_xdgShellSurface);
|
|
|
|
m_pingSerials.insert(pingSerial, PingReason::FocusWindow);
|
|
|
|
}
|
2015-07-09 18:43:41 +00:00
|
|
|
setActive(true);
|
|
|
|
}
|
2015-06-23 09:08:28 +00:00
|
|
|
|
2019-02-27 10:52:44 +00:00
|
|
|
if (!keepAbove() && !isOnScreenDisplay() && !belongsToDesktop()) {
|
2015-06-23 09:08:28 +00:00
|
|
|
workspace()->setShowingDesktop(false);
|
2019-02-27 10:52:44 +00:00
|
|
|
}
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
2015-07-07 14:15:58 +00:00
|
|
|
void ShellClient::doSetActive()
|
|
|
|
{
|
2016-08-10 12:19:12 +00:00
|
|
|
if (!isActive()) {
|
|
|
|
return;
|
|
|
|
}
|
2015-07-07 14:15:58 +00:00
|
|
|
StackingUpdatesBlocker blocker(workspace());
|
|
|
|
workspace()->focusToNull();
|
|
|
|
}
|
|
|
|
|
2015-03-16 08:14:04 +00:00
|
|
|
bool ShellClient::userCanSetFullScreen() const
|
|
|
|
{
|
2017-10-07 09:41:17 +00:00
|
|
|
if (m_xdgShellSurface) {
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-16 08:14:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::userCanSetNoBorder() const
|
|
|
|
{
|
2015-12-17 15:11:15 +00:00
|
|
|
if (m_serverDecoration && m_serverDecoration->mode() == ServerSideDecorationManagerInterface::Mode::Server) {
|
2019-09-14 08:58:12 +00:00
|
|
|
return !isFullScreen() && !isShade();
|
2015-12-17 15:11:15 +00:00
|
|
|
}
|
2019-01-01 17:37:18 +00:00
|
|
|
if (m_xdgDecoration && m_xdgDecoration->requestedMode() != XdgDecorationInterface::Mode::ClientSide) {
|
2019-09-14 08:58:12 +00:00
|
|
|
return !isFullScreen() && !isShade();
|
2019-01-01 17:37:18 +00:00
|
|
|
}
|
2015-03-16 08:14:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::wantsInput() const
|
2015-12-07 15:18:30 +00:00
|
|
|
{
|
|
|
|
return rules()->checkAcceptFocus(acceptsFocus());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::acceptsFocus() const
|
2015-03-16 08:14:04 +00:00
|
|
|
{
|
2016-04-18 11:33:23 +00:00
|
|
|
if (waylandServer()->inputMethodConnection() == surface()->client()) {
|
2015-06-13 02:06:12 +00:00
|
|
|
return false;
|
|
|
|
}
|
2016-06-17 06:32:15 +00:00
|
|
|
if (m_plasmaShellSurface) {
|
2016-06-17 07:46:16 +00:00
|
|
|
if (m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::OnScreenDisplay ||
|
2016-06-28 11:25:15 +00:00
|
|
|
m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::ToolTip ||
|
2019-05-02 08:29:38 +00:00
|
|
|
m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Notification ||
|
|
|
|
m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::CriticalNotification) {
|
2016-06-17 06:32:15 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2016-09-12 08:05:49 +00:00
|
|
|
if (m_closing) {
|
|
|
|
// a closing window does not accept focus
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (m_unmapped) {
|
|
|
|
// an unmapped window does not accept focus
|
|
|
|
return false;
|
|
|
|
}
|
2016-04-18 11:33:23 +00:00
|
|
|
if (m_shellSurface) {
|
|
|
|
if (m_shellSurface->isPopup()) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-09-12 08:05:49 +00:00
|
|
|
return m_shellSurface->acceptsKeyboardFocus();
|
2015-09-11 11:33:57 +00:00
|
|
|
}
|
2016-04-22 12:13:37 +00:00
|
|
|
if (m_xdgShellSurface) {
|
|
|
|
// TODO: proper
|
|
|
|
return true;
|
|
|
|
}
|
2016-04-18 11:33:23 +00:00
|
|
|
return false;
|
2015-03-16 08:14:04 +00:00
|
|
|
}
|
|
|
|
|
2015-05-18 12:51:40 +00:00
|
|
|
void ShellClient::createWindowId()
|
|
|
|
{
|
2019-01-27 19:48:00 +00:00
|
|
|
if (!m_internal) {
|
2016-04-18 11:33:23 +00:00
|
|
|
m_windowId = waylandServer()->createWindowId(surface());
|
2015-05-18 12:51:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-13 15:02:30 +00:00
|
|
|
pid_t ShellClient::pid() const
|
|
|
|
{
|
|
|
|
return surface()->client()->processId();
|
|
|
|
}
|
|
|
|
|
2015-11-06 14:08:13 +00:00
|
|
|
bool ShellClient::isLockScreen() const
|
|
|
|
{
|
2016-04-18 11:33:23 +00:00
|
|
|
return surface()->client() == waylandServer()->screenLockerClientConnection();
|
2015-11-06 14:08:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ShellClient::isInputMethod() const
|
|
|
|
{
|
2016-04-18 11:33:23 +00:00
|
|
|
return surface()->client() == waylandServer()->inputMethodConnection();
|
2015-11-06 14:08:13 +00:00
|
|
|
}
|
|
|
|
|
2019-01-27 19:48:00 +00:00
|
|
|
bool ShellClient::requestGeometry(const QRect &rect)
|
2015-05-19 10:03:53 +00:00
|
|
|
{
|
2016-06-09 14:54:06 +00:00
|
|
|
if (m_requestGeometryBlockCounter != 0) {
|
|
|
|
m_blockedRequestGeometry = rect;
|
2019-01-27 19:48:00 +00:00
|
|
|
return false;
|
2016-06-09 14:54:06 +00:00
|
|
|
}
|
2018-10-05 14:27:05 +00:00
|
|
|
|
2019-02-26 13:40:54 +00:00
|
|
|
QSize size;
|
|
|
|
if (rect.isValid()) {
|
2019-05-17 14:13:54 +00:00
|
|
|
size = toWindowGeometry(rect.size());
|
2019-02-26 13:40:54 +00:00
|
|
|
} else {
|
|
|
|
size = QSize(0, 0);
|
|
|
|
}
|
2019-01-01 17:37:18 +00:00
|
|
|
m_requestedClientSize = size;
|
2018-10-10 11:03:22 +00:00
|
|
|
|
2019-02-26 13:40:54 +00:00
|
|
|
quint64 serialId = 0;
|
|
|
|
|
|
|
|
if (m_shellSurface && !size.isEmpty()) {
|
2016-04-22 12:13:37 +00:00
|
|
|
m_shellSurface->requestSize(size);
|
|
|
|
}
|
|
|
|
if (m_xdgShellSurface) {
|
2019-02-26 13:40:54 +00:00
|
|
|
serialId = m_xdgShellSurface->configure(xdgSurfaceStates(), size);
|
2016-04-18 11:33:23 +00:00
|
|
|
}
|
XdgV6 - Kwin side
Summary:
Adds XDGV6 support for the kwin side.
Popup placement support is limited to the stuff v5 had,
a simple offset, rather than the awesome new positioner.
But Qt doesn't make use of it yet either.
Also ideally we should do all the positioning before sending the first
configure, but again Qt doesn't actually do anything with that anyway.
Also integrate pinging clients
Test Plan: gtk3-demo works nicely.
Reviewers: #plasma, graesslin, mart
Reviewed By: #plasma, graesslin
Subscribers: mart, graesslin, kwin, plasma-devel, #kwin
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D6591
2017-09-25 15:37:59 +00:00
|
|
|
if (m_xdgShellPopup) {
|
|
|
|
auto parent = transientFor();
|
|
|
|
if (parent) {
|
|
|
|
const QPoint globalClientContentPos = parent->geometry().topLeft() + parent->clientPos();
|
2019-02-26 13:40:54 +00:00
|
|
|
const QPoint relativeOffset = rect.topLeft() - globalClientContentPos;
|
2019-05-17 14:13:54 +00:00
|
|
|
serialId = m_xdgShellPopup->configure(QRect(relativeOffset, size));
|
XdgV6 - Kwin side
Summary:
Adds XDGV6 support for the kwin side.
Popup placement support is limited to the stuff v5 had,
a simple offset, rather than the awesome new positioner.
But Qt doesn't make use of it yet either.
Also ideally we should do all the positioning before sending the first
configure, but again Qt doesn't actually do anything with that anyway.
Also integrate pinging clients
Test Plan: gtk3-demo works nicely.
Reviewers: #plasma, graesslin, mart
Reviewed By: #plasma, graesslin
Subscribers: mart, graesslin, kwin, plasma-devel, #kwin
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D6591
2017-09-25 15:37:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-26 13:40:54 +00:00
|
|
|
if (rect.isValid()) { //if there's no requested size, then there's implicity no positional information worth using
|
|
|
|
PendingConfigureRequest configureRequest;
|
|
|
|
configureRequest.serialId = serialId;
|
|
|
|
configureRequest.positionAfterResize = rect.topLeft();
|
|
|
|
configureRequest.maximizeMode = m_requestedMaximizeMode;
|
|
|
|
m_pendingConfigureRequests.append(configureRequest);
|
|
|
|
}
|
2018-10-05 14:27:05 +00:00
|
|
|
|
2016-06-09 14:54:06 +00:00
|
|
|
m_blockedRequestGeometry = QRect();
|
2019-01-27 19:48:00 +00:00
|
|
|
return true;
|
2015-05-19 10:03:53 +00:00
|
|
|
}
|
|
|
|
|
2018-10-05 14:27:05 +00:00
|
|
|
void ShellClient::updatePendingGeometry()
|
|
|
|
{
|
2019-08-10 14:31:06 +00:00
|
|
|
QPoint position = pos();
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
MaximizeMode maximizeMode = m_maximizeMode;
|
2018-10-05 14:27:05 +00:00
|
|
|
for (auto it = m_pendingConfigureRequests.begin(); it != m_pendingConfigureRequests.end(); it++) {
|
|
|
|
if (it->serialId > m_lastAckedConfigureRequest) {
|
|
|
|
//this serial is not acked yet, therefore we know all future serials are not
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (it->serialId == m_lastAckedConfigureRequest) {
|
|
|
|
if (position != it->positionAfterResize) {
|
|
|
|
addLayerRepaint(geometry());
|
|
|
|
}
|
|
|
|
position = it->positionAfterResize;
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
maximizeMode = it->maximizeMode;
|
2018-10-05 14:27:05 +00:00
|
|
|
|
|
|
|
m_pendingConfigureRequests.erase(m_pendingConfigureRequests.begin(), ++it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//else serialId < m_lastAckedConfigureRequest and the state is now irrelevant and can be ignored
|
|
|
|
}
|
|
|
|
doSetGeometry(QRect(position, m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
updateMaximizeMode(maximizeMode);
|
2018-10-05 14:27:05 +00:00
|
|
|
}
|
|
|
|
|
2015-05-19 10:03:53 +00:00
|
|
|
void ShellClient::clientFullScreenChanged(bool fullScreen)
|
|
|
|
{
|
2017-10-07 09:41:17 +00:00
|
|
|
setFullScreen(fullScreen, false);
|
2015-05-19 10:03:53 +00:00
|
|
|
}
|
|
|
|
|
2015-05-27 09:48:33 +00:00
|
|
|
void ShellClient::resizeWithChecks(int w, int h, ForceGeometry_t force)
|
|
|
|
{
|
|
|
|
Q_UNUSED(force)
|
|
|
|
QRect area = workspace()->clientArea(WorkArea, this);
|
|
|
|
// don't allow growing larger than workarea
|
|
|
|
if (w > area.width()) {
|
|
|
|
w = area.width();
|
|
|
|
}
|
|
|
|
if (h > area.height()) {
|
|
|
|
h = area.height();
|
|
|
|
}
|
2016-04-18 11:33:23 +00:00
|
|
|
if (m_shellSurface) {
|
|
|
|
m_shellSurface->requestSize(QSize(w, h));
|
|
|
|
}
|
2016-04-22 12:13:37 +00:00
|
|
|
if (m_xdgShellSurface) {
|
|
|
|
m_xdgShellSurface->configure(xdgSurfaceStates(), QSize(w, h));
|
|
|
|
}
|
2015-05-27 09:48:33 +00:00
|
|
|
}
|
|
|
|
|
2015-06-03 19:19:00 +00:00
|
|
|
void ShellClient::unmap()
|
|
|
|
{
|
|
|
|
m_unmapped = true;
|
2019-03-12 09:35:17 +00:00
|
|
|
if (isMoveResize()) {
|
|
|
|
leaveMoveResize();
|
|
|
|
}
|
2019-01-01 17:37:18 +00:00
|
|
|
m_requestedClientSize = QSize(0, 0);
|
2015-07-09 07:10:33 +00:00
|
|
|
destroyWindowManagementInterface();
|
2015-10-22 09:42:52 +00:00
|
|
|
if (Workspace::self()) {
|
|
|
|
addWorkspaceRepaint(visibleRect());
|
|
|
|
workspace()->clientHidden(this);
|
|
|
|
}
|
2015-06-10 15:45:59 +00:00
|
|
|
emit windowHidden(this);
|
2015-06-03 19:19:00 +00:00
|
|
|
}
|
|
|
|
|
2015-06-09 17:10:56 +00:00
|
|
|
void ShellClient::installPlasmaShellSurface(PlasmaShellSurfaceInterface *surface)
|
|
|
|
{
|
|
|
|
m_plasmaShellSurface = surface;
|
|
|
|
auto updatePosition = [this, surface] {
|
2018-05-24 07:58:43 +00:00
|
|
|
QRect rect = QRect(surface->position(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
|
2019-06-05 13:35:31 +00:00
|
|
|
// Shell surfaces of internal windows are sometimes desync to current value.
|
|
|
|
// Make sure to not set window geometry of internal windows to invalid values (bug 386304).
|
|
|
|
// This is a workaround.
|
|
|
|
if (!m_internal || rect.isValid()) {
|
|
|
|
doSetGeometry(rect);
|
|
|
|
}
|
2015-06-09 17:10:56 +00:00
|
|
|
};
|
|
|
|
auto updateRole = [this, surface] {
|
|
|
|
NET::WindowType type = NET::Unknown;
|
|
|
|
switch (surface->role()) {
|
|
|
|
case PlasmaShellSurfaceInterface::Role::Desktop:
|
|
|
|
type = NET::Desktop;
|
|
|
|
break;
|
|
|
|
case PlasmaShellSurfaceInterface::Role::Panel:
|
|
|
|
type = NET::Dock;
|
|
|
|
break;
|
2015-09-03 16:19:38 +00:00
|
|
|
case PlasmaShellSurfaceInterface::Role::OnScreenDisplay:
|
|
|
|
type = NET::OnScreenDisplay;
|
|
|
|
break;
|
2016-06-17 07:46:16 +00:00
|
|
|
case PlasmaShellSurfaceInterface::Role::Notification:
|
|
|
|
type = NET::Notification;
|
|
|
|
break;
|
2016-06-28 11:25:15 +00:00
|
|
|
case PlasmaShellSurfaceInterface::Role::ToolTip:
|
|
|
|
type = NET::Tooltip;
|
|
|
|
break;
|
2019-05-02 08:29:38 +00:00
|
|
|
case PlasmaShellSurfaceInterface::Role::CriticalNotification:
|
|
|
|
type = NET::CriticalNotification;
|
|
|
|
break;
|
2015-06-09 17:10:56 +00:00
|
|
|
case PlasmaShellSurfaceInterface::Role::Normal:
|
|
|
|
default:
|
|
|
|
type = NET::Normal;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (type != m_windowType) {
|
|
|
|
m_windowType = type;
|
2019-05-02 08:29:38 +00:00
|
|
|
if (m_windowType == NET::Desktop || type == NET::Dock || type == NET::OnScreenDisplay || type == NET::Notification || type == NET::Tooltip || type == NET::CriticalNotification) {
|
2016-06-02 15:53:44 +00:00
|
|
|
setOnAllDesktops(true);
|
|
|
|
}
|
2015-06-09 17:10:56 +00:00
|
|
|
workspace()->updateClientArea();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
connect(surface, &PlasmaShellSurfaceInterface::positionChanged, this, updatePosition);
|
|
|
|
connect(surface, &PlasmaShellSurfaceInterface::roleChanged, this, updateRole);
|
2015-06-25 07:04:51 +00:00
|
|
|
connect(surface, &PlasmaShellSurfaceInterface::panelBehaviorChanged, this,
|
2016-09-15 19:03:40 +00:00
|
|
|
[this] {
|
|
|
|
updateShowOnScreenEdge();
|
2015-06-25 07:04:51 +00:00
|
|
|
workspace()->updateClientArea();
|
|
|
|
}
|
|
|
|
);
|
2016-10-17 09:17:48 +00:00
|
|
|
connect(surface, &PlasmaShellSurfaceInterface::panelAutoHideHideRequested, this,
|
|
|
|
[this] {
|
|
|
|
hideClient(true);
|
|
|
|
m_plasmaShellSurface->hideAutoHidingPanel();
|
|
|
|
updateShowOnScreenEdge();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
connect(surface, &PlasmaShellSurfaceInterface::panelAutoHideShowRequested, this,
|
|
|
|
[this] {
|
|
|
|
hideClient(false);
|
|
|
|
ScreenEdges::self()->reserve(this, ElectricNone);
|
|
|
|
m_plasmaShellSurface->showAutoHidingPanel();
|
|
|
|
}
|
|
|
|
);
|
2015-06-09 17:10:56 +00:00
|
|
|
updatePosition();
|
|
|
|
updateRole();
|
2016-09-15 19:03:40 +00:00
|
|
|
updateShowOnScreenEdge();
|
|
|
|
connect(this, &ShellClient::geometryChanged, this, &ShellClient::updateShowOnScreenEdge);
|
2015-09-29 18:25:04 +00:00
|
|
|
|
|
|
|
setSkipTaskbar(surface->skipTaskbar());
|
|
|
|
connect(surface, &PlasmaShellSurfaceInterface::skipTaskbarChanged, this, [this] {
|
|
|
|
setSkipTaskbar(m_plasmaShellSurface->skipTaskbar());
|
|
|
|
});
|
2018-05-24 04:33:39 +00:00
|
|
|
|
|
|
|
setSkipSwitcher(surface->skipSwitcher());
|
|
|
|
connect(surface, &PlasmaShellSurfaceInterface::skipSwitcherChanged, this, [this] {
|
|
|
|
setSkipSwitcher(m_plasmaShellSurface->skipSwitcher());
|
|
|
|
});
|
2015-06-09 17:10:56 +00:00
|
|
|
}
|
|
|
|
|
2016-09-15 19:03:40 +00:00
|
|
|
void ShellClient::updateShowOnScreenEdge()
|
|
|
|
{
|
|
|
|
if (!ScreenEdges::self()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (m_unmapped || !m_plasmaShellSurface || m_plasmaShellSurface->role() != PlasmaShellSurfaceInterface::Role::Panel) {
|
|
|
|
ScreenEdges::self()->reserve(this, ElectricNone);
|
|
|
|
return;
|
|
|
|
}
|
2016-10-17 09:17:48 +00:00
|
|
|
if ((m_plasmaShellSurface->panelBehavior() == PlasmaShellSurfaceInterface::PanelBehavior::AutoHide && m_hidden) ||
|
2016-09-15 19:03:40 +00:00
|
|
|
m_plasmaShellSurface->panelBehavior() == PlasmaShellSurfaceInterface::PanelBehavior::WindowsCanCover) {
|
|
|
|
// screen edge API requires an edge, thus we need to figure out which edge the window borders
|
2019-08-10 14:31:06 +00:00
|
|
|
const QRect clientGeometry = geometry();
|
2016-09-15 19:03:40 +00:00
|
|
|
Qt::Edges edges;
|
|
|
|
for (int i = 0; i < screens()->count(); i++) {
|
2019-08-10 14:31:06 +00:00
|
|
|
const QRect screenGeometry = screens()->geometry(i);
|
|
|
|
if (screenGeometry.left() == clientGeometry.left()) {
|
2016-09-15 19:03:40 +00:00
|
|
|
edges |= Qt::LeftEdge;
|
|
|
|
}
|
2019-08-10 14:31:06 +00:00
|
|
|
if (screenGeometry.right() == clientGeometry.right()) {
|
2016-09-15 19:03:40 +00:00
|
|
|
edges |= Qt::RightEdge;
|
|
|
|
}
|
2019-08-10 14:31:06 +00:00
|
|
|
if (screenGeometry.top() == clientGeometry.top()) {
|
2016-09-15 19:03:40 +00:00
|
|
|
edges |= Qt::TopEdge;
|
|
|
|
}
|
2019-08-10 14:31:06 +00:00
|
|
|
if (screenGeometry.bottom() == clientGeometry.bottom()) {
|
2016-09-15 19:03:40 +00:00
|
|
|
edges |= Qt::BottomEdge;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// a panel might border multiple screen edges. E.g. a horizontal panel at the bottom will
|
|
|
|
// also border the left and right edge
|
|
|
|
// let's remove such cases
|
|
|
|
if (edges.testFlag(Qt::LeftEdge) && edges.testFlag(Qt::RightEdge)) {
|
|
|
|
edges = edges & (~(Qt::LeftEdge | Qt::RightEdge));
|
|
|
|
}
|
|
|
|
if (edges.testFlag(Qt::TopEdge) && edges.testFlag(Qt::BottomEdge)) {
|
|
|
|
edges = edges & (~(Qt::TopEdge | Qt::BottomEdge));
|
|
|
|
}
|
|
|
|
// it's still possible that a panel borders two edges, e.g. bottom and left
|
|
|
|
// in that case the one which is sharing more with the edge wins
|
2019-08-10 14:31:06 +00:00
|
|
|
auto check = [clientGeometry](Qt::Edges edges, Qt::Edge horiz, Qt::Edge vert) {
|
2016-09-15 19:03:40 +00:00
|
|
|
if (edges.testFlag(horiz) && edges.testFlag(vert)) {
|
2019-08-10 14:31:06 +00:00
|
|
|
if (clientGeometry.width() >= clientGeometry.height()) {
|
2016-09-15 19:03:40 +00:00
|
|
|
return edges & ~horiz;
|
|
|
|
} else {
|
|
|
|
return edges & ~vert;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return edges;
|
|
|
|
};
|
|
|
|
edges = check(edges, Qt::LeftEdge, Qt::TopEdge);
|
|
|
|
edges = check(edges, Qt::LeftEdge, Qt::BottomEdge);
|
|
|
|
edges = check(edges, Qt::RightEdge, Qt::TopEdge);
|
|
|
|
edges = check(edges, Qt::RightEdge, Qt::BottomEdge);
|
|
|
|
|
|
|
|
ElectricBorder border = ElectricNone;
|
|
|
|
if (edges.testFlag(Qt::LeftEdge)) {
|
|
|
|
border = ElectricLeft;
|
|
|
|
}
|
|
|
|
if (edges.testFlag(Qt::RightEdge)) {
|
|
|
|
border = ElectricRight;
|
|
|
|
}
|
|
|
|
if (edges.testFlag(Qt::TopEdge)) {
|
|
|
|
border = ElectricTop;
|
|
|
|
}
|
|
|
|
if (edges.testFlag(Qt::BottomEdge)) {
|
|
|
|
border = ElectricBottom;
|
|
|
|
}
|
|
|
|
ScreenEdges::self()->reserve(this, border);
|
|
|
|
} else {
|
|
|
|
ScreenEdges::self()->reserve(this, ElectricNone);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-09 17:10:56 +00:00
|
|
|
bool ShellClient::isInitialPositionSet() const
|
|
|
|
{
|
|
|
|
if (m_plasmaShellSurface) {
|
|
|
|
return m_plasmaShellSurface->isPositionSet();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-22 14:22:24 +00:00
|
|
|
void ShellClient::installAppMenu(AppMenuInterface *menu)
|
|
|
|
{
|
|
|
|
m_appMenuInterface = menu;
|
|
|
|
|
|
|
|
auto updateMenu = [this](AppMenuInterface::InterfaceAddress address) {
|
|
|
|
updateApplicationMenuServiceName(address.serviceName);
|
|
|
|
updateApplicationMenuObjectPath(address.objectPath);
|
|
|
|
};
|
|
|
|
connect(m_appMenuInterface, &AppMenuInterface::addressChanged, this, [=](AppMenuInterface::InterfaceAddress address) {
|
|
|
|
updateMenu(address);
|
|
|
|
});
|
|
|
|
updateMenu(menu->address());
|
|
|
|
}
|
|
|
|
|
2018-01-04 18:32:18 +00:00
|
|
|
void ShellClient::installPalette(ServerSideDecorationPaletteInterface *palette)
|
|
|
|
{
|
|
|
|
m_paletteInterface = palette;
|
|
|
|
|
|
|
|
auto updatePalette = [this](const QString &palette) {
|
|
|
|
AbstractClient::updateColorScheme(rules()->checkDecoColor(palette));
|
|
|
|
};
|
|
|
|
connect(m_paletteInterface, &ServerSideDecorationPaletteInterface::paletteChanged, this, [=](const QString &palette) {
|
|
|
|
updatePalette(palette);
|
|
|
|
});
|
|
|
|
connect(m_paletteInterface, &QObject::destroyed, this, [=]() {
|
|
|
|
updatePalette(QString());
|
|
|
|
});
|
|
|
|
updatePalette(palette->palette());
|
|
|
|
}
|
|
|
|
|
2017-10-01 14:38:57 +00:00
|
|
|
void ShellClient::updateColorScheme()
|
|
|
|
{
|
2018-01-04 18:32:18 +00:00
|
|
|
if (m_paletteInterface) {
|
|
|
|
AbstractClient::updateColorScheme(rules()->checkDecoColor(m_paletteInterface->palette()));
|
2017-10-01 14:38:57 +00:00
|
|
|
} else {
|
|
|
|
AbstractClient::updateColorScheme(rules()->checkDecoColor(QString()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
void ShellClient::updateMaximizeMode(MaximizeMode maximizeMode)
|
|
|
|
{
|
|
|
|
if (maximizeMode == m_maximizeMode) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_maximizeMode = maximizeMode;
|
2019-07-09 18:07:21 +00:00
|
|
|
updateWindowRules(Rules::MaximizeHoriz | Rules::MaximizeVert | Rules::Position | Rules::Size);
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
|
|
|
|
emit clientMaximizedStateChanged(this, m_maximizeMode);
|
2018-11-07 16:32:56 +00:00
|
|
|
emit clientMaximizedStateChanged(this, m_maximizeMode & MaximizeHorizontal, m_maximizeMode & MaximizeVertical);
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
}
|
|
|
|
|
2015-06-19 22:14:49 +00:00
|
|
|
bool ShellClient::hasStrut() const
|
|
|
|
{
|
|
|
|
if (!isShown(true)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!m_plasmaShellSurface) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (m_plasmaShellSurface->role() != PlasmaShellSurfaceInterface::Role::Panel) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-09-15 12:17:48 +00:00
|
|
|
return m_plasmaShellSurface->panelBehavior() == PlasmaShellSurfaceInterface::PanelBehavior::AlwaysVisible;
|
2015-06-19 22:14:49 +00:00
|
|
|
}
|
|
|
|
|
2015-06-19 23:11:42 +00:00
|
|
|
void ShellClient::updateIcon()
|
|
|
|
{
|
2016-10-11 14:32:47 +00:00
|
|
|
const QString waylandIconName = QStringLiteral("wayland");
|
2016-10-27 13:59:08 +00:00
|
|
|
const QString dfIconName = iconFromDesktopFile();
|
|
|
|
const QString iconName = dfIconName.isEmpty() ? waylandIconName : dfIconName;
|
|
|
|
if (iconName == icon().name()) {
|
|
|
|
return;
|
2015-07-15 15:18:39 +00:00
|
|
|
}
|
2016-10-27 13:59:08 +00:00
|
|
|
setIcon(QIcon::fromTheme(iconName));
|
2015-06-19 23:11:42 +00:00
|
|
|
}
|
|
|
|
|
2015-09-11 10:11:01 +00:00
|
|
|
bool ShellClient::isTransient() const
|
|
|
|
{
|
2015-10-08 09:04:06 +00:00
|
|
|
return m_transient;
|
2015-09-11 10:11:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::setTransient()
|
|
|
|
{
|
2016-04-18 11:33:23 +00:00
|
|
|
SurfaceInterface *s = nullptr;
|
|
|
|
if (m_shellSurface) {
|
|
|
|
s = m_shellSurface->transientFor().data();
|
|
|
|
}
|
2016-04-22 12:13:37 +00:00
|
|
|
if (m_xdgShellSurface) {
|
|
|
|
if (auto transient = m_xdgShellSurface->transientFor().data()) {
|
|
|
|
s = transient->surface();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m_xdgShellPopup) {
|
|
|
|
s = m_xdgShellPopup->transientFor().data();
|
|
|
|
}
|
2017-10-13 09:32:02 +00:00
|
|
|
if (!s) {
|
|
|
|
s = waylandServer()->findForeignTransientForSurface(surface());
|
|
|
|
}
|
2016-04-18 11:33:23 +00:00
|
|
|
auto t = waylandServer()->findClient(s);
|
2015-10-01 12:12:46 +00:00
|
|
|
if (t != transientFor()) {
|
|
|
|
// remove from main client
|
|
|
|
if (transientFor())
|
|
|
|
transientFor()->removeTransient(this);
|
|
|
|
setTransientFor(t);
|
|
|
|
if (t) {
|
|
|
|
t->addTransient(this);
|
|
|
|
}
|
|
|
|
}
|
2016-04-18 11:33:23 +00:00
|
|
|
m_transient = (s != nullptr);
|
2015-09-11 10:11:01 +00:00
|
|
|
}
|
|
|
|
|
2015-09-11 11:31:41 +00:00
|
|
|
bool ShellClient::hasTransientPlacementHint() const
|
|
|
|
{
|
2018-10-19 22:21:54 +00:00
|
|
|
return isTransient() && transientFor() != nullptr &&
|
|
|
|
(m_shellSurface || m_xdgShellPopup);
|
2015-09-11 11:31:41 +00:00
|
|
|
}
|
|
|
|
|
2018-10-19 22:21:54 +00:00
|
|
|
QRect ShellClient::transientPlacement(const QRect &bounds) const
|
2015-09-11 11:31:41 +00:00
|
|
|
{
|
2018-10-19 22:21:54 +00:00
|
|
|
QRect anchorRect;
|
|
|
|
Qt::Edges anchorEdge;
|
|
|
|
Qt::Edges gravity;
|
|
|
|
QPoint offset;
|
|
|
|
PositionerConstraints constraintAdjustments;
|
2019-02-22 14:08:47 +00:00
|
|
|
QSize size = geometry().size();
|
2018-10-19 22:21:54 +00:00
|
|
|
|
|
|
|
const QPoint parentClientPos = transientFor()->pos() + transientFor()->clientPos();
|
|
|
|
QRect popupPosition;
|
|
|
|
|
|
|
|
// returns if a target is within the supplied bounds, optional edges argument states which side to check
|
|
|
|
auto inBounds = [bounds](const QRect &target, Qt::Edges edges = Qt::LeftEdge | Qt::RightEdge | Qt::TopEdge | Qt::BottomEdge) -> bool {
|
|
|
|
if (edges & Qt::LeftEdge && target.left() < bounds.left()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (edges & Qt::TopEdge && target.top() < bounds.top()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (edges & Qt::RightEdge && target.right() > bounds.right()) {
|
|
|
|
//normal QRect::right issue cancels out
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (edges & Qt::BottomEdge && target.bottom() > bounds.bottom()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2016-04-18 11:33:23 +00:00
|
|
|
if (m_shellSurface) {
|
2018-10-19 22:21:54 +00:00
|
|
|
anchorRect = QRect(m_shellSurface->transientOffset(), QSize(1,1));
|
|
|
|
anchorEdge = Qt::TopEdge | Qt::LeftEdge;
|
|
|
|
gravity = Qt::BottomEdge | Qt::RightEdge; //our single point represents the top left of the popup
|
|
|
|
constraintAdjustments = (PositionerConstraint::SlideX | PositionerConstraint::SlideY);
|
|
|
|
} else if (m_xdgShellPopup) {
|
|
|
|
anchorRect = m_xdgShellPopup->anchorRect();
|
|
|
|
anchorEdge = m_xdgShellPopup->anchorEdge();
|
|
|
|
gravity = m_xdgShellPopup->gravity();
|
|
|
|
offset = m_xdgShellPopup->anchorOffset();
|
|
|
|
constraintAdjustments = m_xdgShellPopup->constraintAdjustments();
|
2019-02-22 14:08:47 +00:00
|
|
|
if (!size.isValid()) {
|
|
|
|
size = m_xdgShellPopup->initialSize();
|
|
|
|
}
|
2018-10-19 22:21:54 +00:00
|
|
|
} else {
|
|
|
|
Q_UNREACHABLE();
|
2016-04-18 11:33:23 +00:00
|
|
|
}
|
2018-10-19 22:21:54 +00:00
|
|
|
|
2019-02-22 14:08:47 +00:00
|
|
|
|
2018-10-19 22:21:54 +00:00
|
|
|
//initial position
|
2019-02-22 14:08:47 +00:00
|
|
|
popupPosition = QRect(popupOffset(anchorRect, anchorEdge, gravity, size) + offset + parentClientPos, size);
|
2018-10-19 22:21:54 +00:00
|
|
|
|
|
|
|
//if that fits, we don't need to do anything
|
|
|
|
if (inBounds(popupPosition)) {
|
|
|
|
return popupPosition;
|
|
|
|
}
|
|
|
|
//otherwise apply constraint adjustment per axis in order XDG Shell Popup states
|
|
|
|
|
|
|
|
if (constraintAdjustments & PositionerConstraint::FlipX) {
|
|
|
|
if (!inBounds(popupPosition, Qt::LeftEdge | Qt::RightEdge)) {
|
|
|
|
//flip both edges (if either bit is set, XOR both)
|
|
|
|
auto flippedAnchorEdge = anchorEdge;
|
|
|
|
if (flippedAnchorEdge & (Qt::LeftEdge | Qt::RightEdge)) {
|
|
|
|
flippedAnchorEdge ^= (Qt::LeftEdge | Qt::RightEdge);
|
|
|
|
}
|
|
|
|
auto flippedGravity = gravity;
|
|
|
|
if (flippedGravity & (Qt::LeftEdge | Qt::RightEdge)) {
|
|
|
|
flippedGravity ^= (Qt::LeftEdge | Qt::RightEdge);
|
|
|
|
}
|
2019-02-22 14:08:47 +00:00
|
|
|
auto flippedPopupPosition = QRect(popupOffset(anchorRect, flippedAnchorEdge, flippedGravity, size) + offset + parentClientPos, size);
|
2018-10-19 22:21:54 +00:00
|
|
|
|
|
|
|
//if it still doesn't fit we should continue with the unflipped version
|
|
|
|
if (inBounds(flippedPopupPosition, Qt::LeftEdge | Qt::RightEdge)) {
|
2019-02-22 14:08:47 +00:00
|
|
|
popupPosition.moveLeft(flippedPopupPosition.x());
|
2018-10-19 22:21:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (constraintAdjustments & PositionerConstraint::SlideX) {
|
|
|
|
if (!inBounds(popupPosition, Qt::LeftEdge)) {
|
2019-02-22 14:08:47 +00:00
|
|
|
popupPosition.moveLeft(bounds.x());
|
2018-10-19 22:21:54 +00:00
|
|
|
}
|
|
|
|
if (!inBounds(popupPosition, Qt::RightEdge)) {
|
2019-02-22 14:08:47 +00:00
|
|
|
// moveRight suffers from the classic QRect off by one issue
|
|
|
|
popupPosition.moveLeft(bounds.x() + bounds.width() - size.width());
|
2018-10-19 22:21:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (constraintAdjustments & PositionerConstraint::ResizeX) {
|
|
|
|
//TODO
|
|
|
|
//but we need to sort out when this is run as resize should only happen before first configure
|
|
|
|
}
|
|
|
|
|
|
|
|
if (constraintAdjustments & PositionerConstraint::FlipY) {
|
|
|
|
if (!inBounds(popupPosition, Qt::TopEdge | Qt::BottomEdge)) {
|
|
|
|
//flip both edges (if either bit is set, XOR both)
|
|
|
|
auto flippedAnchorEdge = anchorEdge;
|
|
|
|
if (flippedAnchorEdge & (Qt::TopEdge | Qt::BottomEdge)) {
|
|
|
|
flippedAnchorEdge ^= (Qt::TopEdge | Qt::BottomEdge);
|
|
|
|
}
|
|
|
|
auto flippedGravity = gravity;
|
|
|
|
if (flippedGravity & (Qt::TopEdge | Qt::BottomEdge)) {
|
|
|
|
flippedGravity ^= (Qt::TopEdge | Qt::BottomEdge);
|
|
|
|
}
|
2019-02-22 14:08:47 +00:00
|
|
|
auto flippedPopupPosition = QRect(popupOffset(anchorRect, flippedAnchorEdge, flippedGravity, size) + offset + parentClientPos, size);
|
2018-10-19 22:21:54 +00:00
|
|
|
|
|
|
|
//if it still doesn't fit we should continue with the unflipped version
|
|
|
|
if (inBounds(flippedPopupPosition, Qt::TopEdge | Qt::BottomEdge)) {
|
2019-02-22 14:08:47 +00:00
|
|
|
popupPosition.moveTop(flippedPopupPosition.y());
|
2018-10-19 22:21:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (constraintAdjustments & PositionerConstraint::SlideY) {
|
|
|
|
if (!inBounds(popupPosition, Qt::TopEdge)) {
|
2019-02-22 14:08:47 +00:00
|
|
|
popupPosition.moveTop(bounds.y());
|
2018-10-19 22:21:54 +00:00
|
|
|
}
|
|
|
|
if (!inBounds(popupPosition, Qt::BottomEdge)) {
|
2019-02-22 14:08:47 +00:00
|
|
|
popupPosition.moveTop(bounds.y() + bounds.height() - size.height());
|
2018-10-19 22:21:54 +00:00
|
|
|
}
|
2016-04-22 12:13:37 +00:00
|
|
|
}
|
2018-10-19 22:21:54 +00:00
|
|
|
if (constraintAdjustments & PositionerConstraint::ResizeY) {
|
|
|
|
//TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
return popupPosition;
|
|
|
|
}
|
|
|
|
|
2019-02-22 14:08:47 +00:00
|
|
|
QPoint ShellClient::popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity, const QSize popupSize) const
|
2018-10-19 22:21:54 +00:00
|
|
|
{
|
|
|
|
QPoint anchorPoint;
|
|
|
|
switch (anchorEdge & (Qt::LeftEdge | Qt::RightEdge)) {
|
|
|
|
case Qt::LeftEdge:
|
|
|
|
anchorPoint.setX(anchorRect.x());
|
|
|
|
break;
|
|
|
|
case Qt::RightEdge:
|
|
|
|
anchorPoint.setX(anchorRect.x() + anchorRect.width());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
anchorPoint.setX(qRound(anchorRect.x() + anchorRect.width() / 2.0));
|
|
|
|
}
|
|
|
|
switch (anchorEdge & (Qt::TopEdge | Qt::BottomEdge)) {
|
|
|
|
case Qt::TopEdge:
|
|
|
|
anchorPoint.setY(anchorRect.y());
|
|
|
|
break;
|
|
|
|
case Qt::BottomEdge:
|
|
|
|
anchorPoint.setY(anchorRect.y() + anchorRect.height());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
anchorPoint.setY(qRound(anchorRect.y() + anchorRect.height() / 2.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate where the top left point of the popup will end up with the applied gravity
|
|
|
|
// gravity indicates direction. i.e if gravitating towards the top the popup's bottom edge
|
|
|
|
// will next to the anchor point
|
|
|
|
QPoint popupPosAdjust;
|
|
|
|
switch (gravity & (Qt::LeftEdge | Qt::RightEdge)) {
|
|
|
|
case Qt::LeftEdge:
|
|
|
|
popupPosAdjust.setX(-popupSize.width());
|
|
|
|
break;
|
|
|
|
case Qt::RightEdge:
|
|
|
|
popupPosAdjust.setX(0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
popupPosAdjust.setX(qRound(-popupSize.width() / 2.0));
|
|
|
|
}
|
|
|
|
switch (gravity & (Qt::TopEdge | Qt::BottomEdge)) {
|
|
|
|
case Qt::TopEdge:
|
|
|
|
popupPosAdjust.setY(-popupSize.height());
|
|
|
|
break;
|
|
|
|
case Qt::BottomEdge:
|
|
|
|
popupPosAdjust.setY(0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
popupPosAdjust.setY(qRound(-popupSize.height() / 2.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
return anchorPoint + popupPosAdjust;
|
2015-09-11 11:31:41 +00:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:16:48 +00:00
|
|
|
bool ShellClient::isWaitingForMoveResizeSync() const
|
|
|
|
{
|
2019-04-09 10:13:38 +00:00
|
|
|
if (m_shellSurface) {
|
|
|
|
return !m_pendingConfigureRequests.isEmpty();
|
|
|
|
}
|
|
|
|
return false;
|
2015-10-28 10:16:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::doResizeSync()
|
|
|
|
{
|
|
|
|
requestGeometry(moveResizeGeometry());
|
|
|
|
}
|
|
|
|
|
2015-12-07 13:27:06 +00:00
|
|
|
QMatrix4x4 ShellClient::inputTransformation() const
|
|
|
|
{
|
|
|
|
QMatrix4x4 m = Toplevel::inputTransformation();
|
|
|
|
m.translate(-borderLeft(), -borderTop());
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2015-12-17 10:14:54 +00:00
|
|
|
void ShellClient::installServerSideDecoration(KWayland::Server::ServerSideDecorationInterface *deco)
|
|
|
|
{
|
|
|
|
if (m_serverDecoration == deco) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_serverDecoration = deco;
|
|
|
|
connect(m_serverDecoration, &ServerSideDecorationInterface::destroyed, this,
|
|
|
|
[this] {
|
|
|
|
m_serverDecoration = nullptr;
|
2016-05-19 14:37:59 +00:00
|
|
|
if (m_closing || !Workspace::self()) {
|
2016-02-12 13:15:51 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-05-19 14:37:59 +00:00
|
|
|
if (!m_unmapped) {
|
|
|
|
// maybe delay to next event cycle in case the ShellClient is getting destroyed, too
|
|
|
|
updateDecoration(true);
|
|
|
|
}
|
2015-12-17 10:14:54 +00:00
|
|
|
}
|
|
|
|
);
|
2015-12-17 14:47:36 +00:00
|
|
|
if (!m_unmapped) {
|
|
|
|
updateDecoration(true);
|
|
|
|
}
|
2015-12-17 10:14:54 +00:00
|
|
|
connect(m_serverDecoration, &ServerSideDecorationInterface::modeRequested, this,
|
|
|
|
[this] (ServerSideDecorationManagerInterface::Mode mode) {
|
|
|
|
const bool changed = mode != m_serverDecoration->mode();
|
2015-12-17 14:47:36 +00:00
|
|
|
if (changed && !m_unmapped) {
|
|
|
|
updateDecoration(false);
|
2015-12-17 10:14:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-01 17:37:18 +00:00
|
|
|
void ShellClient::installXdgDecoration(XdgDecorationInterface *deco)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_xdgShellSurface);
|
|
|
|
|
|
|
|
m_xdgDecoration = deco;
|
|
|
|
|
|
|
|
connect(m_xdgDecoration, &QObject::destroyed, this,
|
|
|
|
[this] {
|
|
|
|
m_xdgDecoration = nullptr;
|
|
|
|
if (m_closing || !Workspace::self()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
updateDecoration(true);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
connect(m_xdgDecoration, &XdgDecorationInterface::modeRequested, this,
|
|
|
|
[this] () {
|
|
|
|
//force is true as we must send a new configure response
|
|
|
|
updateDecoration(false, true);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-06-03 11:37:24 +00:00
|
|
|
bool ShellClient::shouldExposeToWindowManagement()
|
|
|
|
{
|
2019-01-27 19:48:00 +00:00
|
|
|
if (m_internal) {
|
2016-06-03 11:37:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
2016-06-03 13:27:36 +00:00
|
|
|
if (isLockScreen()) {
|
|
|
|
return false;
|
|
|
|
}
|
XdgV6 - Kwin side
Summary:
Adds XDGV6 support for the kwin side.
Popup placement support is limited to the stuff v5 had,
a simple offset, rather than the awesome new positioner.
But Qt doesn't make use of it yet either.
Also ideally we should do all the positioning before sending the first
configure, but again Qt doesn't actually do anything with that anyway.
Also integrate pinging clients
Test Plan: gtk3-demo works nicely.
Reviewers: #plasma, graesslin, mart
Reviewed By: #plasma, graesslin
Subscribers: mart, graesslin, kwin, plasma-devel, #kwin
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D6591
2017-09-25 15:37:59 +00:00
|
|
|
if (m_xdgShellPopup) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-03 11:37:24 +00:00
|
|
|
if (m_shellSurface) {
|
|
|
|
if (m_shellSurface->isTransient() && !m_shellSurface->acceptsKeyboardFocus()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-04-22 12:13:37 +00:00
|
|
|
KWayland::Server::XdgShellSurfaceInterface::States ShellClient::xdgSurfaceStates() const
|
|
|
|
{
|
|
|
|
XdgShellSurfaceInterface::States states;
|
|
|
|
if (isActive()) {
|
|
|
|
states |= XdgShellSurfaceInterface::State::Activated;
|
|
|
|
}
|
|
|
|
if (isFullScreen()) {
|
|
|
|
states |= XdgShellSurfaceInterface::State::Fullscreen;
|
|
|
|
}
|
[wayland] Asyncronously update maximise flags
Summary:
A window maximising is an async operation. We work out what size we want
the client to be, then request the client to update. The window isn't
really maximised until we get that new buffer with the new size.
This patch splits the requested, pending and current state, updating as
appropriate.
Things are a bit complex with things like borders. Technically we
shouldn't update them till we get a response, but we also need to have
the correct geometry of the full size window in our request. For now
they behave as before, updating when we request the change.
X code is untouched.
This hopefully fixes maximise animations on wayland as now we update the
geometry before emitting maximisedChanged.
Test Plan:
Maximised a window with the button and double clicking title bar.
I get only the following events on maximise/restore:
19:51:39.156 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(47,24 640x509) QRect(0,0 716x573)
19:51:39.157 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised true true
19:51:40.522 KWin::EffectsHandlerImpl::slotGeometryShapeChanged geometry
shape changed QRect(0,0 716x573) QRect(47,24 640x509)
19:51:40.522 KWin::EffectsHandlerImpl::slotClientMaximized slot client
maximised false false
BUG: 382698
Reviewers: #kwin, romangg
Reviewed By: #kwin, romangg
Subscribers: romangg, zzag, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15150
2018-10-05 14:36:02 +00:00
|
|
|
if (m_requestedMaximizeMode == MaximizeMode::MaximizeFull) {
|
2016-04-22 12:13:37 +00:00
|
|
|
states |= XdgShellSurfaceInterface::State::Maximized;
|
|
|
|
}
|
|
|
|
if (isResize()) {
|
|
|
|
states |= XdgShellSurfaceInterface::State::Resizing;
|
|
|
|
}
|
|
|
|
return states;
|
|
|
|
}
|
|
|
|
|
2016-08-11 15:32:39 +00:00
|
|
|
void ShellClient::doMinimize()
|
|
|
|
{
|
2016-08-18 08:30:27 +00:00
|
|
|
if (isMinimized()) {
|
|
|
|
workspace()->clientHidden(this);
|
|
|
|
} else {
|
|
|
|
emit windowShown(this);
|
|
|
|
}
|
2018-12-13 16:47:10 +00:00
|
|
|
workspace()->updateMinimizedOfTransients(this);
|
2016-08-11 15:32:39 +00:00
|
|
|
}
|
|
|
|
|
2016-08-19 10:33:59 +00:00
|
|
|
bool ShellClient::setupCompositing()
|
|
|
|
{
|
|
|
|
if (m_compositingSetup) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
m_compositingSetup = Toplevel::setupCompositing();
|
|
|
|
return m_compositingSetup;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::finishCompositing(ReleaseReason releaseReason)
|
|
|
|
{
|
|
|
|
m_compositingSetup = false;
|
|
|
|
Toplevel::finishCompositing(releaseReason);
|
|
|
|
}
|
|
|
|
|
2019-09-12 14:52:47 +00:00
|
|
|
void ShellClient::placeIn(const QRect &area)
|
2016-08-30 11:16:52 +00:00
|
|
|
{
|
|
|
|
Placement::self()->place(this, area);
|
|
|
|
setGeometryRestore(geometry());
|
|
|
|
}
|
|
|
|
|
2016-09-15 19:03:40 +00:00
|
|
|
void ShellClient::showOnScreenEdge()
|
|
|
|
{
|
|
|
|
if (!m_plasmaShellSurface || m_unmapped) {
|
|
|
|
return;
|
|
|
|
}
|
2016-10-17 09:17:48 +00:00
|
|
|
hideClient(false);
|
2016-09-15 19:03:40 +00:00
|
|
|
workspace()->raiseClient(this);
|
2016-10-17 09:17:48 +00:00
|
|
|
if (m_plasmaShellSurface->panelBehavior() == PlasmaShellSurfaceInterface::PanelBehavior::AutoHide) {
|
|
|
|
m_plasmaShellSurface->showAutoHidingPanel();
|
|
|
|
}
|
2016-09-15 19:03:40 +00:00
|
|
|
}
|
|
|
|
|
2016-10-12 13:09:52 +00:00
|
|
|
bool ShellClient::dockWantsInput() const
|
|
|
|
{
|
|
|
|
if (m_plasmaShellSurface) {
|
|
|
|
if (m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Panel) {
|
|
|
|
return m_plasmaShellSurface->panelTakesFocus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-11-15 15:48:20 +00:00
|
|
|
void ShellClient::killWindow()
|
|
|
|
{
|
|
|
|
if (!surface()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto c = surface()->client();
|
2017-08-06 18:56:13 +00:00
|
|
|
if (c->processId() == getpid() || c->processId() == 0) {
|
2016-11-15 15:48:20 +00:00
|
|
|
c->destroy();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
::kill(c->processId(), SIGTERM);
|
|
|
|
// give it time to terminate and only if terminate fails, try destroy Wayland connection
|
|
|
|
QTimer::singleShot(5000, c, &ClientConnection::destroy);
|
|
|
|
}
|
|
|
|
|
2017-03-25 17:41:28 +00:00
|
|
|
bool ShellClient::hasPopupGrab() const
|
|
|
|
{
|
XdgV6 - Kwin side
Summary:
Adds XDGV6 support for the kwin side.
Popup placement support is limited to the stuff v5 had,
a simple offset, rather than the awesome new positioner.
But Qt doesn't make use of it yet either.
Also ideally we should do all the positioning before sending the first
configure, but again Qt doesn't actually do anything with that anyway.
Also integrate pinging clients
Test Plan: gtk3-demo works nicely.
Reviewers: #plasma, graesslin, mart
Reviewed By: #plasma, graesslin
Subscribers: mart, graesslin, kwin, plasma-devel, #kwin
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D6591
2017-09-25 15:37:59 +00:00
|
|
|
return m_hasPopupGrab;
|
2017-03-25 17:41:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShellClient::popupDone()
|
|
|
|
{
|
|
|
|
if (m_shellSurface) {
|
|
|
|
m_shellSurface->popupDone();
|
|
|
|
}
|
XdgV6 - Kwin side
Summary:
Adds XDGV6 support for the kwin side.
Popup placement support is limited to the stuff v5 had,
a simple offset, rather than the awesome new positioner.
But Qt doesn't make use of it yet either.
Also ideally we should do all the positioning before sending the first
configure, but again Qt doesn't actually do anything with that anyway.
Also integrate pinging clients
Test Plan: gtk3-demo works nicely.
Reviewers: #plasma, graesslin, mart
Reviewed By: #plasma, graesslin
Subscribers: mart, graesslin, kwin, plasma-devel, #kwin
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D6591
2017-09-25 15:37:59 +00:00
|
|
|
if (m_xdgShellPopup) {
|
|
|
|
m_xdgShellPopup->popupDone();
|
|
|
|
}
|
2017-03-25 17:41:28 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 16:57:30 +00:00
|
|
|
void ShellClient::updateClientOutputs()
|
|
|
|
{
|
|
|
|
QVector<OutputInterface*> clientOutputs;
|
|
|
|
const auto outputs = waylandServer()->display()->outputs();
|
|
|
|
for (OutputInterface* output: qAsConst(outputs)) {
|
|
|
|
const QRect outputGeom(output->globalPosition(), output->pixelSize() / output->scale());
|
|
|
|
if (geometry().intersects(outputGeom)) {
|
|
|
|
clientOutputs << output;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
surface()->setOutputs(clientOutputs);
|
|
|
|
}
|
|
|
|
|
2019-05-17 14:13:54 +00:00
|
|
|
void ShellClient::updateWindowMargins()
|
|
|
|
{
|
|
|
|
QRect windowGeometry;
|
|
|
|
QSize clientSize = m_clientSize;
|
|
|
|
|
|
|
|
if (m_xdgShellSurface) {
|
|
|
|
windowGeometry = m_xdgShellSurface->windowGeometry();
|
|
|
|
} else if (m_xdgShellPopup) {
|
|
|
|
windowGeometry = m_xdgShellPopup->windowGeometry();
|
|
|
|
if (!clientSize.isValid()) {
|
|
|
|
clientSize = m_xdgShellPopup->initialSize();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (windowGeometry.isEmpty() ||
|
|
|
|
windowGeometry.width() > clientSize.width() ||
|
|
|
|
windowGeometry.height() > clientSize.height()) {
|
|
|
|
m_windowMargins = QMargins();
|
|
|
|
} else {
|
|
|
|
m_windowMargins = QMargins(windowGeometry.left(),
|
|
|
|
windowGeometry.top(),
|
|
|
|
clientSize.width() - (windowGeometry.right() + 1),
|
|
|
|
clientSize.height() - (windowGeometry.bottom() + 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[effects] Make Scale and Glide effects Wayland-friendly
Summary:
The Scale effect and the Glide effect have to animate only ordinary
windows(i.e. the ones that are considered to be apps).
On X11, in order to distinguish ordinary windows from combo box popups,
popup menus, and other popups, those effects check whether given window
is managed.
On Wayland, there is no concept of managed/unmanaged windows.
XDG Shell protocol defines 2 surface roles:
* xdg_toplevel;
* and, xdg_popup.
The former can be used to implement typical windows, the ones that can
be minimized, maximized, etc.
The latter can be used to implement tooltips, popup menus, etc. Thus,
that's a good criteria to filter popup windows.
CCBUG: 398100
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, graesslin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15117
2018-10-08 18:08:13 +00:00
|
|
|
bool ShellClient::isPopupWindow() const
|
|
|
|
{
|
2018-11-12 10:47:36 +00:00
|
|
|
if (Toplevel::isPopupWindow()) {
|
|
|
|
return true;
|
|
|
|
}
|
[effects] Make Scale and Glide effects Wayland-friendly
Summary:
The Scale effect and the Glide effect have to animate only ordinary
windows(i.e. the ones that are considered to be apps).
On X11, in order to distinguish ordinary windows from combo box popups,
popup menus, and other popups, those effects check whether given window
is managed.
On Wayland, there is no concept of managed/unmanaged windows.
XDG Shell protocol defines 2 surface roles:
* xdg_toplevel;
* and, xdg_popup.
The former can be used to implement typical windows, the ones that can
be minimized, maximized, etc.
The latter can be used to implement tooltips, popup menus, etc. Thus,
that's a good criteria to filter popup windows.
CCBUG: 398100
Reviewers: #kwin, graesslin, davidedmundson
Reviewed By: #kwin, graesslin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D15117
2018-10-08 18:08:13 +00:00
|
|
|
if (m_shellSurface != nullptr) {
|
|
|
|
return m_shellSurface->isPopup();
|
|
|
|
}
|
|
|
|
if (m_xdgShellPopup != nullptr) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-01-27 19:48:00 +00:00
|
|
|
QWindow *ShellClient::internalWindow() const
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
[wayland] Apply window rules only to xdg-shell clients
Summary:
There are rules that have to be applied only once, e.g. every Remember
and Apply Initially rule, as well rules that need to configure the client,
e.g. size, etc. In the best scenario the compositor would evaluate such
rules when the client is about to be mapped.
This change limits window rules only to xdg-shell clients because right
now only this protocol lets compositors to intervene in the client
initialization process. Also, it makes things a bit easier for us on the
compositor side.
xdg-shell protocol satisfies most of ours requirements to implement window
rules, but not all of them. If the client is about to be mapped for the
second time and its size is forced by a rule, then compositor may need
to configure it. Currently, xdg-shell protocol doesn't have any mechanism
that a client could use to notify the compositor about its intent to map.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: fmonteiro, davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D19411
2019-07-09 11:58:57 +00:00
|
|
|
bool ShellClient::supportsWindowRules() const
|
|
|
|
{
|
|
|
|
if (m_plasmaShellSurface) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return m_xdgShellSurface;
|
|
|
|
}
|
|
|
|
|
2015-03-04 08:21:10 +00:00
|
|
|
}
|