15af09c70a
Summary: Currently we have two signals that are emitted when the Toplevel's geometry changes - geometryShapeChanged() and geometryChanged(). The former signal is used primarily to invalidate cached window quads and the latter is sort of emitted when the frame geometry changes. But it's not that easy. We have a bunch of connects that link those signals together... The worst part about all of this is that the window quads cache gets invalidated every time a geometry update occurs, for example when user moves a window around on the screen. This change introduces a new signal and deprecates the existing geometryChanged signal. frameGeometryChanged is similar to geometryChanged except that it is emitted when an _actual_ geometry change has occurred. We do still emit geometryShapeChanged signal. However, in long term, we need to get rid of this signal or come up with something that makes sense and doesn't require us to waste computational resources. Reviewers: #kwin, davidedmundson Reviewed By: #kwin, davidedmundson Subscribers: davidedmundson, romangg, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D26863
219 lines
6.2 KiB
C++
219 lines
6.2 KiB
C++
/********************************************************************
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
|
|
|
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 "unmanaged.h"
|
|
|
|
#include "workspace.h"
|
|
#include "effects.h"
|
|
#include "deleted.h"
|
|
#include "utils.h"
|
|
#include "xcbutils.h"
|
|
|
|
#include <QTimer>
|
|
#include <QDebug>
|
|
#include <QWindow>
|
|
|
|
#include <xcb/shape.h>
|
|
|
|
namespace KWin
|
|
{
|
|
|
|
// window types that are supported as unmanaged (mainly for compositing)
|
|
const NET::WindowTypes SUPPORTED_UNMANAGED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
|
|
| NET::ToolbarMask | NET::MenuMask | NET::DialogMask /*| NET::OverrideMask*/ | NET::TopMenuMask
|
|
| NET::UtilityMask | NET::SplashMask | NET::DropdownMenuMask | NET::PopupMenuMask
|
|
| NET::TooltipMask | NET::NotificationMask | NET::ComboBoxMask | NET::DNDIconMask | NET::OnScreenDisplayMask
|
|
| NET::CriticalNotificationMask;
|
|
|
|
Unmanaged::Unmanaged()
|
|
: Toplevel()
|
|
{
|
|
QTimer::singleShot(50, this, SLOT(setReadyForPainting()));
|
|
}
|
|
|
|
Unmanaged::~Unmanaged()
|
|
{
|
|
}
|
|
|
|
bool Unmanaged::track(xcb_window_t w)
|
|
{
|
|
XServerGrabber xserverGrabber;
|
|
Xcb::WindowAttributes attr(w);
|
|
Xcb::WindowGeometry geo(w);
|
|
if (attr.isNull() || attr->map_state != XCB_MAP_STATE_VIEWABLE) {
|
|
return false;
|
|
}
|
|
if (attr->_class == XCB_WINDOW_CLASS_INPUT_ONLY) {
|
|
return false;
|
|
}
|
|
if (geo.isNull()) {
|
|
return false;
|
|
}
|
|
setWindowHandles(w); // the window is also the frame
|
|
Xcb::selectInput(w, attr->your_event_mask | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE);
|
|
m_frameGeometry = geo.rect();
|
|
checkScreen();
|
|
m_visual = attr->visual;
|
|
bit_depth = geo->depth;
|
|
info = new NETWinInfo(connection(), w, rootWindow(),
|
|
NET::WMWindowType | NET::WMPid,
|
|
NET::WM2Opacity |
|
|
NET::WM2WindowRole |
|
|
NET::WM2WindowClass |
|
|
NET::WM2OpaqueRegion);
|
|
getResourceClass();
|
|
getWmClientLeader();
|
|
getWmClientMachine();
|
|
if (Xcb::Extensions::self()->isShapeAvailable())
|
|
xcb_shape_select_input(connection(), w, true);
|
|
detectShape(w);
|
|
getWmOpaqueRegion();
|
|
getSkipCloseAnimation();
|
|
setupCompositing();
|
|
if (QWindow *internalWindow = findInternalWindow()) {
|
|
m_outline = internalWindow->property("__kwin_outline").toBool();
|
|
}
|
|
if (effects)
|
|
static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowStacking();
|
|
return true;
|
|
}
|
|
|
|
void Unmanaged::release(ReleaseReason releaseReason)
|
|
{
|
|
Deleted* del = nullptr;
|
|
if (releaseReason != ReleaseReason::KWinShutsDown) {
|
|
del = Deleted::create(this);
|
|
}
|
|
emit windowClosed(this, del);
|
|
finishCompositing(releaseReason);
|
|
if (!QWidget::find(window()) && releaseReason != ReleaseReason::Destroyed) { // don't affect our own windows
|
|
if (Xcb::Extensions::self()->isShapeAvailable())
|
|
xcb_shape_select_input(connection(), window(), false);
|
|
Xcb::selectInput(window(), XCB_EVENT_MASK_NO_EVENT);
|
|
}
|
|
if (releaseReason != ReleaseReason::KWinShutsDown) {
|
|
workspace()->removeUnmanaged(this);
|
|
addWorkspaceRepaint(del->visibleRect());
|
|
disownDataPassedToDeleted();
|
|
del->unrefWindow();
|
|
}
|
|
deleteUnmanaged(this);
|
|
}
|
|
|
|
void Unmanaged::deleteUnmanaged(Unmanaged* c)
|
|
{
|
|
delete c;
|
|
}
|
|
|
|
bool Unmanaged::hasScheduledRelease() const
|
|
{
|
|
return m_scheduledRelease;
|
|
}
|
|
|
|
QRect Unmanaged::bufferGeometry() const
|
|
{
|
|
return m_frameGeometry;
|
|
}
|
|
|
|
int Unmanaged::desktop() const
|
|
{
|
|
return NET::OnAllDesktops; // TODO for some window types should be the current desktop?
|
|
}
|
|
|
|
QStringList Unmanaged::activities() const
|
|
{
|
|
return QStringList();
|
|
}
|
|
|
|
QVector<VirtualDesktop *> Unmanaged::desktops() const
|
|
{
|
|
return QVector<VirtualDesktop *>();
|
|
}
|
|
|
|
QPoint Unmanaged::clientPos() const
|
|
{
|
|
return QPoint(0, 0); // unmanaged windows don't have decorations
|
|
}
|
|
|
|
QSize Unmanaged::clientSize() const
|
|
{
|
|
return size();
|
|
}
|
|
|
|
QRect Unmanaged::transparentRect() const
|
|
{
|
|
return QRect(clientPos(), clientSize());
|
|
}
|
|
|
|
void Unmanaged::debug(QDebug& stream) const
|
|
{
|
|
stream << "\'ID:" << window() << "\'";
|
|
}
|
|
|
|
NET::WindowType Unmanaged::windowType(bool direct, int supportedTypes) const
|
|
{
|
|
// for unmanaged windows the direct does not make any difference
|
|
// as there are no rules to check and no hacks to apply
|
|
Q_UNUSED(direct)
|
|
if (supportedTypes == 0) {
|
|
supportedTypes = SUPPORTED_UNMANAGED_WINDOW_TYPES_MASK;
|
|
}
|
|
return info->windowType(NET::WindowTypes(supportedTypes));
|
|
}
|
|
|
|
bool Unmanaged::isOutline() const
|
|
{
|
|
return m_outline;
|
|
}
|
|
|
|
void Unmanaged::addDamage(const QRegion &damage)
|
|
{
|
|
repaints_region += damage;
|
|
Toplevel::addDamage(damage);
|
|
}
|
|
|
|
QWindow *Unmanaged::findInternalWindow() const
|
|
{
|
|
const QWindowList windows = kwinApp()->topLevelWindows();
|
|
for (QWindow *w : windows) {
|
|
if (w->winId() == window()) {
|
|
return w;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool Unmanaged::setupCompositing()
|
|
{
|
|
if (!Toplevel::setupCompositing()) {
|
|
return false;
|
|
}
|
|
|
|
// With unmanaged windows there is a race condition between the client painting the window
|
|
// and us setting up damage tracking. If the client wins we won't get a damage event even
|
|
// though the window has been painted. To avoid this we mark the whole window as damaged
|
|
// and schedule a repaint immediately after creating the damage object.
|
|
addDamageFull();
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|