Source Code (Use browser search to find items of interest.)

Class Index

kdesktop'SaverEngine (./kdebase/kdesktop/lockeng.h:22)

class SaverEngine 
    : public QWidget,
      virtual public KScreensaverIface
{
    Q_OBJECT
public:
    SaverEngine();
    ~SaverEngine();

    /**
     * Lock the screen
     */
    virtual void lock();

    /**
     * Save the screen
     */
    virtual void save();

    /**
     * return true if the screensaver is enabled
     */
    virtual int  isEnabled();

    /**
     * return true if the screen is currently blanked
     */
    virtual int  isBlanked();

    /**
     * Read and apply configuration.
     */
    virtual void configure();

    enum State { Waiting, Saving, Password };

protected:
    virtual bool x11Event(XEvent *);
    virtual void timerEvent(QTimerEvent *);

protected slots:
    void idleTimeout();
    void passwordChecked(KProcess *);

protected:
    void readSaver(QString saver);
    void createSaverWindow();
    void hideSaverWindow();
    void saveVRoot();
    void setVRoot(Window win);
    void removeVRoot(Window win);
    bool grabKeyboard();
    bool grabMouse();
    bool grabInput();
    void ungrabInput();
    void startSaver();
    void stopSaver();
    bool startHack();
    void stopHack();
    void showPassDlg();
    void hidePassDlg();
    void setPassDlgTimeout(int t);
    void killPassDlgTimeout();
    void startCheckPassword();
    bool handleKeyPress(XKeyEvent *xke);

protected:
    bool        mEnabled;
    bool        mLock;
    int         mPriority;
    bool        mLockOnce;
    State       mState;
    PasswordDlg *mPassDlg;
    Colormap    mColorMap;
    XAutoLock   *mXAutoLock;
    int         mHidePassTimerId;
    int         mCheckPassTimerId;
    KProcess    mPassProc;
    KProcess    mHackProc;
    bool        mCheckingPass;
    bool        mPasswordStars;
    int         mRootWidth;
    int         mRootHeight;
    QString     mSaverExec;

    // the original X screensaver parameters
    int         mXTimeout;
    int         mXInterval;
    int         mXBlanking;
    int         mXExposures;
};

kdesktop'SaverEngine::SaverEngine() (./kdebase/kdesktop/lockeng.cc:45)

SaverEngine::SaverEngine()
    : QWidget(0L, "saver window", WStyle_Customize | WStyle_NoBorder),
      DCOPObject("KScreensaverIface")
{
    kapp->installX11EventFilter(this);

    // Save X screensaver parameters
    XGetScreenSaver(qt_xdisplay(), &mXTimeout, &mXInterval,
                    &mXBlanking, &mXExposures);

    // Get root window size
    XWindowAttributes rootAttr;
    XGetWindowAttributes(qt_xdisplay(), RootWindow(qt_xdisplay(),
                        qt_xscreen()), &rootAttr);
    mRootWidth = rootAttr.width;
    mRootHeight = rootAttr.height;

    // Add non-KDE path
    KGlobal::dirs()->addResourceType("scrsav",
                                    KGlobal::dirs()->kde_default("apps") +
                                    "apps/ScreenSavers/");

    // Add KDE specific screensaver path
    KGlobal::dirs()->addResourceType("scrsav",
                                     KGlobal::dirs()->kde_default("apps") +
                                     "System/ScreenSavers/");

    mState = Waiting;
    mPassDlg = 0;
    mHidePassTimerId = 0;
    mCheckPassTimerId = 0;
    mCheckingPass = false;
    mXAutoLock = 0;
    mEnabled = false;
    mLockOnce = false;

    // virtual root property
    gXA_VROOT = XInternAtom (qt_xdisplay(), "__SWM_VROOT", False);

    createSaverWindow();

    connect(&mPassProc, SIGNAL(processExited(KProcess *)),
                        SLOT(passwordChecked(KProcess *)));

    configure();
}

//---------------------------------------------------------------------------
//
// Destructor - usual cleanups.
//

kdesktop'SaverEngine::~SaverEngine() (./kdebase/kdesktop/lockeng.cc:96)

SaverEngine::~SaverEngine()
{
    hidePassDlg();

    if (mXAutoLock)
    {
        delete mXAutoLock;
    }

    // Restore X screensaver parameters
    XSetScreenSaver(qt_xdisplay(), mXTimeout, mXInterval, mXBlanking,
                    mXExposures);
}

//---------------------------------------------------------------------------

kdesktop'SaverEngine::lock() (./kdebase/kdesktop/lockeng.cc:111)

void SaverEngine::lock()
{
    if (mState == Waiting)
    {
        mLockOnce = true;
        startSaver();
    }
}

//---------------------------------------------------------------------------

kdesktop'SaverEngine::save() (./kdebase/kdesktop/lockeng.cc:121)

void SaverEngine::save()
{
    if (mState == Waiting)
    {
        startSaver();
    }
}

//---------------------------------------------------------------------------

kdesktop'SaverEngine::isEnabled() (./kdebase/kdesktop/lockeng.cc:130)

int SaverEngine::isEnabled()
{
  return mEnabled;
}

//---------------------------------------------------------------------------

kdesktop'SaverEngine::isBlanked() (./kdebase/kdesktop/lockeng.cc:136)

int SaverEngine::isBlanked()
{
  return (mState != Waiting);
}

//---------------------------------------------------------------------------
//
// Read and apply configuration.
//

kdesktop'SaverEngine::configure() (./kdebase/kdesktop/lockeng.cc:145)

void SaverEngine::configure()
{
    // If we aren't in a suitable state, we will not reconfigure.
    if (mState != Waiting)
    {
        return;
    }

    if (mXAutoLock)
    {
        delete mXAutoLock;
        mXAutoLock = 0;
    }

    // create a new config obj to ensure we read the latest options
    KConfig *config = new KConfig( "kdesktoprc", true);

    config->setGroup("ScreenSaver");

    mEnabled  = config->readBoolEntry("Enabled", false);
    mLock     = config->readBoolEntry("Lock", false);
    mPriority = config->readNumEntry("Priority", 0);
    if (mPriority < 0) mPriority = 0;
    if (mPriority > 19) mPriority = 19;
    int timeout = config->readNumEntry("Timeout", 300);
    mPasswordStars = config->readBoolEntry("PasswordAsStars", true);
    QString saver = config->readEntry("Saver");

    if (mEnabled)
    {
        readSaver(saver);

        mXAutoLock = new XAutoLock();
        connect(mXAutoLock, SIGNAL(timeout()), SLOT(idleTimeout()));
        mXAutoLock->setTimeout(timeout);
        mXAutoLock->start();

        XSetScreenSaver(qt_xdisplay(), 0, mXInterval, mXBlanking, mXExposures);

        kdDebug(1204) << "Saver Engine started" << endl;
    }
    else
    {
        mSaverExec = QString::null;
        XSetScreenSaver(qt_xdisplay(), mXTimeout, mXInterval, mXBlanking,
                        mXExposures);

        kdDebug(1204) << "Saver Engine disabled" << endl;
    }

    delete config;
}

//---------------------------------------------------------------------------
//
// Read the command line needed to run the screensaver given a .desktop file.
//

kdesktop'SaverEngine::readSaver() (./kdebase/kdesktop/lockeng.cc:202)

void SaverEngine::readSaver(QString saver)
{
    if (!saver.isEmpty())
    {
        QString file = locate("scrsav", saver);

        debug("Reading saver: %s", saver.ascii());

        KDesktopFile config(file, true);

        if (config.hasActionGroup("Root"))
        {
            config.setActionGroup("Root");
            mSaverExec = config.readEntry("Exec");
        }

        debug("Saver-exec: %s", mSaverExec.ascii());
    }
}

//---------------------------------------------------------------------------
//
// Create a window to draw our screen saver on.
//

kdesktop'SaverEngine::createSaverWindow() (./kdebase/kdesktop/lockeng.cc:226)

void SaverEngine::createSaverWindow()
{
    XWindowAttributes attrs;
    XGetWindowAttributes(qt_xdisplay(), winId(), &attrs);
    mColorMap = attrs.colormap;

    // We only create the window once, but we reset its attributes every
    // time.

    // Set virtual root property
    saveVRoot();
    if (gVRoot)
    {
      removeVRoot(gVRoot);
    }
    setVRoot(winId());

    XSetWindowAttributes attr;
    if (mColorMap != None)
    {
        attr.colormap = mColorMap;
    }
    else
    {
        attr.colormap = DefaultColormapOfScreen(
                                ScreenOfDisplay(qt_xdisplay(), qt_xscreen()));
    }
    attr.event_mask = KeyPressMask | ButtonPressMask | MotionNotify |
                        VisibilityChangeMask | ExposureMask;
    XChangeWindowAttributes(qt_xdisplay(), winId(),
                            CWEventMask | CWColormap, &attr);

    erase();

    // set NoBackground so that the saver can capture the current
    // screen state if necessary
    setBackgroundMode( QWidget::NoBackground );

    QBitmap bm(1, 1, TRUE);
    QCursor c(bm, bm);
    setCursor( c );
    setGeometry(0, 0, mRootWidth, mRootHeight);
    hide();

    debug("Saver window Id: %d", winId());
}

//---------------------------------------------------------------------------
//
// Hide the screensaver window
//

kdesktop'SaverEngine::hideSaverWindow() (./kdebase/kdesktop/lockeng.cc:277)

void SaverEngine::hideSaverWindow()
{
  hide();
  removeVRoot(winId());
  if (gVRoot)
  {
    setVRoot(gVRoot);
    gVRoot = 0;
  }
  XSync(qt_xdisplay(), False);
}

//---------------------------------------------------------------------------
//
// Save the current virtual root window
//

kdesktop'SaverEngine::saveVRoot() (./kdebase/kdesktop/lockeng.cc:293)

void SaverEngine::saveVRoot()
{
  Window rootReturn, parentReturn, *children;
  unsigned int numChildren;
  Window root = kapp->desktop()->winId();

  gVRoot = 0;

  int (*oldHandler)(Display *, XErrorEvent *);
  oldHandler = XSetErrorHandler(ignoreXError);

  if (XQueryTree(qt_xdisplay(), root, &rootReturn, &parentReturn,
      &children, &numChildren))
  {
    for (unsigned int i = 0; i < numChildren; i++)
    {
      Atom actual_type;
      int actual_format;
      unsigned long nitems, bytesafter;
      Window *newRoot = (Window *)0;

      if ((XGetWindowProperty(qt_xdisplay(), children[i], gXA_VROOT, 0, 1,
          False, XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter,
          (unsigned char **) &newRoot) == Success) && newRoot)
      {
        gVRoot = *newRoot;
        break;
      }
    }
    if (children)
    {
      XFree((char *)children);
    }
  }

  XSetErrorHandler(oldHandler);
}

//---------------------------------------------------------------------------
//
// Set the virtual root property
//

kdesktop'SaverEngine::setVRoot() (./kdebase/kdesktop/lockeng.cc:335)

void SaverEngine::setVRoot(Window win)
{
  XChangeProperty(qt_xdisplay(), win, gXA_VROOT, XA_WINDOW, 32,
                  PropModeReplace, (unsigned char *)&win, 1);
}

//---------------------------------------------------------------------------
//
// Remove the virtual root property
//

kdesktop'SaverEngine::removeVRoot() (./kdebase/kdesktop/lockeng.cc:345)

void SaverEngine::removeVRoot(Window win)
{
  XDeleteProperty (qt_xdisplay(), win, gXA_VROOT);
}

//---------------------------------------------------------------------------
//
// Grab the keyboard. Returns true on success
//

kdesktop'SaverEngine::grabKeyboard() (./kdebase/kdesktop/lockeng.cc:354)

bool SaverEngine::grabKeyboard()
{
    int rv = XGrabKeyboard( qt_xdisplay(), QApplication::desktop()->winId(),
        True, GrabModeAsync, GrabModeAsync, CurrentTime );

    return (rv == GrabSuccess);
}

//---------------------------------------------------------------------------
//
// Grab the mouse.  Returns true on success
//

kdesktop'SaverEngine::grabMouse() (./kdebase/kdesktop/lockeng.cc:366)

bool SaverEngine::grabMouse()
{
    int rv = XGrabPointer( qt_xdisplay(), QApplication::desktop()->winId(),
            True, ButtonPressMask
            | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask
            | PointerMotionMask | PointerMotionHintMask | Button1MotionMask
            | Button2MotionMask | Button3MotionMask | Button4MotionMask
            | Button5MotionMask | ButtonMotionMask | KeymapStateMask,
            GrabModeAsync, GrabModeAsync, None, cursor().handle(),
            CurrentTime );

    return (rv == GrabSuccess);
}

//---------------------------------------------------------------------------
//
// Grab keyboard and mouse.  Returns true on success.
//

kdesktop'SaverEngine::grabInput() (./kdebase/kdesktop/lockeng.cc:384)

bool SaverEngine::grabInput()
{
    XSync(qt_xdisplay(), False);

    if (!grabKeyboard())
    {
        sleep(1);
        if (!grabKeyboard())
        {
            return false;
        }
    }

    if (!grabMouse())
    {
        sleep(1);
        if (!grabMouse())
        {
            XUngrabKeyboard(qt_xdisplay(), CurrentTime);
            return false;
        }
    }

    return true;
}

//---------------------------------------------------------------------------
//
// Release mouse an keyboard grab.
//

kdesktop'SaverEngine::ungrabInput() (./kdebase/kdesktop/lockeng.cc:414)

void SaverEngine::ungrabInput()
{
    XUngrabKeyboard(qt_xdisplay(), CurrentTime);
    XUngrabPointer(qt_xdisplay(), CurrentTime);
}

//---------------------------------------------------------------------------
//
// Start the screen saver.
//

kdesktop'SaverEngine::startSaver() (./kdebase/kdesktop/lockeng.cc:424)

void SaverEngine::startSaver()
{
    if (mState != Waiting)
    {
        kdWarning(1204) << "SaverEngine::startSaver() saver already active" << endl;
        return;
    }

    kdDebug(1204) << "SaverEngine: starting saver" << endl;

    if (!grabInput())
    {
        kdWarning(1204) << "SaverEngine::startSaver() grabInput() failed!!!!" << endl;
        return;
    }
    mState = Saving;
    if (mXAutoLock)
    {
        mXAutoLock->stop();
    }
    createSaverWindow();
    move(0, 0);
    show();
    raise();
    XSync(qt_xdisplay(), False);

    if (startHack() == false)
    {
        // failed to start a hack.  Just show a blank screen
        setBackgroundColor(black);
    }
}

//---------------------------------------------------------------------------
//
// Stop the screen saver.
//

kdesktop'SaverEngine::stopSaver() (./kdebase/kdesktop/lockeng.cc:461)

void SaverEngine::stopSaver()
{
    if (mState == Waiting)
    {
        kdWarning(1204) << "SaverEngine::stopSaver() saver not active" << endl;
        return;
    }
    kdDebug(1204) << "SaverEngine: stopping saver" << endl;
    stopHack();
    hideSaverWindow();
    hidePassDlg();
    if (mXAutoLock)
    {
        mXAutoLock->start();
    }
    mState = Waiting;
    ungrabInput();
    mLockOnce = false;
}

//---------------------------------------------------------------------------
//

kdesktop'SaverEngine::startHack() (./kdebase/kdesktop/lockeng.cc:483)

bool SaverEngine::startHack()
{
    if (mSaverExec.isEmpty())
    {
        return false;
    }

    if (mHackProc.isRunning())
    {
        stopHack();
    }

    mHackProc.clearArguments();

    QTextStream ts(&mSaverExec, IO_ReadOnly);
    QString word;
    ts >> word;
    QString path = KStandardDirs::findExe(word);

    if (!path.isEmpty())
    {
        mHackProc << path;

        debug("Starting hack: %s", path.ascii());

        while (!ts.atEnd())
        {
            ts >> word;
            if (word == "%w")
            {
                word = word.setNum(winId());
            }
            mHackProc << word;
        }

        if (mHackProc.start() == true)
        {
#ifdef HAVE_SETPRIORITY
            setpriority(PRIO_PROCESS, mHackProc.getPid(), mPriority);
#endif
            return true;
        }
    }

    return false;
}

//---------------------------------------------------------------------------
//

kdesktop'SaverEngine::stopHack() (./kdebase/kdesktop/lockeng.cc:532)

void SaverEngine::stopHack()
{
    if (mHackProc.isRunning())
    {
        mHackProc.kill();
    }
}

//---------------------------------------------------------------------------
//
// Show the password dialog
//

kdesktop'SaverEngine::showPassDlg() (./kdebase/kdesktop/lockeng.cc:544)

void SaverEngine::showPassDlg()
{
    if (mPassDlg)
    {
        hidePassDlg();
    }
    mPassDlg = new PasswordDlg(this);
    mPassDlg->showStars(mPasswordStars);
    mPassDlg->move((mRootWidth - mPassDlg->width())/2,
                    (mRootHeight - mPassDlg->height())/2);
    mPassDlg->show();
    setPassDlgTimeout(PASSDLG_HIDE_TIMEOUT);
}

//---------------------------------------------------------------------------
//
// Hide the password dialog
//

kdesktop'SaverEngine::hidePassDlg() (./kdebase/kdesktop/lockeng.cc:562)

void SaverEngine::hidePassDlg()
{
    if (mPassDlg)
    {
        delete mPassDlg;
        mPassDlg = 0;
        killPassDlgTimeout();
    }
}

//---------------------------------------------------------------------------
//
// Hide the password dialog in "t" seconds.
//

kdesktop'SaverEngine::setPassDlgTimeout() (./kdebase/kdesktop/lockeng.cc:576)

void SaverEngine::setPassDlgTimeout(int t)
{
    if (mHidePassTimerId)
    {
        killTimer(mHidePassTimerId);
    }
    mHidePassTimerId = startTimer(t);
}

//---------------------------------------------------------------------------
//
// Kill the password dialog hide timer.
//

kdesktop'SaverEngine::killPassDlgTimeout() (./kdebase/kdesktop/lockeng.cc:589)

void SaverEngine::killPassDlgTimeout()
{
    if (mHidePassTimerId)
    {
        killTimer(mHidePassTimerId);
        mHidePassTimerId = 0;
    }
}

//---------------------------------------------------------------------------
//
// XAutoLock has detected the required idle time.
//

kdesktop'SaverEngine::idleTimeout() (./kdebase/kdesktop/lockeng.cc:602)

void SaverEngine::idleTimeout()
{
    startSaver();
}

//---------------------------------------------------------------------------
//
// X11 Event.
//

kdesktop'SaverEngine::x11Event() (./kdebase/kdesktop/lockeng.cc:611)

bool SaverEngine::x11Event(XEvent *event)
{
    if (!mEnabled && mState == Waiting)
    {
        return false;
    }

    bool ret = false;
    switch (event->type)
    {
        case KeyPress:
            ret = handleKeyPress((XKeyEvent *)event);
	    break;

        case ButtonPress:
        case MotionNotify:
            if (mState == Saving)
            {
                if (mLock || mLockOnce)
                {
                    showPassDlg();
                    mState = Password;
                }
                else
                {
                    stopSaver();
                }
            }
            break;

        case CreateNotify:
            if (event->xcreatewindow.window == winId() ||
                (mPassDlg && event->xcreatewindow.window == mPassDlg->winId()))
            {
                break;
            }
            if (mXAutoLock)
            {
                mXAutoLock->windowCreated(event->xcreatewindow.window);
            }
            break;

        case VisibilityNotify:
            if (event->xvisibility.state != VisibilityUnobscured &&
                event->xvisibility.window == winId() &&
                (mState == Saving || mState == Password))
            {
                raise();
                QApplication::flushX();
            }
            break;

        case ConfigureNotify:
            // Workaround for bug in Qt 2.1, as advised by Matthias Ettrich (David)
            if (event->xconfigure.window != event->xconfigure.event)
                return true;

            if (mState == Saving || mState == Password)
            {
                raise();
                QApplication::flushX();
            }
            break;
    }

    return ret;
}

//---------------------------------------------------------------------------
//
// Handle key press event.
//

kdesktop'SaverEngine::handleKeyPress() (./kdebase/kdesktop/lockeng.cc:683)

bool SaverEngine::handleKeyPress(XKeyEvent *xke)
{
    bool ret = false;

    switch (mState)
    {
        case Waiting:
            if (!xke->send_event && mXAutoLock)
            {
                mXAutoLock->keyPressed();
            }
	    break;

        case Password:
            if (!mCheckingPass)
            {
                KeySym keysym = 0;
                XComposeStatus compose;
                char buffer[2] = "";
                XLookupString(xke, buffer, 1, &keysym, &compose);
                switch (keysym)
                {
                    case XK_Escape:
                        hidePassDlg();
                        mState = Saving;
                        break;

                    case XK_Return:
                        startCheckPassword();
                        break;

                    default:
                        setPassDlgTimeout(PASSDLG_HIDE_TIMEOUT);
                        mPassDlg->keyPressed(xke);
                }
            }
	    ret = true;
	    break;

        case Saving:
            if (mLock || mLockOnce)
            {
                showPassDlg();
                mState = Password;
            }
            else
            {
                stopSaver();
            }
	    return true;
    }

    return ret;
}

//---------------------------------------------------------------------------
//
// Starts the kcheckpass process to check the user's password.
//

kdesktop'SaverEngine::startCheckPassword() (./kdebase/kdesktop/lockeng.cc:742)

void SaverEngine::startCheckPassword()
{
    const char *passwd = mPassDlg->password().ascii();
    if (passwd)
    {
        QString kcp_binName = locate("exe", "kcheckpass");

        mPassProc.clearArguments();
        mPassProc << kcp_binName;

        bool ret = mPassProc.start(KProcess::NotifyOnExit, KProcess::Stdin);
        if (ret == false)
        {
            debug("kcheckpass failed to start");
            return;
        }

        // write Password to stdin
        mPassProc.writeStdin(passwd, strlen(passwd));
        mPassProc.closeStdin();

        killPassDlgTimeout();

        mCheckingPass = true;
    }
}

//---------------------------------------------------------------------------
//
// The kcheckpass process has exited.
//

kdesktop'SaverEngine::passwordChecked() (./kdebase/kdesktop/lockeng.cc:773)

void SaverEngine::passwordChecked(KProcess *proc)
{
    if (proc == &mPassProc)
    {
        if (mPassProc.normalExit() && (mPassProc.exitStatus() == 0))
        {
            stopSaver();
        }
        else
        {
            mPassDlg->showFailed();
            mPassDlg->resetPassword();
            setPassDlgTimeout(PASSDLG_HIDE_TIMEOUT);
        }

        mCheckingPass = false;
    }
}

//---------------------------------------------------------------------------
//
// Handle our timer events.
//

kdesktop'SaverEngine::timerEvent() (./kdebase/kdesktop/lockeng.cc:796)

void SaverEngine::timerEvent(QTimerEvent *ev)
{
    if (ev->timerId() == mHidePassTimerId && !mCheckingPass)
    {
        hidePassDlg();
        mState = Saving;
    }
}

//---------------------------------------------------------------------------