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

Class Index

amor'Amor (./kdetoys/amor/amor.h:31)

class Amor : public QObject
{
    Q_OBJECT
public:
    Amor();
    virtual ~Amor();

    void reset();

public slots:
    void slotWindowActivate(WId);
    void slotWindowRemove(WId);
    void slotStackingChanged();
    void slotWindowChange(WId);

protected slots:
    void slotMouseClicked(const QPoint &pos);
    void slotTimeout();
    void slotConfigure();
    void slotConfigChanged();
    void slotOffsetChanged(int);
    void slotAbout();

protected:
    enum State { Focus, Blur, Normal, Sleeping, Waking, Destroy };

    bool readConfig();
    bool readThemeConfig(const char *file);
    void readGroupConfig(KConfigBase &config, QList<AmorAnim> &animList,
                            const char *seq);
    void showBubble(const char *msg);
    void hideBubble();
    AmorAnim *randomAnimation(QList<AmorAnim> &animList);
    void selectAnimation(State state=Normal);
    void restack();
    void active();
    QRect windowGeometry(WId);

    virtual void timerEvent(QTimerEvent *);

private:
    WId              mTargetWin;   // The window that the animations sits on
    QRect            mTargetRect;  // The goemetry of the target window
    WId              mNextTarget;  // The window that will become the target
    AmorWidget       *mAmor;       // The widget displaying the animation
    AmorThemeManager mTheme;       // Animations used by current theme
    AmorAnim         *mBaseAnim;   // The base animation
    AmorAnim         *mCurrAnim;   // The currently running animation
    int              mPosition;    // The position of the animation
    State            mState;       // The current state of the animation
    QTimer           *mTimer;      // Frame timer
    AmorDialog       *mAmorDialog; // Setup dialog
    QPopupMenu       *mMenu;       // Our menu
    int              mResizeId;    // Resize timer Id
    time_t           mActiveTime;  // The time an active event occurred
    QPoint           mCursPos;     // The last recorded position of the pointer
    int              mCursId;      // Pointer position timer id
    AmorBubble       *mBubble;     // Text bubble
    int              mBubbleId;    // Bubble text timer Id
    AmorTips         mTips;        // Tips to display in the bubble

    AmorConfig       mConfig;      // Configuration parameters
};

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


amor'Amor::Amor() (./kdetoys/amor/amor.cpp:49)

Amor::Amor() : QObject()
{
    mAmor = 0;
    mBubble = 0;

    if (readConfig())
    {
        mTargetWin   = 0;
        mNextTarget  = 0;
        mAmorDialog  = 0;
        mMenu        = 0;
        mCurrAnim    = mBaseAnim;
        mPosition    = mCurrAnim->hotspot().x();
        mState       = Normal;
        mResizeId    = 0;
        mCursId      = 0;
        mBubbleId    = 0;

        mAmor = new AmorWidget();
        connect(mAmor, SIGNAL(mouseClicked(const QPoint &)),
                        SLOT(slotMouseClicked(const QPoint &)));
        mAmor->resize(mTheme.maximumSize());

        mTimer = new QTimer(this);
        connect(mTimer, SIGNAL(timeout()), SLOT(slotTimeout()));

        time(&mActiveTime);
        mCursPos = QCursor::pos();
        mCursId = startTimer(200);

        if (KWin::activeWindow())
        {
            mNextTarget = KWin::activeWindow();
            selectAnimation(Focus);
            mTimer->start(0, true);
        }
    }
    else
    {
        kapp->quit();
    }
}

//---------------------------------------------------------------------------
//
// Destructor
//

amor'Amor::~Amor() (./kdetoys/amor/amor.cpp:96)

Amor::~Amor()
{
    if (mAmor)
    {
        delete mAmor;
    }
    if (mBubble)
    {
        delete mBubble;
    }
}

//---------------------------------------------------------------------------
//
// Clear existing theme and reload configuration
//

amor'Amor::reset() (./kdetoys/amor/amor.cpp:112)

void Amor::reset()
{
    mTimer->stop();

    AmorPixmapManager::manager()->reset();
    mTips.reset();
    delete mAmor;

    readConfig();

    mTargetWin  = 0;
    mNextTarget = 0;
    mCurrAnim   = mBaseAnim;
    mPosition   = mCurrAnim->hotspot().x();
    mState      = Normal;

    mAmor = new AmorWidget();
    connect(mAmor, SIGNAL(mouseClicked(const QPoint &)),
                    SLOT(slotMouseClicked(const QPoint &)));
    mAmor->resize(mTheme.maximumSize());
}

//---------------------------------------------------------------------------
//
// Read the selected theme.
//

amor'Amor::readConfig() (./kdetoys/amor/amor.cpp:138)

bool Amor::readConfig()
{
    // Read user preferences
    mConfig.read();

    if (mConfig.mTips)
    {
        mTips.setFile(TIPS_FILE);
    }

    // read selected theme
    if (!mTheme.setTheme(mConfig.mTheme))
    {
        KMessageBox::error(0, i18n("Error reading theme: ") + mConfig.mTheme);
        return false;
    }

    const char *groups[] = { ANIM_BASE, ANIM_NORMAL, ANIM_FOCUS, ANIM_BLUR,
                            ANIM_DESTROY, ANIM_SLEEP, ANIM_WAKE, 0 };

    // Read all the standard animation groups
    for (int i = 0; groups[i]; i++)
    {
        if (mTheme.readGroup(groups[i]) == false)
        {
            KMessageBox::error(0, i18n("Error reading group: ") + groups[i]);
            return false;
        }
    }

    // Get the base animation
    mBaseAnim = mTheme.random(ANIM_BASE);

    return true;
}

//---------------------------------------------------------------------------
//
// Show the bubble text
//

amor'Amor::showBubble() (./kdetoys/amor/amor.cpp:178)

void Amor::showBubble(const char *msg)
{
    if (msg)
    {
        if (!mBubble)
        {
            mBubble = new AmorBubble;
        }

        mBubble->setOrigin(mAmor->x()+mAmor->width()/2,
                           mAmor->y()+mAmor->height()/2);
        mBubble->setMessage(msg);
        mBubble->show();
        mBubbleId = startTimer(BUBBLE_TIMEOUT + strlen(msg) * 30);
    }
}

//---------------------------------------------------------------------------
//
// Hide the bubble text if visible
//

amor'Amor::hideBubble() (./kdetoys/amor/amor.cpp:199)

void Amor::hideBubble()
{
    if (mBubbleId)
    {
        killTimer(mBubbleId);
        mBubbleId = 0;
    }
    if (mBubble)
    {
        delete mBubble;
        mBubble = 0;
    }
}

//---------------------------------------------------------------------------
//
// Select a new animation appropriate for the current state.
//

amor'Amor::selectAnimation() (./kdetoys/amor/amor.cpp:217)

void Amor::selectAnimation(State state)
{
    switch (state)
    {
        case Blur:
            hideBubble();
            mCurrAnim = mTheme.random(ANIM_BLUR);
            mState = Focus;
            break;

        case Focus:
            hideBubble();
            mCurrAnim = mTheme.random(ANIM_FOCUS);
            mCurrAnim->reset();
            mTargetWin = mNextTarget;
            if (mTargetWin != None)
            {
                mTargetRect = windowGeometry(mTargetWin);
//                mTargetRect = KWM::geometry(mTargetWin, true);
                if (mCurrAnim->frame())
                {
                    mPosition = (kapp->random() %
                        (mTargetRect.width() - mCurrAnim->frame()->width())) +
                         mCurrAnim->hotspot().x();
                }
                else
                {
                    mPosition = mTargetRect.width()/2;
                }
            }
            else
            {
                // We don't want to do anything until a window comes into
                // focus.
                mTimer->stop();
            }
            mAmor->hide();
            restack();
            mState = Normal;
            break;

        case Destroy:
            hideBubble();
            mCurrAnim = mTheme.random(ANIM_DESTROY);
            mState = Focus;
            break;

        case Sleeping:
            mCurrAnim = mTheme.random(ANIM_SLEEP);
            break;

        case Waking:
            mCurrAnim = mTheme.random(ANIM_WAKE);
            mState = Normal;
            break;

        default:
            // Select a random normal animation if the current animation
            // is not the base, otherwise select the base.  This makes us
            // alternate between the base animation and a random
            // animination.
            if (mCurrAnim == mBaseAnim && !mBubble)
            {
                mCurrAnim = mTheme.random(ANIM_NORMAL);
            }
            else
            {
                mCurrAnim = mBaseAnim;
            }
            break;
    }

    if (mCurrAnim->totalMovement() + mPosition > mTargetRect.width() ||
        mCurrAnim->totalMovement() + mPosition < 0)
    {
        // The selected animation would end outside of this window's width
        // We could randomly select a different one, but I prefer to just
        // use the default animation.
        mCurrAnim = mBaseAnim;
    }

    mCurrAnim->reset();
}

//---------------------------------------------------------------------------
//
// Set the animation's stacking order to be just above the target window's
// window decoration, or on top.
//

amor'Amor::restack() (./kdetoys/amor/amor.cpp:306)

void Amor::restack()
{
    if (mTargetWin == None)
    {
        return;
    }

    if (mConfig.mOnTop)
    {
        // simply raise the widget to the top
        mAmor->raise();
        return;
    }

    debug("restacking");

    Window dw, parent = None, *wins;
    unsigned int nwins = 0;

    // We must use the target window's parent as our sibling.
    // Is there a faster way to get parent window than XQueryTree?
    if (XQueryTree(qt_xdisplay(), mTargetWin, &dw, &parent, &wins, &nwins))
    {
        if (nwins)
        {
            XFree(wins);
        }
    }

    if (parent != None)
    {
      debug("Parent = %ld", parent);
    }

    // Set animation's stacking order to be above the window manager's
    // decoration of target window.
    XWindowChanges values;
    values.sibling = parent != None ? parent : mTargetWin;
    values.stack_mode = Above;
    XConfigureWindow(qt_xdisplay(), mAmor->winId(), CWSibling | CWStackMode,
                     &values);
}

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

amor'Amor::windowGeometry() (./kdetoys/amor/amor.cpp:351)

QRect Amor::windowGeometry(WId win)
{
    QRect rect;
    XWindowAttributes attr;
    if (XGetWindowAttributes(qt_xdisplay(), win, &attr))
    {
        int x, y;
        Window child;
        XTranslateCoordinates(qt_xdisplay(), win, qt_xrootwin(),
                              0, 0, &x, &y, &child);
        rect.setRect(x, y, attr.width, attr.height);
    }

    debug("Window geometry: %d, %d, %d x %d", rect.x(), rect.y(), rect.width(), rect.height());

    return rect;
}

//---------------------------------------------------------------------------
//
// Handle various timer events.
//

amor'Amor::timerEvent() (./kdetoys/amor/amor.cpp:373)

void Amor::timerEvent(QTimerEvent *te)
{
    if (te->timerId() == mResizeId)
    {
        killTimer(mResizeId);
        mResizeId = 0;
        restack();
    }
    else if (te->timerId() == mCursId)
    {
        QPoint currPos = QCursor::pos();
        QPoint diff = currPos - mCursPos;
        time_t now = time(0);

        if (abs(diff.x()) > 1 || abs(diff.y()) > 1)
        {
            if (mState == Sleeping)
            {
                // Set waking immediatedly
                selectAnimation(Waking);
            }
            mActiveTime = now;
            mCursPos = currPos;
        }
        else if (mState != Sleeping && now - mActiveTime > SLEEP_TIMEOUT)
        {
            // The next animation will become sleeping
            mState = Sleeping;
        }
    }
    else if (te->timerId() == mBubbleId)
    {
        hideBubble();
    }
}

//---------------------------------------------------------------------------
//
// The user clicked on our animation.
//

amor'Amor::slotMouseClicked() (./kdetoys/amor/amor.cpp:413)

void Amor::slotMouseClicked(const QPoint &pos)
{
    bool restartTimer = mTimer->isActive();

    // Stop the animation while the menu is open.
    if (restartTimer)
    {
        mTimer->stop();
    }

    if (!mMenu)
    {
        mMenu = new QPopupMenu();
        mMenu->insertItem(i18n("&Options..."), this, SLOT(slotConfigure()));
        mMenu->insertItem(i18n("&About..."), this, SLOT(slotAbout()));
        mMenu->insertSeparator();
        mMenu->insertItem(i18n("&Quit"), kapp, SLOT(quit()));
    }

    mMenu->exec(pos);

    if (restartTimer)
    {
        mTimer->start(1000, true);
    }
}

//---------------------------------------------------------------------------
//
// Display the next frame or a new animation
//

amor'Amor::slotTimeout() (./kdetoys/amor/amor.cpp:444)

void Amor::slotTimeout()
{
    mPosition += mCurrAnim->movement();
    mAmor->setPixmap(mCurrAnim->frame());
    mAmor->move(mPosition + mTargetRect.x() - mCurrAnim->hotspot().x(),
                 mTargetRect.y() - mCurrAnim->hotspot().y() + mConfig.mOffset);
    if (!mAmor->isVisible())
    {
        mAmor->show();
        restack();
    }

    // At the start of a base animation, we can randomly display
    // a helpful tip.
    if (mCurrAnim == mBaseAnim && mCurrAnim->frameNum() == 0)
    {
        if (kapp->random()%TIP_FREQUENCY == 1 && mConfig.mTips && !mBubble)
        {
            showBubble(mTips.tip());
        }
    }

    mTimer->start(mCurrAnim->delay(), true);

    if (!mCurrAnim->next())
    {
        selectAnimation(mState);
    }
}

//---------------------------------------------------------------------------
//
// Display configuration dialog
//

amor'Amor::slotConfigure() (./kdetoys/amor/amor.cpp:478)

void Amor::slotConfigure()
{
    if (!mAmorDialog)
    {
        mAmorDialog = new AmorDialog();
        connect(mAmorDialog, SIGNAL(changed()), SLOT(slotConfigChanged()));
        connect(mAmorDialog, SIGNAL(offsetChanged(int)),
                SLOT(slotOffsetChanged(int)));
    }

    mAmorDialog->show();
}

//---------------------------------------------------------------------------
//
// Configuration changed.
//

amor'Amor::slotConfigChanged() (./kdetoys/amor/amor.cpp:495)

void Amor::slotConfigChanged()
{
    reset();
}

//---------------------------------------------------------------------------
//
// Offset changed
//

amor'Amor::slotOffsetChanged() (./kdetoys/amor/amor.cpp:504)

void Amor::slotOffsetChanged(int off)
{
    mConfig.mOffset = off;

    if (mCurrAnim->frame())
    {
        mAmor->move(mPosition + mTargetRect.x() - mCurrAnim->hotspot().x(),
                 mTargetRect.y() - mCurrAnim->hotspot().y() + mConfig.mOffset);
    }
}

//---------------------------------------------------------------------------
//
// Display About box
//

amor'Amor::slotAbout() (./kdetoys/amor/amor.cpp:519)

void Amor::slotAbout()
{
    QString about = i18n("Amor Version %1\n\n").arg(AMOR_VERSION) +
                i18n("Amusing Misuse Of Resources\n\n") +
                i18n("Copyright (c) 1999 Martin R. Jones <mjones@kde.org>\n") +
                "\nhttp://www.powerup.com.au/~mjones/amor/";
    QMessageBox mb;
    mb.setText(about);
    mb.setCaption(i18n("About Amor"));
    mb.setIcon(QMessageBox::Information);
    mb.show();
}

//---------------------------------------------------------------------------
//
// Focus changed to a different window
//

amor'Amor::slotWindowActivate() (./kdetoys/amor/amor.cpp:536)

void Amor::slotWindowActivate(WId win)
{
    debug("Window activated");

    mTimer->stop();
    mNextTarget = win;

    // This is an active event that affects the target window
    time(&mActiveTime);

    // A window gaining focus implies that the current window has lost
    // focus.  Initiate a blur event if there is a current active window.
    if (mTargetWin)
    {
        // We are losing focus from the current window
        selectAnimation(Blur);
        mTimer->start(0, true);
    }
    else if (mNextTarget)
    {
        // We are setting focus to a new window
        mState = Focus;
        mTimer->start(0, true);
    }
    else
    {
        // No action - We can get this when we switch between two empty
        // desktops
        mAmor->hide();
    }
}

//---------------------------------------------------------------------------
//
// Window removed
//

amor'Amor::slotWindowRemove() (./kdetoys/amor/amor.cpp:572)

void Amor::slotWindowRemove(WId win)
{
    debug("Window removed");
    if (win == mTargetWin)
    {
        // This is an active event that affects the target window
        time(&mActiveTime);

        selectAnimation(Destroy);
        mTimer->stop();
        mTimer->start(0, true);
    }
}

//---------------------------------------------------------------------------
//
// Window stacking changed
//

amor'Amor::slotStackingChanged() (./kdetoys/amor/amor.cpp:590)

void Amor::slotStackingChanged()
{
    debug("Stacking changed");

    // This is an active event that affects the target window
    time(&mActiveTime);

    // We seem to get this signal before the window has been restacked,
    // so we just schedule a restack.
    mResizeId = startTimer(20);
}

//---------------------------------------------------------------------------
//
// Properties of a window changed
//

amor'Amor::slotWindowChange() (./kdetoys/amor/amor.cpp:606)

void Amor::slotWindowChange(WId win)
{
    debug("Window changed");

    if (win != mTargetWin)
    {
        return;
    }

    // This is an active event that affects the target window
    time(&mActiveTime);

    if (KWin::windowState(mTargetWin) == KWin::IconicState ||
        KWin::windowState(mTargetWin) == KWin::WithdrawnState)
    {
        debug("Iconic");
        // The target window has been iconified
        selectAnimation(Destroy);
        mTargetWin = None;
        mTimer->stop();
        mTimer->start(0, true);
    }
    else
    {
        // The size or position of the window has changed.
        mTargetRect = windowGeometry(mTargetWin);

        // make sure the animation is still on the window.
        if (mCurrAnim->frame())
        {
            hideBubble();
            if (mPosition > mTargetRect.width() -
                    (mCurrAnim->frame()->width() - mCurrAnim->hotspot().x()))
            {
                mPosition = mTargetRect.width() -
                    (mCurrAnim->frame()->width() - mCurrAnim->hotspot().x());
            }
            mAmor->move(mPosition + mTargetRect.x() - mCurrAnim->hotspot().x(),
                     mTargetRect.y() - mCurrAnim->hotspot().y() +
                     mConfig.mOffset);
        }
    }
}

//===========================================================================