2020-08-02 22:22:19 +00:00
|
|
|
/*
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2007-04-29 17:35:43 +00:00
|
|
|
#include "toplevel.h"
|
|
|
|
|
2020-08-20 17:34:15 +00:00
|
|
|
#include "abstract_client.h"
|
2013-04-04 14:14:12 +00:00
|
|
|
#ifdef KWIN_BUILD_ACTIVITIES
|
|
|
|
#include "activities.h"
|
|
|
|
#endif
|
2007-04-29 17:35:43 +00:00
|
|
|
#include "atoms.h"
|
2013-01-07 07:07:27 +00:00
|
|
|
#include "client_machine.h"
|
2019-06-22 10:00:56 +00:00
|
|
|
#include "composite.h"
|
2007-04-29 17:35:43 +00:00
|
|
|
#include "effects.h"
|
2013-04-03 10:19:27 +00:00
|
|
|
#include "screens.h"
|
2011-03-27 10:33:07 +00:00
|
|
|
#include "shadow.h"
|
2019-06-22 10:00:56 +00:00
|
|
|
#include "workspace.h"
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-04-29 15:18:41 +00:00
|
|
|
#include <KWaylandServer/surface_interface.h>
|
2015-02-24 09:54:28 +00:00
|
|
|
|
2013-09-02 11:14:39 +00:00
|
|
|
#include <QDebug>
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
2013-05-08 11:39:06 +00:00
|
|
|
Toplevel::Toplevel()
|
2014-04-25 10:06:39 +00:00
|
|
|
: m_visual(XCB_NONE)
|
2015-06-01 14:25:21 +00:00
|
|
|
, bit_depth(24)
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
, info(nullptr)
|
2019-09-15 14:59:40 +00:00
|
|
|
, ready_for_painting(false)
|
2012-11-15 06:48:08 +00:00
|
|
|
, m_isDamaged(false)
|
2018-11-18 19:13:55 +00:00
|
|
|
, m_internalId(QUuid::createUuid())
|
2013-09-10 05:09:44 +00:00
|
|
|
, m_client()
|
2019-09-06 14:30:26 +00:00
|
|
|
, damage_handle(XCB_NONE)
|
2011-01-30 14:34:42 +00:00
|
|
|
, is_shape(false)
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
, effect_window(nullptr)
|
2013-01-07 07:07:27 +00:00
|
|
|
, m_clientMachine(new ClientMachine(this))
|
2019-09-06 14:30:26 +00:00
|
|
|
, m_wmClientLeader(XCB_WINDOW_NONE)
|
2012-03-28 18:29:33 +00:00
|
|
|
, m_damageReplyPending(false)
|
2013-03-26 06:45:08 +00:00
|
|
|
, m_screen(0)
|
2014-01-24 11:34:16 +00:00
|
|
|
, m_skipCloseAnimation(false)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2020-09-22 00:13:11 +00:00
|
|
|
connect(this, &Toplevel::damaged, this, &Toplevel::needsRepaint);
|
2020-09-23 18:39:59 +00:00
|
|
|
connect(screens(), &Screens::changed, this, &Toplevel::checkScreen);
|
|
|
|
connect(screens(), &Screens::countChanged, this, &Toplevel::checkScreen);
|
2013-03-26 06:45:08 +00:00
|
|
|
setupCheckScreenConnection();
|
2020-07-14 11:34:25 +00:00
|
|
|
connect(this, &Toplevel::bufferGeometryChanged, this, &Toplevel::inputTransformationChanged);
|
2020-02-05 09:28:50 +00:00
|
|
|
|
|
|
|
// Only for compatibility reasons, drop in the next major release.
|
|
|
|
connect(this, &Toplevel::frameGeometryChanged, this, &Toplevel::geometryChanged);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
Toplevel::~Toplevel()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2019-09-06 14:30:26 +00:00
|
|
|
Q_ASSERT(damage_handle == XCB_NONE);
|
2007-04-29 17:35:43 +00:00
|
|
|
delete info;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2020-08-20 17:34:15 +00:00
|
|
|
QDebug operator<<(QDebug debug, const Toplevel *toplevel)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2020-08-20 17:34:15 +00:00
|
|
|
QDebugStateSaver saver(debug);
|
|
|
|
debug.nospace();
|
|
|
|
if (toplevel) {
|
|
|
|
debug << toplevel->metaObject()->className() << '(' << static_cast<const void *>(toplevel);
|
2020-11-04 15:49:10 +00:00
|
|
|
if (toplevel->window()) {
|
|
|
|
debug << ", windowId=0x" << Qt::hex << toplevel->window() << Qt::dec;
|
|
|
|
}
|
2020-08-20 17:34:15 +00:00
|
|
|
if (const KWaylandServer::SurfaceInterface *surface = toplevel->surface()) {
|
|
|
|
debug << ", surface=" << surface;
|
|
|
|
}
|
|
|
|
const AbstractClient *client = qobject_cast<const AbstractClient *>(toplevel);
|
|
|
|
if (client) {
|
|
|
|
if (!client->isPopupWindow()) {
|
|
|
|
debug << ", caption=" << client->caption();
|
|
|
|
}
|
|
|
|
if (client->transientFor()) {
|
|
|
|
debug << ", transientFor=" << client->transientFor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (debug.verbosity() > 2) {
|
|
|
|
debug << ", frameGeometry=" << toplevel->frameGeometry();
|
|
|
|
debug << ", resourceName=" << toplevel->resourceName();
|
|
|
|
debug << ", resourceClass=" << toplevel->resourceClass();
|
|
|
|
}
|
|
|
|
debug << ')';
|
|
|
|
} else {
|
|
|
|
debug << "Toplevel(0x0)";
|
|
|
|
}
|
|
|
|
return debug;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-09-06 14:30:26 +00:00
|
|
|
void Toplevel::detectShape(xcb_window_t id)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2012-01-15 10:03:15 +00:00
|
|
|
const bool wasShape = is_shape;
|
2012-12-21 14:11:31 +00:00
|
|
|
is_shape = Xcb::Extensions::self()->hasShape(id);
|
2012-01-15 10:03:15 +00:00
|
|
|
if (wasShape != is_shape) {
|
|
|
|
emit shapedChanged();
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
// used only by Deleted::copy()
|
2011-01-30 14:34:42 +00:00
|
|
|
void Toplevel::copyToDeleted(Toplevel* c)
|
|
|
|
{
|
2018-11-18 19:13:55 +00:00
|
|
|
m_internalId = c->internalId();
|
2019-12-04 13:18:34 +00:00
|
|
|
m_frameGeometry = c->m_frameGeometry;
|
2020-06-01 10:43:49 +00:00
|
|
|
m_clientGeometry = c->m_clientGeometry;
|
2014-04-25 10:06:39 +00:00
|
|
|
m_visual = c->m_visual;
|
2007-04-29 17:35:43 +00:00
|
|
|
bit_depth = c->bit_depth;
|
|
|
|
info = c->info;
|
2013-09-10 05:09:44 +00:00
|
|
|
m_client.reset(c->m_client, false);
|
2007-06-25 08:51:44 +00:00
|
|
|
ready_for_painting = c->ready_for_painting;
|
2019-09-06 14:30:26 +00:00
|
|
|
damage_handle = XCB_NONE;
|
2007-04-29 17:35:43 +00:00
|
|
|
damage_region = c->damage_region;
|
|
|
|
is_shape = c->is_shape;
|
|
|
|
effect_window = c->effect_window;
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (effect_window != nullptr)
|
2011-01-30 14:34:42 +00:00
|
|
|
effect_window->setWindow(this);
|
2007-04-29 17:35:43 +00:00
|
|
|
resource_name = c->resourceName();
|
|
|
|
resource_class = c->resourceClass();
|
2013-01-07 07:07:27 +00:00
|
|
|
m_clientMachine = c->m_clientMachine;
|
|
|
|
m_clientMachine->setParent(this);
|
2019-09-06 14:30:26 +00:00
|
|
|
m_wmClientLeader = c->wmClientLeader();
|
2011-10-22 09:02:49 +00:00
|
|
|
opaque_region = c->opaqueRegion();
|
2013-03-26 06:45:08 +00:00
|
|
|
m_screen = c->m_screen;
|
2014-01-24 11:34:16 +00:00
|
|
|
m_skipCloseAnimation = c->m_skipCloseAnimation;
|
2015-08-18 12:40:26 +00:00
|
|
|
m_internalFBO = c->m_internalFBO;
|
2019-09-29 10:31:08 +00:00
|
|
|
m_internalImage = c->m_internalImage;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
// before being deleted, remove references to everything that's now
|
|
|
|
// owner by Deleted
|
|
|
|
void Toplevel::disownDataPassedToDeleted()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
info = nullptr;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2009-06-11 20:12:11 +00:00
|
|
|
QRect Toplevel::visibleRect() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2019-09-30 08:30:04 +00:00
|
|
|
// There's no strict order between frame geometry and buffer geometry.
|
|
|
|
QRect rect = frameGeometry() | bufferGeometry();
|
|
|
|
|
2019-09-29 11:15:18 +00:00
|
|
|
if (shadow() && !shadow()->shadowRegion().isEmpty()) {
|
2019-09-30 08:30:04 +00:00
|
|
|
rect |= shadow()->shadowRegion().boundingRect().translated(pos());
|
2011-03-27 10:33:07 +00:00
|
|
|
}
|
2019-09-30 08:30:04 +00:00
|
|
|
|
|
|
|
return rect;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-06-11 20:12:11 +00:00
|
|
|
|
2015-01-15 13:33:28 +00:00
|
|
|
Xcb::Property Toplevel::fetchWmClientLeader() const
|
|
|
|
{
|
|
|
|
return Xcb::Property(false, window(), atoms->wm_client_leader, XCB_ATOM_WINDOW, 0, 10000);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::readWmClientLeader(Xcb::Property &prop)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2019-09-06 14:30:26 +00:00
|
|
|
m_wmClientLeader = prop.value<xcb_window_t>(window());
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2015-01-15 13:33:28 +00:00
|
|
|
void Toplevel::getWmClientLeader()
|
|
|
|
{
|
|
|
|
auto prop = fetchWmClientLeader();
|
|
|
|
readWmClientLeader(prop);
|
|
|
|
}
|
|
|
|
|
2019-02-02 18:17:44 +00:00
|
|
|
/**
|
|
|
|
* Returns sessionId for this client,
|
|
|
|
* taken either from its window or from the leader window.
|
2019-07-29 18:58:33 +00:00
|
|
|
*/
|
2012-04-12 19:52:44 +00:00
|
|
|
QByteArray Toplevel::sessionId() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2014-04-15 08:09:25 +00:00
|
|
|
QByteArray result = Xcb::StringProperty(window(), atoms->sm_client_id);
|
2019-09-06 14:30:26 +00:00
|
|
|
if (result.isEmpty() && m_wmClientLeader && m_wmClientLeader != window()) {
|
|
|
|
result = Xcb::StringProperty(m_wmClientLeader, atoms->sm_client_id);
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
return result;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-02-02 18:17:44 +00:00
|
|
|
/**
|
|
|
|
* Returns command property for this client,
|
|
|
|
* taken either from its window or from the leader window.
|
2019-07-29 18:58:33 +00:00
|
|
|
*/
|
2016-06-23 17:40:40 +00:00
|
|
|
QByteArray Toplevel::wmCommand()
|
|
|
|
{
|
|
|
|
QByteArray result = Xcb::StringProperty(window(), XCB_ATOM_WM_COMMAND);
|
2019-09-06 14:30:26 +00:00
|
|
|
if (result.isEmpty() && m_wmClientLeader && m_wmClientLeader != window()) {
|
|
|
|
result = Xcb::StringProperty(m_wmClientLeader, XCB_ATOM_WM_COMMAND);
|
|
|
|
}
|
2016-06-23 17:40:40 +00:00
|
|
|
result.replace(0, ' ');
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
void Toplevel::getWmClientMachine()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2013-01-07 07:07:27 +00:00
|
|
|
m_clientMachine->resolve(window(), wmClientLeader());
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-02-02 18:17:44 +00:00
|
|
|
/**
|
|
|
|
* Returns client machine for this client,
|
|
|
|
* taken either from its window or from the leader window.
|
2019-07-29 18:58:33 +00:00
|
|
|
*/
|
2011-01-30 14:34:42 +00:00
|
|
|
QByteArray Toplevel::wmClientMachine(bool use_localhost) const
|
|
|
|
{
|
2013-01-07 07:07:27 +00:00
|
|
|
if (!m_clientMachine) {
|
|
|
|
// this should never happen
|
|
|
|
return QByteArray();
|
|
|
|
}
|
|
|
|
if (use_localhost && m_clientMachine->isLocal()) {
|
2011-01-30 14:34:42 +00:00
|
|
|
// special name for the local machine (localhost)
|
2013-01-07 07:07:27 +00:00
|
|
|
return ClientMachine::localhost();
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2013-01-07 07:07:27 +00:00
|
|
|
return m_clientMachine->hostName();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-02-02 18:17:44 +00:00
|
|
|
/**
|
|
|
|
* Returns client leader window for this client.
|
|
|
|
* Returns the client window itself if no leader window is defined.
|
2019-07-29 18:58:33 +00:00
|
|
|
*/
|
2019-09-06 14:30:26 +00:00
|
|
|
xcb_window_t Toplevel::wmClientLeader() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2019-09-06 14:30:26 +00:00
|
|
|
if (m_wmClientLeader != XCB_WINDOW_NONE) {
|
|
|
|
return m_wmClientLeader;
|
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
return window();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
|
|
|
void Toplevel::getResourceClass()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2020-03-17 14:51:21 +00:00
|
|
|
if (!info) {
|
|
|
|
return;
|
|
|
|
}
|
2015-07-20 07:37:36 +00:00
|
|
|
setResourceClass(QByteArray(info->windowClassName()).toLower(), QByteArray(info->windowClassClass()).toLower());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::setResourceClass(const QByteArray &name, const QByteArray &className)
|
|
|
|
{
|
|
|
|
resource_name = name;
|
|
|
|
resource_class = className;
|
2014-04-11 06:06:26 +00:00
|
|
|
emit windowClassChanged();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-12-03 10:14:43 +00:00
|
|
|
bool Toplevel::resourceMatch(const Toplevel *c1, const Toplevel *c2)
|
|
|
|
{
|
|
|
|
return c1->resourceClass() == c2->resourceClass();
|
|
|
|
}
|
|
|
|
|
2007-09-03 15:00:43 +00:00
|
|
|
double Toplevel::opacity() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2020-03-17 14:51:21 +00:00
|
|
|
if (!info) {
|
|
|
|
return 1.0;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
if (info->opacity() == 0xffffffff)
|
2007-04-29 17:35:43 +00:00
|
|
|
return 1.0;
|
|
|
|
return info->opacity() * 1.0 / 0xffffffff;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void Toplevel::setOpacity(double new_opacity)
|
|
|
|
{
|
2020-03-17 14:51:21 +00:00
|
|
|
if (!info) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-09-03 15:00:43 +00:00
|
|
|
double old_opacity = opacity();
|
2011-01-30 14:34:42 +00:00
|
|
|
new_opacity = qBound(0.0, new_opacity, 1.0);
|
|
|
|
if (old_opacity == new_opacity)
|
2007-04-29 17:35:43 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
info->setOpacity(static_cast< unsigned long >(new_opacity * 0xffffffff));
|
|
|
|
if (compositing()) {
|
2007-04-29 17:35:43 +00:00
|
|
|
addRepaintFull();
|
2011-03-06 09:30:23 +00:00
|
|
|
emit opacityChanged(this, old_opacity);
|
2007-04-29 17:35:43 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2007-04-29 17:35:43 +00:00
|
|
|
|
2019-06-22 10:00:56 +00:00
|
|
|
bool Toplevel::setupCompositing()
|
|
|
|
{
|
|
|
|
if (!compositing())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (damage_handle != XCB_NONE)
|
|
|
|
return false;
|
|
|
|
|
2019-12-02 17:36:13 +00:00
|
|
|
if (kwinApp()->operationMode() == Application::OperationModeX11 && !surface()) {
|
2019-06-22 10:00:56 +00:00
|
|
|
damage_handle = xcb_generate_id(connection());
|
2019-12-02 17:36:13 +00:00
|
|
|
xcb_damage_create(connection(), damage_handle, frameId(), XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
|
2019-06-22 10:00:56 +00:00
|
|
|
}
|
|
|
|
|
2019-12-02 17:36:13 +00:00
|
|
|
damage_region = QRegion(0, 0, width(), height());
|
2019-06-22 10:00:56 +00:00
|
|
|
effect_window = new EffectWindowImpl(this);
|
|
|
|
|
|
|
|
Compositor::self()->scene()->addToplevel(this);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::finishCompositing(ReleaseReason releaseReason)
|
|
|
|
{
|
|
|
|
if (kwinApp()->operationMode() == Application::OperationModeX11 && damage_handle == XCB_NONE)
|
|
|
|
return;
|
|
|
|
if (effect_window->window() == this) { // otherwise it's already passed to Deleted, don't free data
|
|
|
|
discardWindowPixmap();
|
|
|
|
delete effect_window;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (damage_handle != XCB_NONE &&
|
|
|
|
releaseReason != ReleaseReason::Destroyed) {
|
|
|
|
xcb_damage_destroy(connection(), damage_handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
damage_handle = XCB_NONE;
|
|
|
|
damage_region = QRegion();
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
effect_window = nullptr;
|
2019-06-22 10:00:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::discardWindowPixmap()
|
|
|
|
{
|
|
|
|
addDamageFull();
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
if (effectWindow() != nullptr && effectWindow()->sceneWindow() != nullptr)
|
[x11] Fix visual artifacts during interactive resize
Summary:
When a window is being interactively resized, its contents may jump. The
reason why that happens is because KWin renders partially resized client
window. Composite extension spec says that a window will get a new pixmap
each time it is resized or mapped. This applies to the frame window, but
not to the client window itself. If the client window is resized,
off-screen storage for the frame window won't be reallocated. Therefore,
KWin may render partially resized client window if the client doesn't
attempt to be in sync with our rendering loop. Currently, the only way
to do that is to use extended frame counters, which are not supported by
KWin.
So, in order to fix visual artifacts during interactive resize, we need
somehow forcefully re-allocate off-screen storage for the frame window.
Unfortunately, Composite extension doesn't provide any request to do
that, so the only option we have is to resize the frame window.
BUG: 415839
FIXED-IN: 5.18.0
Reviewers: #kwin
Subscribers: davidedmundson, ngraham, alexde, fredrik, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D26914
2020-02-03 11:29:43 +00:00
|
|
|
effectWindow()->sceneWindow()->discardPixmap();
|
2019-06-22 10:00:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::damageNotifyEvent()
|
|
|
|
{
|
|
|
|
m_isDamaged = true;
|
|
|
|
|
2020-09-22 00:13:11 +00:00
|
|
|
// Note: The damage is supposed to specify the damage extents,
|
2019-06-22 10:00:56 +00:00
|
|
|
// but we don't know it at this point. No one who connects
|
|
|
|
// to this signal uses the rect however.
|
2020-09-22 00:13:11 +00:00
|
|
|
emit damaged(this, {});
|
2019-06-22 10:00:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Toplevel::compositing() const
|
|
|
|
{
|
|
|
|
if (!Workspace::self()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return Workspace::self()->compositing();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Toplevel::resetAndFetchDamage()
|
|
|
|
{
|
|
|
|
if (!m_isDamaged)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (damage_handle == XCB_NONE) {
|
|
|
|
m_isDamaged = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
xcb_connection_t *conn = connection();
|
|
|
|
|
|
|
|
// Create a new region and copy the damage region to it,
|
|
|
|
// resetting the damaged state.
|
|
|
|
xcb_xfixes_region_t region = xcb_generate_id(conn);
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
xcb_xfixes_create_region(conn, region, 0, nullptr);
|
2019-06-22 10:00:56 +00:00
|
|
|
xcb_damage_subtract(conn, damage_handle, 0, region);
|
|
|
|
|
|
|
|
// Send a fetch-region request and destroy the region
|
|
|
|
m_regionCookie = xcb_xfixes_fetch_region_unchecked(conn, region);
|
|
|
|
xcb_xfixes_destroy_region(conn, region);
|
|
|
|
|
|
|
|
m_isDamaged = false;
|
|
|
|
m_damageReplyPending = true;
|
|
|
|
|
|
|
|
return m_damageReplyPending;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::getDamageRegionReply()
|
|
|
|
{
|
|
|
|
if (!m_damageReplyPending)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_damageReplyPending = false;
|
|
|
|
|
|
|
|
// Get the fetch-region reply
|
|
|
|
xcb_xfixes_fetch_region_reply_t *reply =
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
xcb_xfixes_fetch_region_reply(connection(), m_regionCookie, nullptr);
|
2019-06-22 10:00:56 +00:00
|
|
|
|
|
|
|
if (!reply)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Convert the reply to a QRegion
|
|
|
|
int count = xcb_xfixes_fetch_region_rectangles_length(reply);
|
|
|
|
QRegion region;
|
|
|
|
|
|
|
|
if (count > 1 && count < 16) {
|
|
|
|
xcb_rectangle_t *rects = xcb_xfixes_fetch_region_rectangles(reply);
|
|
|
|
|
|
|
|
QVector<QRect> qrects;
|
|
|
|
qrects.reserve(count);
|
|
|
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
qrects << QRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height);
|
|
|
|
|
|
|
|
region.setRects(qrects.constData(), count);
|
|
|
|
} else
|
|
|
|
region += QRect(reply->extents.x, reply->extents.y,
|
|
|
|
reply->extents.width, reply->extents.height);
|
|
|
|
|
[x11] Add support for _GTK_FRAME_EXTENTS
Summary:
KDE is known for having a strong view on the client-side decorations vs
server-side decorations issue. The main argument raised against CSD is
that desktop will look less consistent when clients start drawing window
decorations by themselves, which is somewhat true. It all ties to how
well each toolkit is integrated with the desktop environment.
KDE doesn't control the desktop market on Linux. Another big "player"
is GNOME. Both KDE and GNOME have very polarized views on in which
direction desktop should move forward. The KDE community is pushing more
toward server-side decorations while the GNOME community is pushing
more toward client-side decorations. Both communities have developed
great applications and it's not rare to see a GNOME application being
used in KDE Plasma. The only problem is that these different views are
not left behind the curtain and our users pay the price. Resizing GTK
clients in Plasma became practically impossible due to resize borders
having small hit area.
When a client draws its window decoration, it's more likely that it also
draws the drop-shadow around the decoration. The compositor must know
the extents of the shadow so things like snapping and so on work as
expected. And here lies the problem... While the xdg-shell protocol has
a way to specify such things, the NetWM spec doesn't have anything like
that. There's _GTK_FRAME_EXTENTS in the wild, however the problem with
it is that it's a proprietary atom, which is specific only to GTK apps.
Due to that, _GTK_FRAME_EXTENTS wasn't implemented because implementing
anything like that would require major changes in how we think about
geometry.
Recent xdg-shell window geometry patches adjusted geometry abstractions
in kwin to such a degree that it's very easy to add support for client
side decorated clients on X11. We just have to make sure that the
X11Client class provides correct buffer geometry and frame geometry when
the gtk frame extents are set.
Even though the X11 code is feature frozen, I still think it's worth
to have _GTK_FRAME_EXTENTS support in kwin because it will fix the resize
issues. Also, because KWin/Wayland is unfortunately far from becoming
default, it will help us with testing some implementation bits of the
window geometry from xdg-shell.
BUG: 390550
FIXED-IN: 5.18.0
Test Plan:
Things like quick tiling, maximizing, tiling scripts and so on work as
expected with GTK clients.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: cblack, trmdi, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D24660
2019-10-08 08:46:59 +00:00
|
|
|
const QRect bufferRect = bufferGeometry();
|
|
|
|
const QRect frameRect = frameGeometry();
|
|
|
|
|
2019-06-22 10:00:56 +00:00
|
|
|
damage_region += region;
|
2020-10-29 18:25:39 +00:00
|
|
|
addRepaint(region.translated(bufferRect.topLeft() - frameRect.topLeft()));
|
2019-06-22 10:00:56 +00:00
|
|
|
|
|
|
|
free(reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::addDamageFull()
|
|
|
|
{
|
|
|
|
if (!compositing())
|
|
|
|
return;
|
|
|
|
|
2019-09-30 09:28:07 +00:00
|
|
|
const QRect bufferRect = bufferGeometry();
|
|
|
|
const QRect frameRect = frameGeometry();
|
2019-06-22 10:00:56 +00:00
|
|
|
|
2019-09-30 09:28:07 +00:00
|
|
|
const int offsetX = bufferRect.x() - frameRect.x();
|
|
|
|
const int offsetY = bufferRect.y() - frameRect.y();
|
|
|
|
|
2020-09-22 00:13:11 +00:00
|
|
|
const QRect damagedRect(0, 0, bufferRect.width(), bufferRect.height());
|
2019-09-30 09:28:07 +00:00
|
|
|
|
|
|
|
damage_region = damagedRect;
|
2020-10-29 18:25:39 +00:00
|
|
|
addRepaint(damagedRect.translated(offsetX, offsetY));
|
2019-09-30 09:28:07 +00:00
|
|
|
|
2020-09-22 00:13:11 +00:00
|
|
|
emit damaged(this, damage_region);
|
2019-06-22 10:00:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::resetDamage()
|
|
|
|
{
|
|
|
|
damage_region = QRegion();
|
|
|
|
}
|
|
|
|
|
2020-10-29 18:25:39 +00:00
|
|
|
void Toplevel::addRepaint(const QRect &rect)
|
2019-06-22 10:00:56 +00:00
|
|
|
{
|
2020-10-29 18:25:39 +00:00
|
|
|
addRepaint(QRegion(rect));
|
2019-06-22 10:00:56 +00:00
|
|
|
}
|
|
|
|
|
2020-10-29 18:25:39 +00:00
|
|
|
void Toplevel::addRepaint(int x, int y, int width, int height)
|
2019-06-22 10:00:56 +00:00
|
|
|
{
|
2020-10-29 18:25:39 +00:00
|
|
|
addRepaint(QRegion(x, y, width, height));
|
2019-06-22 10:00:56 +00:00
|
|
|
}
|
|
|
|
|
2020-10-29 18:25:39 +00:00
|
|
|
void Toplevel::addRepaint(const QRegion ®ion)
|
2019-06-22 10:00:56 +00:00
|
|
|
{
|
2020-10-29 18:25:39 +00:00
|
|
|
if (!effectWindow() || !effectWindow()->sceneWindow()) {
|
2019-06-22 10:00:56 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-10-29 18:25:39 +00:00
|
|
|
effectWindow()->sceneWindow()->addRepaint(region);
|
2019-06-22 10:00:56 +00:00
|
|
|
emit needsRepaint();
|
|
|
|
}
|
|
|
|
|
2020-10-29 18:25:39 +00:00
|
|
|
void Toplevel::addLayerRepaint(const QRect &rect)
|
2019-06-22 10:00:56 +00:00
|
|
|
{
|
2020-10-29 18:25:39 +00:00
|
|
|
addLayerRepaint(QRegion(rect));
|
2019-06-22 10:00:56 +00:00
|
|
|
}
|
|
|
|
|
2020-10-29 18:25:39 +00:00
|
|
|
void Toplevel::addLayerRepaint(int x, int y, int width, int height)
|
2019-06-22 10:00:56 +00:00
|
|
|
{
|
2020-10-29 18:25:39 +00:00
|
|
|
addLayerRepaint(QRegion(x, y, width, height));
|
2019-06-22 10:00:56 +00:00
|
|
|
}
|
|
|
|
|
2020-10-29 18:25:39 +00:00
|
|
|
void Toplevel::addLayerRepaint(const QRegion ®ion)
|
2019-06-22 10:00:56 +00:00
|
|
|
{
|
2020-10-29 18:25:39 +00:00
|
|
|
if (!effectWindow() || !effectWindow()->sceneWindow()) {
|
2019-06-22 10:00:56 +00:00
|
|
|
return;
|
2020-10-29 18:25:39 +00:00
|
|
|
}
|
|
|
|
effectWindow()->sceneWindow()->addLayerRepaint(region);
|
2019-06-22 10:00:56 +00:00
|
|
|
emit needsRepaint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::addRepaintFull()
|
|
|
|
{
|
2020-10-29 18:25:39 +00:00
|
|
|
addRepaint(visibleRect().translated(-pos()));
|
2019-06-22 10:00:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::addWorkspaceRepaint(int x, int y, int w, int h)
|
|
|
|
{
|
|
|
|
addWorkspaceRepaint(QRect(x, y, w, h));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::addWorkspaceRepaint(const QRect& r2)
|
|
|
|
{
|
|
|
|
if (!compositing())
|
|
|
|
return;
|
|
|
|
Compositor::self()->addRepaint(r2);
|
|
|
|
}
|
|
|
|
|
2020-10-29 10:48:10 +00:00
|
|
|
void Toplevel::addWorkspaceRepaint(const QRegion ®ion)
|
|
|
|
{
|
|
|
|
if (compositing()) {
|
|
|
|
Compositor::self()->addRepaint(region);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-29 18:25:39 +00:00
|
|
|
bool Toplevel::wantsRepaint() const
|
|
|
|
{
|
|
|
|
if (!effectWindow() || !effectWindow()->sceneWindow()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return effectWindow()->sceneWindow()->wantsRepaint();
|
|
|
|
}
|
|
|
|
|
2012-01-24 16:00:40 +00:00
|
|
|
void Toplevel::setReadyForPainting()
|
|
|
|
{
|
|
|
|
if (!ready_for_painting) {
|
|
|
|
ready_for_painting = true;
|
|
|
|
if (compositing()) {
|
|
|
|
addRepaintFull();
|
|
|
|
emit windowShown(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-23 14:41:27 +00:00
|
|
|
void Toplevel::deleteEffectWindow()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2008-05-23 14:41:27 +00:00
|
|
|
delete effect_window;
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
effect_window = nullptr;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-05-23 14:41:27 +00:00
|
|
|
|
2013-03-26 06:45:08 +00:00
|
|
|
void Toplevel::checkScreen()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2013-04-03 10:19:27 +00:00
|
|
|
if (screens()->count() == 1) {
|
2013-03-26 06:45:08 +00:00
|
|
|
if (m_screen != 0) {
|
|
|
|
m_screen = 0;
|
|
|
|
emit screenChanged();
|
|
|
|
}
|
2017-11-01 17:54:21 +00:00
|
|
|
} else {
|
2019-09-27 10:01:10 +00:00
|
|
|
const int s = screens()->number(frameGeometry().center());
|
2017-11-01 17:54:21 +00:00
|
|
|
if (s != m_screen) {
|
|
|
|
m_screen = s;
|
|
|
|
emit screenChanged();
|
|
|
|
}
|
2008-06-09 16:09:56 +00:00
|
|
|
}
|
2017-11-01 17:54:21 +00:00
|
|
|
qreal newScale = screens()->scale(m_screen);
|
|
|
|
if (newScale != m_screenScale) {
|
|
|
|
m_screenScale = newScale;
|
|
|
|
emit screenScaleChanged();
|
2013-03-26 06:45:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::setupCheckScreenConnection()
|
|
|
|
{
|
2020-02-05 09:28:50 +00:00
|
|
|
connect(this, &Toplevel::frameGeometryChanged, this, &Toplevel::checkScreen);
|
2013-03-26 06:45:08 +00:00
|
|
|
checkScreen();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::removeCheckScreenConnection()
|
|
|
|
{
|
2020-02-05 09:28:50 +00:00
|
|
|
disconnect(this, &Toplevel::frameGeometryChanged, this, &Toplevel::checkScreen);
|
2013-03-26 06:45:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int Toplevel::screen() const
|
|
|
|
{
|
|
|
|
return m_screen;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-06-09 16:09:56 +00:00
|
|
|
|
2017-11-01 17:54:21 +00:00
|
|
|
qreal Toplevel::screenScale() const
|
|
|
|
{
|
|
|
|
return m_screenScale;
|
|
|
|
}
|
|
|
|
|
2019-08-26 07:44:04 +00:00
|
|
|
qreal Toplevel::bufferScale() const
|
|
|
|
{
|
2020-06-19 07:20:57 +00:00
|
|
|
return surface() ? surface()->bufferScale() : 1;
|
2019-08-26 07:44:04 +00:00
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
bool Toplevel::isOnScreen(int screen) const
|
|
|
|
{
|
2019-09-27 10:01:10 +00:00
|
|
|
return screens()->geometry(screen).intersects(frameGeometry());
|
2013-04-03 10:19:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Toplevel::isOnActiveScreen() const
|
|
|
|
{
|
|
|
|
return isOnScreen(screens()->current());
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2008-06-09 16:09:56 +00:00
|
|
|
|
2019-09-29 11:26:04 +00:00
|
|
|
void Toplevel::updateShadow()
|
2011-03-27 10:33:07 +00:00
|
|
|
{
|
2011-07-02 19:39:01 +00:00
|
|
|
QRect dirtyRect; // old & new shadow region
|
2012-03-24 21:42:29 +00:00
|
|
|
const QRect oldVisibleRect = visibleRect();
|
2020-09-24 14:15:57 +00:00
|
|
|
addWorkspaceRepaint(oldVisibleRect);
|
2019-09-29 11:15:18 +00:00
|
|
|
if (shadow()) {
|
2011-07-02 19:39:01 +00:00
|
|
|
dirtyRect = shadow()->shadowRegion().boundingRect();
|
2018-12-06 12:54:27 +00:00
|
|
|
if (!effectWindow()->sceneWindow()->shadow()->updateShadow()) {
|
|
|
|
effectWindow()->sceneWindow()->updateShadow(nullptr);
|
|
|
|
}
|
|
|
|
emit shadowChanged();
|
2011-03-27 10:33:07 +00:00
|
|
|
} else {
|
2011-04-03 09:31:33 +00:00
|
|
|
Shadow::createShadow(this);
|
2011-07-02 19:39:01 +00:00
|
|
|
}
|
2019-09-29 11:15:18 +00:00
|
|
|
if (shadow())
|
2011-07-02 19:39:01 +00:00
|
|
|
dirtyRect |= shadow()->shadowRegion().boundingRect();
|
2012-03-24 21:42:29 +00:00
|
|
|
if (oldVisibleRect != visibleRect())
|
|
|
|
emit paddingChanged(this, oldVisibleRect);
|
2011-07-02 19:39:01 +00:00
|
|
|
if (dirtyRect.isValid()) {
|
|
|
|
dirtyRect.translate(pos());
|
2012-03-16 17:53:19 +00:00
|
|
|
addLayerRepaint(dirtyRect);
|
2011-03-27 10:33:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-03 09:31:33 +00:00
|
|
|
Shadow *Toplevel::shadow()
|
2011-03-27 10:33:07 +00:00
|
|
|
{
|
2011-04-03 09:31:33 +00:00
|
|
|
if (effectWindow() && effectWindow()->sceneWindow()) {
|
|
|
|
return effectWindow()->sceneWindow()->shadow();
|
|
|
|
} else {
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
return nullptr;
|
2011-04-03 09:31:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const Shadow *Toplevel::shadow() const
|
|
|
|
{
|
|
|
|
if (effectWindow() && effectWindow()->sceneWindow()) {
|
|
|
|
return effectWindow()->sceneWindow()->shadow();
|
|
|
|
} else {
|
Use nullptr everywhere
Summary:
Because KWin is a very old project, we use three kinds of null pointer
literals: 0, NULL, and nullptr. Since C++11, it's recommended to use
nullptr keyword.
This change converts all usages of 0 and NULL literal to nullptr. Even
though it breaks git history, we need to do it in order to have consistent
code as well to ease code reviews (it's very tempting for some people to
add unrelated changes to their patches, e.g. converting NULL to nullptr).
Test Plan: Compiles.
Reviewers: #kwin, davidedmundson, romangg
Reviewed By: #kwin, davidedmundson, romangg
Subscribers: romangg, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D23618
2019-09-19 14:46:54 +00:00
|
|
|
return nullptr;
|
2011-04-03 09:31:33 +00:00
|
|
|
}
|
2011-03-27 10:33:07 +00:00
|
|
|
}
|
2008-06-09 16:09:56 +00:00
|
|
|
|
2014-07-24 06:55:57 +00:00
|
|
|
bool Toplevel::wantsShadowToBeRendered() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-10-22 09:02:49 +00:00
|
|
|
void Toplevel::getWmOpaqueRegion()
|
|
|
|
{
|
2020-03-17 14:51:21 +00:00
|
|
|
if (!info) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-22 14:46:12 +00:00
|
|
|
const auto rects = info->opaqueRegion();
|
2011-10-22 09:02:49 +00:00
|
|
|
QRegion new_opaque_region;
|
2015-01-22 14:46:12 +00:00
|
|
|
for (const auto &r : rects) {
|
|
|
|
new_opaque_region += QRect(r.pos.x, r.pos.y, r.size.width, r.size.height);
|
|
|
|
}
|
2011-10-22 09:02:49 +00:00
|
|
|
|
|
|
|
opaque_region = new_opaque_region;
|
|
|
|
}
|
|
|
|
|
2012-01-15 09:51:09 +00:00
|
|
|
bool Toplevel::isClient() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Toplevel::isDeleted() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-04-04 14:14:12 +00:00
|
|
|
bool Toplevel::isOnCurrentActivity() const
|
|
|
|
{
|
|
|
|
#ifdef KWIN_BUILD_ACTIVITIES
|
2015-07-07 09:48:42 +00:00
|
|
|
if (!Activities::self()) {
|
|
|
|
return true;
|
|
|
|
}
|
2013-04-04 14:14:12 +00:00
|
|
|
return isOnActivity(Activities::self()->current());
|
|
|
|
#else
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-04-24 08:46:34 +00:00
|
|
|
void Toplevel::elevate(bool elevate)
|
|
|
|
{
|
|
|
|
if (!effectWindow()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
effectWindow()->elevate(elevate);
|
2013-07-02 10:45:55 +00:00
|
|
|
addWorkspaceRepaint(visibleRect());
|
2013-04-24 08:46:34 +00:00
|
|
|
}
|
|
|
|
|
2013-04-26 09:18:57 +00:00
|
|
|
pid_t Toplevel::pid() const
|
|
|
|
{
|
2020-03-17 14:51:21 +00:00
|
|
|
if (!info) {
|
|
|
|
return -1;
|
|
|
|
}
|
2013-04-26 09:18:57 +00:00
|
|
|
return info->pid();
|
|
|
|
}
|
|
|
|
|
2013-09-10 06:13:33 +00:00
|
|
|
xcb_window_t Toplevel::frameId() const
|
|
|
|
{
|
|
|
|
return m_client;
|
|
|
|
}
|
|
|
|
|
2015-01-15 14:19:04 +00:00
|
|
|
Xcb::Property Toplevel::fetchSkipCloseAnimation() const
|
|
|
|
{
|
|
|
|
return Xcb::Property(false, window(), atoms->kde_skip_close_animation, XCB_ATOM_CARDINAL, 0, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::readSkipCloseAnimation(Xcb::Property &property)
|
2014-01-24 11:34:16 +00:00
|
|
|
{
|
2014-04-15 08:09:25 +00:00
|
|
|
setSkipCloseAnimation(property.toBool());
|
2014-01-24 11:34:16 +00:00
|
|
|
}
|
|
|
|
|
2015-01-15 14:19:04 +00:00
|
|
|
void Toplevel::getSkipCloseAnimation()
|
|
|
|
{
|
|
|
|
Xcb::Property property = fetchSkipCloseAnimation();
|
|
|
|
readSkipCloseAnimation(property);
|
|
|
|
}
|
|
|
|
|
2014-01-24 11:34:16 +00:00
|
|
|
bool Toplevel::skipsCloseAnimation() const
|
|
|
|
{
|
|
|
|
return m_skipCloseAnimation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::setSkipCloseAnimation(bool set)
|
|
|
|
{
|
|
|
|
if (set == m_skipCloseAnimation) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_skipCloseAnimation = set;
|
|
|
|
emit skipCloseAnimationChanged();
|
|
|
|
}
|
|
|
|
|
2020-04-29 15:18:41 +00:00
|
|
|
void Toplevel::setSurface(KWaylandServer::SurfaceInterface *surface)
|
2015-02-24 09:54:28 +00:00
|
|
|
{
|
|
|
|
if (m_surface == surface) {
|
|
|
|
return;
|
|
|
|
}
|
2020-04-29 15:18:41 +00:00
|
|
|
using namespace KWaylandServer;
|
2015-02-24 09:54:28 +00:00
|
|
|
if (m_surface) {
|
|
|
|
disconnect(m_surface, &SurfaceInterface::damaged, this, &Toplevel::addDamage);
|
2016-08-26 06:32:03 +00:00
|
|
|
disconnect(m_surface, &SurfaceInterface::sizeChanged, this, &Toplevel::discardWindowPixmap);
|
2015-02-24 09:54:28 +00:00
|
|
|
}
|
|
|
|
m_surface = surface;
|
|
|
|
connect(m_surface, &SurfaceInterface::damaged, this, &Toplevel::addDamage);
|
2016-08-26 06:32:03 +00:00
|
|
|
connect(m_surface, &SurfaceInterface::sizeChanged, this, &Toplevel::discardWindowPixmap);
|
2016-03-21 15:24:59 +00:00
|
|
|
connect(m_surface, &SurfaceInterface::subSurfaceTreeChanged, this,
|
|
|
|
[this] {
|
|
|
|
// TODO improve to only update actual visual area
|
|
|
|
if (ready_for_painting) {
|
|
|
|
addDamageFull();
|
|
|
|
m_isDamaged = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
2015-06-01 14:51:27 +00:00
|
|
|
connect(m_surface, &SurfaceInterface::destroyed, this,
|
|
|
|
[this] {
|
|
|
|
m_surface = nullptr;
|
2020-11-03 12:30:48 +00:00
|
|
|
m_surfaceId = 0;
|
2015-06-01 14:51:27 +00:00
|
|
|
}
|
|
|
|
);
|
2020-11-03 12:30:48 +00:00
|
|
|
m_surfaceId = surface->id();
|
2016-06-26 13:57:38 +00:00
|
|
|
emit surfaceChanged();
|
2015-02-24 09:54:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Toplevel::addDamage(const QRegion &damage)
|
|
|
|
{
|
|
|
|
m_isDamaged = true;
|
|
|
|
damage_region += damage;
|
2020-09-22 00:13:11 +00:00
|
|
|
emit damaged(this, damage);
|
2015-02-24 09:54:28 +00:00
|
|
|
}
|
|
|
|
|
2015-03-04 07:53:51 +00:00
|
|
|
QByteArray Toplevel::windowRole() const
|
|
|
|
{
|
2020-03-17 14:51:21 +00:00
|
|
|
if (!info) {
|
|
|
|
return {};
|
|
|
|
}
|
2015-03-04 07:53:51 +00:00
|
|
|
return QByteArray(info->windowRole());
|
|
|
|
}
|
|
|
|
|
2015-06-01 14:25:21 +00:00
|
|
|
void Toplevel::setDepth(int depth)
|
|
|
|
{
|
|
|
|
if (bit_depth == depth) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const bool oldAlpha = hasAlpha();
|
|
|
|
bit_depth = depth;
|
|
|
|
if (oldAlpha != hasAlpha()) {
|
|
|
|
emit hasAlphaChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-18 21:19:13 +00:00
|
|
|
QRegion Toplevel::inputShape() const
|
|
|
|
{
|
|
|
|
if (m_surface) {
|
|
|
|
return m_surface->input();
|
2015-08-10 14:31:45 +00:00
|
|
|
} else {
|
|
|
|
// TODO: maybe also for X11?
|
|
|
|
return QRegion();
|
|
|
|
}
|
2015-06-18 21:19:13 +00:00
|
|
|
}
|
|
|
|
|
2015-12-07 13:25:08 +00:00
|
|
|
QMatrix4x4 Toplevel::inputTransformation() const
|
|
|
|
{
|
|
|
|
QMatrix4x4 m;
|
|
|
|
m.translate(-x(), -y());
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
Adapt to input region changes in kwayland-server
SurfaceInterface::inputIsInfinite() has been dropped. If the surface has
no any input region specified, SurfaceInterface::input() will return a
region that corresponds to the rect of the surface (0, 0, width, height).
While the new design is more robust, for example it's no longer possible
to forget to check SurfaceInterface::inputIsInfinite(), it has shown some
issues in the input stack of kwin.
Currently, acceptsInput() will return false if you attempt to click the
server-side decoration for a surface whose input region is not empty.
Therefore, it's possible for an application to set an input region with
a width and a height of 1. If user doesn't know about KSysGuard or the
possibility of closing apps via the task manager, they won't be able to
close such an application.
Another issue is that if an application has specified an empty input
region on purpose, user will be still able click it. With the new
behavior of SurfaceInterface::input(), this is no longer an issue and it
is handled properly by kwin.
2020-10-17 12:47:25 +00:00
|
|
|
bool Toplevel::hitTest(const QPoint &point) const
|
|
|
|
{
|
|
|
|
if (m_surface && m_surface->isMapped()) {
|
|
|
|
return m_surface->inputSurfaceAt(mapToLocal(point));
|
|
|
|
}
|
|
|
|
return inputGeometry().contains(point);
|
|
|
|
}
|
|
|
|
|
2020-10-17 12:40:51 +00:00
|
|
|
QPoint Toplevel::mapToFrame(const QPoint &point) const
|
|
|
|
{
|
|
|
|
return point - frameGeometry().topLeft();
|
|
|
|
}
|
|
|
|
|
|
|
|
QPoint Toplevel::mapToLocal(const QPoint &point) const
|
|
|
|
{
|
|
|
|
return point - bufferGeometry().topLeft();
|
|
|
|
}
|
|
|
|
|
|
|
|
QPointF Toplevel::mapToLocal(const QPointF &point) const
|
|
|
|
{
|
|
|
|
return point - bufferGeometry().topLeft();
|
|
|
|
}
|
|
|
|
|
2016-09-15 09:44:32 +00:00
|
|
|
QRect Toplevel::inputGeometry() const
|
|
|
|
{
|
2019-09-27 10:01:10 +00:00
|
|
|
return frameGeometry();
|
2016-09-15 09:44:32 +00:00
|
|
|
}
|
|
|
|
|
2018-12-23 07:56:15 +00:00
|
|
|
bool Toplevel::isLocalhost() const
|
|
|
|
{
|
|
|
|
if (!m_clientMachine) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return m_clientMachine->isLocal();
|
|
|
|
}
|
|
|
|
|
2019-12-02 17:36:13 +00:00
|
|
|
QMargins Toplevel::bufferMargins() const
|
|
|
|
{
|
|
|
|
return QMargins();
|
|
|
|
}
|
|
|
|
|
2019-09-27 10:33:42 +00:00
|
|
|
QMargins Toplevel::frameMargins() const
|
|
|
|
{
|
|
|
|
return QMargins();
|
|
|
|
}
|
|
|
|
|
2007-04-29 17:35:43 +00:00
|
|
|
} // namespace
|
|
|
|
|