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);
}
}
}
//===========================================================================