diff options
Diffstat (limited to 'src-qt5/src-cpp')
-rw-r--r-- | src-qt5/src-cpp/framework-OSInterface-template.cpp | 150 | ||||
-rw-r--r-- | src-qt5/src-cpp/framework-OSInterface.h | 190 | ||||
-rw-r--r-- | src-qt5/src-cpp/framework-OSInterface.pri | 9 | ||||
-rw-r--r-- | src-qt5/src-cpp/framework-OSInterface_private.cpp | 110 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-base.cpp | 50 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-base.h | 107 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-base.pri | 8 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-desktop.cpp | 40 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-desktop.h | 29 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-screensaver.cpp | 118 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-screensaver.h | 37 | ||||
-rw-r--r-- | src-qt5/src-cpp/plugins-screensaver.pri | 4 | ||||
-rw-r--r-- | src-qt5/src-cpp/tests/main.cpp | 38 | ||||
-rw-r--r-- | src-qt5/src-cpp/tests/test.pro | 7 |
14 files changed, 749 insertions, 148 deletions
diff --git a/src-qt5/src-cpp/framework-OSInterface-template.cpp b/src-qt5/src-cpp/framework-OSInterface-template.cpp new file mode 100644 index 00000000..972e02e0 --- /dev/null +++ b/src-qt5/src-cpp/framework-OSInterface-template.cpp @@ -0,0 +1,150 @@ +//=========================================== +// Lumina desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include <framework-OSInterface.h> +#include <QNetworkConfiguration> +#include <QNetworkInterface> + +//Start/stop interface watchers/notifications +void OSInterface::start(){ + setupMediaWatcher(); //will create/connect the filesystem watcher automatically + setupNetworkManager(); +} + +void OSInterface::stop(){ + if(isRunning()){ + watcher->deleteLater(); + watcher = 0; + } +} + +bool OSInterface::isRunning(){ return (watcher!=0); } //status of the object - whether it has been started yet + +// = Battery = +bool OSInterface::batteryAvailable(){ return false; } +float OSInterface::batteryCharge(){ return -1; } +bool OSInterface::batteryCharging(){ return false; } +double OSInterface::batterySecondsLeft(){ return -1; } + +// = Volume = +bool OSInterface::volumeAvailable(){ return false; } +int OSInterface::volume(){ return -1; } +void OSInterface::setVolume(int){} + +// = Network Information = +bool OSInterface::networkAvailable(){ + if(INFO.contains("netaccess/available")){ return INFO.value("netaccess/available").toBool(); } + return false; +} + +QString OSInterface::networkType(){ + if(INFO.contains("netaccess/type")){ return INFO.value("netaccess/type").toString(); } //"wifi", "wired", or "cell" + return ""; +} + +float OSInterface::networkStrength(){ return -1; } //percentage. ("wired" type should always be 100%) + +QString OSInterface::networkHostname(){ + return QHostInfo::localHostName(); +} + +QHostAddress OSInterface::networkAddress(){ + QString addr; + if(INFO.contains("netaccess/address")){ addr = INFO.value("netaccess/address").toString(); } + return QHostAddress(addr); +} +// = Network Modification = + +// = Media Shortcuts = +QStringList OSInterface::mediaDirectories(){ return QStringList() << "/media"; } //directory where XDG shortcuts are placed for interacting with media (local/remote) +QStringList OSInterface::mediaShortcuts(){ return autoHandledMediaFiles(); } //List of currently-available XDG shortcut file paths + +// = Updates = +bool OSInterface::updatesAvailable(){ return false; } +QString OSInterface::updateDetails(){ return QString(); } //Information about any available updates +bool OSInterface::updatesRunning(){ return false; } +QString OSInterface::updateLog(){ return QString(); } //Information about any currently-running update +bool OSInterface::updatesFinished(){ return false; } +QString OSInterface::updateResults(){ return QString(); } //Information about any finished update +void OSInterface::startUpdates(){} +bool OSInterface::updateOnlyOnReboot(){ return false; } //Should the startUpdates function be called only when rebooting the system? +QDateTime OSInterface::lastUpdate(){ return QDateTime(); } //The date/time of the previous updates +QString OSInterface::lastUpdateResults(){ return QString(); } //Information about the previously-finished update + +// = System Power = +bool OSInterface::canReboot(){ return false; } +void OSInterface::startReboot(){} +bool OSInterface::canShutdown(){ return false; } +void OSInterface::startShutdown(){} +bool OSInterface::canSuspend(){ return false; } +void OSInterface::startSuspend(){} + +// = Screen Brightness = +int OSInterface::brightness(){ return -1; } //percentage: 0-100 with -1 for errors +void OSInterface::setBrightness(int){} + +// = System Status Monitoring +QList<int> OSInterface::cpuPercentage(){ return QList<int>(); } // (one per CPU) percentage: 0-100 with empty list for errors +QStringList OSInterface::cpuTemperatures(){ return QStringList(); } // (one per CPU) Temperature of CPU ("50C" for example) +int OSInterface::memoryUsedPercentage(){ return -1; } //percentage: 0-100 with -1 for errors +QString OSInterface::memoryTotal(){ return QString(); } //human-readable form - does not tend to change within a session +QStringList OSInterface::diskIO(){ return QStringList(); } //Returns list of current read/write stats for each device +int OSInterface::fileSystemPercentage(QString dir){ return -1; } //percentage of capacity used: 0-100 with -1 for errors +QString OSInterface::fileSystemCapacity(QString dir){ return QString(); } //human-readable form - total capacity + +// = OS-Specific Utilities = +bool OSInterface::hasControlPanel(){ return false; } +QString OSInterface::controlPanelShortcut(){ return QString(); } //relative *.desktop shortcut name (Example: "some_utility.desktop") +bool OSInterface::hasAudioMixer(){ return false; } +QString OSInterface::audioMixerShortcut(){ return QString(); } //relative *.desktop shortcut name (Example: "some_utility.desktop") +bool OSInterface::hasAppStore(){ return false; } +QString OSInterface::appStoreShortcut(){ return QString(); } //relative *.desktop shortcut name (Example: "some_utility.desktop") + +//FileSystemWatcher slots +void OSInterface::watcherFileChanged(QString){} +void OSInterface::watcherDirChanged(QString dir){ + if(handleMediaDirChange(dir)){ return; } +} + +//IO Device slots +void OSInterface::iodeviceReadyRead(){} +void OSInterface::iodeviceAboutToClose(){} + +//NetworkAccessManager slots +void OSInterface::netAccessChanged(QNetworkAccessManager::NetworkAccessibility stat){ + INFO.insert("netaccess/available", stat== QNetworkAccessManager::Accessible); + //Update all the other network status info at the same time + QNetworkConfiguration active = netman->activeConfiguration(); + //Type of connection + QString type; + switch(active.bearerTypeFamily()){ + case QNetworkConfiguration::BearerEthernet: type="wired"; break; + case QNetworkConfiguration::BearerWLAN: type="wifi"; break; + case QNetworkConfiguration::Bearer2G: type="cell-2G"; break; + case QNetworkConfiguration::Bearer3G: type="cell-3G"; break; + case QNetworkConfiguration::Bearer4G: type="cell-4G"; break; + default: type=""; + } + INFO.insert("netaccess/type", type); + qDebug() << "Detected Device Status:" << active.identifier() << type << stat; + QNetworkInterface iface = QNetworkInterface::interfaceFromName(active.name()); + qDebug() << " - Configuration: Name:" << active.name() << active.bearerTypeName() << active.identifier(); + qDebug() << " - Interface: MAC Address:" << iface.hardwareAddress() << "Name:" << iface.name() << iface.humanReadableName() << iface.isValid(); + QList<QNetworkAddressEntry> addressList = iface.addressEntries(); + QStringList address; + //NOTE: There are often 2 addresses, IPv4 and IPv6 + for(int i=0; i<addressList.length(); i++){ + address << addressList[i].ip().toString(); + } + qDebug() << " - IP Address:" << address; + qDebug() << " - Hostname:" << networkHostname(); + INFO.insert("netaccess/address", address.join(", ")); + emit networkStatusChanged(); +} + +void OSInterface::netRequestFinished(QNetworkReply*){} +void OSInterface::netSslErrors(QNetworkReply*, const QList<QSslError>&){} +void OSInterface::timerUpdate(){} diff --git a/src-qt5/src-cpp/framework-OSInterface.h b/src-qt5/src-cpp/framework-OSInterface.h new file mode 100644 index 00000000..a173ad5a --- /dev/null +++ b/src-qt5/src-cpp/framework-OSInterface.h @@ -0,0 +1,190 @@ +//=========================================== +// Lumina desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This is the main interface for any OS-specific system calls +// To port Lumina to a different operating system, just create a file +// called "OSInterface-<Operating System>.cpp" +//=========================================== +#ifndef _LUMINA_LIBRARY_OS_INTERFACE_H +#define _LUMINA_LIBRARY_OS_INTERFACE_H + +#include <QString> +#include <QStringList> +#include <QList> +#include <QObject> +#include <QVariant> +#include <QHash> +#include <QTimer> + +#include <QIODevice> +#include <QFileSystemWatcher> +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QSslError> +#include <QHostInfo> +#include <QHostAddress> + +class OSInterface : public QObject{ + Q_OBJECT + // == QML ACCESSIBLE PROPERTIES == + //Battery + Q_PROPERTY( float batteryCharge READ batteryCharge NOTIFY batteryChargeChanged) + Q_PROPERTY( bool batteryCharging READ batteryCharging NOTIFY batteryChargingChanged) + Q_PROPERTY( double batterySecondsLeft READ batterySecondsLeft NOTIFY batterySecondsLeftChanged) + //Volume + Q_PROPERTY( int volume READ volume WRITE setVolume NOTIFY volumeChanged) + //Network + Q_PROPERTY( bool networkAvailable READ networkAvailable NOTIFY networkStatusChanged) + Q_PROPERTY( QString networkType READ networkType NOTIFY networkStatusChanged) + Q_PROPERTY( float networkStrength READ networkStrength NOTIFY networkStatusChanged) + Q_PROPERTY( QString networkHostname READ networkHostname NOTIFY networkStatusChanged) + Q_PROPERTY( QHostAddress networkAddress READ networkAddress NOTIFY networkStatusChanged) + //Media + Q_PROPERTY( QStringList mediaShortcuts READ mediaShortcuts NOTIFY mediaShortcutsChanged) + //Updates + Q_PROPERTY( bool updatesAvailable READ updatesAvailable NOTIFY updateStatusChanged) + Q_PROPERTY( bool updatesRunning READ updatesRunning NOTIFY updateStatusChanged) + Q_PROPERTY( bool updatesFinished READ updatesFinished NOTIFY updateStatusChanged) + //Power options + Q_PROPERTY( bool canReboot READ canReboot NOTIFY powerAvailableChanged) + Q_PROPERTY( bool canShutdown READ canShutdown NOTIFY powerAvailableChanged) + Q_PROPERTY( bool canSuspend READ canSuspend NOTIFY powerAvailableChanged) + //Brightness + Q_PROPERTY( int brightness READ brightness WRITE setBrightness NOTIFY brightnessChanged) + +public: + // ================ + // SEMI-VIRTUAL FUNCTIONS - NEED TO BE DEFINED IN THE OS-SPECIFIC FILES + // ================ + //Start/stop interface watchers/notifications + void start(); + void stop(); + bool isRunning(); //status of the object - whether it has been started yet + + // = Battery = + Q_INVOKABLE bool batteryAvailable(); + Q_INVOKABLE float batteryCharge(); + Q_INVOKABLE bool batteryCharging(); + Q_INVOKABLE double batterySecondsLeft(); + // = Volume = + Q_INVOKABLE bool volumeAvailable(); + Q_INVOKABLE int volume(); + Q_INVOKABLE void setVolume(int); + // = Network Information = + Q_INVOKABLE bool networkAvailable(); + Q_INVOKABLE QString networkType(); //"wifi", "wired", "cell", "cell-2G", "cell-3G", "cell-4G" + Q_INVOKABLE float networkStrength(); //percentage. ("wired" type should always be 100%) + Q_INVOKABLE QString networkHostname(); + Q_INVOKABLE QHostAddress networkAddress(); + // = Network Modification = + + // = Media Shortcuts = + Q_INVOKABLE QStringList mediaDirectories(); //directory where XDG shortcuts are placed for interacting with media (local/remote) + Q_INVOKABLE QStringList mediaShortcuts(); //List of currently-available XDG shortcut file paths + // = Updates = + Q_INVOKABLE bool updatesAvailable(); + Q_INVOKABLE QString updateDetails(); //Information about any available updates + Q_INVOKABLE bool updatesRunning(); + Q_INVOKABLE QString updateLog(); //Information about any currently-running update + Q_INVOKABLE bool updatesFinished(); + Q_INVOKABLE QString updateResults(); //Information about any finished update + Q_INVOKABLE void startUpdates(); + Q_INVOKABLE bool updateOnlyOnReboot(); //Should the startUpdates function be called only when rebooting the system? + Q_INVOKABLE QDateTime lastUpdate(); //The date/time of the previous updates + Q_INVOKABLE QString lastUpdateResults(); //Information about the previously-finished update + // = System Power = + Q_INVOKABLE bool canReboot(); + Q_INVOKABLE void startReboot(); + Q_INVOKABLE bool canShutdown(); + Q_INVOKABLE void startShutdown(); + Q_INVOKABLE bool canSuspend(); + Q_INVOKABLE void startSuspend(); + // = Screen Brightness = + Q_INVOKABLE int brightness(); //percentage: 0-100 with -1 for errors + Q_INVOKABLE void setBrightness(int); + // = System Status Monitoring + Q_INVOKABLE QList<int> cpuPercentage(); // (one per CPU) percentage: 0-100 with -1 for errors + Q_INVOKABLE QStringList cpuTemperatures(); // (one per CPU) Temperature of CPU ("50C" for example) + Q_INVOKABLE int memoryUsedPercentage(); //percentage: 0-100 with -1 for errors + Q_INVOKABLE QString memoryTotal(); //human-readable form - does not tend to change within a session + Q_INVOKABLE QStringList diskIO(); //Returns list of current read/write stats for each device + Q_INVOKABLE int fileSystemPercentage(QString dir); //percentage of capacity used: 0-100 with -1 for errors + Q_INVOKABLE QString fileSystemCapacity(QString dir); //human-readable form - total capacity + // = OS-Specific Utilities = + Q_INVOKABLE bool hasControlPanel(); + Q_INVOKABLE QString controlPanelShortcut(); //relative *.desktop shortcut name (Example: "some_utility.desktop") + Q_INVOKABLE bool hasAudioMixer(); + Q_INVOKABLE QString audioMixerShortcut(); //relative *.desktop shortcut name (Example: "some_utility.desktop") + Q_INVOKABLE bool hasAppStore(); + Q_INVOKABLE QString appStoreShortcut(); //relative *.desktop shortcut name (Example: "some_utility.desktop") + +private slots: + // ================ + // SEMI-VIRTUAL FUNCTIONS - NEED TO BE DEFINED IN THE OS-SPECIFIC FILES + // ================ + //FileSystemWatcher slots + void watcherFileChanged(QString); + void watcherDirChanged(QString); + //IO Device slots + void iodeviceReadyRead(); + void iodeviceAboutToClose(); + //NetworkAccessManager slots + void netAccessChanged(QNetworkAccessManager::NetworkAccessibility); + void netRequestFinished(QNetworkReply*); + void netSslErrors(QNetworkReply*, const QList<QSslError>&); + //Timer slots + void timerUpdate(); + +signals: + void batteryChargeChanged(); + void batteryChargingChanged(); + void batterySecondsLeftChanged(); + void volumeChanged(); + void networkStatusChanged(); + void mediaShortcutsChanged(); + void updateStatusChanged(); + void powerAvailableChanged(); + void brightnessChanged(); + +private: + //Internal persistant data storage, OS-specific usage implementation + QHash< QString, QVariant> INFO; + + // ============ + // Internal possibilities for watching the system (OS-Specific usage/implementation) + // ============ + //File System Watcher + QFileSystemWatcher *watcher; + //IO Device (QLocalSocket, QTcpConnection, QFile, etc) + QIODevice *iodevice; + //Network Access Manager (check network connectivity, etc) + QNetworkAccessManager *netman; + //Timer for regular probes/updates + QTimer *timer; + + // Internal implifications for connecting the various watcher objects to their respective slots + // (OS-agnostic - defined in the "OSInterface_private.cpp" file) + void connectWatcher(); //setup the internal connections *only* + void connectIodevice(); //setup the internal connections *only* + void connectNetman(); //setup the internal connections *only* + void connectTimer(); //setup the internal connections *only* + + // External Media Management (if system uses *.desktop shortcuts only) + void setupMediaWatcher(); + bool handleMediaDirChange(QString dir); //returns true if directory was handled + QStringList autoHandledMediaFiles(); + + // Qt-based NetworkAccessManager usage + void setupNetworkManager(); + +public: + OSInterface(QObject *parent = 0); + ~OSInterface(); + + static OSInterface* instance(); //Get the currently-active instance of this class (or make a new one) + +}; +#endif diff --git a/src-qt5/src-cpp/framework-OSInterface.pri b/src-qt5/src-cpp/framework-OSInterface.pri new file mode 100644 index 00000000..be705e44 --- /dev/null +++ b/src-qt5/src-cpp/framework-OSInterface.pri @@ -0,0 +1,9 @@ +QT *= core network + +HEADERS *= $${PWD}/framework-OSInterface.h +SOURCES *= $${PWD}/framework-OSInterface_private.cpp + +_os=template +SOURCES *= $${PWD}/framework-OSInterface-$${_os}.cpp + +INCLUDEPATH *= $${PWD} diff --git a/src-qt5/src-cpp/framework-OSInterface_private.cpp b/src-qt5/src-cpp/framework-OSInterface_private.cpp new file mode 100644 index 00000000..d15d9be8 --- /dev/null +++ b/src-qt5/src-cpp/framework-OSInterface_private.cpp @@ -0,0 +1,110 @@ +//=========================================== +// Lumina desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// Internal, OS-agnostic functionality for managing the object itself +//=========================================== +#include <framework-OSInterface.h> +#include <QFile> +#include <QDir> +#include <QVariant> + +OSInterface::OSInterface(QObject *parent) : QObject(parent){ + watcher = 0; + iodevice = 0; + netman = 0; +} + +OSInterface::~OSInterface(){ + if(watcher!=0){ + QStringList paths; paths << watcher->files() << watcher->directories(); + if(!paths.isEmpty()){ watcher->removePaths(paths); } + watcher->deleteLater(); + } + if(iodevice!=0){ + if(iodevice->isOpen()){ iodevice->close(); } + iodevice->deleteLater(); + } + if(netman!=0){ + netman->deleteLater(); + } +} + +OSInterface* OSInterface::instance(){ + static OSInterface* m_os_object = 0; + if(m_os_object==0){ + m_os_object = new OSInterface(); + } + return m_os_object; +} + +void OSInterface::connectWatcher(){ + if(watcher==0){ return; } + connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(watcherFileChanged(QString)) ); + connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(watcherDirChanged(QString)) ); +} + +void OSInterface::connectIodevice(){ + if(iodevice==0){ return; } + connect(iodevice, SIGNAL(readyRead()), this, SLOT(iodeviceReadyRead()) ); +} + +void OSInterface::connectNetman(){ + if(netman==0){ return; } + connect(netman, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(netAccessChanged(QNetworkAccessManager::NetworkAccessibility)) ); + connect(netman, SIGNAL(finished(QNetworkReply*)), this, SLOT(netRequestFinished(QNetworkReply*)) ); + connect(netman, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(netSslErrors(QNetworkReply*, const QList<QSslError>&)) ); +} + +void OSInterface::connectTimer(){ + if(timer==0){ return; } + connect(timer, SIGNAL(timeout()), this, SLOT(timerUpdate()) ); +} + +// External Media Management (if system uses *.desktop shortcuts) +void OSInterface::setupMediaWatcher(){ + //Create/connect the watcher if needed + if(watcher == 0){ watcher = new QFileSystemWatcher(); connectWatcher(); } + QStringList dirs = this->mediaDirectories(); + if(dirs.isEmpty()){ return; } //nothing to do + //Make sure each directory is scanned **right now** (if it exists) + for(int i=0; i<dirs.length(); i++){ + if(QFile::exists(dirs[i])){ + handleMediaDirChange(dirs[i]); + } + } +} + +bool OSInterface::handleMediaDirChange(QString dir){ //returns true if directory was handled + if( !this->mediaDirectories().contains(dir) ){ return false; } //not a media directory + QDir qdir(dir); + QStringList files = qdir.entryList(QStringList() << "*.desktop", QDir::Files, QDir::Name); + for(int i=0; i<files.length(); i++){ files[i] = qdir.absoluteFilePath(files[i]); } + QString key = "media_files/"+dir; + if(files.isEmpty() && INFO.contains(key)){ INFO.remove(key); emit mediaShortcutsChanged(); } //no files for this directory at the moment + else{ INFO.insert("media_files/"+dir, files); emit mediaShortcutsChanged(); } //save these file paths for later + //Make sure the directory is still watched (sometimes the dir is removed/recreated on modification) + if(!watcher->directories().contains(dir)){ watcher->addPath(dir); } + return true; +} + +QStringList OSInterface::autoHandledMediaFiles(){ + QStringList files; + QStringList keys = INFO.keys().filter("media_files/"); + for(int i=0; i<keys.length(); i++){ + if(keys[i].startsWith("media_files/")){ files << INFO[keys[i]].toStringList(); } + } + return files; +} + +// Qt-based NetworkAccessManager usage +void OSInterface::setupNetworkManager(){ + if(netman==0){ + netman = new QNetworkAccessManager(this); + connectNetman(); + } + //Load the initial state of the network accessibility + netAccessChanged(netman->networkAccessible()); +} diff --git a/src-qt5/src-cpp/plugins-base.cpp b/src-qt5/src-cpp/plugins-base.cpp new file mode 100644 index 00000000..f38374df --- /dev/null +++ b/src-qt5/src-cpp/plugins-base.cpp @@ -0,0 +1,50 @@ +//=========================================== +// Lumina-desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "plugins-base.h" + +// ============ +// Base PLUGIN +// ============ +BasePlugin::BasePlugin(){ + +} + +BasePlugin::~BasePlugin(){ + +} + +void BasePlugin::loadFile(QString path){ + data = QJsonObject(); + currentfile = path; + QFile file(path); + if(!file.exists() || !file.open(QIODevice::ReadOnly)){ return; } + data = QJsonDocument::fromJson(file.readAll()).object(); + //qDebug() << "Loaded ScreenSaver Data:" << currentfile << data; + file.close(); +} + +QString BasePlugin::translatedObject(QString obj){ + QJsonObject tmp = data.value(obj).toObject(); + //Get the current locale + QString locale = getenv("LC_ALL"); + if(locale.isEmpty()){ locale = getenv("LC_MEBaseAGES"); } + if(locale.isEmpty()){ locale = getenv("LANG"); } + if(locale.isEmpty()){ locale = "default"; } + if(locale.contains(".")){ locale = locale.section(".",0,0); } //chop any charset code off the end + //Now find which localized string is available and return it + if(tmp.contains(locale)){ return tmp.value(locale).toString(); } + locale = locale.section("_",0,0); //full locale not found - look for shortened form + if(tmp.contains(locale)){ return tmp.value(locale).toString(); } + return tmp.value("default").toString(); //use the default version +} + +QUrl BasePlugin::scriptURL(){ + QString exec = data.value("qml").toObject().value("exec").toString(); + if(!exec.startsWith("/")){ exec.prepend( currentfile.section("/",0,-2)+"/" ); } + return QUrl::fromLocalFile(exec); +} + diff --git a/src-qt5/src-cpp/plugins-base.h b/src-qt5/src-cpp/plugins-base.h new file mode 100644 index 00000000..26b0eacc --- /dev/null +++ b/src-qt5/src-cpp/plugins-base.h @@ -0,0 +1,107 @@ +//=========================================== +// Lumina-desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This is a simple class for managing all the various desktop +// screensaver plugins that could be available +//=========================================== +// NOTE: +// This class has a heirarchy-based lookup system +// USER plugins > SYSTEM plugins +// XDG_DATA_HOME/lumina-desktop/screensavers > XDG_DATA_DIRS/lumina-desktop/screensavers +//=========================================== +#ifndef _LUMINA_DESKTOP_BASE_PLUGINS_CLASS_H +#define _LUMINA_DESKTOP_BASE_PLUGINS_CLASS_H + +#include <QJsonObject> +#include <QString> +#include <QUrl> +#include <QObject> +#include <QJsonDocument> +#include <QJsonArray> +#include <QFile> +#include <QDir> +#include <QDebug> + +class BasePlugin{ +protected: + QString currentfile; + +public: + BasePlugin(); + virtual ~BasePlugin(); + + virtual void loadFile(QString path); + bool isLoaded() { return !data.isEmpty(); }; + bool containsDefault(QString obj) { return data.value(obj).toObject().contains("default"); } + + /** + * Check if the plugin is valid as long as the JSON is not empty, + * it contains at least a "name", "qml", and "description" object, + * and the "name" and "description" objects contain a "default" key. + **/ + virtual bool isValid() = 0; + + virtual QString translatedObject(QString obj); + virtual QUrl scriptURL(); + + QJsonObject data; //Hazardous to manually modify + QString relDir; +}; + +class PluginSystem{ +public: + template <class T> + static T findPlugin(QString, QString); + + template <class T> + static QList<T> findAllPlugins(QString, bool validonly=true); +}; + +// =================== +// Base PLUGIN SYSTEM +// =================== +template <class T> +T PluginSystem::findPlugin(QString name, QString REL_DIR){ + //qDebug() << "FindPlugin:" << name; + T BaseP; + if(name.startsWith("/") && QFile::exists(name)){ BaseP.loadFile(name); return BaseP;} //absolute path give - just load that one + //Cleanup the input name and ensure it has the right suffix + name = name.section("/",-1); + if(!name.endsWith(".json")){ name.append(".json"); } + //Get the list of directories to search + QStringList dirs; + dirs << QString(getenv("XDG_DATA_HOME")) << QString(getenv("XDG_DATA_DIRS")).split(":"); + //Look for that file within these directories and return the first one found + for(int i=0; i<dirs.length(); i++){ + if(!QFile::exists(dirs[i]+REL_DIR+"/"+name)){ continue; } + BaseP.loadFile(dirs[i]+REL_DIR+"/"+name); + if(BaseP.isValid()){ break; } //got a good one - stop here + } + return BaseP; +} + +template <class T> +QList<T> PluginSystem::findAllPlugins(QString REL_DIR, bool validonly) { + QList<T> LIST; + //Get the list of directories to search + QStringList dirs; + dirs << QString(getenv("XDG_DATA_HOME")) << QString(getenv("XDG_DATA_DIRS")).split(":"); + //Look for that file within these directories and return the first one found + for(int i=0; i<dirs.length(); i++){ + if(!QFile::exists(dirs[i]+REL_DIR)){ continue; } + QDir dir(dirs[i]+REL_DIR); + QStringList files = dir.entryList(QStringList() << "*.json", QDir::Files, QDir::Name); + //qDebug() << "Found Files:" << files; + for(int j=0; j<files.length(); j++){ + T tmp; + tmp.loadFile(dir.absoluteFilePath(files[j])); + //qDebug() << "Loaded File:" << files[j] << tmp.isValid(); + if(!validonly || tmp.isValid()){ LIST << tmp; } + } + } + return LIST; +} +#endif diff --git a/src-qt5/src-cpp/plugins-base.pri b/src-qt5/src-cpp/plugins-base.pri new file mode 100644 index 00000000..4aa9d96e --- /dev/null +++ b/src-qt5/src-cpp/plugins-base.pri @@ -0,0 +1,8 @@ +HEADERS *= $${PWD}/plugins-base.h \ + $${PWD}/plugins-screensaver.h \ + $${PWD}/plugins-desktop.h +SOURCES *= $${PWD}/plugins-base.cpp \ + $${PWD}/plugins-screensaver.cpp \ + $${PWD}/plugins-desktop.cpp + +INCLUDEPATH *= $${PWD} diff --git a/src-qt5/src-cpp/plugins-desktop.cpp b/src-qt5/src-cpp/plugins-desktop.cpp new file mode 100644 index 00000000..fdbd676d --- /dev/null +++ b/src-qt5/src-cpp/plugins-desktop.cpp @@ -0,0 +1,40 @@ +//=========================================== +// Lumina-desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "plugins-desktop.h" + +// ============ +// DT PLUGIN +// ============ +DTPlugin::DTPlugin(){ + +} + +DTPlugin::~DTPlugin(){ + +} + +bool DTPlugin::isValid(){ + if(data.isEmpty()){ return false; } + bool ok = data.contains("name") && data.contains("qml") && data.contains("description"); + ok &= containsDefault("name"); + ok &= containsDefault("description"); + if(ok) { + QJsonObject tmp = data.value("qml").toObject(); + QStringList mustexist; + QString exec = tmp.value("exec").toString(); + if(exec.isEmpty() || !exec.endsWith(".qml")){ return false; } + mustexist << exec; + QJsonArray tmpA = data.value("additional_files").toArray(); + for(int i=0; i<tmpA.count(); i++){ mustexist << tmpA[i].toString(); } + QString reldir = currentfile.section("/",0,-2) + "/"; + for(int i=0; i<mustexist.length() && ok; i++){ + if(mustexist[i].startsWith("/")){ ok = QFile::exists(mustexist[i]); } + else { ok = QFile::exists(reldir+mustexist[i]); } + } + } + return ok; +} diff --git a/src-qt5/src-cpp/plugins-desktop.h b/src-qt5/src-cpp/plugins-desktop.h new file mode 100644 index 00000000..ed576db1 --- /dev/null +++ b/src-qt5/src-cpp/plugins-desktop.h @@ -0,0 +1,29 @@ +//=========================================== +// Lumina-desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#ifndef _LUMINA_DESKTOP_DESKTOP_PLUGINS_CLASS_H +#define _LUMINA_DESKTOP_DESKTOP_PLUGINS_CLASS_H + +#include "plugins-base.h" +#include <QJsonObject> +#include <QString> +#include <QUrl> +#include <QObject> +#include <QJsonDocument> +#include <QJsonArray> +#include <QFile> +#include <QDir> +#include <QDebug> + +class DTPlugin : public BasePlugin{ +public: + DTPlugin(); + ~DTPlugin(); + + virtual bool isValid() Q_DECL_OVERRIDE; +}; + +#endif diff --git a/src-qt5/src-cpp/plugins-screensaver.cpp b/src-qt5/src-cpp/plugins-screensaver.cpp index 4cb90aff..6370b068 100644 --- a/src-qt5/src-cpp/plugins-screensaver.cpp +++ b/src-qt5/src-cpp/plugins-screensaver.cpp @@ -5,14 +5,6 @@ // See the LICENSE file for full details //=========================================== #include "plugins-screensaver.h" -#include <QJsonDocument> -#include <QJsonArray> -#include <QFile> -#include <QDir> -#include <QDebug> - -//Relative directory to search along the XDG paths for screensavers -#define REL_DIR QString("/lumina-desktop/screensavers") // ============ // SS PLUGIN @@ -25,35 +17,12 @@ SSPlugin::~SSPlugin(){ } -void SSPlugin::loadFile(QString path){ - data = QJsonObject(); - currentfile = path; - QFile file(path); - if(!file.exists() || !file.open(QIODevice::ReadOnly)){ return; } - data = QJsonDocument::fromJson(file.readAll()).object(); - qDebug() << "Loaded ScreenSaver Data:" << currentfile << data; - file.close(); -} - -bool SSPlugin::isLoaded(){ - return !data.isEmpty(); -} - bool SSPlugin::isValid(){ if(data.isEmpty()){ return false; } bool ok = data.contains("name") && data.contains("qml") && data.contains("description"); - if(ok){ - //go to the next name level and see if required sub-items exist - QJsonObject tmp = data.value("name").toObject(); - ok = tmp.contains("default"); - } - if(ok){ - //go to the next description level and see if required sub-items exist - QJsonObject tmp = data.value("description").toObject(); - ok = tmp.contains("default"); - } -if(ok){ - //go to the next qml level and see if required sub-items exist + ok &= containsDefault("name"); + ok &= containsDefault("description"); + if(ok) { QJsonObject tmp = data.value("qml").toObject(); QStringList mustexist; QString exec = tmp.value("exec").toString(); @@ -62,7 +31,6 @@ if(ok){ QJsonArray tmpA = data.value("additional_files").toArray(); for(int i=0; i<tmpA.count(); i++){ mustexist << tmpA[i].toString(); } QString reldir = currentfile.section("/",0,-2) + "/"; - //qDebug() << "Got MustExist:" << mustexist << reldir; for(int i=0; i<mustexist.length() && ok; i++){ if(mustexist[i].startsWith("/")){ ok = QFile::exists(mustexist[i]); } else { ok = QFile::exists(reldir+mustexist[i]); } @@ -70,83 +38,3 @@ if(ok){ } return ok; } - -QString SSPlugin::translatedName(){ - QJsonObject tmp = data.value("name").toObject(); - //Get the current locale - QString locale = getenv("LC_ALL"); - if(locale.isEmpty()){ locale = getenv("LC_MESSAGES"); } - if(locale.isEmpty()){ locale = getenv("LANG"); } - if(locale.isEmpty()){ locale = "default"; } - if(locale.contains(".")){ locale = locale.section(".",0,0); } //chop any charset code off the end - //Now find which localized string is available and return it - if(tmp.contains(locale)){ return tmp.value(locale).toString(); } - locale = locale.section("_",0,0); //full locale not found - look for shortened form - if(tmp.contains(locale)){ return tmp.value(locale).toString(); } - return tmp.value("default").toString(); //use the default version -} - -QString SSPlugin::translatedDescription(){ - QJsonObject tmp = data.value("description").toObject(); - //Get the current locale - QString locale = getenv("LC_ALL"); - if(locale.isEmpty()){ locale = getenv("LC_MESSAGES"); } - if(locale.isEmpty()){ locale = getenv("LANG"); } - if(locale.isEmpty()){ locale = "default"; } - if(locale.contains(".")){ locale = locale.section(".",0,0); } //chop any charset code off the end - //Now find which localized string is available and return it - if(tmp.contains(locale)){ return tmp.value(locale).toString(); } - locale = locale.section("_",0,0); //full locale not found - look for shortened form - if(tmp.contains(locale)){ return tmp.value(locale).toString(); } - return tmp.value("default").toString(); //use the default version -} - -QUrl SSPlugin::scriptURL(){ - QString exec = data.value("qml").toObject().value("exec").toString(); - qDebug() << "got exec:" << exec << data; - if(!exec.startsWith("/")){ exec.prepend( currentfile.section("/",0,-2)+"/" ); } - return QUrl::fromLocalFile(exec); -} - -// =================== -// SS PLUGIN SYSTEM -// =================== -SSPlugin SSPluginSystem::findPlugin(QString name){ - //qDebug() << "FindPlugin:" << name; - SSPlugin SSP; - if(name.startsWith("/") && QFile::exists(name)){ SSP.loadFile(name); return SSP;} //absolute path give - just load that one - //Cleanup the input name and ensure it has the right suffix - name = name.section("/",-1); - if(!name.endsWith(".json")){ name.append(".json"); } - //Get the list of directories to search - QStringList dirs; - dirs << QString(getenv("XDG_DATA_HOME")) << QString(getenv("XDG_DATA_DIRS")).split(":"); - //Look for that file within these directories and return the first one found - for(int i=0; i<dirs.length(); i++){ - if(!QFile::exists(dirs[i]+REL_DIR+"/"+name)){ continue; } - SSP.loadFile(dirs[i]+REL_DIR+"/"+name); - if(SSP.isValid()){ break; } //got a good one - stop here - } - return SSP; -} - -QList<SSPlugin> SSPluginSystem::findAllPlugins(bool validonly){ - QList<SSPlugin> LIST; - //Get the list of directories to search - QStringList dirs; - dirs << QString(getenv("XDG_DATA_HOME")) << QString(getenv("XDG_DATA_DIRS")).split(":"); - //Look for that file within these directories and return the first one found - for(int i=0; i<dirs.length(); i++){ - if(!QFile::exists(dirs[i]+REL_DIR)){ continue; } - QDir dir(dirs[i]+REL_DIR); - QStringList files = dir.entryList(QStringList() << "*.json", QDir::Files, QDir::Name); - //qDebug() << "Found Files:" << files; - for(int j=0; j<files.length(); j++){ - SSPlugin tmp; - tmp.loadFile(dir.absoluteFilePath(files[j])); - //qDebug() << "Loaded File:" << files[j] << tmp.isValid(); - if(!validonly || tmp.isValid()){ LIST << tmp; } - } - } - return LIST; -} diff --git a/src-qt5/src-cpp/plugins-screensaver.h b/src-qt5/src-cpp/plugins-screensaver.h index 9a7e98f5..042f824d 100644 --- a/src-qt5/src-cpp/plugins-screensaver.h +++ b/src-qt5/src-cpp/plugins-screensaver.h @@ -4,47 +4,26 @@ // Available under the 3-clause BSD license // See the LICENSE file for full details //=========================================== -// This is a simple class for managing all the various desktop -// screensaver plugins that could be available -//=========================================== -// NOTE: -// This class has a heirarchy-based lookup system -// USER plugins > SYSTEM plugins -// XDG_DATA_HOME/lumina-desktop/screensavers > XDG_DATA_DIRS/lumina-desktop/screensavers -//=========================================== #ifndef _LUMINA_DESKTOP_SCREENSAVER_PLUGINS_CLASS_H #define _LUMINA_DESKTOP_SCREENSAVER_PLUGINS_CLASS_H +#include "plugins-base.h" #include <QJsonObject> #include <QString> #include <QUrl> #include <QObject> +#include <QJsonDocument> +#include <QJsonArray> +#include <QFile> +#include <QDir> +#include <QDebug> -class SSPlugin{ -private: - QString currentfile; - +class SSPlugin : public BasePlugin { public: - QJsonObject data; //Hazardous to manually modify - SSPlugin(); ~SSPlugin(); - void loadFile(QString path); - bool isLoaded(); - - bool isValid(); - - QString translatedName(); - QString translatedDescription(); - QUrl scriptURL(); -}; - -class SSPluginSystem{ -public: - static SSPlugin findPlugin(QString name); - static QList<SSPlugin> findAllPlugins(bool validonly = true); - + virtual bool isValid() Q_DECL_OVERRIDE; }; #endif diff --git a/src-qt5/src-cpp/plugins-screensaver.pri b/src-qt5/src-cpp/plugins-screensaver.pri deleted file mode 100644 index ad03f34c..00000000 --- a/src-qt5/src-cpp/plugins-screensaver.pri +++ /dev/null @@ -1,4 +0,0 @@ -HEADERS *= $${PWD}/plugins-screensaver.h -SOURCES *= $${PWD}/plugins-screensaver.cpp - -INCLUDEPATH *= $${PWD} diff --git a/src-qt5/src-cpp/tests/main.cpp b/src-qt5/src-cpp/tests/main.cpp new file mode 100644 index 00000000..682c318a --- /dev/null +++ b/src-qt5/src-cpp/tests/main.cpp @@ -0,0 +1,38 @@ +#include <QDebug> +#include <QApplication> + +#include <framework-OSInterface.h> + +/* +class tester : public QObject{ + Q_OBJECT +public slots: + void finished(){ QApplication::exit(0); } + +public: + QTimer *timer; + + tester(){ + timer = new QTimer(this); + timer->setInterval(5000); + timer->setSingleShot(true); + connect(timer, SIGNAL(timeout()), this, SLOT(finished()) ); + } + +}; +*/ + +int main(int argc, char** argv){ + + QApplication A(argc,argv); + OSInterface OS; + OS.start(); + QTimer *timer = new QTimer(); + timer->setInterval(5000); + timer->setSingleShot(true); + QObject::connect(timer, SIGNAL(timeout()), &A, SLOT(quit()) ); + timer->start(); + int ret = A.exec(); + qDebug() << " - Finished"; + return ret; +} diff --git a/src-qt5/src-cpp/tests/test.pro b/src-qt5/src-cpp/tests/test.pro new file mode 100644 index 00000000..425e7de6 --- /dev/null +++ b/src-qt5/src-cpp/tests/test.pro @@ -0,0 +1,7 @@ +QT = core gui widgets + +include(../framework-OSInterface.pri) + +TARGET = test + +SOURCES += main.cpp |