1 //-----------------------------------------------------------------------------
3 // kblob - Basic screen saver for KDE
5 // Copyright (c) Tiaan Wessels, 1997
8 // - add blob_alg enum in blob.h before ALG_LAST
9 // - choose 2 letter prefix for alg and add vars needed to private vars
10 // in KBlobSaver in blob.h
11 // - add xxSetup and xxNextFrame method definitions in blob.h
12 // - implement methods in this file. xxSetup to init vars mentioned
13 // in step 2. xxNextFrame to advance blob painter ( calc tx,ty and
14 // use box() method to position painter
15 // - add descriptive string in alg_str array in this file before "Random"
16 // - add to Algs array in KBlobSaver constructor in this file
17 // - test by setup saver and choosing alg from list
27 #include <q3listbox.h>
33 #include <QVBoxLayout>
34 #include <QHBoxLayout>
36 #include <kapplication.h>
38 #include <kmessagebox.h>
39 #include <knuminput.h>
42 #include <krandomsequence.h>
47 #define SMALLRAND(a) (int)(rnd->getLong(a)+1)
50 // libkscreensaver interface
51 class KBlobSaverInterface
: public KScreenSaverInterface
56 virtual KAboutData
* aboutData() {
57 return new KAboutData( "kblob.kss", I18N_NOOP( "KBlob" ), "2.2.0", I18N_NOOP( "KBlob" ) );
61 virtual KScreenSaver
* create( WId id
)
63 return new KBlobSaver( id
);
66 virtual QDialog
* setup()
68 return new KBlobSetup();
72 int main( int argc
, char *argv
[] )
74 KBlobSaverInterface kss
;
75 return kScreenSaverMain( argc
, argv
, kss
);
78 static KRandomSequence
*rnd
= 0;
83 alg_str
[0] = i18n("Random Linear");
84 alg_str
[1] = i18n("Horizontal Sine");
85 alg_str
[2] = i18n("Circular Bounce");
86 alg_str
[3] = i18n("Polar Coordinates");
87 alg_str
[4] = i18n("Random");
90 //-----------------------------------------------------------------------------
91 // the blob screensaver's code
93 KBlobSaver::KBlobSaver ( WId id
)
96 rnd
= new KRandomSequence();
99 float ramp
= (256.0-64.0)/(float)RAMP
;
101 i18n("This screen saver requires a color display.");
105 // needs colors to work this one
106 if (QPixmap::defaultDepth() < 8)
109 p
.setPen( Qt::white
);
110 p
.drawText( width()/2, height()/2, msg
);
115 // if 8-bit, create lookup table for color ramping further down
116 if (QPixmap::defaultDepth() == 8)
118 memset(lookup
, 0, 256*sizeof(uint
));
120 for (i
= 0; i
< RAMP
; i
++)
122 color
.setRgb(64+(int)(ramp
*(float)i
), 0, 0);
123 colors
[i
] = color
.pixel();
125 memset(lookup
, QColor(Qt::black
).pixel(), sizeof(uint
)*256);
126 for (i
= 0; i
< RAMP
-1; i
++)
127 lookup
[colors
[i
]] = colors
[i
+1];
128 lookup
[QColor(Qt::black
).pixel()] = lookup
[colors
[RAMP
-1]] = colors
[0];
132 // make special provision for preview mode
135 if (QPixmap::defaultDepth() > 8 )
142 if (QPixmap::defaultDepth() > 8 )
149 // the dimensions of the blob painter
152 // record starting time to know when to change frames
155 // init some parameters used by all algorithms
159 // means a new algorithm should be set at entrance of timer
160 newalg
= newalgp
= 1;
162 // init algorithm space
163 Algs
[0].Name
= alg_str
[0];
164 Algs
[0].Init
= &KBlobSaver::lnSetup
;
165 Algs
[0].NextFrame
= &KBlobSaver::lnNextFrame
;
167 Algs
[1].Name
= alg_str
[1];
168 Algs
[1].Init
= &KBlobSaver::hsSetup
;
169 Algs
[1].NextFrame
= &KBlobSaver::hsNextFrame
;
171 Algs
[2].Name
= alg_str
[2];
172 Algs
[2].Init
= &KBlobSaver::cbSetup
;
173 Algs
[2].NextFrame
= &KBlobSaver::cbNextFrame
;
175 Algs
[3].Name
= alg_str
[3];
176 Algs
[3].Init
= &KBlobSaver::pcSetup
;
177 Algs
[3].NextFrame
= &KBlobSaver::pcNextFrame
;
179 // get setup from kde registry
182 // start timer which will update blob painter
184 connect(&timer
, SIGNAL(timeout()), SLOT(slotTimeout()));
187 KBlobSaver::~KBlobSaver()
194 void KBlobSaver::setAlgorithm(int a
)
196 newalg
= newalgp
= ((a
== ALG_RANDOM
) ? 1 : 2);
200 void KBlobSaver::lnSetup()
202 // initialize the blob movement dictators with random vals
203 // incrementals on axis
204 ln_xinc
= SMALLRAND(3);
205 ln_yinc
= SMALLRAND(2);
208 tx
= SMALLRAND(width()-dim
-ln_xinc
*2);
209 ty
= SMALLRAND(height()-dim
-ln_yinc
*2);
212 void KBlobSaver::hsSetup()
214 hs_per
= SMALLRAND(7);
216 hs_rinc
= (hs_per
*M_PI
)/(hs_per
*90*4);
220 void KBlobSaver::cbSetup()
223 cb_rinc
= (2.0*M_PI
)/360.0;
225 cb_deviate
= SMALLRAND(height()/20)+(height()/15);
226 cb_radius
= height()/2-cb_deviate
*2-2*dim
;
227 cb_devradinc
= (rnd
->getDouble()*10.0*2.0*M_PI
)/360.0;
230 void KBlobSaver::pcSetup()
234 pc_inc
= (2.0*M_PI
)/720.0;
236 pc_div
= SMALLRAND(4)-1;
239 // render next frame ( or change algorithms )
240 void KBlobSaver::slotTimeout()
242 time_t now
= time(NULL
);
244 // should algorithm be changed
245 if (now
-start
> showlen
)
253 alg
= SMALLRAND(ALG_LAST
)-1;
254 (this->*Algs
[alg
].Init
)();
259 // gen next fram for current algorithm
260 (this->*Algs
[alg
].NextFrame
)();
263 void KBlobSaver::lnNextFrame()
267 // depending on the algorithm to use, move the blob painter to
269 // check for wall hit to change direction
270 if (tx
+dim
+ln_xinc
> (int)width()-1 || tx
+ln_xinc
< 0)
276 ln_xinc
= SMALLRAND(3)*dir
;
278 if (ty
+dim
+ln_yinc
> (int)height()-1 || ty
+ln_yinc
< 0)
284 ln_yinc
= SMALLRAND(2)*dir
;
287 // move box to new position
295 void KBlobSaver::hsNextFrame()
297 static int xlen
= width()-(4*dim
);
298 static int ylen
= height()-(4*dim
);
300 // calc x as offset on angle line and y as vertical offset
301 // on interval -1..1 sine of angle
302 tx
= (int)((hs_radians
/(hs_per
*M_PI
))*(float)xlen
);
303 ty
= (int)((float)(ylen
/4)*(hs_flip
*sin(hs_radians
)))+yhalf
;
309 hs_radians
+= hs_rinc
;
310 if (hs_radians
> hs_per
*M_PI
)
313 hs_radians
+= hs_rinc
;
316 else if (hs_radians
< 0.0)
320 void KBlobSaver::cbNextFrame()
324 // calculate deviation of circle main radius
325 deviate
= (int)(sin(cb_sradians
)*cb_deviate
);
327 // calculate topleft of box as a circle with a sine perturbed radius
328 tx
= (int)(cos(cb_radians
)*(cb_radius
+deviate
))+xhalf
;
329 ty
= (int)(sin(cb_radians
)*(cb_radius
+deviate
))+yhalf
;
334 // increase greater circle render angle
335 cb_radians
+= cb_rinc
;
336 if (cb_radians
> 2.0*M_PI
)
337 cb_radians
-= 2.0*M_PI
;
339 // increase radius deviation offset on sine wave
340 cb_sradians
+= cb_devradinc
;
343 void KBlobSaver::pcNextFrame()
345 static float scale
= (float)height()/3.0 - 4.0*dim
;
347 // simple polar coordinate equation
349 pc_radius
= cos(2.0*pc_angle
);
351 pc_radius
= 1.0/pc_div
+ cos(2.0*pc_angle
);
353 tx
= (int)(scale
*pc_radius
*cos(pc_angle
+pc_crot
))+xhalf
;
354 ty
= (int)(scale
*pc_radius
*sin(pc_angle
+pc_crot
))+yhalf
;
356 // advance blob painter
359 // new movement parameters
361 if (pc_angle
> 2.0*M_PI
)
363 pc_angle
-= 2.0*M_PI
;
364 pc_crot
+= M_PI
/45.0;
368 void KBlobSaver::box ( int x
, int y
)
370 // for bad behaving algorithms that wants to cause an X trap
371 // confine to the valid region before using potentially fatal XGetImage
372 if ((x
+dim
) >= width())
376 if ((y
+dim
) > height())
381 // get the box region from the display to upgrade
382 QImage img
= QPixmap::grabWindow(winId(), x
, y
, dim
, dim
).convertToImage();
384 // depending on the depth of the display, use either lookup table for
385 // next rgb val ( 8-bit ) or ramp the color directly for other displays
386 if ( img
.depth() == 8)
388 // manipulate image by upgrading each pixel with 1 using a lookup
389 // table as the color allocation could have resulted in a spread out
390 // configuration of the color ramp
391 for (int j
= 0; j
< img
.height(); j
++)
393 for (int i
= 0; i
< img
.width(); i
++)
395 img
.scanLine(j
)[i
] = lookup
[img
.scanLine(j
)[i
]];
401 for (int j
= 0; j
< img
.height(); j
++)
403 for (int i
= 0; i
< img
.width(); i
++)
405 QRgb p
= img
.pixel( i
, j
);
407 img
.setPixel( i
, j
, p
);
412 // put the image back onto the screen
414 p
.drawImage( x
, y
, img
);
417 void KBlobSaver::blank()
419 setBackgroundColor( Qt::black
);
423 void KBlobSaver::readSettings()
425 KConfig
*config
= KGlobal::config();
426 config
->setGroup("Settings");
428 // number of seconds to spend on a frame
429 showlen
= config
->readEntry("Showtime", 3*60);
431 // algorithm to use. if not set then use random
432 alg
= config
->readEntry("Algorithm", int(ALG_RANDOM
));
433 if (alg
== ALG_RANDOM
)
440 //-----------------------------------------------------------------------------
441 // dialog to setup screen saver parameters
443 KBlobSetup::KBlobSetup
450 setCaption(i18n( "Setup Blob Screen Saver" ));
451 setButtons(Ok
|Cancel
|Help
);
452 setDefaultButton(Ok
);
456 // get saver configuration from kde registry
459 setButtonText( Help
, i18n( "A&bout" ) );
460 QWidget
*main
= new QWidget(this);
463 QHBoxLayout
*tl
= new QHBoxLayout( main
, 0, spacingHint() );
465 QVBoxLayout
*vbox
= new QVBoxLayout
;
468 // seconds to generate on a frame
469 QLabel
*label
= new QLabel(i18n("Frame duration:"), main
);
470 stime
= new KIntNumInput( showtime
, main
);
471 stime
->setSuffix( i18n( " sec" ) );
472 vbox
->addWidget(label
);
473 vbox
->addWidget(stime
);
475 // available algorithms
476 label
= new QLabel(i18n("Algorithm:"), main
);
477 algs
= new Q3ListBox(main
);
478 algs
->setMinimumSize(150, 105);
479 for (int i
= 0; i
<= ALG_RANDOM
; i
++)
480 algs
->insertItem(alg_str
[i
]);
481 algs
->setCurrentItem(alg
);
482 vbox
->addWidget(label
);
483 vbox
->addWidget(algs
);
486 QWidget
*preview
= new QWidget( main
);
487 preview
->setFixedSize(220, 170);
488 preview
->setBackgroundColor(Qt::black
);
490 tl
->addWidget(preview
);
491 saver
= new KBlobSaver(preview
->winId());
492 saver
->setDimension(3);
493 if (QPixmap::defaultDepth() > 8)
494 saver
->setColorInc(7);
496 saver
->setColorInc(4);
500 // so selecting an algorithm will start previewing that alg
501 connect(algs
, SIGNAL(highlighted(int)), saver
,
502 SLOT(setAlgorithm(int)));
505 void KBlobSetup::readSettings()
507 KConfig
*config
= KGlobal::config();
508 config
->setGroup("Settings");
510 // number of seconds to spend on a frame
511 showtime
= config
->readEntry("Showtime", 3*60);
513 // algorithm to use. if not set then use random
514 alg
= config
->readEntry("Algorithm", (int)ALG_LAST
);
517 // Ok pressed - save settings and exit
518 void KBlobSetup::slotOk()
520 KConfig
*config
= KGlobal::config();
522 config
->setGroup("Settings");
524 config
->writeEntry("Showtime", stime
->value());
525 config
->writeEntry("Algorithm", algs
->currentItem());
532 void KBlobSetup::slotHelp()
534 KMessageBox::about(this,
535 i18n("Blobsaver Version 0.1\n\nWritten by Tiaan Wessels 1997\ntiaan@netsys.co.za"));
537 saver
->setAlgorithm(algs
->currentItem());