Fix evaluating window rules for closed windows

gedit changes its caption from "Untitled document - gedit" to "gedit"
when it closes. This schedules Window::evaluateWindowRules() to be
called when the window is already marked as deleted. kwin then crashes.

In order to prevent that, a direct connection can be used instead. But
then the caption must be initialized extra carefully because if the
window rule changes the window type, "<N>" can be lost.
This commit is contained in:
Vlad Zahorodnii 2024-01-11 14:44:40 +02:00
parent 4ab504c994
commit bc30ca64dc
3 changed files with 8 additions and 11 deletions

View file

@ -408,10 +408,7 @@ bool Rules::match(const Window *c) const
return false; return false;
} }
if (titlematch != UnimportantMatch) { // track title changes to rematch rules if (titlematch != UnimportantMatch) { // track title changes to rematch rules
QObject::connect(c, &Window::captionChanged, c, &Window::evaluateWindowRules, QObject::connect(c, &Window::captionNormalChanged, c, &Window::evaluateWindowRules, Qt::UniqueConnection);
// QueuedConnection, because title may change before
// the client is ready (could segfault!)
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
} }
if (!matchTitle(c->captionNormal())) { if (!matchTitle(c->captionNormal())) {
return false; return false;

View file

@ -4084,7 +4084,7 @@ void Window::evaluateWindowRules()
void Window::setupWindowRules() void Window::setupWindowRules()
{ {
disconnect(this, &Window::captionChanged, this, &Window::evaluateWindowRules); disconnect(this, &Window::captionNormalChanged, this, &Window::evaluateWindowRules);
m_rules = workspace()->rulebook()->find(this); m_rules = workspace()->rulebook()->find(this);
// check only after getting the rules, because there may be a rule forcing window type // check only after getting the rules, because there may be a rule forcing window type
} }
@ -4099,6 +4099,7 @@ void Window::updateWindowRules(Rules::Types selection)
void Window::finishWindowRules() void Window::finishWindowRules()
{ {
disconnect(this, &Window::captionNormalChanged, this, &Window::evaluateWindowRules);
updateWindowRules(Rules::All); updateWindowRules(Rules::All);
m_rules = WindowRules(); m_rules = WindowRules();
} }
@ -4107,6 +4108,7 @@ void Window::finishWindowRules()
// Used e.g. after the rules have been modified using the kcm. // Used e.g. after the rules have been modified using the kcm.
void Window::applyWindowRules() void Window::applyWindowRules()
{ {
Q_ASSERT(!isDeleted());
// apply force rules // apply force rules
// Placement - does need explicit update, just like some others below // Placement - does need explicit update, just like some others below
// Geometry : setGeometry() doesn't check rules // Geometry : setGeometry() doesn't check rules

View file

@ -639,15 +639,13 @@ bool X11Window::manage(xcb_window_t w, bool isMapped)
readWmClientLeader(wmClientLeaderCookie); readWmClientLeader(wmClientLeaderCookie);
getWmClientMachine(); getWmClientMachine();
getSyncCounter(); getSyncCounter();
// First only read the caption text, so that setupWindowRules() can use it for matching, setCaption(readName());
// and only then really set the caption using setCaption(), which checks for duplicates etc.
// and also relies on rules already existing
cap_normal = readName();
setupWindowRules();
setCaption(cap_normal, true);
setupWindowRules();
connect(this, &X11Window::windowClassChanged, this, &X11Window::evaluateWindowRules); connect(this, &X11Window::windowClassChanged, this, &X11Window::evaluateWindowRules);
updateCaption(); // in case the window type has been changed by a window rule and <N> has been dropped
if (Xcb::Extensions::self()->isShapeAvailable()) { if (Xcb::Extensions::self()->isShapeAvailable()) {
xcb_shape_select_input(kwinApp()->x11Connection(), window(), true); xcb_shape_select_input(kwinApp()->x11Connection(), window(), true);
} }