Back to index

kdeartwork  4.3.2
science.cpp
Go to the documentation of this file.
00001 //-----------------------------------------------------------------------------
00002 //
00003 // kscience - screen saver for KDE
00004 //
00005 // Copyright (c)  Rene Beutler 1998
00006 //
00007 
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <math.h>
00011 #include <sys/types.h>
00012 #include <time.h>
00013 
00014 #include <qpainter.h>
00015 #include <qcolormap.h>
00016 #include <qpixmap.h>
00017 #include <qlabel.h>
00018 #include <qlistwidget.h>
00019 #include <qcheckbox.h>
00020 #include <qslider.h>
00021 #include <qlayout.h>
00022 #include <QPaintEvent>
00023 
00024 #include <kapplication.h>
00025 #include <kglobal.h>
00026 #include <kmessagebox.h>
00027 #include <klocale.h>
00028 #include <kconfig.h>
00029 #include <kstandarddirs.h>
00030 #include <krandomsequence.h>
00031 
00032 #include "science.h"
00033 #include "science.moc"
00034 
00035 #if defined Q_WS_X11 && !defined K_WS_QTONLY
00036 #include <X11/Xlib.h>
00037 #include <X11/Xutil.h>
00038 #endif
00039 
00040 #define SCI_DEFAULT_MODE          0
00041 #define SCI_DEFAULT_MOVEX         6
00042 #define SCI_DEFAULT_MOVEY         8
00043 #define SCI_DEFAULT_SIZE         15
00044 #define SCI_DEFAULT_INTENSITY     4
00045 #define SCI_DEFAULT_SPEED        70
00046 #define SCI_DEFAULT_INVERSE   false
00047 #define SCI_DEFAULT_GRAVITY   false
00048 #define SCI_DEFAULT_HIDE      false
00049 #define SCI_MAX_SPEED           100
00050 #define SCI_MAX_MOVE             20
00051 
00052 #undef Below
00053 
00054 
00055 // libkscreensaver interface
00056 class KScienceSaverInterface : public KScreenSaverInterface
00057 {
00058 
00059 
00060 public:
00061     virtual KAboutData* aboutData() {
00062         return new KAboutData( "kscience.kss", "klock", ki18n( "Science Screen Saver" ), "2.2.0", ki18n( "Science Screen Saver" ) );
00063     }
00064 
00065 
00066     virtual KScreenSaver* create( WId id )
00067     {
00068         return new KScienceSaver( id );
00069     }
00070 
00071     virtual QDialog* setup()
00072     {
00073         return new KScienceSetup();
00074     }
00075 };
00076 
00077 int main( int argc, char *argv[] )
00078 {
00079     KScienceSaverInterface kss;
00080     return kScreenSaverMain( argc, argv, kss );
00081 }
00082 
00083 static struct {
00084        QString name;
00085        bool inverseEnable;
00086        } modeInfo[MAX_MODES];
00087 
00088 enum { MODE_WHIRL=0, MODE_CURVATURE, MODE_SPHERE, MODE_WAVE, MODE_EXPONENTIAL, MODE_CONTRACTION };
00089 
00090 void initModeInfo()
00091 {
00092        modeInfo[MODE_WHIRL].name = i18n( "Whirl" );
00093        modeInfo[MODE_WHIRL].inverseEnable = true;
00094 
00095        modeInfo[MODE_SPHERE].name = i18n( "Sphere" );
00096        modeInfo[MODE_SPHERE].inverseEnable = true;
00097 
00098        modeInfo[MODE_EXPONENTIAL].name = i18n( "Exponential" );
00099        modeInfo[MODE_EXPONENTIAL].inverseEnable = false;
00100 
00101        modeInfo[MODE_CONTRACTION].name = i18n( "Contraction" );
00102        modeInfo[MODE_CONTRACTION].inverseEnable = false;
00103 
00104        modeInfo[MODE_WAVE].name = i18n( "Wave" );
00105        modeInfo[MODE_WAVE].inverseEnable = false;
00106 
00107        modeInfo[MODE_CURVATURE].name = i18n( "Curvature" );
00108        modeInfo[MODE_CURVATURE].inverseEnable = true;
00109 }
00110 
00111 //-----------------------------------------------------------------------------
00112 // KPreviewWidget
00113 //
00114 
00115 KPreviewWidget::KPreviewWidget( QWidget *parent ) :
00116                 QWidget ( parent ) { }
00117 
00118 void KPreviewWidget::paintEvent( QPaintEvent *event )
00119 {
00120        if( saver != 0 )
00121               saver->do_refresh( event->rect() );
00122 }
00123 
00124 void KPreviewWidget::notifySaver( KScienceSaver *s )
00125 {
00126        saver = s;
00127 }
00128 
00129 //-----------------------------------------------------------------------------
00130 // Screen Saver
00131 //
00132 
00133 struct KScienceData
00134 {
00135     T32bit     **offset;
00136     XImage     *buffer;
00137     XImage     *xRootWin;
00138     GC         gc;
00139 };
00140 
00141 KScienceSaver::KScienceSaver( WId id, bool s, bool gP )
00142     : KScreenSaver( id )
00143 {
00144     setAttribute( Qt::WA_NoSystemBackground );
00145 
00146     d = new KScienceData;
00147     d->gc = XCreateGC(QX11Info::display(), id, 0, 0);
00148     d->xRootWin = 0;
00149     d->buffer = 0;
00150 
00151     moveOn = true;
00152     grabPixmap = gP;
00153     setup = s;
00154 
00155     vx = vy = 0.0;
00156     readSettings();
00157 
00158     if( !grabPixmap )
00159     {
00160         grabRootWindow();
00161         initialize();
00162         do_refresh( QRect ( 0, 0, width(), height() ) );
00163     }
00164 
00165     connect( &timer, SIGNAL( timeout() ), SLOT( slotTimeout() ) );
00166     timer.start( SCI_MAX_SPEED - speed[mode] );
00167 }
00168 
00169 KScienceSaver::~KScienceSaver()
00170 {
00171     timer.stop();
00172     releaseLens();
00173     if ( d->xRootWin )
00174         XDestroyImage( d->xRootWin );
00175     XFreeGC(QX11Info::display(), d->gc );
00176     delete d;
00177 }
00178 
00179 void KScienceSaver::myAssert( bool term, const char *eMsg )
00180 {
00181        if( !term ) {
00182               fprintf(stderr, "Error in KScreensaver - mode Science: %s\n", eMsg);
00183               releaseLens();
00184               exit(-1);
00185        }
00186 }
00187 
00188 void KScienceSaver::initialize()
00189 {
00190        KRandomSequence rnd;
00191        initLens();
00192        signed int ws = (signed int) (width() -  diam);
00193        signed int hs = (signed int) (height() - diam);
00194 
00195        x = (ws > 0) ? (rnd.getDouble() * ws ) : 0.0;
00196        y = (hs > 0) ? (rnd.getDouble() * hs ) : 0.0;
00197 
00198        xcoord = (int) x;
00199        ycoord = (int) y;
00200 
00201        switch( bpp ) {
00202               case 1 : applyLens = &KScienceSaver::applyLens8bpp;  break;
00203               case 2 : applyLens = &KScienceSaver::applyLens16bpp; break;
00204               case 3 : applyLens = &KScienceSaver::applyLens24bpp; break;
00205               case 4 : applyLens = &KScienceSaver::applyLens32bpp; break;
00206               default: myAssert( false, "unsupported colordepth "\
00207                                  "(only 8, 16, 24, 32 bpp supported)" );
00208        }
00209 }
00210 
00211 void KScienceSaver::initWhirlLens()
00212 {
00213        double dx, dy, r, phi, intens;
00214        T32bit *off;
00215        T32bit xo, yo;
00216 
00217        intens = double( intensity[mode] + 1) / 5.0;
00218        if( inverse[mode] )
00219               intens = -intens;
00220 
00221        for(int y = side-1; y >= 0; y--)
00222        {
00223               dy = y - origin;
00224               off = d->offset[y] = (T32bit *) malloc(sizeof(T32bit) * side);
00225               myAssert( off != 0, "too few memory" );
00226               for(int x = side-1; x >= 0; x--)
00227               {
00228                   dx = x - origin;
00229                   r = sqrt( dx*dx + dy*dy );
00230 
00231                   if( r < radius )
00232                   {
00233                          if ( dx == 0.0 )
00234                                 phi = (dy > 0.0) ? M_PI_2 :-(M_PI_2);
00235                          else
00236                                 phi = atan2( dy, dx );
00237                          phi +=  intens * ( radius - r ) / ( r+7.0 );
00238                          xo = (T32bit) ( origin + r*cos( phi ) - x );
00239                          yo = (T32bit) ( origin + r*sin( phi ) - y );
00240                          off[x] = xo*bpp + yo*imgnext;
00241                   }
00242                   else
00243                      if( hideBG[mode] )
00244                             off[x] = (border-y)*imgnext + (border-x)*bpp;
00245                      else
00246                             off[x] = 0;
00247               }
00248         }
00249 }
00250 
00251 void KScienceSaver::initSphereLens()
00252 {
00253        double dx, dy, r, xr, yr, phi, intens;
00254        T32bit *off;
00255        T32bit xo, yo;
00256 
00257        intens = 1.0 - double( intensity[mode] ) / 20.0;
00258 
00259        if( inverse[mode] )
00260               intens = -intens;
00261 
00262        for(int y = side-1; y >= 0; y--)
00263        {
00264               dy = y - origin;
00265               off = d->offset[y] = (T32bit *) malloc(sizeof(T32bit) * side);
00266               myAssert( off != 0, "too few memory" );
00267               for(int x = side-1; x >= 0; x--)
00268               {
00269                   dx = x - origin;
00270                   r = sqrt( dx*dx + dy*dy );
00271 
00272               if( r < radius )
00273               {
00274                      xr = (double) radius*cos(asin(dy/radius));
00275                      yr = (double) radius*cos(asin(dx/radius));
00276                      phi = (xr != 0.0) ? asin(dx/xr) : 0.0;
00277                      xo = (T32bit) (origin + intens*2.0*phi*xr / M_PI - x);
00278                      phi = (yr != 0.0) ? asin(dy/yr) : 0.0;
00279                      yo = (T32bit) (origin + intens*2.0*phi*yr / M_PI - y);
00280                      off[x] = xo*bpp + yo*imgnext;
00281               }
00282               else
00283                      if( hideBG[mode] )
00284                             off[x] = (border-y)*imgnext + (border-x)*bpp;
00285                      else
00286                             off[x] = 0;
00287               }
00288         }
00289 }
00290 
00291 void KScienceSaver::initExponentialLens()
00292 {
00293        double dx, dy, r, rnew, f, intens;
00294        T32bit *off;
00295        T32bit xo, yo;
00296 
00297        if( mode == MODE_EXPONENTIAL )
00298               intens = - (0.1 + 0.8 * double( intensity[mode] + 2) / 10.0);
00299        else
00300               intens = 0.9 - 0.8 * double( intensity[mode] ) / 10.0;
00301 
00302        for(int y = side-1; y >= 0; y--)
00303        {
00304               dy = y - origin;
00305               off = d->offset[y] = (T32bit *) malloc(sizeof(T32bit) * side);
00306               myAssert( off != 0, "too few memory" );
00307               for(int x = side-1; x >= 0; x--)
00308               {
00309                   dx = x - origin;
00310                   r = sqrt( dx*dx + dy*dy );
00311 
00312                   if( r < radius )
00313                   {
00314                          if( r == 0.0 )
00315                                 f = 0.0;
00316                          else
00317                          {
00318                                 rnew = radius*(pow(r, intens) /  pow(radius, intens));
00319                                 f = double ((int)rnew % radius) / r;
00320                          }
00321                          xo = (T32bit) ( origin + f*dx - x );
00322                          yo = (T32bit) ( origin + f*dy - y );
00323                          off[x] = xo*bpp + yo*imgnext;
00324                   }
00325                   else
00326                      if( hideBG[mode] )
00327                             off[x] = (border-y)*imgnext + (border-x)*bpp;
00328                      else
00329                             off[x] = 0;
00330               }
00331         }
00332 }
00333 
00334 void KScienceSaver::initCurvatureLens()
00335 {
00336        double dx, dy, r, f, intens;
00337        T32bit *off;
00338        T32bit xo, yo;
00339 
00340        intens = (double) radius*intensity[mode] / 20.0;
00341        if( inverse[mode] ) intens = -intens;
00342 
00343        for(int y = side-1; y >= 0; y--)
00344        {
00345               dy = y - origin;
00346               off = d->offset[y] = (T32bit *) malloc(sizeof(T32bit) * side);
00347               myAssert( off != 0, "too few memory" );
00348               for(int x = side-1; x >= 0; x--)
00349               {
00350                   dx = x - origin;
00351                   r = sqrt( dx*dx + dy*dy );
00352 
00353                   if( r < radius )
00354                   {
00355                          if( r == 0.0 )
00356                                 f = 0.0;
00357                          else
00358                                 f = (r - intens * sin(M_PI * r/(double)radius)) / r;
00359                          xo = (T32bit) ( origin + f*dx - x );
00360                          yo = (T32bit) ( origin + f*dy - y );
00361                          off[x] = xo*bpp + yo*imgnext;
00362                   }
00363                   else
00364                      if( hideBG[mode] )
00365                             off[x] = (border-y)*imgnext + (border-x)*bpp;
00366                      else
00367                             off[x] = 0;
00368               }
00369        }
00370 }
00371 
00372 void KScienceSaver::initWaveLens()
00373 {
00374        double dx, dy, r, rnew, f, intens, k;
00375        T32bit *off;
00376        T32bit xo, yo;
00377 
00378        intens = (double) intensity[mode] + 1.0;
00379        k = (intensity[mode] % 2) ? -12.0 : 12.0;
00380 
00381        for(int y = side-1; y >= 0; y--)
00382        {
00383               dy = y - origin;
00384               off = d->offset[y] = (T32bit *) malloc(sizeof(T32bit) * side);
00385               myAssert( off != 0, "too few memory" );
00386               for(int x = side-1; x >= 0; x--)
00387               {
00388                   dx = x - origin;
00389                   r = sqrt( dx*dx + dy*dy );
00390 
00391                   if( r < radius )
00392                   {
00393                          if( r == 0.0 )
00394                                 f = 0.0;
00395                          else
00396                          {
00397                                 rnew = r - k * sin( M_PI * intens * r/(double)radius);
00398                                 f = double ((int)rnew % radius) / r;
00399                          }
00400                          xo = (T32bit) ( origin + f*dx - x );
00401                          yo = (T32bit) ( origin + f*dy - y );
00402                          off[x] = xo*bpp + yo*imgnext;
00403                   }
00404                   else
00405                      if( hideBG[mode] )
00406                             off[x] = (border-y)*imgnext + (border-x)*bpp;
00407                      else
00408                             off[x] = 0;
00409               }
00410        }
00411 }
00412 
00413 void KScienceSaver::initLens()
00414 {
00415        int min = (width() < height()) ? width() : height();
00416        border = 1 + SCI_MAX_MOVE;
00417 
00418        radius = (size[mode] * min) / 100;
00419        if( radius<<1 == min ) radius--;
00420        diam = radius << 1;
00421        myAssert( diam < min, "assertion violated: diam < min" );
00422        origin = radius + border;
00423        side  = origin << 1;
00424 
00425        d->buffer = XSubImage( d->xRootWin, 0, 0, side, side );
00426         myAssert( d->buffer != 0, "cannot allocate pixmap" );
00427 
00428        d->offset = (T32bit **) malloc( sizeof(T32bit *) * side );
00429        myAssert( d->offset != 0, "too few memory" );
00430 
00431        switch( mode ) {
00432               case MODE_WHIRL:     initWhirlLens();  break;
00433               case MODE_SPHERE:    initSphereLens(); break;
00434               case MODE_EXPONENTIAL:
00435               case MODE_CONTRACTION:      initExponentialLens(); break;
00436               case MODE_CURVATURE:    initCurvatureLens(); break;
00437               case MODE_WAVE:      initWaveLens(); break;
00438               default: myAssert( false, "internal error (wrong mode in initLens() )" );
00439        }
00440 }
00441 
00442 void KScienceSaver::releaseLens()
00443 {
00444        if( d->offset != 0 ) {
00445               for(int i=0; i<side; i++)
00446                      if( d->offset[i] != 0 ) free( d->offset[i] );
00447               free( d->offset );
00448               d->offset = 0;
00449        }
00450        if( d->buffer != 0 ) {
00451               XDestroyImage( d->buffer );
00452               d->buffer = 0;
00453        }
00454 }
00455 
00456 void KScienceSaver::setMode( int m )
00457 {
00458        timer.stop();
00459 
00460        releaseLens();
00461        int old = mode;
00462        mode = m;
00463        vx = copysign( moveX[mode], vx );
00464        vy = copysign( moveY[mode], vy );
00465        int dm = diam;
00466        initLens();
00467        if( hideBG[old] ^ hideBG[m] )
00468               do_refresh( QRect( 0, 0, width(), height() ) );
00469        else
00470               if( diam < dm )
00471               {
00472                      do_refresh( QRect( (int) x+diam, (int) y,      dm-diam, diam    ) );
00473                      do_refresh( QRect( (int) x,      (int) y+diam, dm,      dm-diam ) );
00474               }
00475 
00476        timer.start( SCI_MAX_SPEED - speed[mode] );
00477 }
00478 
00479 void KScienceSaver::setMoveX( int s )
00480 {
00481        timer.stop();
00482 
00483        moveX[mode] = s;
00484        vx = copysign( moveX[mode], vx );
00485 
00486        timer.start( SCI_MAX_SPEED - speed[mode] );
00487 }
00488 
00489 void KScienceSaver::setMoveY( int s )
00490 {
00491        timer.stop();
00492 
00493        moveY[mode] = s;
00494        vy = copysign( moveY[mode], vy );
00495 
00496        timer.start( SCI_MAX_SPEED - speed[mode] );
00497 }
00498 
00499 void KScienceSaver::setMove( bool s )
00500 {
00501        moveOn = s;
00502 }
00503 
00504 void KScienceSaver::setSize( int s )
00505 {
00506        timer.stop();
00507 
00508        releaseLens();
00509        int dm = diam;
00510        size[mode] = s;
00511        initLens();
00512        if( diam < dm )
00513        {
00514               do_refresh( QRect( (int) x+diam, (int) y,      dm-diam, diam    ) );
00515               do_refresh( QRect( (int) x,      (int) y+diam, dm,      dm-diam ) );
00516        }
00517 
00518        timer.start( SCI_MAX_SPEED - speed[mode] );
00519 }
00520 
00521 void KScienceSaver::setSpeed( int s )
00522 {
00523        speed[mode] = s;
00524 
00525        timer.start( SCI_MAX_SPEED - speed[mode] );
00526 }
00527 
00528 void KScienceSaver::setIntensity( int i )
00529 {
00530        timer.stop();
00531 
00532        releaseLens();
00533        intensity[mode] = i;
00534        initLens();
00535 
00536        timer.start( SCI_MAX_SPEED - speed[mode]);
00537 }
00538 
00539 void KScienceSaver::setInverse( bool b )
00540 {
00541        timer.stop();
00542 
00543        releaseLens();
00544        inverse[mode] = b;
00545        initLens();
00546 
00547        timer.start( SCI_MAX_SPEED - speed[mode]);
00548 }
00549 
00550 void KScienceSaver::setGravity( bool b )
00551 {
00552        timer.stop();
00553 
00554        releaseLens();
00555        gravity[mode] = b;
00556        vy = copysign( moveY[mode], vy );
00557        initLens();
00558 
00559        timer.start( SCI_MAX_SPEED - speed[mode]);
00560 }
00561 
00562 void KScienceSaver::setHideBG( bool b )
00563 {
00564        timer.stop();
00565 
00566        releaseLens();
00567        hideBG[mode] = b;
00568        initLens();
00569        do_refresh( QRect( 0, 0, width(), height() ) );
00570 
00571        timer.start( SCI_MAX_SPEED - speed[mode]);
00572 }
00573 
00574 void KScienceSaver::readSettings()
00575 {
00576     KConfigGroup group = KGlobal::config()->group("Settings");
00577         QString sMode;
00578 
00579        mode = group.readEntry( "ModeNr", SCI_DEFAULT_MODE );
00580 
00581        for(int i=0; i < MAX_MODES; i++)
00582        {
00583               sMode.setNum( i );
00584               group = KGlobal::config()->group( "Mode" + sMode );
00585               moveX[i]     = group.readEntry(  "MoveX",     SCI_DEFAULT_MOVEX);
00586               moveY[i]     = group.readEntry(  "MoveY",     SCI_DEFAULT_MOVEY);
00587               size[i]      = group.readEntry(  "Size",      SCI_DEFAULT_SIZE);
00588               speed[i]     = group.readEntry(  "Speed",     SCI_DEFAULT_SPEED);
00589               intensity[i] = group.readEntry(  "Intensity", SCI_DEFAULT_INTENSITY);
00590               inverse[i]   = group.readEntry( "Inverse",   SCI_DEFAULT_INVERSE);
00591               gravity[i]   = group.readEntry( "Gravity",   SCI_DEFAULT_GRAVITY);
00592               hideBG[i]    = group.readEntry( "HideBG",    SCI_DEFAULT_HIDE);
00593        }
00594 
00595        vx = copysign( moveX[mode], vx );
00596        vy = copysign( moveY[mode], vy );
00597 }
00598 
00599 void KScienceSaver::do_refresh( const QRect & origRect )
00600 {
00601        if( grabPixmap )
00602               return;
00603         QRect rect(origRect.normalized());
00604 
00605        if( hideBG[mode] )
00606        {
00607               XSetWindowBackground( QX11Info::display(), winId(), QColormap::instance().pixel(Qt::black) );
00608               XClearArea( QX11Info::display(), winId(), rect.left(), rect.top(),
00609                             rect.width(), rect.height(), false );
00610        }
00611        else
00612        {
00613               myAssert( d->xRootWin != 0, "root window not grabbed" );
00614               XPutImage( QX11Info::display(), winId(), d->gc, d->xRootWin,
00615                          rect.left(), rect.top(),
00616                            rect.left(), rect.top(),
00617                            rect.width(), rect.height() );
00618        }
00619 }
00620 
00621 void KScienceSaver::slotTimeout()
00622 {
00623        if( grabPixmap ) {
00624               if( !QWidget::find(winId())->isActiveWindow() )
00625                      return;
00626               grabPreviewWidget();
00627               grabPixmap = false;
00628               initialize();
00629               if( hideBG[mode] )
00630                      do_refresh( QRect ( 0, 0, width(), height() ) );
00631        }
00632 
00633        signed int oldx = xcoord, oldy = ycoord;
00634 
00635        if( gravity[mode] ) {
00636               double h = double(y+1.0) / double(height()-diam);
00637               if( h > 1.0 ) h = 1.0;
00638               vy = sqrt( h ) * ( (vy > 0.0) ? moveY[mode] : -moveY[mode] );
00639        }
00640        myAssert( abs((int)rint(vy)) <= border, "assertion violated: vy <= border" );
00641 
00642        if( moveOn )
00643        {
00644               x += vx;
00645               y += vy;
00646        }
00647 
00648        if( x <= 0.0 ) {
00649               vx = -vx;
00650               x = 0.0;
00651        }
00652        if( int(x) + diam >= width()) {
00653               vx = -vx;
00654               myAssert( width()-diam > 0, "assertion violated: width-diam > 0" );
00655               x = (double) (width() - diam - 1);
00656        }
00657        if( y <= 0.0 ) {
00658               vy = -vy;
00659               y = 0.0;
00660        }
00661        if( int(y) + diam >= height() ) {
00662               vy = -vy;
00663               myAssert( height() - diam > 0, "assertion violated: height-diam > 0" );
00664               y = (double) (height() - diam - 1);
00665        }
00666        
00667        xcoord = (int) x ;
00668        ycoord = (int) y ;
00669        signed int dx = (signed int) xcoord - oldx;
00670        signed int dy = (signed int) ycoord - oldy;
00671        signed int xs, ys, xd, yd, w, h;
00672 
00673        if( dx > 0 ) {
00674               w = diam+dx;
00675               xd = oldx;
00676               xs = border-dx;
00677               if( dy > 0 ) {
00678                      h = diam+dy;
00679                      yd = oldy;
00680                      ys = border-dy;
00681               }
00682               else {
00683                      h = diam-dy;
00684                      yd = ycoord;
00685                      ys = border;
00686               }
00687        }
00688        else {
00689               w = diam-dx;
00690               xd = xcoord;
00691               xs = border;
00692               if( dy > 0 ) {
00693                      h = diam+dy;
00694                      yd = oldy;
00695                      ys = border-dy;
00696               } else {
00697                      h = diam-dy;
00698                      yd = ycoord;
00699                      ys = border;
00700               }
00701        }
00702 
00703        if(  xd + w >= width()  ) w = width()  - xd - 1;
00704        if(  yd + h >= height() ) h = height() - yd - 1;
00705 
00706 //printf("%d: (dx: %3d, dy: %3d), diam: %3d, (xc: %3d, yc: %3d), (xs: %3d, ys: %3d), (xd: %3d, yd: %3d), (w: %3d, h: %3d)\n", mode, dx, dy, diam, xcoord, ycoord, xs, ys, xd, yd, w, h);
00707        myAssert( dx <= border && dy <=border, "assertion violated: dx or dy <= border");
00708        myAssert( xcoord >= 0 && ycoord >= 0, "assertion violated: xcoord, ycoord >= 0 ");
00709        myAssert( xd+w < width(), "assertion violated: xd+w < width" );
00710        myAssert( yd+h < height(), "assertion violated: yd+h < height" );
00711 
00712        if( hideBG[mode] )
00713               blackPixel( xcoord, ycoord );
00714        (this->*applyLens)(xs, ys, xd, yd, w, h);
00715        XPutImage( QX11Info::display(), winId(), d->gc, d->buffer, 0, 0, xd, yd, w, h );
00716        if( hideBG[mode] )
00717               blackPixelUndo( xcoord, ycoord );
00718 }
00719 
00720 void KScienceSaver::grabRootWindow()
00721 {
00722        Display *dsp = QX11Info::display();
00723        Window rootwin = RootWindow( dsp, QX11Info::appScreen() );
00724 
00725        // grab contents of root window
00726        if( d->xRootWin )
00727               XDestroyImage( d->xRootWin );
00728 
00729        d->xRootWin = XGetImage( dsp, rootwin, 0, 0, width(),
00730                              height(), AllPlanes, ZPixmap);
00731        myAssert( d->xRootWin, "unable to grab root window\n" );
00732 
00733        imgnext = d->xRootWin->bytes_per_line;
00734        bpp = ( d->xRootWin->bits_per_pixel ) >> 3;
00735 }
00736 
00737 void KScienceSaver::grabPreviewWidget()
00738 {
00739        myAssert( QWidget::find(winId())->isActiveWindow(), "cannot grab preview widget: dialog not active()" );
00740 
00741        if( d->xRootWin )
00742               XDestroyImage( d->xRootWin );
00743 
00744        Display *dsp = QX11Info::display();
00745        d->xRootWin = XGetImage( dsp, winId(), 0, 0, width(), height(), AllPlanes, ZPixmap);
00746        myAssert( d->xRootWin, "unable to grab preview window\n" );
00747 
00748        imgnext = d->xRootWin->bytes_per_line;
00749        bpp = ( d->xRootWin->bits_per_pixel ) >> 3;
00750 }
00751 
00752 void KScienceSaver::blackPixel( int x, int y )
00753 {
00754        unsigned char black = (char) BlackPixel( QX11Info::display(), QX11Info::appScreen() );
00755        unsigned int adr = x*bpp + y*imgnext;
00756 
00757        for(int i=0; i<bpp; i++) {
00758               blackRestore[i] = d->xRootWin->data[adr];
00759               d->xRootWin->data[adr++] = black;
00760        }
00761 }
00762 
00763 void KScienceSaver::blackPixelUndo( int x, int y )
00764 {
00765        unsigned int adr = x*bpp + y*imgnext;
00766        for(int i=0; i<bpp; i++)
00767               d->xRootWin->data[adr++] = blackRestore[i];
00768 }
00769 
00770 // hm....
00771 
00772 void KScienceSaver::applyLens8bpp(int xs, int ys, int xd, int yd, int w, int h)
00773 {
00774        T32bit *off;
00775        char *img1, *img2, *data;
00776        signed int ix, iy, datanext = d->buffer->bytes_per_line - w;
00777 
00778        img1 = d->xRootWin->data + xd + yd*imgnext;
00779        data = d->buffer->data;
00780        for(iy = ys; iy < ys+h; iy++)
00781        {
00782               off = d->offset[iy] + xs;
00783               img2 = img1;
00784               for(ix = w; ix > 0; ix--)
00785                      *data++ = img2++[*off++];
00786               img1 += imgnext;
00787               data += datanext;
00788        }
00789 
00790 }
00791 
00792 void KScienceSaver::applyLens16bpp(int xs, int ys, int xd, int yd, int w, int h)
00793 {
00794        T32bit *off;
00795        char *img1, *img2, *data;
00796        int ix, iy, datanext = d->buffer->bytes_per_line - (w << 1);
00797 
00798        img1 = d->xRootWin->data + (xd << 1) + yd*imgnext;
00799        data = d->buffer->data;
00800        for(iy = ys; iy < ys+h; iy++)
00801        {
00802               off = d->offset[iy] + xs;
00803               img2 = img1;
00804               for(ix = w; ix > 0; ix--) {
00805                      *data++ = img2++[*off];
00806                      *data++ = img2++[*off++];
00807               }
00808               img1 += imgnext;
00809               data += datanext;
00810        }
00811 }
00812 
00813 void KScienceSaver::applyLens24bpp(int xs, int ys, int xd, int yd, int w, int h)
00814 {
00815        T32bit *off;
00816        char *img1, *img2, *data;
00817        signed int ix, iy, datanext = d->buffer->bytes_per_line - 3*w;
00818 
00819        img1 = d->xRootWin->data + 3*xd + yd*imgnext;
00820        data = d->buffer->data;
00821        for(iy = ys; iy < ys+h; iy++)
00822        {
00823               off = d->offset[iy] + xs;
00824               img2 = img1;
00825               for(ix = w; ix > 0; ix--) {
00826                      *data++ = img2++[*off];
00827                      *data++ = img2++[*off];
00828                      *data++ = img2++[*off++];
00829               }
00830               img1 += imgnext;
00831               data += datanext;
00832        }
00833 }
00834 
00835 void KScienceSaver::applyLens32bpp(int xs, int ys, int xd, int yd, int w, int h)
00836 {
00837        T32bit *off;
00838        char *img1, *img2, *data;
00839        signed int ix, iy, datanext = d->buffer->bytes_per_line - (w << 2);
00840 
00841        img1 = d->xRootWin->data + (xd << 2) + yd*imgnext;
00842        data = d->buffer->data;
00843        for(iy = ys; iy < ys+h; iy++)
00844        {
00845               off = d->offset[iy] + xs;
00846               img2 = img1;
00847               for(ix = w; ix > 0; ix--) {
00848                      *data++ = img2++[*off];
00849                      *data++ = img2++[*off];
00850                      *data++ = img2++[*off];
00851                      *data++ = img2++[*off++];
00852               }
00853               img1 += imgnext;
00854               data += datanext;
00855        }
00856 }
00857 
00858 
00859 //-----------------------------------------------------------------------------
00860 
00861 KScienceSetup::KScienceSetup(  QWidget *parent )
00862        : KDialog( parent)
00863          , saver( 0 )
00864 {
00865        setCaption(i18n( "Setup Science Screen Saver" ));
00866        setModal(true);
00867        setButtons(Ok|Cancel|Help);
00868        setDefaultButton(Ok);
00869        showButtonSeparator(true);
00870        readSettings();
00871        initModeInfo();
00872 
00873        QWidget *main = new QWidget(this);
00874        setMainWidget(main);
00875 
00876        QHBoxLayout *lt  = new QHBoxLayout( main );
00877         lt->setSpacing( spacingHint() );
00878        QVBoxLayout *ltm = new QVBoxLayout;
00879        lt->addLayout( ltm );
00880        QVBoxLayout *ltc = new QVBoxLayout;
00881        lt->addLayout( ltc );
00882 
00883        // mode
00884        QLabel *label = new QLabel( i18n("Mode:"), main );
00885        ltm->addWidget( label );
00886 
00887        QListWidget *c = new QListWidget( main );
00888        for(int i = 0; i<MAX_MODES; i++)
00889               c->addItem( modeInfo[i].name );
00890        c->setCurrentRow( mode );
00891        c->setFixedHeight( 5 * c->fontMetrics().height() );
00892        connect( c, SIGNAL( currentRowChanged( int ) ), SLOT( slotMode( int ) ) );
00893        ltm->addWidget( c );
00894 
00895        // inverse
00896        QCheckBox *cbox = checkInverse = new QCheckBox( i18n("Inverse"), main );
00897        cbox->setEnabled( modeInfo[mode].inverseEnable );
00898        cbox->setChecked( inverse[mode] );
00899        connect( cbox, SIGNAL( clicked() ), SLOT( slotInverse() ) );
00900        ltm->addWidget( cbox );
00901 
00902        // gravity
00903        cbox = checkGravity = new QCheckBox( i18n("Gravity"), main );
00904        cbox->setChecked( gravity[mode] );
00905        connect( cbox, SIGNAL( clicked() ), SLOT( slotGravity() ) );
00906        ltm->addWidget( cbox );
00907 
00908        // hide background
00909        cbox = checkHideBG = new QCheckBox( i18n("Hide background"), main );
00910        cbox->setChecked( hideBG[mode] );
00911        connect( cbox, SIGNAL( clicked() ), SLOT( slotHideBG() ) );
00912        ltm->addWidget( cbox );
00913        ltm->addStretch();
00914 
00915        // size
00916        label = new QLabel( i18n("Size:"), main );
00917        ltc->addWidget( label );
00918 
00919        slideSize = new QSlider(Qt::Horizontal, main );
00920        slideSize->setMinimum(9);
00921        slideSize->setMaximum(50);
00922        slideSize->setPageStep(5);
00923        slideSize->setValue(size[mode]);
00924        slideSize->setMinimumSize( 90, 20 );
00925        slideSize->setTickPosition(QSlider::TicksBelow);
00926        slideSize->setTickInterval(5);
00927        connect( slideSize, SIGNAL( sliderMoved( int ) ),
00928               SLOT( slotSize( int ) ) );
00929        connect( slideSize, SIGNAL( sliderPressed() ),
00930               SLOT( slotSliderPressed() ) );
00931        connect( slideSize, SIGNAL( sliderReleased() ),
00932               SLOT( slotSliderReleased() ) );
00933 
00934        ltc->addWidget( slideSize );
00935 
00936        // intensity
00937        label = new QLabel( i18n("Intensity:"), main );
00938        ltc->addWidget( label );
00939 
00940        slideIntensity = new QSlider(Qt::Horizontal, main );
00941        slideIntensity->setMinimum(0);
00942        slideIntensity->setMaximum(10);
00943        slideIntensity->setPageStep(1);
00944        slideIntensity->setValue(intensity[mode]);
00945        slideIntensity->setMinimumSize( 90, 20 );
00946        slideIntensity->setTickPosition(QSlider::TicksBelow);
00947        slideIntensity->setTickInterval(1);
00948        connect( slideIntensity, SIGNAL( sliderMoved( int ) ),
00949               SLOT( slotIntensity( int )) );
00950        connect( slideIntensity, SIGNAL( sliderPressed() ),
00951               SLOT( slotSliderPressed() ) );
00952        connect( slideIntensity, SIGNAL( sliderReleased() ),
00953               SLOT( slotSliderReleased() ) );
00954        ltc->addWidget( slideIntensity );
00955 
00956        // speed
00957        label = new QLabel( i18n("Speed:"), main );
00958        ltc->addWidget( label );
00959 
00960        slideSpeed = new QSlider(Qt::Horizontal, main );
00961        slideSpeed->setMinimum(0);
00962        slideSpeed->setMaximum(SCI_MAX_SPEED);
00963        slideSpeed->setPageStep(10);
00964        slideSpeed->setValue(speed[mode]);
00965        slideSpeed->setMinimumSize( 90, 20 );
00966        slideSpeed->setTickPosition(QSlider::TicksBelow);
00967        slideSpeed->setTickInterval(10);
00968        connect( slideSpeed, SIGNAL( sliderMoved( int ) ),
00969               SLOT( slotSpeed( int ) ) );
00970        ltc->addWidget( slideSpeed );
00971 
00972        // motion
00973        label = new QLabel( i18n("Motion:"), main );
00974        ltc->addWidget( label );
00975 
00976        QHBoxLayout *ltcm = new QHBoxLayout;
00977        ltc->addLayout( ltcm );
00978 
00979        slideMoveX = new QSlider(Qt::Horizontal, main );
00980        slideMoveX->setMinimum(0);
00981        slideMoveX->setMaximum(SCI_MAX_MOVE);
00982        slideMoveX->setPageStep(5);
00983        slideMoveX->setValue(moveX[mode]);
00984        slideMoveX->setMinimumSize( 40, 20 );
00985        slideMoveX->setTickPosition(QSlider::TicksBelow);
00986        slideMoveX->setTickInterval(5);
00987        connect( slideMoveX, SIGNAL( sliderMoved( int ) ),
00988               SLOT( slotMoveX( int ) ) );
00989        ltcm->addWidget( slideMoveX );
00990 
00991        slideMoveY = new QSlider(Qt::Horizontal, main );
00992        slideMoveY->setMinimum(0);
00993        slideMoveY->setMaximum(SCI_MAX_MOVE);
00994        slideMoveY->setPageStep(5);
00995        slideMoveY->setValue(moveY[mode]);
00996        slideMoveY->setMinimumSize( 40, 20 );
00997        slideMoveY->setTickPosition(QSlider::TicksBelow);
00998        slideMoveY->setTickInterval(5);
00999        connect( slideMoveY, SIGNAL( sliderMoved( int ) ),
01000               SLOT( slotMoveY( int ) ) );
01001        ltcm->addWidget( slideMoveY );
01002 
01003        ltc->addStretch();
01004 
01005        // preview
01006        preview = new KPreviewWidget( main );
01007        preview->setFixedSize( 220, 170 );
01008        QPixmap p( KStandardDirs::locate("data", "kscreensaver/pics/kscience.png") );
01009        QPalette palette;
01010        if( p.isNull() ) {
01011               palette.setColor( preview->backgroundRole(), Qt::black );
01012        } else {
01013               palette.setBrush( preview->backgroundRole(), QBrush( p ) );
01014        }
01015        preview->setPalette( palette );
01016        preview->setAutoFillBackground(true);
01017        preview->show();     // otherwise saver does not get correct size
01018        lt->addWidget( preview );
01019 
01020        // let the preview window display before creating the saver
01021        kapp->processEvents();
01022 
01023        saver = new KScienceSaver( preview->winId(), true, !p.isNull() );
01024        preview->notifySaver( saver );
01025        connect(this,SIGNAL(okClicked()),SLOT(slotOk()));
01026        connect(this,SIGNAL(helpClicked()),SLOT(slotHelp()));
01027 }
01028 
01029 KScienceSetup::~KScienceSetup()
01030 {
01031        delete saver;        // be sure to delete this first
01032 }
01033 
01034 void KScienceSetup::updateSettings()
01035 {
01036        // update dialog
01037        slideMoveX    ->setValue(   moveX[mode]     );
01038        slideMoveY    ->setValue(   moveY[mode]     );
01039        slideSize     ->setValue(   size[mode]      );
01040        slideSpeed    ->setValue(   speed[mode]     );
01041        slideIntensity->setValue(   intensity[mode] );
01042        checkInverse  ->setEnabled( modeInfo[mode].inverseEnable );
01043        checkInverse  ->setChecked( inverse[mode]   );
01044        checkGravity  ->setChecked( gravity[mode]   );
01045        checkHideBG   ->setChecked( hideBG[mode]    );
01046 }
01047 
01048 // read settings from config file
01049 void KScienceSetup::readSettings()
01050 {
01051     KConfigGroup group = KGlobal::config()->group("Settings");
01052         QString sMode;
01053 
01054        mode = group.readEntry( "ModeNr", SCI_DEFAULT_MODE );
01055 
01056        for(int i=0; i < MAX_MODES; i++)
01057        {
01058               sMode.setNum( i );
01059               group = KGlobal::config()->group( "Mode" + sMode );
01060               moveX[i]     = group.readEntry(  "MoveX",     SCI_DEFAULT_MOVEX);
01061               moveY[i]     = group.readEntry(  "MoveY",     SCI_DEFAULT_MOVEY);
01062               size[i]      = group.readEntry(  "Size",      SCI_DEFAULT_SIZE);
01063               speed[i]     = group.readEntry(  "Speed",     SCI_DEFAULT_SPEED);
01064               intensity[i] = group.readEntry(  "Intensity", SCI_DEFAULT_INTENSITY);
01065               inverse[i]   = group.readEntry( "Inverse",   SCI_DEFAULT_INVERSE);
01066               gravity[i]   = group.readEntry( "Gravity",   SCI_DEFAULT_GRAVITY);
01067               hideBG[i]    = group.readEntry( "HideBG",    SCI_DEFAULT_HIDE);
01068        }
01069 }
01070 
01071 void KScienceSetup::slotMode( int m )
01072 {
01073        mode = m;
01074 
01075        if( saver )
01076               saver->setMode( mode );
01077 
01078        updateSettings();
01079 }
01080 
01081 void KScienceSetup::slotInverse( )
01082 {
01083        inverse[mode] = checkInverse->isChecked();
01084 
01085        if( saver )
01086               saver->setInverse( inverse[mode] );
01087 }
01088 
01089 void KScienceSetup::slotGravity( )
01090 {
01091        gravity[mode] = checkGravity->isChecked();
01092 
01093        if( saver )
01094               saver->setGravity( gravity[mode] );
01095 }
01096 
01097 void KScienceSetup::slotHideBG( )
01098 {
01099        hideBG[mode] = checkHideBG->isChecked();
01100 
01101        if( saver )
01102               saver->setHideBG( hideBG[mode] );
01103 }
01104 
01105 void KScienceSetup::slotMoveX( int x )
01106 {
01107        moveX[mode] = x;
01108 
01109        if( saver )
01110               saver->setMoveX( x );
01111 }
01112 
01113 void KScienceSetup::slotMoveY( int y )
01114 {
01115        moveY[mode] = y;
01116 
01117        if( saver )
01118               saver->setMoveY( y );
01119 }
01120 
01121 void KScienceSetup::slotSize( int s )
01122 {
01123        size[mode] = s;
01124 
01125        if( saver )
01126               saver->setSize( s );
01127 }
01128 
01129 void KScienceSetup::slotSpeed( int s )
01130 {
01131        speed[mode] = s;
01132 
01133        if( saver )
01134               saver->setSpeed( s );
01135 }
01136 
01137 void KScienceSetup::slotIntensity( int i )
01138 {
01139        intensity[mode] = i;
01140 
01141        if( saver )
01142               saver->setIntensity( i );
01143 }
01144 
01145 void KScienceSetup::slotSliderPressed()
01146 {
01147        if( saver )
01148               saver->setMove( false );
01149 }
01150 
01151 void KScienceSetup::slotSliderReleased()
01152 {
01153        if( saver )
01154               saver->setMove( true );
01155 }
01156 
01157 // Ok pressed - save settings and exit
01158 void KScienceSetup::slotOk()
01159 {
01160     KConfigGroup group = KGlobal::config()->group("Settings");
01161        QString sSize, sSpeed, sIntensity, sMode;
01162 
01163        group.writeEntry( "ModeNr", mode );
01164 
01165        for(int i=0; i<MAX_MODES; i++)
01166        {
01167               sMode.setNum( i );
01168               group = KGlobal::config()->group("Mode" + sMode );
01169               group.writeEntry( "MoveX",     moveX[i]     );
01170               group.writeEntry( "MoveY",     moveY[i]     );
01171               group.writeEntry( "Size",      size[i]      );
01172               group.writeEntry( "Speed",     speed[i]     );
01173               group.writeEntry( "Intensity", intensity[i] );
01174               group.writeEntry( "Inverse",   inverse[i]   );
01175               group.writeEntry( "Gravity",   gravity[i]   );
01176               group.writeEntry( "HideBG",    hideBG[i]    );
01177        }
01178 
01179        group.sync();
01180 
01181        accept();
01182 }
01183 
01184 void KScienceSetup::slotHelp()
01185 {
01186        QString about = i18n("Science Version 0.26.5\n\nWritten by Rene Beutler (1998)\nrbeutler@g26.ethz.ch");
01187        KMessageBox::about(this,
01188                              about);
01189 }