/******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2007 Lubos Lunak Copyright (C) 2009 Martin Gräßlin Copyright (C) 2009, 2010 Lucas Murray 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 . *********************************************************************/ #include "logout.h" // KConfigSkeleton #include "logoutconfig.h" #include #include #include #include namespace KWin { LogoutEffect::LogoutEffect() : progress(0.0) , displayEffect(false) , logoutWindow(NULL) , logoutWindowClosed(true) , logoutWindowPassed(false) , canDoPersistent(false) , ignoredWindows() { // Persistent effect logoutAtom = XInternAtom(display(), "_KDE_LOGGING_OUT", False); effects->registerPropertyType(logoutAtom, true); // Block KSMServer's effect char net_wm_cm_name[100]; ::memset(net_wm_cm_name, '\0', sizeof(net_wm_cm_name) * sizeof(char)); sprintf(net_wm_cm_name, "_NET_WM_CM_S%d", DefaultScreen(display())); Atom net_wm_cm = XInternAtom(display(), net_wm_cm_name, False); Window sel = XGetSelectionOwner(display(), net_wm_cm); Atom hack = XInternAtom(display(), "_KWIN_LOGOUT_EFFECT", False); XChangeProperty(display(), sel, hack, hack, 8, PropModeReplace, (unsigned char*)&hack, 1); // the atom is not removed when effect is destroyed, this is temporary anyway reconfigure(ReconfigureAll); connect(effects, SIGNAL(windowAdded(KWin::EffectWindow*)), this, SLOT(slotWindowAdded(KWin::EffectWindow*))); connect(effects, SIGNAL(windowClosed(KWin::EffectWindow*)), this, SLOT(slotWindowClosed(KWin::EffectWindow*))); connect(effects, SIGNAL(windowDeleted(KWin::EffectWindow*)), this, SLOT(slotWindowDeleted(KWin::EffectWindow*))); connect(effects, SIGNAL(propertyNotify(KWin::EffectWindow*,long)), this, SLOT(slotPropertyNotify(KWin::EffectWindow*,long))); } LogoutEffect::~LogoutEffect() { } void LogoutEffect::reconfigure(ReconfigureFlags) { LogoutConfig::self()->readConfig(); frameDelay = 0; } void LogoutEffect::prePaintScreen(ScreenPrePaintData& data, int time) { if (frameDelay) --frameDelay; else { if (displayEffect) progress = qMin(1.0, progress + time / animationTime(2000.0)); else if (progress > 0.0) progress = qMax(0.0, progress - time / animationTime(500.0)); } data.paint |= effects->clientArea(FullArea, 0, 0); effects->prePaintScreen(data, time); } void LogoutEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) { if (progress > 0.0) { if (effects->compositingType() == KWin::XRenderCompositing) { // Since we can't do vignetting in XRender just do a stronger desaturation and darken if (w != logoutWindow && !logoutWindowPassed && !ignoredWindows.contains(w)) { data.multiplySaturation((1.0 - progress * 0.8)); data.multiplyBrightness((1.0 - progress * 0.3)); } } if (w == logoutWindow || ignoredWindows.contains(w)) // HACK: All windows past the first ignored one should not be // blurred as it affects the stacking order. // All following windows are on top of the logout window and should not be altered either logoutWindowPassed = true; } effects->paintWindow(w, mask, region, data); } void LogoutEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data) { effects->paintScreen(mask, region, data); } void LogoutEffect::postPaintScreen() { if ((progress != 0.0 && progress != 1.0) || frameDelay) effects->addRepaintFull(); if (progress > 0.0) logoutWindowPassed = false; effects->postPaintScreen(); } void LogoutEffect::slotWindowAdded(EffectWindow* w) { if (isLogoutDialog(w)) { logoutWindow = w; logoutWindowClosed = false; // So we don't blur the window on close progress = 0.0; displayEffect = true; ignoredWindows.clear(); effects->addRepaintFull(); } else if (canDoPersistent) // TODO: Add parent ignoredWindows.append(w); } void LogoutEffect::slotWindowClosed(EffectWindow* w) { if (w == logoutWindow) { logoutWindowClosed = true; if (!canDoPersistent) displayEffect = false; // Fade back to normal effects->addRepaintFull(); } } void LogoutEffect::slotWindowDeleted(EffectWindow* w) { windows.removeAll(w); ignoredWindows.removeAll(w); if (w == logoutWindow) logoutWindow = NULL; } bool LogoutEffect::isLogoutDialog(EffectWindow* w) { // TODO there should be probably a better way (window type?) if (w->windowClass() == "ksmserver ksmserver" && (w->windowRole() == "logoutdialog" || w->windowRole() == "logouteffect")) { return true; } return false; } void LogoutEffect::slotPropertyNotify(EffectWindow* w, long a) { if (w || a != logoutAtom) return; // Not our atom QByteArray byteData = effects->readRootProperty(logoutAtom, logoutAtom, 8); if (byteData.length() < 1) { // Property was deleted displayEffect = false; return; } // We are using a compatible KSMServer therefore only terminate the effect when the // atom is deleted, not when the dialog is closed. canDoPersistent = true; effects->addRepaintFull(); } bool LogoutEffect::isActive() const { return progress != 0 || logoutWindow; } } // namespace