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
53 KDE_EXPORT
const char *kss_applicationName
= "kblob.kss";
54 KDE_EXPORT
const char *kss_description
= I18N_NOOP( "KBlob" );
55 KDE_EXPORT
const char *kss_version
= "2.2.0";
57 KDE_EXPORT KScreenSaver
*kss_create( WId id
)
59 return new KBlobSaver( id
);
62 KDE_EXPORT QDialog
*kss_setup()
64 return new KBlobSetup();
68 static KRandomSequence
*rnd
= 0;
73 alg_str
[0] = i18n("Random Linear");
74 alg_str
[1] = i18n("Horizontal Sine");
75 alg_str
[2] = i18n("Circular Bounce");
76 alg_str
[3] = i18n("Polar Coordinates");
77 alg_str
[4] = i18n("Random");
80 //-----------------------------------------------------------------------------
81 // the blob screensaver's code
83 KBlobSaver::KBlobSaver ( WId id
)
86 rnd
= new KRandomSequence();
89 float ramp
= (256.0-64.0)/(float)RAMP
;
91 i18n("This screen saver requires a color display.");
95 // needs colors to work this one
96 if (QPixmap::defaultDepth() < 8)
100 p
.drawText( width()/2, height()/2, msg
);
104 colorContext
= QColor::enterAllocContext();
106 // if 8-bit, create lookup table for color ramping further down
107 if (QPixmap::defaultDepth() == 8)
109 memset(lookup
, 0, 256*sizeof(uint
));
111 for (i
= 0; i
< RAMP
; i
++)
113 color
.setRgb(64+(int)(ramp
*(float)i
), 0, 0);
114 colors
[i
] = color
.alloc();
116 memset(lookup
, black
.pixel(), sizeof(uint
)*256);
117 for (i
= 0; i
< RAMP
-1; i
++)
118 lookup
[colors
[i
]] = colors
[i
+1];
119 lookup
[black
.pixel()] = lookup
[colors
[RAMP
-1]] = colors
[0];
123 // make special provision for preview mode
126 if (QPixmap::defaultDepth() > 8 )
133 if (QPixmap::defaultDepth() > 8 )
140 // the dimensions of the blob painter
143 // record starting time to know when to change frames
146 // init some parameters used by all algorithms
150 // means a new algorithm should be set at entrance of timer
151 newalg
= newalgp
= 1;
153 // init algorithm space
154 Algs
[0].Name
= alg_str
[0];
155 Algs
[0].Init
= &KBlobSaver::lnSetup
;
156 Algs
[0].NextFrame
= &KBlobSaver::lnNextFrame
;
158 Algs
[1].Name
= alg_str
[1];
159 Algs
[1].Init
= &KBlobSaver::hsSetup
;
160 Algs
[1].NextFrame
= &KBlobSaver::hsNextFrame
;
162 Algs
[2].Name
= alg_str
[2];
163 Algs
[2].Init
= &KBlobSaver::cbSetup
;
164 Algs
[2].NextFrame
= &KBlobSaver::cbNextFrame
;
166 Algs
[3].Name
= alg_str
[3];
167 Algs
[3].Init
= &KBlobSaver::pcSetup
;
168 Algs
[3].NextFrame
= &KBlobSaver::pcNextFrame
;
170 // get setup from kde registry
173 // start timer which will update blob painter
175 connect(&timer
, SIGNAL(timeout()), SLOT(slotTimeout()));
178 KBlobSaver::~KBlobSaver()
182 QColor::leaveAllocContext();
183 QColor::destroyAllocContext(colorContext
);
187 void KBlobSaver::setAlgorithm(int a
)
189 newalg
= newalgp
= ((a
== ALG_RANDOM
) ? 1 : 2);
193 void KBlobSaver::lnSetup()
195 // initialize the blob movement dictators with random vals
196 // incrementals on axis
197 ln_xinc
= SMALLRAND(3);
198 ln_yinc
= SMALLRAND(2);
201 tx
= SMALLRAND(width()-dim
-ln_xinc
*2);
202 ty
= SMALLRAND(height()-dim
-ln_yinc
*2);
205 void KBlobSaver::hsSetup()
207 hs_per
= SMALLRAND(7);
209 hs_rinc
= (hs_per
*M_PI
)/(hs_per
*90*4);
213 void KBlobSaver::cbSetup()
216 cb_rinc
= (2.0*M_PI
)/360.0;
218 cb_deviate
= SMALLRAND(height()/20)+(height()/15);
219 cb_radius
= height()/2-cb_deviate
*2-2*dim
;
220 cb_devradinc
= (rnd
->getDouble()*10.0*2.0*M_PI
)/360.0;
223 void KBlobSaver::pcSetup()
227 pc_inc
= (2.0*M_PI
)/720.0;
229 pc_div
= SMALLRAND(4)-1;
232 // render next frame ( or change algorithms )
233 void KBlobSaver::slotTimeout()
235 time_t now
= time(NULL
);
237 // should algorithm be changed
238 if (now
-start
> showlen
)
246 alg
= SMALLRAND(ALG_LAST
)-1;
247 (this->*Algs
[alg
].Init
)();
252 // gen next fram for current algorithm
253 (this->*Algs
[alg
].NextFrame
)();
256 void KBlobSaver::lnNextFrame()
260 // depending on the algorithm to use, move the blob painter to
262 // check for wall hit to change direction
263 if (tx
+dim
+ln_xinc
> (int)width()-1 || tx
+ln_xinc
< 0)
269 ln_xinc
= SMALLRAND(3)*dir
;
271 if (ty
+dim
+ln_yinc
> (int)height()-1 || ty
+ln_yinc
< 0)
277 ln_yinc
= SMALLRAND(2)*dir
;
280 // move box to new position
288 void KBlobSaver::hsNextFrame()
290 static int xlen
= width()-(4*dim
);
291 static int ylen
= height()-(4*dim
);
293 // calc x as offset on angle line and y as vertical offset
294 // on interval -1..1 sine of angle
295 tx
= (int)((hs_radians
/(hs_per
*M_PI
))*(float)xlen
);
296 ty
= (int)((float)(ylen
/4)*(hs_flip
*sin(hs_radians
)))+yhalf
;
302 hs_radians
+= hs_rinc
;
303 if (hs_radians
> hs_per
*M_PI
)
306 hs_radians
+= hs_rinc
;
309 else if (hs_radians
< 0.0)
313 void KBlobSaver::cbNextFrame()
317 // calculate deviation of circle main radius
318 deviate
= (int)(sin(cb_sradians
)*cb_deviate
);
320 // calculate topleft of box as a circle with a sine perturbed radius
321 tx
= (int)(cos(cb_radians
)*(cb_radius
+deviate
))+xhalf
;
322 ty
= (int)(sin(cb_radians
)*(cb_radius
+deviate
))+yhalf
;
327 // increase greater circle render angle
328 cb_radians
+= cb_rinc
;
329 if (cb_radians
> 2.0*M_PI
)
330 cb_radians
-= 2.0*M_PI
;
332 // increase radius deviation offset on sine wave
333 cb_sradians
+= cb_devradinc
;
336 void KBlobSaver::pcNextFrame()
338 static float scale
= (float)height()/3.0 - 4.0*dim
;
340 // simple polar coordinate equation
342 pc_radius
= cos(2.0*pc_angle
);
344 pc_radius
= 1.0/pc_div
+ cos(2.0*pc_angle
);
346 tx
= (int)(scale
*pc_radius
*cos(pc_angle
+pc_crot
))+xhalf
;
347 ty
= (int)(scale
*pc_radius
*sin(pc_angle
+pc_crot
))+yhalf
;
349 // advance blob painter
352 // new movement parameters
354 if (pc_angle
> 2.0*M_PI
)
356 pc_angle
-= 2.0*M_PI
;
357 pc_crot
+= M_PI
/45.0;
361 void KBlobSaver::box ( int x
, int y
)
363 // for bad behaving algorithms that wants to cause an X trap
364 // confine to the valid region before using potentially fatal XGetImage
365 if ((x
+dim
) >= width())
369 if ((y
+dim
) > height())
374 // get the box region from the display to upgrade
375 QImage img
= QPixmap::grabWindow(winId(), x
, y
, dim
, dim
).convertToImage();
377 // depending on the depth of the display, use either lookup table for
378 // next rgb val ( 8-bit ) or ramp the color directly for other displays
379 if ( img
.depth() == 8)
381 // manipulate image by upgrading each pixel with 1 using a lookup
382 // table as the color allocation could have resulted in a spread out
383 // configuration of the color ramp
384 for (int j
= 0; j
< img
.height(); j
++)
386 for (int i
= 0; i
< img
.width(); i
++)
388 img
.scanLine(j
)[i
] = lookup
[img
.scanLine(j
)[i
]];
394 for (int j
= 0; j
< img
.height(); j
++)
396 for (int i
= 0; i
< img
.width(); i
++)
398 QRgb p
= img
.pixel( i
, j
);
400 img
.setPixel( i
, j
, p
);
405 // put the image back onto the screen
407 p
.drawImage( x
, y
, img
);
410 void KBlobSaver::blank()
412 setBackgroundColor( black
);
416 void KBlobSaver::readSettings()
418 KConfig
*config
= KGlobal::config();
419 config
->setGroup("Settings");
421 // number of seconds to spend on a frame
422 showlen
= config
->readNumEntry("Showtime", 3*60);
424 // algorithm to use. if not set then use random
425 alg
= config
->readNumEntry("Algorithm", ALG_RANDOM
);
426 if (alg
== ALG_RANDOM
)
433 //-----------------------------------------------------------------------------
434 // dialog to setup screen saver parameters
436 KBlobSetup::KBlobSetup
441 : KDialogBase( parent
, name
, true, i18n( "Setup Blob Screen Saver" ),
442 Ok
|Cancel
|Help
, Ok
, true )
447 // get saver configuration from kde registry
450 setButtonText( Help
, i18n( "A&bout" ) );
451 QWidget
*main
= makeMainWidget();
453 QHBoxLayout
*tl
= new QHBoxLayout( main
, 0, spacingHint() );
455 QVBoxLayout
*vbox
= new QVBoxLayout
;
458 // seconds to generate on a frame
459 QLabel
*label
= new QLabel(i18n("Frame duration:"), main
);
460 stime
= new KIntNumInput( showtime
, main
);
461 stime
->setSuffix( i18n( " sec" ) );
462 vbox
->addWidget(label
);
463 vbox
->addWidget(stime
);
465 // available algorithms
466 label
= new QLabel(i18n("Algorithm:"), main
);
467 algs
= new Q3ListBox(main
);
468 algs
->setMinimumSize(150, 105);
469 for (int i
= 0; i
<= ALG_RANDOM
; i
++)
470 algs
->insertItem(alg_str
[i
]);
471 algs
->setCurrentItem(alg
);
472 vbox
->addWidget(label
);
473 vbox
->addWidget(algs
);
476 QWidget
*preview
= new QWidget( main
);
477 preview
->setFixedSize(220, 170);
478 preview
->setBackgroundColor(black
);
480 tl
->addWidget(preview
);
481 saver
= new KBlobSaver(preview
->winId());
482 saver
->setDimension(3);
483 if (QPixmap::defaultDepth() > 8)
484 saver
->setColorInc(7);
486 saver
->setColorInc(4);
490 // so selecting an algorithm will start previewing that alg
491 connect(algs
, SIGNAL(highlighted(int)), saver
,
492 SLOT(setAlgorithm(int)));
495 void KBlobSetup::readSettings()
497 KConfig
*config
= KGlobal::config();
498 config
->setGroup("Settings");
500 // number of seconds to spend on a frame
501 showtime
= config
->readNumEntry("Showtime", 3*60);
503 // algorithm to use. if not set then use random
504 alg
= config
->readNumEntry("Algorithm", ALG_LAST
);
507 // Ok pressed - save settings and exit
508 void KBlobSetup::slotOk()
510 KConfig
*config
= KGlobal::config();
512 config
->setGroup("Settings");
514 config
->writeEntry("Showtime", stime
->value());
515 config
->writeEntry("Algorithm", algs
->currentItem());
522 void KBlobSetup::slotHelp()
524 KMessageBox::about(this,
525 i18n("Blobsaver Version 0.1\n\nWritten by Tiaan Wessels 1997\ntiaan@netsys.co.za"));
527 saver
->setAlgorithm(algs
->currentItem());