19ad172584
If the Xwayland process crashes, it will bring down the entire session together with itself. Obviously, we don't want that. At least, Wayland clients should survive the crash. This change refactors relevant X11 parts to handle Xwayland crashes in a less fatal way. In order to handle Xwayland crashes better, a pair of start() and stop() methods had been introduced in the Xwayland class to allow starting and stopping the Xwayland process at any moment. If we detect that the Xwayland process has crashed, we will immediately stop the Xwayland server, which in its turn will deactivate the socket notifier and destroy all connected X11 clients. Unfortunately, a couple of subtle changes in X11Client::releaseWindow() and Unmanaged::release() had to be made to ensure that we are left with a valid state after the Xwayland server has been stopped.
215 lines
6.1 KiB
C++
215 lines
6.1 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();
|
|
m_clientGeometry = 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);
|
|
}
|
|
workspace()->removeUnmanaged(this);
|
|
addWorkspaceRepaint(visibleRect());
|
|
if (releaseReason != ReleaseReason::KWinShutsDown) {
|
|
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
|
|
}
|
|
|
|
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
|
|
|