1 /* Slide Show Screen Saver
2 * (C) 1999 Stefan Taferner <taferner@kde.org>
3 * (C) 2001 Martin R. Jones <mjones@kde.org>
4 * (C) 2003 Chris Howells <howells@kde.org>
5 * (C) 2003 Sven Leiber <s.leiber@web.de>
7 * This code is under GPL
9 * 2001/03/04 Converted to libkscreensaver by Martin R. Jones.
18 #include <q3paintdevicemetrics.h>
19 #include <qcheckbox.h>
20 #include <qcombobox.h>
25 #include <Q3PointArray>
26 #include <QVBoxLayout>
30 #include <kapplication.h>
32 #include <kmessagebox.h>
34 #include <kfiledialog.h>
35 #include <kstandarddirs.h>
36 #include <kurlrequester.h>
37 #include <kaboutdata.h>
38 #include <kaboutapplication.h>
46 #include "slideshow.h"
47 #include "slideshow.moc"
48 #include "slideshowcfg.h"
51 #define SLIDESHOW_VERSION "2.3.0"
52 static const char version
[] = SLIDESHOW_VERSION
;
53 static const char description
[] = I18N_NOOP("KSlideshow");
56 // libkscreensaver interface
59 KDE_EXPORT
const char *kss_applicationName
= "kslideshow.kss";
60 KDE_EXPORT
const char *kss_description
= I18N_NOOP( "KSlideshow" );
61 KDE_EXPORT
const char *kss_version
= SLIDESHOW_VERSION
;
63 KDE_EXPORT KScreenSaver
*kss_create( WId id
)
65 return new kSlideShowSaver( id
);
68 KDE_EXPORT QDialog
*kss_setup()
70 return new kSlideShowSetup();
75 //=============================================================================
76 // Class kSlideShowSaver
77 //=============================================================================
78 kSlideShowSaver::kSlideShowSaver( WId id
): KScreenSaver(id
)
83 srand((unsigned int)t
);
85 KImageIO::registerFormats();
98 mColorContext
= QColor::enterAllocContext();
100 mEffectRunning
= false;
104 mTimer
.start(10, true);
105 connect(&mTimer
, SIGNAL(timeout()), SLOT(slotTimeout()));
109 //----------------------------------------------------------------------------
110 kSlideShowSaver::~kSlideShowSaver()
113 delete [] mEffectList
;
116 if (mPainter
.isActive()) mPainter
.end();
117 QColor::leaveAllocContext();
118 QColor::destroyAllocContext(mColorContext
);
122 //-----------------------------------------------------------------------------
123 void kSlideShowSaver::initNextScreen()
125 Q3PaintDeviceMetrics
metric(this);
130 mNextScreen
= QPixmap(w
, h
, metric
.depth());
134 //-----------------------------------------------------------------------------
135 void kSlideShowSaver::readConfig()
137 KConfig
*config
= KGlobal::config();
138 config
->setGroup("Settings");
139 mShowRandom
= config
->readBoolEntry("ShowRandom", true);
140 mZoomImages
= config
->readBoolEntry("ZoomImages", false);
141 mPrintName
= config
->readBoolEntry("PrintName", true);
142 mDirectory
= config
->readPathEntry("Directory", KGlobal::dirs()->findDirs("wallpaper", "").last());
143 mDelay
= config
->readNumEntry("Delay", 10) * 1000;
144 mSubdirectory
= config
->readBoolEntry("SubDirectory", false);
145 mRandomPosition
= config
->readBoolEntry("RandomPosition", false);
151 //----------------------------------------------------------------------------
152 void kSlideShowSaver::registerEffects()
156 mEffectList
= new EffectMethod
[64];
157 mEffectList
[i
++] = &kSlideShowSaver::effectChessboard
;
158 mEffectList
[i
++] = &kSlideShowSaver::effectMultiCircleOut
;
159 mEffectList
[i
++] = &kSlideShowSaver::effectSpiralIn
;
160 mEffectList
[i
++] = &kSlideShowSaver::effectSweep
;
161 mEffectList
[i
++] = &kSlideShowSaver::effectMeltdown
;
162 mEffectList
[i
++] = &kSlideShowSaver::effectCircleOut
;
163 mEffectList
[i
++] = &kSlideShowSaver::effectBlobs
;
164 mEffectList
[i
++] = &kSlideShowSaver::effectHorizLines
;
165 mEffectList
[i
++] = &kSlideShowSaver::effectVertLines
;
166 mEffectList
[i
++] = &kSlideShowSaver::effectRandom
;
167 mEffectList
[i
++] = &kSlideShowSaver::effectGrowing
;
168 mEffectList
[i
++] = &kSlideShowSaver::effectIncomingEdges
;
171 // mNumEffects = 1; //...for testing
175 //----------------------------------------------------------------------------
176 int kSlideShowSaver::effectMultiCircleOut(bool aInit
)
180 static Q3PointArray
pa(4);
189 pa
.setPoint(0, mw
>>1, mh
>>1);
190 pa
.setPoint(3, mw
>>1, mh
>>1);
191 mfy
= sqrt((double)mw
*mw
+ mh
*mh
) / 2;
196 mfx
= M_PI
/32; // divisor must be powers of 8
206 for (alpha
=mAlpha
, i
=mi
; i
>=0; i
--, alpha
+=mfd
)
208 x
= (mw
>>1) + (int)(mfy
* cos(-alpha
));
209 y
= (mh
>>1) + (int)(mfy
* sin(-alpha
));
211 mx
= (mw
>>1) + (int)(mfy
* cos(-alpha
+ mfx
));
212 my
= (mh
>>1) + (int)(mfy
* sin(-alpha
+ mfx
));
214 pa
.setPoint(1, x
, y
);
215 pa
.setPoint(2, mx
, my
);
217 mPainter
.drawPolygon(pa
);
225 //----------------------------------------------------------------------------
226 int kSlideShowSaver::effectSpiralIn(bool aInit
)
247 if (mi
==0 && mx0
>=mx1
)
254 if (mi
==0 && mx
>=mx1
) // switch to: down on right side
261 else if (mi
==1 && my
>=my1
) // switch to: right to left on bottom side
268 else if (mi
==2 && mx
<=mx0
) // switch to: up on left side
275 else if (mi
==3 && my
<=my0
) // switch to: left to right on top side
283 bitBlt(this, mx
, my
, &mNextScreen
, mx
, my
, mix
, miy
, CopyROP
, true);
293 //----------------------------------------------------------------------------
294 int kSlideShowSaver::effectMeltdown(bool aInit
)
307 mIntArray
= new int[mix
];
308 for (i
=mix
-1; i
>=0; i
--)
313 for (i
=0,x
=0; i
<mix
; i
++,x
+=mdx
)
316 if (y
>= mh
) continue;
318 if ((rand()&15) < 6) continue;
319 bitBlt(this, x
, y
+mdy
, this, x
, y
, mdx
, mh
-y
-mdy
, CopyROP
, true);
320 bitBlt(this, x
, y
, &mNextScreen
, x
, y
, mdx
, mdy
, CopyROP
, true);
335 //----------------------------------------------------------------------------
336 int kSlideShowSaver::effectCircleOut(bool aInit
)
339 static Q3PointArray
pa(4);
349 pa
.setPoint(0, mw
>>1, mh
>>1);
350 pa
.setPoint(3, mw
>>1, mh
>>1);
351 mfx
= M_PI
/16; // divisor must be powers of 8
352 mfy
= sqrt((double)mw
*mw
+ mh
*mh
) / 2;
364 mx
= (mw
>>1) + (int)(mfy
* cos(mAlpha
));
365 my
= (mh
>>1) + (int)(mfy
* sin(mAlpha
));
368 pa
.setPoint(1, x
, y
);
369 pa
.setPoint(2, mx
, my
);
371 mPainter
.drawPolygon(pa
);
377 //----------------------------------------------------------------------------
378 int kSlideShowSaver::effectSweep(bool aInit
)
384 // subtype: 0=sweep right to left, 1=sweep left to right
385 // 2=sweep bottom to top, 3=sweep top to bottom
386 mSubType
= rand() % 4;
389 mdx
= (mSubType
==1 ? 16 : -16);
390 mdy
= (mSubType
==3 ? 16 : -16);
391 mx
= (mSubType
==1 ? 0 : mw
);
392 my
= (mSubType
==3 ? 0 : mh
);
395 if (mSubType
==0 || mSubType
==1)
398 if ((mSubType
==0 && mx
< -64) ||
399 (mSubType
==1 && mx
> mw
+64))
403 for (w
=2,i
=4,x
=mx
; i
>0; i
--, w
<<=1, x
-=mdx
)
405 bitBlt(this, x
, 0, &mNextScreen
, x
, 0, w
, mh
, CopyROP
, true);
412 if ((mSubType
==2 && my
< -64) ||
413 (mSubType
==3 && my
> mh
+64))
417 for (h
=2,i
=4,y
=my
; i
>0; i
--, h
<<=1, y
-=mdy
)
419 bitBlt(this, 0, y
, &mNextScreen
, 0, y
, mw
, h
, CopyROP
, true);
428 //----------------------------------------------------------------------------
429 int kSlideShowSaver::effectBlobs(bool aInit
)
451 r
= (rand() % 200) + 50;
453 mPainter
.drawEllipse(mx
-r
, my
-r
, r
, r
);
460 //----------------------------------------------------------------------------
461 int kSlideShowSaver::effectRandom(bool /*aInit*/)
463 int x
, y
, i
, w
, h
, fact
, sz
;
465 fact
= (rand() % 3) + 1;
468 h
= height() >> fact
;
471 for (i
= (w
*h
)<<1; i
> 0; i
--)
473 x
= (rand() % w
) << fact
;
474 y
= (rand() % h
) << fact
;
475 bitBlt(this, x
, y
, &mNextScreen
, x
, y
, sz
, sz
, CopyROP
, true);
483 //----------------------------------------------------------------------------
484 int kSlideShowSaver::effectGrowing(bool aInit
)
497 mx
= (mw
>>1) - (int)(mi
* mfx
);
498 my
= (mh
>>1) - (int)(mi
* mfy
);
507 bitBlt(this, mx
, my
, &mNextScreen
, mx
, my
,
508 mw
- (mx
<<1), mh
- (my
<<1), CopyROP
, true);
514 //----------------------------------------------------------------------------
515 int kSlideShowSaver::effectChessboard(bool aInit
)
523 mdx
= 8; // width of one tile
524 mdy
= 8; // height of one tile
525 mj
= (mw
+mdx
-1)/mdx
; // number of tiles
526 mx
= mj
*mdx
; // shrinking x-offset from screen border
527 mix
= 0; // growing x-offset from screen border
528 miy
= 0; // 0 or mdy for growing tiling effect
529 my
= mj
&1 ? 0 : mdy
; // 0 or mdy for shrinking tiling effect
530 mwait
= 800 / mj
; // timeout between effects
544 for (y
=0; y
<mw
; y
+=(mdy
<<1))
546 bitBlt(this, mix
, y
+miy
, &mNextScreen
, mix
, y
+miy
,
547 mdx
, mdy
, CopyROP
, true);
548 bitBlt(this, mx
, y
+my
, &mNextScreen
, mx
, y
+my
,
549 mdx
, mdy
, CopyROP
, true);
556 //----------------------------------------------------------------------------
557 int kSlideShowSaver::effectIncomingEdges(bool aInit
)
570 mSubType
= rand() & 1;
573 mx
= (int)(mfx
* mi
);
574 my
= (int)(mfy
* mi
);
576 if (mx
>mix
|| my
>miy
)
588 // moving image edges
589 bitBlt(this, 0, 0, &mNextScreen
, mix
-mx
, miy
-my
, mx
, my
, CopyROP
, true);
590 bitBlt(this, x1
, 0, &mNextScreen
, mix
, miy
-my
, mx
, my
, CopyROP
, true);
591 bitBlt(this, 0, y1
, &mNextScreen
, mix
-mx
, miy
, mx
, my
, CopyROP
, true);
592 bitBlt(this, x1
, y1
, &mNextScreen
, mix
, miy
, mx
, my
, CopyROP
, true);
597 bitBlt(this, 0, 0, &mNextScreen
, 0, 0, mx
, my
, CopyROP
, true);
598 bitBlt(this, x1
, 0, &mNextScreen
, x1
, 0, mx
, my
, CopyROP
, true);
599 bitBlt(this, 0, y1
, &mNextScreen
, 0, y1
, mx
, my
, CopyROP
, true);
600 bitBlt(this, x1
, y1
, &mNextScreen
, x1
, y1
, mx
, my
, CopyROP
, true);
606 //----------------------------------------------------------------------------
607 int kSlideShowSaver::effectHorizLines(bool aInit
)
609 static int iyPos
[] = { 0, 4, 2, 6, 1, 5, 3, 7, -1 };
619 if (iyPos
[mi
] < 0) return -1;
621 for (y
=iyPos
[mi
]; y
<mh
; y
+=8)
623 bitBlt(this, 0, y
, &mNextScreen
, 0, y
, mw
, 1, CopyROP
, true);
627 if (iyPos
[mi
] >= 0) return 160;
632 //----------------------------------------------------------------------------
633 int kSlideShowSaver::effectVertLines(bool aInit
)
635 static int ixPos
[] = { 0, 4, 2, 6, 1, 5, 3, 7, -1 };
645 if (ixPos
[mi
] < 0) return -1;
647 for (x
=ixPos
[mi
]; x
<mw
; x
+=8)
649 bitBlt(this, x
, 0, &mNextScreen
, x
, 0, 1, mh
, CopyROP
, true);
653 if (ixPos
[mi
] >= 0) return 160;
658 //-----------------------------------------------------------------------------
659 void kSlideShowSaver::startPainter(Qt::PenStyle aPen
)
662 brush
.setPixmap(mNextScreen
);
663 if (mPainter
.isActive()) mPainter
.end();
664 mPainter
.begin(this);
665 mPainter
.setBrush(brush
);
666 mPainter
.setPen(aPen
);
670 //-----------------------------------------------------------------------------
671 void kSlideShowSaver::restart()
673 mEffectRunning
= false;
680 //-----------------------------------------------------------------------------
681 void kSlideShowSaver::slotTimeout()
688 tmout
= (this->*mEffect
)(false);
695 if (mNumEffects
> 1) i
= rand() % mNumEffects
;
698 mEffect
= mEffectList
[i
];
699 mEffectRunning
= true;
700 tmout
= (this->*mEffect
)(true);
705 mEffectRunning
= false;
707 mTimer
.start(tmout
, true);
711 //----------------------------------------------------------------------------
712 void kSlideShowSaver::showNextScreen()
714 bitBlt(this, 0, 0, &mNextScreen
, 0, 0,
715 mNextScreen
.width(), mNextScreen
.height(), CopyROP
, true);
719 //----------------------------------------------------------------------------
720 void kSlideShowSaver::createNextScreen()
723 int ww
, wh
, iw
, ih
, x
, y
;
726 if (mNextScreen
.size() != size())
727 mNextScreen
.resize(size());
729 mNextScreen
.fill(black
);
731 ww
= mNextScreen
.width();
732 wh
= mNextScreen
.height();
734 ih
= mImage
.height();
736 p
.begin(&mNextScreen
);
738 if (mFileList
.isEmpty())
740 p
.setPen(QColor("white"));
741 p
.drawText(20 + (rand() % (ww
>>1)), 20 + (rand() % (wh
>>1)),
742 i18n("No images found"));
748 fx
= (double)ww
/ iw
;
749 fy
= (double)wh
/ ih
;
750 if (fx
> fy
) fx
= fy
;
754 QImage scaledImg
= mImage
.smoothScale(iw
, ih
);
759 p
.drawImage(x
, y
, scaledImg
);
763 if(iw
> ww
|| ih
> wh
)
765 fx
= (double)ww
/ iw
;
766 fy
= (double)wh
/ ih
;
767 if (fx
> fy
) fx
= fy
;
771 QImage scaledImg
= mImage
.smoothScale(iw
, ih
);
776 p
.drawImage(x
, y
, scaledImg
);
782 x
= rand() % (ww
- iw
);
783 y
= rand() % (wh
- ih
);
791 // bitBlt(&mNextScreen, x, y, &mImage, 0, 0, iw, ih, CopyROP, false);
792 p
.drawImage(x
, y
, mImage
);
798 p
.setPen(QColor("black"));
799 for (x
=9; x
<=11; x
++)
800 for (y
=21; y
>=19; y
--)
801 p
.drawText(x
, wh
-y
, mImageName
);
802 p
.setPen(QColor("white"));
803 p
.drawText(10, wh
-20, mImageName
);
811 //----------------------------------------------------------------------------
812 void kSlideShowSaver::loadNextImage()
817 num
= mFileList
.count();
818 if (num
<= 0) //no files in the directory
825 mFileIdx
= rand() % num
;
826 fname
= mFileList
[mFileIdx
];
827 mFileList
.remove(fname
);
828 if (num
== 1) //we're about to run out of images
830 mFileList
= mRandomList
;
835 if (mFileIdx
>= num
) mFileIdx
= 0;
836 fname
= mFileList
[mFileIdx
];
839 if (!mImage
.load(fname
))
841 kdDebug() << "Failed to load image " << fname
<< endl
;
842 mFileList
.remove(fname
);
843 mRandomList
.remove(fname
);
844 if (!mFileList
.isEmpty())
851 i
= fname
.findRev('.');
852 if (i
< 0) i
= 32767;
853 j
= fname
.findRev('/') + 1;
855 mImageName
= fname
.mid(j
, i
-j
);
859 //----------------------------------------------------------------------------
860 void kSlideShowSaver::loadDirectory()
864 traverseDirectory(mDirectory
);
865 mRandomList
= mFileList
;
868 void kSlideShowSaver::traverseDirectory(const QString
&dirName
)
875 dir
.setFilter(QDir::Dirs
| QDir::Files
);
877 const QFileInfoList
*fileinfolist
= dir
.entryInfoList();
878 QFileInfoListIterator
it(*fileinfolist
);
880 while ((fi
= it
.current()))
882 if (fi
->fileName() == "." || fi
->fileName() == "..")
887 if (fi
->isDir() && fi
->isReadable() && mSubdirectory
)
889 traverseDirectory(fi
->filePath());
895 mFileList
.append(fi
->filePath().data());
903 //-----------------------------------------------------------------------------
904 void kSlideShowSaver::blank()
910 //=============================================================================
911 // Class kSlideShowSetup
912 //=============================================================================
913 kSlideShowSetup::kSlideShowSetup(QWidget
*aParent
, const char *aName
)
914 : KDialogBase(aParent
, aName
, true, i18n( "Setup Slide Show Screen Saver" ),
915 Ok
|Cancel
|Help
, Ok
, true )
917 setButtonText( Help
, i18n( "A&bout" ) );
919 QWidget
*main
= makeMainWidget();
920 QVBoxLayout
*top
= new QVBoxLayout( main
, 0, spacingHint() );
922 cfg
= new SlideShowCfg( main
, "SlideShowCfg" );
923 top
->addWidget( cfg
);
926 cfg
->mPreview
->setFixedSize(220, 170);
927 cfg
->mPreview
->setBackgroundColor(Qt::black
);
928 cfg
->mPreview
->show(); // otherwise saver does not get correct size
929 mSaver
= new kSlideShowSaver(cfg
->mPreview
->winId());
931 cfg
->mDirChooser
->setMode(KFile::Directory
| KFile::ExistingOnly
);
932 connect(cfg
->mDirChooser
, SIGNAL(returnPressed(const QString
&)),
933 SLOT(slotDirSelected(const QString
&)));
934 connect(cfg
->mDirChooser
, SIGNAL(urlSelected(const QString
&)),
935 SLOT(slotDirSelected(const QString
&)));
940 kSlideShowSetup::~kSlideShowSetup()
945 //-----------------------------------------------------------------------------
946 void kSlideShowSetup::readSettings()
948 KConfig
*config
= KGlobal::config();
950 config
->setGroup("Settings");
951 cfg
->mCbxRandom
->setChecked(config
->readBoolEntry("ShowRandom", true));
952 cfg
->mCbxZoom
->setChecked(config
->readBoolEntry("ZoomImages", false));
953 cfg
->mCbxShowName
->setChecked(config
->readBoolEntry("PrintName", true));
954 cfg
->mDelay
->setValue(config
->readNumEntry("Delay", 20));
955 cfg
->mDirChooser
->setURL(config
->readPathEntry("Directory"));
956 cfg
->mCbxSubdirectory
->setChecked(config
->readBoolEntry("SubDirectory", false));
957 cfg
->mCbxRandomPosition
->setChecked(config
->readBoolEntry("RandomPosition", false));
961 //-----------------------------------------------------------------------------
962 void kSlideShowSetup::writeSettings()
964 KConfig
*config
= KGlobal::config();
966 config
->setGroup("Settings");
967 config
->writeEntry("ShowRandom", cfg
->mCbxRandom
->isChecked());
968 config
->writeEntry("ZoomImages", cfg
->mCbxZoom
->isChecked());
969 config
->writeEntry("PrintName", cfg
->mCbxShowName
->isChecked());
970 config
->writeEntry("Delay", cfg
->mDelay
->value());
971 config
->writePathEntry("Directory", cfg
->mDirChooser
->url());
972 config
->writeEntry("SubDirectory", cfg
->mCbxSubdirectory
->isChecked());
973 config
->writeEntry("RandomPosition", cfg
->mCbxRandomPosition
->isChecked());
979 mSaver
->readConfig();
985 //-----------------------------------------------------------------------------
986 void kSlideShowSetup::slotDirSelected(const QString
&)
992 //-----------------------------------------------------------------------------
993 void kSlideShowSetup::slotOk()
1000 //-----------------------------------------------------------------------------
1001 void kSlideShowSetup::slotHelp()
1003 KAboutData
aboutData( "kslideshow.kss", I18N_NOOP("SlideShow"),
1004 version
, description
, KAboutData::License_GPL
,
1005 "(c) 1999-2003, The KDE Team" );
1006 aboutData
.addAuthor("Stefan Taferner", 0, "taferner@kde.org");
1007 aboutData
.addAuthor("Chris Howells", 0, "howells@kde.org");
1008 aboutData
.addAuthor("Sven Leiber", 0, "s.leiber@web.de");
1010 KAboutApplication
mAbout(&aboutData
, this, 0);