diff options
Diffstat (limited to 'src-qt5/core/lumina-desktop')
22 files changed, 1626 insertions, 3 deletions
diff --git a/src-qt5/core/lumina-desktop/Globals.h b/src-qt5/core/lumina-desktop/Globals.h index 109731d2..3da9b3ae 100644 --- a/src-qt5/core/lumina-desktop/Globals.h +++ b/src-qt5/core/lumina-desktop/Globals.h @@ -45,6 +45,7 @@ public: } return QString::fromLocal8Bit(name,count); } + }; #endif diff --git a/src-qt5/core/lumina-desktop/LSession.cpp b/src-qt5/core/lumina-desktop/LSession.cpp index 32bd409f..0b82fdc2 100644 --- a/src-qt5/core/lumina-desktop/LSession.cpp +++ b/src-qt5/core/lumina-desktop/LSession.cpp @@ -67,6 +67,7 @@ LSession::LSession(int &argc, char ** argv) : LSingleApplication(argc, argv, "lu currTranslator=0; mediaObj=0; sessionsettings=0; + ScreenSaver=0; //Setup the event filter for Qt5 evFilter = new XCBEventFilter(this); this->installNativeEventFilter( evFilter ); @@ -90,6 +91,7 @@ LSession::~LSession(){ //delete WM; settingsmenu->deleteLater(); appmenu->deleteLater(); + if(ScreenSaver!=0){ ScreenSaver->deleteLater(); } delete currTranslator; if(mediaObj!=0){delete mediaObj;} } @@ -238,6 +240,9 @@ void LSession::setupSession(){ connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(watcherChange(QString)) ); connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(watcherChange(QString)) ); connect(this, SIGNAL(aboutToQuit()), this, SLOT(SessionEnding()) ); + if(DEBUG){ qDebug() << " - Start screensaver:" << timer->elapsed(); } + ScreenSaver = new LScreenSaver(); + ScreenSaver->start(); //if(DEBUG){ qDebug() << " - Process Events (4x):" << timer->elapsed();} //for(int i=0; i<4; i++){ LSession::processEvents(); } //Again, just a few event loops here so thing can settle before we close the splash screen if(DEBUG){ qDebug() << " - Launch Startup Apps:" << timer->elapsed();} @@ -719,6 +724,10 @@ QSettings* LSession::DesktopPluginSettings(){ return DPlugSettings; } +LScreenSaver* LSession::screenSaver(){ + return ScreenSaver; +} + WId LSession::activeWindow(){ //Check the last active window pointer first WId active = XCB->ActiveWindow(); diff --git a/src-qt5/core/lumina-desktop/LSession.h b/src-qt5/core/lumina-desktop/LSession.h index ee17660d..71036b09 100644 --- a/src-qt5/core/lumina-desktop/LSession.h +++ b/src-qt5/core/lumina-desktop/LSession.h @@ -30,6 +30,7 @@ #include "LDesktop.h" //#include "WMProcess.h" //#include "BootSplash.h" +#include <LScreenSaver.h> #include <LuminaX11.h> #include <LuminaSingleApplication.h> @@ -97,6 +98,7 @@ public: QSettings* sessionSettings(); QSettings* DesktopPluginSettings(); + LScreenSaver* screenSaver(); //Keep track of which non-desktop window should be treated as active WId activeWindow(); //This will return the last active window if a desktop element is currently active @@ -125,6 +127,7 @@ private: QMediaPlayer *mediaObj; QSettings *sessionsettings, *DPlugSettings; bool cleansession; + LScreenSaver *ScreenSaver; //QList<QRect> savedScreens; //System Tray Variables diff --git a/src-qt5/core/lumina-desktop/global-includes.h b/src-qt5/core/lumina-desktop/global-includes.h new file mode 100644 index 00000000..be33a45b --- /dev/null +++ b/src-qt5/core/lumina-desktop/global-includes.h @@ -0,0 +1,85 @@ +//=========================================== +// Lumina-desktop source code +// Copyright (c) 2015-2016, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// Global defines and enumerations for external includes +//=========================================== +#ifndef _LUMINA_EXTERNAL_GLOBAL_DEFINES_H +#define _LUMINA_EXTERNAL_GLOBAL_DEFINES_H + +//Qt includes +#include <QObject> +#include <QFrame> +#include <QLabel> +#include <QToolButton> +#include <QMenu> +#include <QHBoxLayout> +#include <QMouseEvent> +#include <QAction> +#include <QPoint> +#include <QTemporaryFile> +#include <QFile> +#include <QDir> +#include <QString> +#include <QTextStream> +#include <QUrl> +#include <QDebug> +#include <QStringList> +#include <QAbstractNativeEventFilter> +#include <QList> +#include <QX11Info> +#include <QCoreApplication> +#include <QPropertyAnimation> +#include <QAnimationGroup> +#include <QParallelAnimationGroup> +#include <QSequentialAnimationGroup> +#include <QGraphicsOpacityEffect> +#include <QWindow> +#include <QWidget> +#include <QWidgetAction> +#include <QBackingStore> +#include <QPaintEvent> +#include <QPainter> +#include <QSettings> +#include <QHostInfo> +#include <QDesktopWidget> +#include <QStyleOption> +#include <QThread> +#include <QMediaObject> +#include <QMediaPlayer> +#include <QVideoWidget> +#include <QMediaPlaylist> +#include <QJsonObject> +#include <QJsonArray> +#include <QJsonDocument> +#include <QQuickView> +#include <QQmlContext> +#include <QQmlEngine> +#include <QQuickImageProvider> +#include <QtConcurrent> + +// libLumina includes +#include <LuminaX11.h> +#include <LuminaXDG.h> +#include <LuminaOS.h> +#include <LuminaThemes.h> +#include <LUtils.h> +#include <LDesktopUtils.h> +#include <LuminaSingleApplication.h> +#include <DesktopSettings.h> +#include <ExternalProcess.h> +#include <XDGMime.h> +#include <LIconCache.h> +#include <LFileInfo.h> +#include <framework-OSInterface.h> + +// C++ Backend classes for QML interface +//#include <NativeWindowObject.h> +//#include <ScreenObject.h> + +//Setup any global defines (no classes or global objects: use "global-objects.h" for that) + + +#endif diff --git a/src-qt5/core/lumina-desktop/lumina-desktop.pro b/src-qt5/core/lumina-desktop/lumina-desktop.pro index cc4b63ae..07bffe4a 100644 --- a/src-qt5/core/lumina-desktop/lumina-desktop.pro +++ b/src-qt5/core/lumina-desktop/lumina-desktop.pro @@ -1,8 +1,14 @@ include($${PWD}/../../OS-detect.pri) -QT += core gui network -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets x11extras multimedia concurrent svg - +lessThan(QT_MAJOR_VERSION, 5) { + message("[ERROR] Qt 5.11+ is required to use the Lumina Desktop!") + exit +} +lessThan(QT_MINOR_VERSION, 11){ + message("[ERROR] Qt 5.11+ is required to use the Lumina Desktop!") + exit +} +QT += core gui network widgets x11extras multimedia multimediawidgets concurrent svg quick qml TARGET = lumina-desktop @@ -17,6 +23,7 @@ include(../libLumina/LuminaSingleApplication.pri) include(../libLumina/LuminaThemes.pri) include(../libLumina/ExternalProcess.pri) include(../libLumina/LIconCache.pri) +include(../libLumina/DesktopSettings.pri) TEMPLATE = app @@ -37,6 +44,7 @@ SOURCES += main.cpp \ HEADERS += Globals.h \ + global-includes.h \ WMProcess.h \ LXcbEventFilter.h \ LSession.h \ @@ -60,6 +68,10 @@ FORMS += SystemWindow.ui \ BootSplash.ui +#include the individual desktop components +include(../../src-cpp/plugins-base.pri) +include(src-screensaver/screensaver.pri) + #Now include all the files for the various plugins include(panel-plugins/panel-plugins.pri) include(desktop-plugins/desktop-plugins.pri) 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, ¢er); + 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) |