Back to index

kdeartwork  4.3.2
swarm.cpp
Go to the documentation of this file.
00001 /*-
00002  * swarm.c - swarm of bees for xlock, the X Window System lockscreen.
00003  *
00004  * Copyright (c) 1991 by Patrick J. Naughton.
00005  *
00006  * Revision History:
00007  * 31-Aug-90: Adapted from xswarm by Jeff Butterworth. (butterwo@ncsc.org)
00008  */
00009 
00010 /* Ported to kscreensaver:
00011    July 1997, Emanuel Pirker <epirker@edu.uni-klu.ac.at>
00012    Contact me in case of problems, not the original author!
00013    Last revised: 10-Jul-97
00014 */
00015 // layout management added 1998/04/19 by Mario Weilguni <mweilguni@kde.org>
00016 
00017 #define MAXSPEED 100
00018 #define MINSPEED 0
00019 #define DEFSPEED 50
00020 #define MAXBATCH 200
00021 #define MINBATCH 0
00022 #define DEFBATCH 20
00023 #include <qslider.h>
00024 //Added by qt3to4:
00025 #include <QVBoxLayout>
00026 #include <QHBoxLayout>
00027 #include <kglobal.h>
00028 #include <kconfig.h>
00029 #include <krandomsequence.h>
00030 #include "xlock.h"
00031 
00032 #undef index
00033 
00034 #define TIMES 4             /* number of time positions recorded */
00035 #define BEEACC       2             /* acceleration of bees */
00036 #define WASPACC 5           /* maximum acceleration of wasp */
00037 #define BEEVEL       12            /* maximum bee velocity */
00038 #define WASPVEL 10          /* maximum wasp velocity */
00039 
00040 /* Macros */
00041 #define X(t,b)       (sp->x[(t)*sp->beecount+(b)])
00042 #define Y(t,b)       (sp->y[(t)*sp->beecount+(b)])
00043 #define balance_rand(v)     (rnd.getLong(v)-((v)/2))           /* random number around 0 */
00044 
00045 //ModeSpecOpt swarm_opts = {0, NULL, NULL, NULL};
00046 
00047 typedef struct {
00048        int         pix;
00049        int         width;
00050        int         height;
00051        int         border;  /* wasp won't go closer than this to the edge */
00052        int         beecount;       /* number of bees */
00053        XSegment    segs[MAXBATCH]; /* bee lines */
00054        XSegment    old_segs[MAXBATCH];    /* old bee lines */
00055        short       x[MAXBATCH*TIMES];
00056        short       y[MAXBATCH*TIMES];            /* bee positions x[time][bee#] */
00057        short       xv[MAXBATCH];
00058        short       yv[MAXBATCH];          /* bee velocities xv[bee#] */
00059        short       wx[3];
00060        short       wy[3];
00061        short       wxv;
00062        short       wyv;
00063 } swarmstruct;
00064 
00065 static swarmstruct swarms[MAXSCREENS];
00066 
00067 void
00068 initswarm(Window win, KRandomSequence &rnd)
00069 {
00070        swarmstruct *sp = &swarms[screen];
00071        int         b;
00072        XWindowAttributes xwa;
00073 
00074        sp->beecount = batchcount;
00075        (void) XGetWindowAttributes(dsp, win, &xwa);
00076        sp->width = xwa.width;
00077        sp->height = xwa.height;
00078 
00079        sp->border = (sp->width + sp->height) / 50;
00080 
00081        /* Clear the background. */
00082        XSetForeground(dsp, Scr[screen].gc, BlackPixel(dsp, screen));
00083        XFillRectangle(dsp, win, Scr[screen].gc, 0, 0, sp->width, sp->height);
00084 
00085        /*  Now static data structures. epirker */
00086        //if (!sp->segs) {
00087        //sp->segs = (XSegment *) malloc(sizeof (XSegment) * sp->beecount);
00088        //sp->old_segs = (XSegment *) malloc(sizeof (XSegment) * sp->beecount);
00089        //sp->x = (short *) malloc(sizeof (short) * sp->beecount * TIMES);
00090        //sp->y = (short *) malloc(sizeof (short) * sp->beecount * TIMES);
00091        //sp->xv = (short *) malloc(sizeof (short) * sp->beecount);
00092        //sp->yv = (short *) malloc(sizeof (short) * sp->beecount);
00093        //}
00094        /* Initialize point positions, velocities, etc. */
00095 
00096        /* wasp */
00097        sp->wx[0] = sp->border + rnd.getLong(sp->width - 2 * sp->border);
00098        sp->wy[0] = sp->border + rnd.getLong(sp->height - 2 * sp->border);
00099        sp->wx[1] = sp->wx[0];
00100        sp->wy[1] = sp->wy[0];
00101        sp->wxv = 0;
00102        sp->wyv = 0;
00103 
00104        /* bees */
00105        for (b = 0; b < sp->beecount; b++) {
00106               X(0, b) = rnd.getLong(sp->width);
00107               X(1, b) = X(0, b);
00108               Y(0, b) = rnd.getLong(sp->height);
00109               Y(1, b) = Y(0, b);
00110               sp->xv[b] = balance_rand(7);
00111               sp->yv[b] = balance_rand(7);
00112        }
00113 }
00114 
00115 
00116 
00117 void
00118 drawswarm(Window win, KRandomSequence &rnd)
00119 {
00120        swarmstruct *sp = &swarms[screen];
00121        int         b;
00122 
00123        /* <=- Wasp -=> */
00124        /* Age the arrays. */
00125        sp->wx[2] = sp->wx[1];
00126        sp->wx[1] = sp->wx[0];
00127        sp->wy[2] = sp->wy[1];
00128        sp->wy[1] = sp->wy[0];
00129        /* Accelerate */
00130        sp->wxv += balance_rand(WASPACC);
00131        sp->wyv += balance_rand(WASPACC);
00132 
00133        /* Speed Limit Checks */
00134        if (sp->wxv > WASPVEL)
00135               sp->wxv = WASPVEL;
00136        if (sp->wxv < -WASPVEL)
00137               sp->wxv = -WASPVEL;
00138        if (sp->wyv > WASPVEL)
00139               sp->wyv = WASPVEL;
00140        if (sp->wyv < -WASPVEL)
00141               sp->wyv = -WASPVEL;
00142 
00143        /* Move */
00144        sp->wx[0] = sp->wx[1] + sp->wxv;
00145        sp->wy[0] = sp->wy[1] + sp->wyv;
00146 
00147        /* Bounce Checks */
00148        if ((sp->wx[0] < sp->border) || (sp->wx[0] > sp->width - sp->border - 1)) {
00149               sp->wxv = -sp->wxv;
00150               sp->wx[0] += sp->wxv;
00151        }
00152        if ((sp->wy[0] < sp->border) || (sp->wy[0] > sp->height - sp->border - 1)) {
00153               sp->wyv = -sp->wyv;
00154               sp->wy[0] += sp->wyv;
00155        }
00156        /* Don't let things settle down. */
00157        sp->xv[rnd.getLong(sp->beecount)] += balance_rand(3);
00158        sp->yv[rnd.getLong(sp->beecount)] += balance_rand(3);
00159 
00160        /* <=- Bees -=> */
00161        for (b = 0; b < sp->beecount; b++) {
00162               int         distance, dx, dy;
00163 
00164               /* Age the arrays. */
00165               X(2, b) = X(1, b);
00166               X(1, b) = X(0, b);
00167               Y(2, b) = Y(1, b);
00168               Y(1, b) = Y(0, b);
00169 
00170               /* Accelerate */
00171               dx = sp->wx[1] - X(1, b);
00172               dy = sp->wy[1] - Y(1, b);
00173               distance = abs(dx) + abs(dy);      /* approximation */
00174               if (distance == 0)
00175                      distance = 1;
00176               sp->xv[b] += (dx * BEEACC) / distance;
00177               sp->yv[b] += (dy * BEEACC) / distance;
00178 
00179               /* Speed Limit Checks */
00180               if (sp->xv[b] > BEEVEL)
00181                      sp->xv[b] = BEEVEL;
00182               if (sp->xv[b] < -BEEVEL)
00183                      sp->xv[b] = -BEEVEL;
00184               if (sp->yv[b] > BEEVEL)
00185                      sp->yv[b] = BEEVEL;
00186               if (sp->yv[b] < -BEEVEL)
00187                      sp->yv[b] = -BEEVEL;
00188 
00189               /* Move */
00190               X(0, b) = X(1, b) + sp->xv[b];
00191               Y(0, b) = Y(1, b) + sp->yv[b];
00192 
00193               /* Fill the segment lists. */
00194               sp->segs[b].x1 = X(0, b);
00195               sp->segs[b].y1 = Y(0, b);
00196               sp->segs[b].x2 = X(1, b);
00197               sp->segs[b].y2 = Y(1, b);
00198               sp->old_segs[b].x1 = X(1, b);
00199               sp->old_segs[b].y1 = Y(1, b);
00200               sp->old_segs[b].x2 = X(2, b);
00201               sp->old_segs[b].y2 = Y(2, b);
00202        }
00203 
00204        XSetForeground(dsp, Scr[screen].gc, BlackPixel(dsp, screen));
00205        XDrawLine(dsp, win, Scr[screen].gc,
00206                 sp->wx[1], sp->wy[1], sp->wx[2], sp->wy[2]);
00207        XDrawSegments(dsp, win, Scr[screen].gc, sp->old_segs, sp->beecount);
00208 
00209        XSetForeground(dsp, Scr[screen].gc, WhitePixel(dsp, screen));
00210        XDrawLine(dsp, win, Scr[screen].gc,
00211                 sp->wx[0], sp->wy[0], sp->wx[1], sp->wy[1]);
00212        if (!mono && Scr[screen].npixels > 2) {
00213               XSetForeground(dsp, Scr[screen].gc, Scr[screen].pixels[sp->pix]);
00214               if (++sp->pix >= Scr[screen].npixels)
00215                      sp->pix = 0;
00216        }
00217        XDrawSegments(dsp, win, Scr[screen].gc, sp->segs, sp->beecount);
00218 }
00219 
00220 //-----------------------------------------------------------------------------
00221 
00222 #include <qcheckbox.h>
00223 #include <qlabel.h>
00224 #include <qcolor.h>
00225 #include <qlayout.h>
00226 #include <QX11Info>
00227 #include <klocale.h>
00228 #include <kmessagebox.h>
00229 
00230 #include "swarm.h"
00231 #include "swarm.moc"
00232 #include "helpers.h"
00233 
00234 #undef Below
00235 
00236 static kSwarmSaver *saver = NULL;
00237 
00238 void startScreenSaver( Drawable d )
00239 {
00240        if ( saver )
00241               return;
00242        saver = new kSwarmSaver( d );
00243 }
00244 
00245 void stopScreenSaver()
00246 {
00247        if ( saver )
00248               delete saver;
00249        saver = NULL;
00250 }
00251 
00252 int setupScreenSaver()
00253 {
00254        kSwarmSetup dlg;
00255 
00256        return dlg.exec();
00257 }
00258 
00259 //-----------------------------------------------------------------------------
00260 
00261 kSwarmSaver::kSwarmSaver( Drawable drawable ) : kScreenSaver( drawable )
00262 {
00263        readSettings();
00264 
00265     // Clear to background colour when exposed
00266     XSetWindowBackground(QX11Info::display(), mDrawable,
00267                             BlackPixel(QX11Info::display(), QX11Info::appScreen()));
00268 
00269        batchcount = maxLevels;
00270 
00271        initXLock( mGc );
00272        initswarm( mDrawable, rnd );
00273 
00274        timer.start( speed );
00275        connect( &timer, SIGNAL( timeout() ), SLOT( slotTimeout() ) );
00276 }
00277 
00278 kSwarmSaver::~kSwarmSaver()
00279 {
00280        timer.stop();
00281 }
00282 
00283 void kSwarmSaver::setSpeed( int spd )
00284 {
00285        timer.stop();
00286        speed = MAXSPEED - spd;
00287        timer.start( speed );
00288 }
00289 
00290 void kSwarmSaver::setLevels( int l )
00291 {
00292        batchcount = maxLevels = l;
00293        initswarm( mDrawable, rnd );
00294 }
00295 
00296 void kSwarmSaver::readSettings()
00297 {
00298     KConfig *config = klock_config();
00299     KConfigGroup group = config->group( "Settings" );
00300 
00301        speed = MAXSPEED - group.readEntry( "Speed", MAXSPEED - DEFSPEED );
00302        maxLevels = group.readEntry( "MaxLevels", DEFBATCH );
00303 
00304        delete config;
00305 }
00306 
00307 void kSwarmSaver::slotTimeout()
00308 {
00309        drawswarm( mDrawable, rnd );
00310 }
00311 
00312 //-----------------------------------------------------------------------------
00313 
00314 kSwarmSetup::kSwarmSetup( QWidget *parent, const char *name )
00315        : KDialog( parent)
00316 {
00317        setCaption(i18n( "Setup Swarm Screen Saver" ));
00318        setButtons(Ok|Cancel|Help);
00319               setDefaultButton(Ok);
00320        setModal(true);
00321        showButtonSeparator(true);
00322        readSettings();
00323 
00324        setButtonText( Help, i18n( "A&bout" ) );
00325        QWidget *main = new QWidget(this);
00326        setMainWidget(main);
00327 
00328        QHBoxLayout *top = new QHBoxLayout(main );
00329        QVBoxLayout *left = new QVBoxLayout;
00330        top->addLayout(left);
00331 
00332        QLabel *label = new QLabel( i18n("Speed:"), main );
00333        min_size(label);
00334        left->addWidget(label);
00335 
00336        QSlider *slider = new QSlider(Qt::Horizontal,main);
00337        slider->setMaximum(MAXSPEED);
00338        slider->setMinimum(MINSPEED);
00339        slider->setValue(speed);
00340        slider->setMinimumSize( 120, 20 );
00341     slider->setTickPosition(QSlider::TicksBelow);
00342     slider->setTickInterval(10);
00343        connect( slider, SIGNAL( valueChanged( int ) ),
00344                SLOT( slotSpeed( int ) ) );
00345        left->addWidget(slider);
00346 
00347        label = new QLabel( i18n("Number of bees:"), main );
00348        min_size(label);
00349        left->addWidget(label);
00350 
00351        slider = new QSlider(Qt::Horizontal,main);
00352        slider->setMaximum(MAXBATCH);
00353        slider->setMinimum(MINBATCH);
00354        slider->setValue(20);
00355 
00356        slider->setMinimumSize( 120, 20 );
00357     slider->setTickPosition(QSlider::TicksBelow);
00358     slider->setTickInterval(20);
00359        connect( slider, SIGNAL( valueChanged( int ) ),
00360                SLOT( slotLevels( int ) ) );
00361        left->addWidget(slider);
00362        left->addStretch();
00363 
00364        preview = new QWidget( main );
00365        preview->setFixedSize( 220, 170 );
00366        QPalette palette = preview->palette();
00367        palette.setColor(preview->backgroundRole(), Qt::black);
00368        preview->setPalette(palette);
00369        preview->setAutoFillBackground(true);
00370 
00371        preview->show();    // otherwise saver does not get correct size
00372        saver = new kSwarmSaver( preview->winId() );
00373        top->addWidget(preview);
00374 
00375        top->addStretch();
00376        connect(this,SIGNAL(okClicked()),this,SLOT(slotOk()));
00377        connect(this,SIGNAL(helpClicked()),this,SLOT(slotHelp()));
00378 }
00379 
00380 void kSwarmSetup::readSettings()
00381 {
00382        KConfig *config = klock_config();
00383        KConfigGroup group = config->group( "Settings" );
00384 
00385        speed = group.readEntry( "Speed", speed );
00386 
00387        if ( speed > MAXSPEED )
00388               speed = MAXSPEED;
00389        else if ( speed < MINSPEED )
00390               speed = MINSPEED;
00391 
00392        maxLevels = group.readEntry( "MaxLevels", DEFBATCH );
00393        delete config;
00394 }
00395 
00396 void kSwarmSetup::slotSpeed( int num )
00397 {
00398        speed = num;
00399 
00400        if ( saver )
00401               saver->setSpeed( speed );
00402 }
00403 
00404 void kSwarmSetup::slotLevels( int num )
00405 {
00406        maxLevels = num;
00407 
00408        if ( saver )
00409               saver->setLevels( maxLevels );
00410 }
00411 
00412 void kSwarmSetup::slotOk()
00413 {
00414        KConfig *config = klock_config();
00415        KConfigGroup group = config->group( "Settings" );
00416 
00417        QString sspeed;
00418        sspeed.setNum( speed );
00419        group.writeEntry( "Speed", sspeed );
00420 
00421        QString slevels;
00422        slevels.setNum( maxLevels );
00423        group.writeEntry( "MaxLevels", slevels );
00424 
00425        config->sync();
00426        delete config;
00427        accept();
00428 }
00429 
00430 void kSwarmSetup::slotHelp()
00431 {
00432        KMessageBox::information(this,
00433                           i18n("Swarm\n\nCopyright (c) 1991 by Patrick J. Naughton\n\nPorted to kscreensaver by Emanuel Pirker."),
00434                           i18n("About Swarm"));
00435 }