aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/core/lumina-desktop/src-screensaver
diff options
context:
space:
mode:
authorKen Moore <moorekou@gmail.com>2020-04-24 17:53:28 -0400
committerKen Moore <moorekou@gmail.com>2020-04-24 17:55:02 -0400
commitbf545b933bcb59a695702ecfcc7b1fa5f07fa557 (patch)
tree1030e63496788315e279b3c50f59ded8e370afb8 /src-qt5/core/lumina-desktop/src-screensaver
parentDisable xscreensaver from auto-start. (diff)
downloadlumina-bf545b933bcb59a695702ecfcc7b1fa5f07fa557.tar.gz
lumina-bf545b933bcb59a695702ecfcc7b1fa5f07fa557.tar.bz2
lumina-bf545b933bcb59a695702ecfcc7b1fa5f07fa557.zip
Initial merge of the screensaver into the main lumina-desktop builds
Diffstat (limited to 'src-qt5/core/lumina-desktop/src-screensaver')
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.cpp109
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.h42
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.ui144
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/LScreenSaver.cpp214
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/LScreenSaver.h62
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/SSBaseWidget.cpp64
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/SSBaseWidget.h50
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/animations/BaseAnimGroup.cpp51
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/animations/BaseAnimGroup.h40
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/animations/Fireflies.h122
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/animations/Grav.h195
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/animations/ImageSlideshow.h165
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/animations/SampleAnimation.h45
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/animations/Text.h100
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/animations/VideoSlideshow.h85
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/animations/animations.pri10
-rw-r--r--src-qt5/core/lumina-desktop/src-screensaver/screensaver.pri15
17 files changed, 1513 insertions, 0 deletions
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.cpp b/src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.cpp
new file mode 100644
index 00000000..2cfd0f4a
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.cpp
@@ -0,0 +1,109 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LLockScreen.h"
+#include "ui_LLockScreen.h"
+
+#include <unistd.h>
+
+#define NUMTRIES 3
+#define DEBUG 1
+
+LLockScreen::LLockScreen(QWidget *parent) : QWidget(parent), ui(new Ui::LLockScreen()){
+ ui->setupUi(this);
+ waittime = new QTimer(this);
+ waittime->setSingleShot(true);
+ refreshtime = new QTimer(this); //timer to update the wait time display
+ refreshtime->setInterval(6000); //6 seconds (1/10 second)
+
+ connect(ui->tool_unlock, SIGNAL(clicked()), this, SLOT(TryUnlock()) );
+ connect(ui->line_password, SIGNAL(returnPressed()), this, SLOT(TryUnlock()) );
+ connect(ui->line_password, SIGNAL(textEdited(QString)), this, SIGNAL(InputDetected()) );
+ connect(ui->line_password, SIGNAL(cursorPositionChanged(int,int)), this, SIGNAL(InputDetected()) );
+ connect(waittime, SIGNAL(timeout()), this, SLOT(aboutToShow()) );
+ connect(refreshtime, SIGNAL(timeout()), this, SLOT(UpdateLockInfo()) );
+}
+
+LLockScreen::~LLockScreen(){
+
+}
+
+void LLockScreen::LoadSystemDetails(){
+ //Run every time the screen is initially locked
+ QString user = QString(getlogin());
+ ui->label_username->setText( QString(tr("Locked by: %1")).arg(user) );
+ ui->label_hostname->setText( QHostInfo::localHostName() );
+ ui->tool_unlock->setIcon( LXDG::findIcon("document-decrypt","") );
+ attempts = 0;
+}
+
+void LLockScreen::aboutToHide(){
+ //auto-hide timeout - clear display
+ ui->line_password->clear();
+ ui->line_password->clearFocus();
+ if(refreshtime->isActive()){ refreshtime->stop(); }
+}
+
+void LLockScreen::aboutToShow(){
+ if(!waittime->isActive()){
+ ui->label_info->clear();
+ this->setEnabled(true);
+ triesleft = NUMTRIES; //back to initial number of tries
+ if(refreshtime->isActive()){ refreshtime->stop(); }
+ }else{
+ if(!refreshtime->isActive()){ refreshtime->start(); }
+ }
+ UpdateLockInfo();
+ ui->line_password->clear();
+ ui->line_password->setFocus();
+}
+
+// =================
+// PRIVATE SLOTS
+// =================
+void LLockScreen::UpdateLockInfo(){
+ QString info;
+ if(waittime->isActive()){
+ info = tr("Too Many Failures")+"\n"+ QString(tr("Wait %1 Minutes")).arg( QString::number(qRound(waittime->remainingTime()/6000.0)/10.0) );
+ }else if(attempts>0){ info.append("\n"+QString(tr("Failed Attempts: %1")).arg(QString::number(attempts)) ); }
+ ui->label_info->setText(info);
+}
+
+void LLockScreen::TryUnlock(){
+ attempts++;
+ this->setEnabled(false);
+ QString pass = ui->line_password->text();
+ ui->line_password->clear();
+ //Create a temporary file for the password, then pass that file descriptor to lumina-checkpass
+ QTemporaryFile *TF = new QTemporaryFile(".XXXXXXXXXX");
+ TF->setAutoRemove(true);
+ bool ok = false;
+ if( TF->open() ){
+ QTextStream in(TF);
+ in << pass.toUtf8()+"\0"; //make sure it is null-terminated
+ TF->close();
+ //qDebug() << "Trying to unlock session:" << TF->fileName() << LUtils::readFile(TF->fileName());
+ //qDebug() << "UserName:" << getlogin();
+ LUtils::runCommand(ok, "lumina-checkpass",QStringList() << "-f" << TF->fileName() );
+ }
+ delete TF; //ensure the temporary file is removed **right now** for security purposes
+ if(ok){
+ emit ScreenUnlocked();
+ this->setEnabled(true);
+ }else{
+ triesleft--;
+ if(triesleft>0){
+ this->setEnabled(true);
+ }else{
+ waittime->setInterval( (attempts/NUMTRIES)*60000);
+ waittime->start();
+ refreshtime->start();
+ }
+ ui->line_password->setFocus();
+ }
+ UpdateLockInfo();
+
+}
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.h b/src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.h
new file mode 100644
index 00000000..79892714
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.h
@@ -0,0 +1,42 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_LOCK_SCREEN_WIDGET_H
+#define _LUMINA_DESKTOP_LOCK_SCREEN_WIDGET_H
+
+#include "global-includes.h"
+
+namespace Ui{
+ class LLockScreen;
+};
+
+class LLockScreen : public QWidget{
+ Q_OBJECT
+public:
+ LLockScreen(QWidget *parent = 0);
+ ~LLockScreen();
+
+ void LoadSystemDetails(); //Run right after the screen is initially locked
+
+public slots:
+ void aboutToHide(); //auto-hide timeout (can happen multiple times per lock)
+ void aboutToShow(); //about to be re-shown (can happen multiple times per lock)
+
+private:
+ Ui::LLockScreen *ui;
+ int triesleft, attempts;
+ QTimer *waittime;
+ QTimer *refreshtime;
+
+private slots:
+ void UpdateLockInfo();
+ void TryUnlock();
+
+signals:
+ void ScreenUnlocked();
+ void InputDetected();
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.ui b/src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.ui
new file mode 100644
index 00000000..7f0b45b8
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/LLockScreen.ui
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LLockScreen</class>
+ <widget class="QWidget" name="LLockScreen">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>289</width>
+ <height>188</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QFrame" name="frame_unlock">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label_hostname">
+ <property name="font">
+ <font>
+ <weight>50</weight>
+ <italic>true</italic>
+ <bold>false</bold>
+ <underline>true</underline>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">hostname</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_username">
+ <property name="text">
+ <string notr="true">Locked by username</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_info">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QLineEdit" name="line_password">
+ <property name="inputMask">
+ <string notr="true"/>
+ </property>
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="placeholderText">
+ <string>Password</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QToolButton" name="tool_unlock">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="text">
+ <string>Unlock Session</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/LScreenSaver.cpp b/src-qt5/core/lumina-desktop/src-screensaver/LScreenSaver.cpp
new file mode 100644
index 00000000..9b8aa649
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/LScreenSaver.cpp
@@ -0,0 +1,214 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LScreenSaver.h"
+#include <QScreen>
+#include <QApplication>
+
+#define DEBUG 0
+
+LScreenSaver::LScreenSaver() : QWidget(0,Qt::BypassWindowManagerHint | Qt::WindowStaysOnTopHint){
+ starttimer = new QTimer(this);
+ starttimer->setSingleShot(true);
+ locktimer = new QTimer(this);
+ locktimer->setSingleShot(true);
+ hidetimer = new QTimer(this);
+ hidetimer->setSingleShot(true);
+ checkTimer = new QTimer(this);
+ checkTimer->setInterval(1500); //1.5 seconds
+
+ lastTimeCode = 0;
+
+ LOCKER = new LLockScreen(this);
+ LOCKER->hide();
+ SSRunning = SSLocked = updating = false;
+ this->setObjectName("LSCREENSAVERBASE");
+ this->setStyleSheet("LScreenSaver#LSCREENSAVERBASE{ background: grey; }");
+ this->setMouseTracking(true);
+ connect(starttimer, SIGNAL(timeout()), this, SLOT(ShowScreenSaver()) );
+ connect(locktimer, SIGNAL(timeout()), this, SLOT(LockScreen()) );
+ connect(hidetimer, SIGNAL(timeout()), this, SLOT(HideLockScreen()) );
+ connect(checkTimer, SIGNAL(timeout()), this, SLOT(checkInputEvents()) );
+ connect(LOCKER, SIGNAL(ScreenUnlocked()), this, SLOT(SSFinished()) );
+ connect(LOCKER, SIGNAL(InputDetected()), this, SLOT(newInputEvent()) );
+}
+
+LScreenSaver::~LScreenSaver(){
+
+}
+
+bool LScreenSaver::isLocked(){
+ return SSLocked;
+}
+
+void LScreenSaver::UpdateTimers(){
+ //This is generally used for programmatic changes
+ if(starttimer->isActive()){ starttimer->stop();}
+ if(locktimer->isActive()){ locktimer->stop(); }
+ if(hidetimer->isActive()){ hidetimer->stop(); }
+
+ if(!SSRunning && !SSLocked && (starttimer->interval() > 1000) ){ starttimer->start(); } //time to SS start
+ else if( SSRunning && !SSLocked && (locktimer->interval() > 1000 ) ){ locktimer->start(); } //time to lock
+ else if( !SSRunning && SSLocked ){ hidetimer->start(); } //time to hide lock screen
+}
+
+// ===========
+// PUBLIC SLOTS
+// ===========
+void LScreenSaver::start(){
+ reloadSettings(); //setup all the initial time frames
+ starttimer->start();
+ checkTimer->start();
+}
+
+void LScreenSaver::reloadSettings(){
+ starttimer->setInterval( DesktopSettings::instance()->value(DesktopSettings::ScreenSaver, "timedelaymin",10).toInt() * 60000 );
+ locktimer->setInterval( DesktopSettings::instance()->value(DesktopSettings::ScreenSaver, "lockdelaymin",1).toInt() * 60000 );
+ hidetimer->setInterval( DesktopSettings::instance()->value(DesktopSettings::ScreenSaver, "hidesecs",15).toInt() * 1000 );
+}
+
+void LScreenSaver::newInputEvent(){
+ if(updating){ return; } //in the middle of making changes which could cause an event
+ if(DEBUG){ qDebug() << "New Input Event"; }
+ if(SSRunning && SSLocked){
+ //Running and locked
+ // Hide the running setting, and display the lock screen
+ HideScreenSaver();
+ ShowLockScreen();
+ }else if(SSRunning){
+ //Only running, not locked
+ HideScreenSaver();
+ }
+ UpdateTimers();
+}
+
+void LScreenSaver::LockScreenNow(){
+ ShowScreenSaver();
+ LockScreen();
+}
+
+// ===========
+// PRIVATE SLOTS
+// ===========
+void LScreenSaver::checkInputEvents(){
+ //Check mouse position first
+ QPoint pos = QCursor::pos();
+ bool change = false;
+ if(pos != lastMousePos){
+ lastMousePos = QCursor::pos(); //update the internal point
+ change = true;
+ }
+ //Check the last keyboard input timestamp
+ //unsigned int timecode = WM_Get_User_Time( WM_Get_Active_Window() );
+ unsigned int timecode = 0; //Not done yet - read the _NET_WM_USER_TIME number on the active window
+ if(timecode > lastTimeCode){
+ lastTimeCode = timecode;
+ change = true;
+ }
+ //If there was an input event detected, update timers and such
+ if(change){ newInputEvent(); }
+}
+
+void LScreenSaver::ShowScreenSaver(){
+ if(DEBUG){ qDebug() << "Showing Screen Saver:" << QDateTime::currentDateTime().toString(); }
+ //QApplication::setOverrideCursor(QCursor::BlankCursor);
+ SSRunning = true;
+ updating = true;
+ //Now remove any current Base widgets (prevent any lingering painting between sessions)
+ for(int i=0; i<BASES.length(); i++){
+ if(DEBUG){ qDebug() << " - Removing SS Base"; }
+ delete BASES.takeAt(i); i--;
+ }
+ //Now go through and create/show all the various widgets
+ QList<QScreen*> SCREENS = QApplication::screens();
+ QRect bounds;
+ //cBright = LOS::ScreenBrightness();
+ //if(cBright>0){ LOS::setScreenBrightness(cBright/2); } //cut to half while the screensaver is active
+ for(int i=0; i<SCREENS.length(); i++){
+ bounds = bounds.united(SCREENS[i]->geometry());
+ if(DEBUG){ qDebug() << " - New SS Base:" << i; }
+ BASES << new SSBaseWidget(this);
+ connect(BASES[i], SIGNAL(InputDetected()), this, SLOT(newInputEvent()) );
+
+ //Setup the geometry of the base to match the screen
+ BASES[i]->setGeometry(SCREENS[i]->geometry()); //match this screen geometry
+ QString plug = DesktopSettings::instance()->value(DesktopSettings::ScreenSaver, "plugin_"+SCREENS[i]->name(), "").toString();
+ if(plug.isEmpty()){ plug = DesktopSettings::instance()->value(DesktopSettings::ScreenSaver, "default_plugin","random").toString(); }
+ BASES[i]->setPlugin(plug);
+ }
+ //Now set the overall parent widget geometry and show everything
+ this->setGeometry(bounds); //overall background widget
+ if(!this->isActiveWindow()){
+ this->raise();
+ this->show();
+ this->activateWindow();
+ }
+ for(int i=0; i<BASES.length(); i++){
+ BASES[i]->show();
+ BASES[i]->startPainting();
+ }
+ updating = false;
+ UpdateTimers();
+}
+
+void LScreenSaver::ShowLockScreen(){
+ if(DEBUG){ qDebug() << "Showing Lock Screen:" << QDateTime::currentDateTime().toString(); }
+ LOCKER->aboutToShow();
+ //Move the screen locker to the appropriate spot
+ QPoint ctr = QApplication::screenAt(QCursor::pos())->geometry().center();
+ LOCKER->resize(LOCKER->sizeHint());
+ LOCKER->move(ctr - QPoint(LOCKER->width()/2, LOCKER->height()/2) );
+ LOCKER->show();
+ //Start the timer for hiding the lock screen due to inactivity
+ UpdateTimers();
+}
+
+void LScreenSaver::HideScreenSaver(){
+ //QApplication::restoreOverrideCursor();
+ if(DEBUG){ qDebug() << "Hiding Screen Saver:" << QDateTime::currentDateTime().toString(); }
+ SSRunning = false;
+ //if(cBright>0){ LOS::setScreenBrightness(cBright); } //return to current brightness
+ if(!SSLocked){
+ this->hide();
+ emit ClosingScreenSaver();
+ emit LockStatusChanged(false);
+ }
+ if(DEBUG){ qDebug() << "Stop ScreenSavers"; }
+ for(int i=0; i<BASES.length(); i++){
+ BASES[i]->stopPainting();
+ BASES[i]->hide();
+ BASES.takeAt(i)->deleteLater();
+ i--;
+ }
+ UpdateTimers();
+}
+
+void LScreenSaver::HideLockScreen(){
+ if(DEBUG){ qDebug() << "Hiding Lock Screen:" << QDateTime::currentDateTime().toString(); }
+ //Leave the Locked flag set (still locked, just not visible)
+ LOCKER->aboutToHide();
+ LOCKER->hide();
+ this->repaint();
+ if(SSLocked){ ShowScreenSaver(); }
+ UpdateTimers();
+}
+
+void LScreenSaver::LockScreen(){
+ if(SSLocked){ return; }
+ if(DEBUG){ qDebug() << "Locking Screen:" << QDateTime::currentDateTime().toString(); }
+ SSLocked = true;
+ emit LockStatusChanged(true);
+ LOCKER->LoadSystemDetails();
+ UpdateTimers();
+}
+
+void LScreenSaver::SSFinished(){
+ if(DEBUG){ qDebug() << "Screensaver Finished:" << QDateTime::currentDateTime().toString(); }
+ SSLocked = false;
+ emit LockStatusChanged(false);
+ HideLockScreen();
+ HideScreenSaver();
+}
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/LScreenSaver.h b/src-qt5/core/lumina-desktop/src-screensaver/LScreenSaver.h
new file mode 100644
index 00000000..571eea18
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/LScreenSaver.h
@@ -0,0 +1,62 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_SCREEN_SAVER_H
+#define _LUMINA_DESKTOP_SCREEN_SAVER_H
+
+#include "global-includes.h"
+
+#include "SSBaseWidget.h"
+#include "LLockScreen.h"
+
+class LScreenSaver : public QWidget{
+ Q_OBJECT
+public:
+ LScreenSaver();
+ ~LScreenSaver();
+
+ bool isLocked();
+
+private:
+ QTimer *starttimer, *locktimer, *hidetimer, *checkTimer;
+ QList<SSBaseWidget*> BASES;
+ LLockScreen *LOCKER;
+ QPoint lastMousePos;
+ unsigned int lastTimeCode;
+ int cBright;
+ bool SSRunning, SSLocked, updating;
+
+ void UpdateTimers();
+
+public slots:
+ void start();
+ void reloadSettings();
+ void newInputEvent();
+ void LockScreenNow();
+
+private slots:
+ void checkInputEvents();
+ void ShowScreenSaver();
+ void ShowLockScreen();
+ void HideScreenSaver();
+ void HideLockScreen();
+
+ void LockScreen();
+ void SSFinished();
+
+signals:
+ void StartingScreenSaver();
+ void ClosingScreenSaver();
+ void LockStatusChanged(bool locked);
+
+protected:
+ void mouseMoveEvent(QMouseEvent*){
+ QTimer::singleShot(0,this, SLOT(newInputEvent()));
+ }
+
+};
+
+#endif
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/SSBaseWidget.cpp b/src-qt5/core/lumina-desktop/src-screensaver/SSBaseWidget.cpp
new file mode 100644
index 00000000..aa3214a2
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/SSBaseWidget.cpp
@@ -0,0 +1,64 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+
+#include "SSBaseWidget.h"
+
+//Relative directory to search along the XDG paths for screensavers
+#define REL_DIR QString("/lumina-desktop/screensavers")
+
+#define DEBUG 0
+
+// ========
+// PUBLIC
+// ========
+SSBaseWidget::SSBaseWidget(QWidget *parent) : QQuickView(parent->windowHandle()){
+ this->setObjectName("LuminaBaseSSWidget");
+ this->setResizeMode(QQuickView::SizeRootObjectToView);
+ this->setColor(QColor("black")); //default color for the view
+ this->setCursor(Qt::BlankCursor);
+ plugType="none";
+ restartTimer = new QTimer(this);
+ restartTimer->setInterval( DesktopSettings::instance()->value(DesktopSettings::ScreenSaver, "globals/plugin_time_seconds", 120).toInt() * 1000);
+ restartTimer->setSingleShot(true);
+ connect(restartTimer, SIGNAL(timeout()), this, SLOT(startPainting()) );
+}
+
+SSBaseWidget::~SSBaseWidget(){
+}
+
+void SSBaseWidget::setPlugin(QString plug){
+ plugType = plug.toLower();
+}
+
+// =============
+// PUBLIC SLOTS
+// =============
+void SSBaseWidget::startPainting(){
+ //free up any old animation instance
+ stopPainting();
+ //If a random plugin - grab one of the known plugins
+ if(plugType=="random"){
+ QList<SSPlugin> valid = PluginSystem::findAllPlugins<SSPlugin>(REL_DIR);
+ if(!valid.isEmpty()){ cplug = valid[ qrand()%valid.length() ]; } //grab a random plugin
+ }else if(plugType!="none"){
+ cplug = PluginSystem::findPlugin<SSPlugin>(plugType, REL_DIR);
+ }
+ if(DEBUG){ qDebug() << " - Screen Saver:" << plugType << cplug.scriptURL() << cplug.isValid(); }
+ if(cplug.isValid()){
+ this->setSource( cplug.scriptURL() );
+ if(plugType=="random"){ restartTimer->start(); }
+ }
+
+}
+
+void SSBaseWidget::stopPainting(){
+ if(!this->source().isEmpty()){
+ this->setSource(QUrl());
+ cplug = SSPlugin(); //empty structure
+ }
+ if(restartTimer->isActive()){ restartTimer->stop(); }
+}
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/SSBaseWidget.h b/src-qt5/core/lumina-desktop/src-screensaver/SSBaseWidget.h
new file mode 100644
index 00000000..e0a03d17
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/SSBaseWidget.h
@@ -0,0 +1,50 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is the widget which provides the screensaver painting/plugin functionality
+//===========================================
+#ifndef _LUMINA_DESKTOP_SCREEN_SAVER_BASE_WIDGET_H
+#define _LUMINA_DESKTOP_SCREEN_SAVER_BASE_WIDGET_H
+
+#include "global-includes.h"
+#include <plugins-base.h>
+#include <plugins-screensaver.h>
+
+class SSBaseWidget : public QQuickView{
+ Q_OBJECT
+public:
+ SSBaseWidget(QWidget *parent);
+ ~SSBaseWidget();
+
+ void setPlugin(QString);
+
+public slots:
+ void startPainting();
+ void stopPainting();
+
+private:
+ QString plugType;
+ SSPlugin cplug;
+ QTimer *restartTimer;
+
+private slots:
+
+signals:
+ void InputDetected(); //just in case no event handling setup at the WM level
+
+protected:
+ void mouseMoveEvent(QMouseEvent *ev){
+ ev->accept();
+ emit InputDetected();
+ }
+ void keyPressEvent(QKeyEvent *ev){
+ ev->accept();
+ emit InputDetected();
+ }
+
+};
+
+#endif
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/animations/BaseAnimGroup.cpp b/src-qt5/core/lumina-desktop/src-screensaver/animations/BaseAnimGroup.cpp
new file mode 100644
index 00000000..9b095fe4
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/animations/BaseAnimGroup.cpp
@@ -0,0 +1,51 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015-2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "BaseAnimGroup.h"
+
+//Include all the known subclasses here, then add a unique ID for it to the functions at the bottom
+//#include "SampleAnimation.h"
+#include "Fireflies.h"
+#include "Grav.h"
+#include "SampleAnimation.h"
+#include "Text.h"
+#include "ImageSlideshow.h"
+#include "VideoSlideshow.h"
+
+
+QVariant BaseAnimGroup::readSetting(QString variable, QVariant defaultvalue){
+ return DesktopSettings::instance()->value(DesktopSettings::ScreenSaver,
+ "Animations/"+animPlugin+"/"+variable, defaultvalue);
+}
+
+//==============================
+// PLUGIN LOADING/LISTING
+//==============================
+BaseAnimGroup* BaseAnimGroup::NewAnimation(QString type, QWidget *parent){
+ //This is where we place all the known plugin ID's, and load the associated subclass
+ BaseAnimGroup *anim = 0;
+ if(type=="fireflies"){
+ anim = new FirefliesAnimation(parent);
+ }else if(type == "grav") {
+ anim = new GravAnimation(parent);
+ }else if(type == "text") {
+ anim = new TextAnimation(parent);
+ }else if(type == "imageSlideshow") {
+ anim = new ImageAnimation(parent);
+ }else if(type == "videoSlideshow") {
+ anim = new VideoAnimation(parent);
+ }else {
+ //Unknown screensaver, return a blank animation group
+ anim = new BaseAnimGroup(parent);
+ }
+ //tag the animation with the type it is and return it
+ if(anim!=0){ anim->animPlugin = type; }
+ return anim;
+}
+
+QStringList BaseAnimGroup::KnownAnimations(){
+ return (QStringList() << "none" << "grav" << "text" << "imageSlideshow" << "videoSlideshow" << "fireflies");
+}
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/animations/BaseAnimGroup.h b/src-qt5/core/lumina-desktop/src-screensaver/animations/BaseAnimGroup.h
new file mode 100644
index 00000000..92e038ed
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/animations/BaseAnimGroup.h
@@ -0,0 +1,40 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015-2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is the container which provides the screensaver animations
+// and should be subclassed for each of the various animation types
+//===========================================
+#ifndef _LUMINA_DESKTOP_SCREEN_SAVER_BASE_ANIMATION_GROUP_H
+#define _LUMINA_DESKTOP_SCREEN_SAVER_BASE_ANIMATION_GROUP_H
+
+#include "global-includes.h"
+
+class BaseAnimGroup : public QParallelAnimationGroup{
+ Q_OBJECT
+public:
+ QWidget *canvas;
+ QString animPlugin;
+
+ virtual void LoadAnimations(){} //This is the main function which needs to be subclassed
+
+ BaseAnimGroup(QWidget *parent){
+ canvas = parent;
+ canvas->setCursor( QCursor(Qt::BlankCursor) );
+ }
+ ~BaseAnimGroup(){}
+
+ QVariant readSetting(QString variable, QVariant defaultvalue = QVariant());
+
+
+ //==============================
+ // PLUGIN LOADING/LISTING (Change in the .cpp file)
+ //==============================
+ static BaseAnimGroup* NewAnimation(QString type, QWidget *parent);
+ static QStringList KnownAnimations();
+
+};
+
+#endif
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/animations/Fireflies.h b/src-qt5/core/lumina-desktop/src-screensaver/animations/Fireflies.h
new file mode 100644
index 00000000..dfc12e79
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/animations/Fireflies.h
@@ -0,0 +1,122 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is the sample plugin for a ScreenSaver animation
+//===========================================
+#ifndef _LUMINA_DESKTOP_SCREEN_SAVER_FIREFLIES_ANIMATION_H
+#define _LUMINA_DESKTOP_SCREEN_SAVER_FIREFLIES_ANIMATION_H
+
+#include "global-includes.h"
+#include "BaseAnimGroup.h"
+#include <QSequentialAnimationGroup>
+#include <QGraphicsOpacityEffect>
+
+class Firefly : public QSequentialAnimationGroup{
+ Q_OBJECT
+private:
+ QWidget *fly;
+ QPropertyAnimation *movement, *flash;
+ int maxX, maxY; //maximum jitter in X/Y directions
+ QSize range;
+private slots:
+ void LoopChanged(){
+ //Adjust the movement animation a bit
+ movement->setStartValue(movement->endValue()); //start at the previous end point
+ QPoint pt = movement->startValue().toPoint();
+ QPoint diff( (qrand()% maxX) - (maxX/2), (qrand()% maxY) - (maxY/2) );
+ //Need to ensure it stays in the current box
+ if( (pt.x()+diff.x()) < 0 || (pt.x()+diff.x())>range.width()){ pt.setX(pt.x() - diff.x()); } //reverse the direction - otherwise will go out of bounds
+ else{ pt.setX( pt.x() + diff.x() ); }
+ if( (pt.y()+diff.y()) < 0 || (pt.y()+diff.y())>range.height()){ pt.setY(pt.y() - diff.y()); } //reverse the direction - otherwise will go out of bounds
+ else{ pt.setY( pt.y() + diff.y() ); }
+ movement->setEndValue(pt);
+ movement->setDuration( qrand() %500 + 1000); //between 1000->1500 ms animations for movements
+ //Adjust the flash duration/size a bit
+ flash->setDuration(qrand() %200 + 500); //500-700 ms
+ int sz = qrand()%4 + 4; //6-10 pixel square
+ //flash->setKeyValueAt(0.5, (qrand()%50) /100.0);
+ //fly->resize(sz,sz);
+ flash->setKeyValueAt(0.5, QSize(sz,sz)); //half-way point for the flash
+
+ fly->show();
+ }
+ void stopped(){ fly->hide(); }
+
+public:
+ Firefly(QWidget *parent) : QSequentialAnimationGroup(parent){
+ fly = new QWidget(parent);
+ range = parent->size();
+ maxX = range.width()/4; maxY = range.height()/4;
+ QString B = QString::number(qrand()%70);
+ QString RY = QString::number(qrand()%200+50);
+ QString style = "background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(245, 245, 143, 200), stop:0.83871 rgba(%1, %1, %2, 140), stop:0.99 rgba(0, 0, 0, 255), stop:1 transparent);";
+ fly->setStyleSheet(style.arg(RY, B) );
+ //setup the movement animation
+ movement = new QPropertyAnimation(fly);
+ movement->setTargetObject(fly);
+ movement->setPropertyName("pos");
+ movement->setEndValue( QPoint( qrand() % range.width(), qrand()%range.height()) ); //on anim start, this will become the starting point
+ //setup the flashing animation
+ /*QGraphicsOpacityEffect *eff = new QGraphicsOpacityEffect(parent);
+ fly->setGraphicsEffect(eff);
+ flash = new QPropertyAnimation(eff, "opacity");*/
+ flash = new QPropertyAnimation(this);
+ flash->setTargetObject(fly);
+ flash->setPropertyName("size");
+ flash->setStartValue(QSize(0,0));
+ flash->setEndValue(flash->startValue());
+ //fly->setProperty("opacity",0);
+ //flash->setPropertyName("opacity");
+ //flash->setStartValue(0);
+ //flash->setEndValue(0);
+ //now setup the order of the animations
+ this->setLoopCount(100); //do this 100 times
+ //Roughly half the number of fireflies with start with movement/flash
+ if(qrand()%2 == 1){
+ this->addAnimation(movement);
+ this->addAnimation(flash);
+ }else{
+ this->addAnimation(flash);
+ this->addAnimation(movement);
+ }
+ //Start up this firefly
+ LoopChanged(); //load initial values
+
+ fly->setGeometry( QRect(movement->startValue().toPoint(), flash->startValue().toSize()) );
+ connect(this, SIGNAL(currentLoopChanged(int)), this, SLOT(LoopChanged()) );
+ connect(this, SIGNAL(finished()), this, SLOT(stopped()) );
+ }
+ ~Firefly(){}
+
+};
+
+class FirefliesAnimation : public BaseAnimGroup{
+ Q_OBJECT
+private:
+ QList<Firefly*> fireflies;
+
+public:
+ FirefliesAnimation(QWidget *parent) : BaseAnimGroup(parent){}
+ ~FirefliesAnimation(){
+ this->stop();
+ //while(fireflies.length()>0){ fireflies.takeAt(0)->deleteLater(); }
+ }
+
+ void LoadAnimations(){
+ while(fireflies.length()>0){ fireflies.takeAt(0)->deleteLater(); }
+ canvas->setStyleSheet("background: black;");
+ int number = readSetting("number",qrand()%30 + 50).toInt();
+ for(int i=0; i<number; i++){
+ if(fireflies.length()>number){ continue; }
+ Firefly *tmp = new Firefly(canvas);
+ this->addAnimation(tmp);
+ fireflies << tmp;
+ }
+
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/animations/Grav.h b/src-qt5/core/lumina-desktop/src-screensaver/animations/Grav.h
new file mode 100644
index 00000000..df75ad67
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/animations/Grav.h
@@ -0,0 +1,195 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_SCREEN_SAVER_GRAV_ANIMATION_H
+#define _LUMINA_DESKTOP_SCREEN_SAVER_GRAV_ANIMATION_H
+
+//PI is equal to 2*pi
+#define PI 6.2832
+#include "global-includes.h"
+#include "BaseAnimGroup.h"
+#include <QtMath>
+#include <QMatrix>
+
+class Grav: public QParallelAnimationGroup{
+ Q_OBJECT
+private:
+ QWidget *planet;
+ QPropertyAnimation *orbit;
+ QSize range;
+ //QList<QPoint> path;
+ double radius;
+
+ void setupLoop(QPoint start, QPoint *ref){
+ //orbit->setStartValue(start);
+
+ //Used to find overall speed. Distance from the planet to the sun
+ radius = qSqrt( (qPow(start.x()-ref->x(),2) + qPow(start.y()-ref->y(),2) ));
+
+ //Number of frames in animation. Increase for smother motion
+ double step = 300.0;
+
+ //Random values that give the eliptical pattern to the orbit. Between 0.4 and 2.3
+ double xrand = 0.4; //(qrand()%10+4)/10.0;
+ double yrand = 0.4; //(qrand()%10+4)/10.0;
+
+ double theta = 1.5707963;
+ //double theta = aTan((start.x() - ref->x())/(start.y() - ref->y()));
+ QMatrix rotation = QMatrix(qCos(theta), qSin(theta), -qSin(theta), qCos(theta), -ref->x(), -ref->y());
+ qDebug() << rotation;
+ //qDebug() << "Starting Point" << start;
+ //qDebug() << "Angle" << theta;
+ //qDebug() << "Distance" << radius;
+ //qDebug() << "Center" << *ref;
+
+ QPoint firstP = (QPoint(ref->x() + xrand*start.x()*(qCos(0/step) -qSin(0/step)), ref->y() + yrand*start.y()*(qCos(0/step) -qSin(0/step))));
+ QPoint rotFP = rotation.map(firstP);
+ qDebug() << "First Point" << firstP;
+ qDebug() << "Rotation by Matrix" << rotFP;
+ QPoint lastP = (QPoint(ref->x() + xrand*start.x()*(qCos(PI/step) -qSin(PI/step)), ref->y() + yrand*start.y()*(qCos(PI/step) -qSin(PI/step))));
+ orbit->setKeyValueAt(0, firstP);
+ orbit->setKeyValueAt(1, lastP);
+ //path.push_back(firstP);
+
+ //Loops through all steps and creates all the points of the orbit
+ for(int i=1; i<step; i++) {
+ //Calculates the new point, including gravitational pull and eccentricity. Goes from 0 to 2PI in steps.
+ double newX = ref->x() + xrand*start.x()*(qCos((PI*i)/step) - qSin((PI*i)/step));
+ double newY = ref->y() + yrand*start.y()*(qSin((PI*i)/step) + qCos((PI*i)/step));
+
+ //Creates a new point and creates a key as part of the animation
+ QPoint newLoc = (QPoint(newX, newY));
+ orbit->setKeyValueAt(i/step, newLoc);
+ //path.push_back(newLoc);
+ }
+ //Sets the time for a full orbit. Increasing makes the orbit slower.
+ //path.push_back(lastP);
+ }
+private slots:
+ /*void LoopChanged(int loop){
+ //Adjust the orbit animation a bit
+ if(loop >= 0) {
+ orbit->setStartValue(orbit->endValue()); //start at the previous end point
+ orbit->setEndValue(path.at(loop%1000));
+ orbit->setDuration(10);
+ }
+ }*/
+ void stopped(){ planet->hide();}
+
+public:
+ Grav(QWidget *parent) : QParallelAnimationGroup(parent){
+ planet = new QWidget(parent);
+ range = parent->size();
+ QPoint center = QRect(QPoint(0,0), parent->size()).center();;
+
+ //Creates a random planet size. Between 12 and 45 pixels
+ int planet_radius = qRound(1.75* ((qrand()%20)+7) );
+
+ //Creates a random color in RGB, then creates a circular gradient
+ QString color = "rgba(" + QString::number(qrand() % 256) + ", " + QString::number(qrand() % 256) + ", " + QString::number(qrand() % 256);
+ QString style = "background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 " + color+
+ ", 255)" + " , stop:0.83871 " + color + ", 140)" + " , stop:0.99 rgba(0, 0, 0, 255), stop:1 transparent);";
+ planet->setStyleSheet(style);
+
+ //setup the orbit animation
+ orbit = new QPropertyAnimation(planet);
+ orbit->setPropertyName("pos");
+ orbit->setTargetObject(planet);
+
+ //Creates the random position of the planet, making sure it isn't too close to the sun
+ QRect invalid = QRect(center+QPoint(-50,-50), center+QPoint(50,50));
+ QPoint tmp = center;
+ while(invalid.contains(tmp)){
+ int randwidth = qrand()%(range.width() - 2*planet_radius) + planet_radius;
+ int randheight = qrand()%(range.height()- 2*planet_radius) + planet_radius;
+ tmp = QPoint(randwidth, randheight);
+ }
+
+ //Creates all frames for the animation
+ setupLoop(tmp, &center);
+ this->addAnimation(orbit);
+ planet->show();
+
+ //Ensures the screensaver will not stop until the user wishes to login or it times out
+ this->setLoopCount(3); //number of orbits
+ orbit->setDuration( qrand() %1000 + 19000); //20 second orbits
+ //orbit->setEndValue(path.at(0));
+ //LoopChanged(0); //load initial values
+
+ //Sets the initial size and location of the planet
+ planet->setGeometry(QRect(orbit->startValue().toPoint(), QSize(planet_radius, planet_radius)));
+ //connect(this, SIGNAL(currentLoopChanged(int)), this, SLOT(LoopChanged(int)) );
+ connect(this, SIGNAL(finished()), this, SLOT(stopped()) );
+ }
+ ~Grav(){}
+
+};
+
+class GravAnimation : public BaseAnimGroup{
+ Q_OBJECT
+private:
+ QList<Grav*> planets;
+ QWidget *sun;
+ QPropertyAnimation *wobble;
+
+private slots:
+ void checkFinished(){
+ int running = 0;
+ for(int i=0; i<this->animationCount(); i++){
+ if(this->animationAt(i)->state()==QAbstractAnimation::Running){ running++; }
+ }
+ if(running<=1){ wobble->stop(); emit wobble->finished();}
+ }
+
+public:
+ GravAnimation(QWidget *parent) : BaseAnimGroup(parent){}
+ ~GravAnimation(){
+ sun->deleteLater();
+ while(planets.length()>0){ planets.takeAt(0)->deleteLater(); }
+ }
+
+ void LoadAnimations(){
+ //Creates the sun, which is a thin shell with a gradient from green to yellow
+ sun = new QWidget(canvas);
+ QPoint center = QRect(QPoint(0,0), canvas->size()).center();
+ QString sunstyle = QStringLiteral("background-color:qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, ") +
+ QStringLiteral("stop:0 rgba(0, 0, 0, 0), stop:0.38 rgba(0, 0, 0, 0), stop:0.4 rgba(82, 121, 76, 33), stop:0.5 rgba(159, 235, 148, 64), ") +
+ QStringLiteral("stop:0.6 rgba(255, 238, 150, 129), stop:0.7 rgba(0, 0, 0, 0));");
+ sun->setStyleSheet(sunstyle);
+
+ //Creates the sun's pulsing animation
+ wobble = new QPropertyAnimation(sun);
+ wobble->setPropertyName("geometry");
+ wobble->setTargetObject(sun);
+ QRect initgeom = QRect(center-QPoint(30,30), QSize(60, 60));
+ wobble->setStartValue(initgeom);
+ wobble->setKeyValueAt(0, initgeom ); //starting point
+ wobble->setKeyValueAt(1, initgeom ); //starting point
+ wobble->setKeyValueAt(0.5, QRect(center-QPoint(45,45), QSize(90, 90))); //starting point
+ wobble->setDuration(2000);
+ wobble->setLoopCount(-1);
+ this->addAnimation(wobble);
+ sun->show();
+ sun->setGeometry(initgeom);
+
+ //Gives the screensaver a black background
+ //canvas->setStyleSheet("background: black;");
+
+ //Pulls number of planets from settings, with 10 as default
+ int number = readSetting("planets/number",qrand()%5+3).toInt();
+
+ //Loops through all planets and sets up the animations, then adds them to the base group and vector, which
+ //qDebug() << "Starting planets";
+ for(int i=0; i<number; i++){
+ Grav *tmp = new Grav(canvas);
+ this->addAnimation(tmp);
+ connect(tmp, SIGNAL(finished()), this, SLOT(checkFinished()));
+ planets << tmp;
+ }
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/animations/ImageSlideshow.h b/src-qt5/core/lumina-desktop/src-screensaver/animations/ImageSlideshow.h
new file mode 100644
index 00000000..81bc2b35
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/animations/ImageSlideshow.h
@@ -0,0 +1,165 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_SCREEN_SAVER_IMAGESLIDESHOW_ANIMATION_H
+#define _LUMINA_DESKTOP_SCREEN_SAVER_IMAGESLIDESHOW_ANIMATION_H
+
+#include "global-includes.h"
+#include "BaseAnimGroup.h"
+
+class ImageSlideshow: public QParallelAnimationGroup{
+ Q_OBJECT
+private:
+ QLabel *image;
+ QPropertyAnimation *bounce, *fading;
+ QPixmap pixmap;
+ QStringList imageFiles;
+ QString imagePath, scriptPath, curpixmap;
+ QSize screenSize;
+ bool animate, scriptLoad;
+
+private:
+ void setupAnimation() {
+ //Choose between starting from top or bottom at random
+ if(qrand() % 2) {
+ bounce->setKeyValueAt(0, QPoint(0,screenSize.height()-image->height()));
+ bounce->setKeyValueAt(0.25, QPoint((screenSize.width()-image->width())/2,0));
+ bounce->setKeyValueAt(0.5, QPoint(screenSize.width()-image->width(),screenSize.height()-image->height()));
+ bounce->setKeyValueAt(0.75, QPoint((screenSize.width()-image->width())/2,0));
+ bounce->setKeyValueAt(1, QPoint(0,screenSize.height()-image->height()));
+ }else{
+ bounce->setKeyValueAt(0, QPoint(0,0));
+ bounce->setKeyValueAt(0.25, QPoint((screenSize.width()-image->width())/2,screenSize.height()-image->height()));
+ bounce->setKeyValueAt(0.5, QPoint(screenSize.width()-image->width(),0));
+ bounce->setKeyValueAt(0.75, QPoint((screenSize.width()-image->width())/2,screenSize.height()-image->height()));
+ bounce->setKeyValueAt(1, QPoint(0,0));
+ }
+ }
+
+ void chooseImage() {
+ /*if(scriptLoad){
+ QProcess process;
+ process.start("/home/zwelch/test.sh");
+ process.waitForFinished(1000);
+ QByteArray output = process.readAllStandardOutput();
+ //qDebug() << output;
+ //pixmap.load(randomFile);
+ }else{*/
+ //File Load
+ QString randomFile = curpixmap;
+ if(imageFiles.size()>1 || curpixmap.isEmpty()){
+ while(curpixmap==randomFile){ randomFile = imagePath+imageFiles[qrand() % imageFiles.size()]; }
+ }
+ if(curpixmap!=randomFile){
+ curpixmap = randomFile; //save this for later
+ //no need to load the new file or change the label
+ pixmap.load(randomFile);
+ //If the image is larger than the screen, then shrink the image down to 3/4 it's size (so there's still some bounce)
+ //Scale the pixmap to keep the aspect ratio instead of resizing the label itself
+ if(pixmap.width() >= (screenSize.width()-10) || pixmap.height() >= (screenSize.height()-10) ){
+ pixmap = pixmap.scaled(screenSize*(3.0/4.0), Qt::KeepAspectRatio);
+ }
+ //Set pixmap to the image label
+ image->setPixmap(pixmap);
+ image->resize(pixmap.size());
+ }
+ //}
+
+ }
+
+private slots:
+ void LoopChanged(){
+ //Load a new random image. Resize the label based on the image's size
+ chooseImage();
+ setupAnimation();
+ }
+ void stopped(){ image->hide();}
+
+public:
+ ImageSlideshow(QWidget *parent, QString path, bool animate, bool scriptLoad, QString scriptPath) : QParallelAnimationGroup(parent){
+ imagePath = path;
+ image = new QLabel(parent);
+ screenSize = parent->size();
+ this->animate = animate;
+ this->scriptLoad = scriptLoad;
+ this->scriptPath = scriptPath;
+
+ //Generate the list of files in the directory
+ imageFiles = QDir(imagePath).entryList(QDir::Files);
+ //Ensure all the files are actually images
+ for(int i=0; i<imageFiles.length(); i++){
+ if(QImageReader::imageFormat(imagePath+"/"+imageFiles[i]).isEmpty()){ imageFiles.removeAt(i); i--; }
+ }
+ if(imageFiles.empty()){
+ qDebug() << "Current image file path has no files.";
+ image->setText("No image files found:\n"+imagePath);
+ }else{
+ //Change some default settings for the image. If scaledContents is false, the image will be cut off if resized
+ image->setScaledContents(true);
+ image->setAlignment(Qt::AlignHCenter);
+ //Load a random initial image
+ chooseImage();
+ }
+
+ //Create the animation that moves the image across the screen
+ bounce = new QPropertyAnimation(image, "pos", parent);
+
+ //Add the animation that fades the image in and out
+ QGraphicsOpacityEffect *eff = new QGraphicsOpacityEffect(parent);
+ image->setGraphicsEffect(eff);
+ fading = new QPropertyAnimation(eff,"opacity");
+ fading->setKeyValueAt(0, 0);
+ fading->setKeyValueAt(0.20, 1);
+ fading->setKeyValueAt(0.80, 1);
+ fading->setKeyValueAt(1, 0);
+ this->addAnimation(fading);
+
+ setupAnimation();
+ image->show();
+ //Only add the animation if set in the configuration file
+ if(animate)
+ this->addAnimation(bounce);
+ else
+ //If no animation, center the image in the middle of the screen
+ image->move(QPoint((parent->width()-image->width())/2,(parent->height()-image->height())/2));
+
+ //Loop through 15 times for a total for 2 minutes
+ this->setLoopCount(15);
+ bounce->setDuration(8000);
+ fading->setDuration(8000);
+
+ connect(this, SIGNAL(currentLoopChanged(int)), this, SLOT(LoopChanged()) );
+ connect(this, SIGNAL(finished()), this, SLOT(stopped()) );
+ }
+ ~ImageSlideshow(){}
+
+};
+
+class ImageAnimation: public BaseAnimGroup{
+ Q_OBJECT
+public:
+ ImageAnimation(QWidget *parent) : BaseAnimGroup(parent){}
+ ~ImageAnimation(){
+ this->stop();
+ }
+
+ void LoadAnimations(){
+ canvas->setStyleSheet("background: black;");
+ //Load the path of the images from the configuration file (default /usr/local/backgrounds/)
+ QString imagePath = readSetting("path", LOS::LuminaShare()+"../wallpapers/").toString();
+ //Load whether to animate the image (default true)
+ bool animate = readSetting("animate", true).toBool();
+ bool scriptLoad = readSetting("scriptLoad", true).toBool();
+ QString scriptPath;
+ if(scriptLoad){
+ scriptPath = readSetting("scriptPath", "/usr/local/backgrounds/script.sh").toString();
+ }
+ ImageSlideshow *tmp = new ImageSlideshow(canvas, imagePath, animate, scriptLoad, scriptPath);
+ this->addAnimation(tmp);
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/animations/SampleAnimation.h b/src-qt5/core/lumina-desktop/src-screensaver/animations/SampleAnimation.h
new file mode 100644
index 00000000..c7a8b237
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/animations/SampleAnimation.h
@@ -0,0 +1,45 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is the sample plugin for a ScreenSaver animation
+//===========================================
+#ifndef _LUMINA_DESKTOP_SCREEN_SAVER_SAMPLE_ANIMATION_H
+#define _LUMINA_DESKTOP_SCREEN_SAVER_SAMPLE_ANIMATION_H
+
+#include "global-includes.h"
+#include "BaseAnimGroup.h"
+
+class SampleAnimation : public BaseAnimGroup{
+ Q_OBJECT
+private:
+ QWidget *ball;
+
+public:
+ SampleAnimation(QWidget *parent) : BaseAnimGroup(parent){}
+ ~SampleAnimation(){ this->stop(); delete ball; }
+
+ void LoadAnimations(){
+ //qDebug() << "Loading Sample Animation";
+ ball = new QWidget(canvas);
+ //This creates a red "ball" on the widget which is going to expand/contract in the center of the screen
+ ball->setStyleSheet("background: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.341, fy:0.796, stop:0.00531915 rgba(107, 10, 10, 255), stop:0.521277 rgba(170, 10, 10, 255), stop:0.957447 rgba(200, 0, 0, 255), stop:0.994681 rgba(0, 0, 0, 225), stop:1 rgba(255, 255, 255, 0));");
+ //Now setup the movements
+ QPropertyAnimation *move = new QPropertyAnimation(ball,"geometry");
+ QPoint ctr(canvas->width()/2, canvas->height()/2);
+ QRect initgeom(ctr-QPoint(12,12), QSize(24,24) );
+ move->setKeyValueAt(0, initgeom ); //starting point
+ move->setKeyValueAt(1, initgeom ); //ending point (same as start for continuity)
+ int size = canvas->width();
+ if(size > canvas->height()){ size = canvas->height(); }
+ move->setKeyValueAt(0.5, QRect(ctr-QPoint(size/2, size/2), QSize(size,size))); //touch the edge of the screen
+ move->setDuration(10000); //10 seconds
+ this->addAnimation(move);
+ this->setLoopCount(10); //repeat 10 times
+ ball->show();
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/animations/Text.h b/src-qt5/core/lumina-desktop/src-screensaver/animations/Text.h
new file mode 100644
index 00000000..bdde5ba2
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/animations/Text.h
@@ -0,0 +1,100 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_SCREEN_SAVER_TEXT_ANIMATION_H
+#define _LUMINA_DESKTOP_SCREEN_SAVER_TEXT_ANIMATION_H
+
+#include "global-includes.h"
+#include "BaseAnimGroup.h"
+#include <QParallelAnimationGroup>
+#include <QtMath>
+
+#include <unistd.h>
+
+class Text: public QParallelAnimationGroup{
+ Q_OBJECT
+private:
+ QLabel *text;
+ QPropertyAnimation *movement;
+ QSize range;
+ QPoint v;
+ bool bounce;
+
+private slots:
+ void LoopChanged(){
+ movement->setStartValue(movement->endValue());
+ QPoint currLoc = movement->startValue().toPoint();
+ bounce = !(currLoc.y() < 100 or currLoc.y() > range.height()-100 or currLoc.x() > range.width()-100 or currLoc.x() < 100);
+ if((currLoc.y() < 10 or currLoc.y() > range.height()-40) and !bounce) {
+ v.setY((v.y() * -1) + (qrand() % 20 - 10));
+ }else if((currLoc.x() > range.width()-10 or currLoc.x() < 10) and !bounce) {
+ v.setX((v.x() * -1) + (qrand() % 20 - 10));
+ }
+ currLoc.setX(currLoc.x() + v.x());
+ currLoc.setY(currLoc.y() + v.y());
+ movement->setEndValue(currLoc);
+ }
+ void stopped(){ qDebug() << "Text Stopped"; text->hide();}
+
+public:
+ Text(QWidget *parent, QString display) : QParallelAnimationGroup(parent){
+ text = new QLabel(parent);
+ range = parent->size();
+ QPoint center = QRect( QPoint(0,0), parent->size()).center();
+
+ QString color = "rgba(" + QString::number(qrand() % 206 + 50) + ", " + QString::number(qrand() % 206 + 50) + ", " + QString::number(qrand() % 206 + 50);
+ text->setStyleSheet("QLabel {background-color: transparent; color: " + color + "); }");
+ text->setFont(QFont("Courier", 24, QFont::Bold));
+ text->setText(display);
+ QFontMetrics metrics(text->font());
+ text->setMinimumSize(QSize( metrics.horizontalAdvance(text->text())+10, metrics.height()*text->text().count("\n") +10));
+
+ movement = new QPropertyAnimation(text);
+ movement->setPropertyName("pos");
+ movement->setTargetObject(text);
+
+ this->addAnimation(movement);
+ text->show();
+ v.setX((qrand() % 100 + 50) * qPow(-1, qrand() % 2));
+ v.setY((qrand() % 100 + 50) * qPow(-1, qrand() % 2));
+ movement->setStartValue(center);
+ //Ensures the screensaver will not stop until the user wishes to login or it times out
+ this->setLoopCount(200); //number of wall bounces
+ movement->setDuration(200);
+ movement->setEndValue(QPoint(qrand() % (int)range.height(), qrand() % range.width()));
+ LoopChanged(); //load initial values
+
+ connect(this, SIGNAL(currentLoopChanged(int)), this, SLOT(LoopChanged()) );
+ connect(this, SIGNAL(finished()), this, SLOT(stopped()) );
+ }
+ ~Text(){}
+
+};
+
+class TextAnimation : public BaseAnimGroup{
+ Q_OBJECT
+public:
+ TextAnimation(QWidget *parent) : BaseAnimGroup(parent){}
+ ~TextAnimation(){
+ this->stop();
+ }
+
+ void LoadAnimations(){
+ canvas->setStyleSheet("background: black;");
+ //Read off the text that needs to be displayed
+ QString textToShow = readSetting("text", "").toString();
+ if(textToShow.isEmpty()){
+ char hname[300];
+ gethostname(hname, 300);
+ textToShow = QString::fromLocal8Bit(hname);
+ }
+ // Now create the animation
+ Text *tmp = new Text(canvas, textToShow);
+ this->addAnimation(tmp);
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/animations/VideoSlideshow.h b/src-qt5/core/lumina-desktop/src-screensaver/animations/VideoSlideshow.h
new file mode 100644
index 00000000..358b4bfb
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/animations/VideoSlideshow.h
@@ -0,0 +1,85 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_SCREEN_SAVER_VIDEOSLIDESHOW_ANIMATION_H
+#define _LUMINA_DESKTOP_SCREEN_SAVER_VIDEOSLIDESHOW_ANIMATION_H
+
+#include "global-includes.h"
+#include "BaseAnimGroup.h"
+
+class VideoAnimation: public BaseAnimGroup{
+ Q_OBJECT
+private:
+ QString videoPath, singleVideo;
+ QVideoWidget *videoWidget;
+ QMediaPlayer *video;
+ QStringList videoFiles;
+ bool multiple;
+
+private slots:
+
+public:
+ VideoAnimation(QWidget *parent) : BaseAnimGroup(parent){}
+
+ ~VideoAnimation(){
+ this->stop();
+ }
+
+ void LoadAnimations(){
+ canvas->setStyleSheet("background: black;");
+
+ //Load the path of the videos from the configuration file (default /usr/local/videos/)
+ videoPath = readSetting("path","/usr/local/videos").toString();
+ singleVideo = readSetting("videoLocation","").toString();
+ multiple = readSetting("multiple",true).toBool();
+ if(!videoPath.endsWith("/")){ videoPath.append("/"); }
+
+ //Set whether to copy videos on two monitors or play different videos
+ //multimonitor = settings->value("videoSlideshow/multimonitor",true).toBool();
+
+ //Set up the VideoWidget
+ video = new QMediaPlayer(canvas, QMediaPlayer::VideoSurface);
+ videoWidget = new QVideoWidget(canvas);
+ video->setVideoOutput(videoWidget);
+ videoWidget->setGeometry(QRect(QPoint(0,0), canvas->size()));
+
+ //Generate the list of files in the directory
+ videoFiles = QDir(videoPath).entryList(QDir::Files);
+ if(videoFiles.empty()){
+ qDebug() << "Current video file path has no files:" << videoPath;
+ return;
+ }
+
+ if(singleVideo.isNull())
+ singleVideo = videoPath+videoFiles[0];
+
+ //Loading a random file from a directory
+ QDesktopWidget *dw = new QDesktopWidget();
+ QMediaPlaylist *playlist = new QMediaPlaylist();
+ if(multiple) {
+ for(int i = 0; i < videoFiles.size(); i++){
+ playlist->addMedia(QUrl::fromLocalFile(videoPath+videoFiles[i]));
+ }
+ playlist->shuffle();
+ }else{
+ playlist->addMedia(QUrl::fromLocalFile(singleVideo));
+ playlist->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
+ }
+ videoWidget->show();
+ if(multiple)
+ video->setPlaylist(playlist);
+
+ //Only play sound for one monitor to prevent messed up audio
+ if(dw->screenNumber(canvas) == 0)
+ video->setVolume(100);
+ else
+ video->setVolume(0);
+
+ video->play();
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/animations/animations.pri b/src-qt5/core/lumina-desktop/src-screensaver/animations/animations.pri
new file mode 100644
index 00000000..fdc75717
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/animations/animations.pri
@@ -0,0 +1,10 @@
+SOURCES += $$PWD/BaseAnimGroup.cpp
+
+HEADERS += $$PWD/BaseAnimGroup.h \
+ $$PWD/SampleAnimation.h \
+ $${PWD}/Fireflies.h \
+ $${PWD}/Grav.h \
+ $${PWD}/ImageSlideshow.h \
+ $${PWD}/VideoSlideshow.h \
+ $${PWD}/Text.h
+#FORMS +=
diff --git a/src-qt5/core/lumina-desktop/src-screensaver/screensaver.pri b/src-qt5/core/lumina-desktop/src-screensaver/screensaver.pri
new file mode 100644
index 00000000..92cc7bd2
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/src-screensaver/screensaver.pri
@@ -0,0 +1,15 @@
+SOURCES *= $${PWD}/LLockScreen.cpp \
+ $${PWD}/LScreenSaver.cpp \
+ $${PWD}/SSBaseWidget.cpp
+
+HEADERS *= $${PWD}/LLockScreen.h \
+ $${PWD}/LScreenSaver.h \
+ $${PWD}/SSBaseWidget.h
+
+FORMS *= $${PWD}/LLockScreen.ui
+
+#update the includepath so we can just (#include <LScreenSaver.h>) as needed without paths
+INCLUDEPATH *= $${PWD}
+
+#Now include all the screensaver animations/options
+#include(animations/animations.pri)
bgstack15