aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Moore <ken@ixsystems.com>2018-02-01 17:10:42 -0500
committerKen Moore <ken@ixsystems.com>2018-02-01 17:10:42 -0500
commit6f251cac292ee2657ec60e0e33ba02e3d08fade8 (patch)
tree5f5d7eacbf12bff4d7dd6061a8b5b747f12a8fa8
parentFix up the single application numbering. (diff)
downloadlumina-6f251cac292ee2657ec60e0e33ba02e3d08fade8.tar.gz
lumina-6f251cac292ee2657ec60e0e33ba02e3d08fade8.tar.bz2
lumina-6f251cac292ee2657ec60e0e33ba02e3d08fade8.zip
Get the FreeBSD OSInterface class all setup.
Also test/fix some stuff in the build side of things. OSInterface no longer uses the LUtils and LXDG classes from libLumina.
-rw-r--r--src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/plugins/status_tray/BatteryButton.qml2
-rw-r--r--src-qt5/src-cpp/framework-OSInterface-FreeBSD.cpp245
-rw-r--r--src-qt5/src-cpp/framework-OSInterface-template.cpp10
-rw-r--r--src-qt5/src-cpp/framework-OSInterface.h22
-rw-r--r--src-qt5/src-cpp/framework-OSInterface.pri17
-rw-r--r--src-qt5/src-cpp/framework-OSInterface_private.cpp120
6 files changed, 383 insertions, 33 deletions
diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/plugins/status_tray/BatteryButton.qml b/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/plugins/status_tray/BatteryButton.qml
index 38ed6a64..8603e072 100644
--- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/plugins/status_tray/BatteryButton.qml
+++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/plugins/status_tray/BatteryButton.qml
@@ -16,5 +16,5 @@ ToolButton{
iconName: os.batteryIcon
tooltip: os.batteryCharge+"%: "+os.batteryRemaining
visible: os.batteryAvailable()
- enabled: false
+ //enabled: false
}
diff --git a/src-qt5/src-cpp/framework-OSInterface-FreeBSD.cpp b/src-qt5/src-cpp/framework-OSInterface-FreeBSD.cpp
new file mode 100644
index 00000000..a1bdbdca
--- /dev/null
+++ b/src-qt5/src-cpp/framework-OSInterface-FreeBSD.cpp
@@ -0,0 +1,245 @@
+//===========================================
+// Lumina desktop source code
+// Copyright (c) 2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// FreeBSD/TrueOS specific OS Interactions
+//===========================================
+// USEFUL INTERNAL FUNCTIONS:
+//----------------------------------------------
+// bool verifyAppOrBin(QString chk)
+//===========================================
+#include <framework-OSInterface.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+
+// = Battery =
+bool OSInterface::OS_batteryAvailable(){
+ static int bat_avail = -1; //this will not change during a single session - keep later calls fast
+ if(bat_avail < 0){
+ int val = getCmdOutput("apm -l").join("").toInt();
+ bat_avail = ((val >= 0 && val <= 100) ? 1 : 0 );
+ }
+ return (bat_avail==1);
+}
+
+float OSInterface::OS_batteryCharge(){
+ int charge = getCmdOutput("apm -l").join("").toInt();
+ if(charge > 100){ charge = -1; } //invalid charge
+ return charge;
+}
+
+bool OSInterface::OS_batteryCharging(){
+ return (getCmdOutput("apm -a").join("").simplified() == "1");
+}
+
+double OSInterface::OS_batterySecondsLeft(){ //Returns: estimated number of seconds remaining
+ return getCmdOutput("apm -t").join("").toDouble();
+}
+
+// = Volume =
+bool OSInterface::OS_volumeSupported(){ return true; }
+int OSInterface::OS_volume(){
+ int out = -1;
+ /*bool remoteSession = !QString(getenv("PICO_CLIENT_LOGIN")).isEmpty();
+ if(remoteSession){
+ QStringList info = getCmdOutput("pactl list short sinks");
+ qDebug() << "Got PA sinks:" << info;
+ out = 50; //TEMPORARY - still need to write up the info parsing
+ }else{*/
+ //probe the system for the current volume (other utils could be changing it)
+ QString info = getCmdOutput("mixer -S vol").join(":").simplified(); //ignores any other lines
+ if(!info.isEmpty()){
+ int L = info.section(":",1,1).toInt();
+ int R = info.section(":",2,2).toInt();
+ if(L>R){ out = L; }
+ else{ out = R; }
+ }
+ //} //end of Remote Session check
+ return out;
+}
+
+bool OSInterface::OS_setVolume(int percent){
+ if(percent<0){percent=0;}
+ else if(percent>100){percent=100;}
+ /*bool remoteSession = !QString(getenv("PICO_CLIENT_LOGIN")).isEmpty();
+ if(remoteSession){
+ runCmd(QString("pactl set-sink-volume @DEFAULT_SINK@ ")+QString::number(percent)+"%");
+ }else{*/
+ QString info = getCmdOutput("mixer -S vol").join(":").simplified(); //ignores any other lines
+ if(!info.isEmpty()){
+ int L = info.section(":",1,1).toInt();
+ int R = info.section(":",2,2).toInt();
+ int diff = L-R;
+ if((percent == L) && (L==R)){ return false; } //already set to that volume
+ if(diff<0){ R=percent; L=percent+diff; } //R Greater
+ else{ L=percent; R=percent-diff; } //L Greater or equal
+ //Check bounds
+ if(L<0){L=0;}else if(L>100){L=100;}
+ if(R<0){R=0;}else if(R>100){R=100;}
+ //Run Command
+ return (0==runCmd("mixer vol "+QString::number(L)+":"+QString::number(R)) );
+ }
+ //} //end of Remote Session check
+ return false;
+}
+
+// = Network Information =
+QString OSInterface::OS_networkTypeFromDeviceName(QString name){
+ //Return options: wifi, wired, cell, cell-2G, cell-3G, cell-4G
+ QString type = "wired";
+ if(name.startsWith("wlan")){ type = "wifi"; }
+ //Not sure about cell connections . Probably still treated as wifi devices (wlan*)
+ return type;
+}
+
+float OSInterface::OS_networkStrengthFromDeviceName(QString name){
+ //NOTE: This will only run for non-wired devices (wifi, cell[-*])
+ // Step 1 : Figure out which access point is currently connected
+ QStringList info = getCmdOutput("ifconfig", QStringList() << name).filter("bssid");
+ if(info.isEmpty()){ return -1; }
+ QString bssid = info.first().section("bssid ",1,-1).section(" ",0,0);
+ // Step 2: Scan access point to get signal/noise
+ info = getCmdOutput("ifconfig", QStringList() << name << "list" << "scan").filter(bssid);
+ if(info.isEmpty()){ return -1; }
+ QString signoise =info.first().section(" ", 4,4).simplified();
+ int sig = signoise.section(":",0,0).toInt();
+ int noise = signoise.section(":",1,1).toInt();
+ // Step 3: Turn signal/noise ratio into a percentage
+ int perc = qAbs(sig - noise) * 4;
+ return perc; //percentage
+}
+
+// = Media Shortcuts =
+QStringList OSInterface::OS_mediaDirectories(){ return QStringList() << "/media"; } //directory where XDG shortcuts are placed for interacting with media (local/remote)
+
+// = Updates =
+bool OSInterface::OS_updatesSupported(){ return verifyAppOrBin("pc-updatemanager"); }
+
+bool OSInterface::OS_updatesAvailable(){ return QFile::exists("/tmp/.trueos-update-staged"); }
+QString OSInterface::OS_updateDetails(){ return readFile("/tmp/.trueos-update-staged"); } //Information about any available updates
+
+bool OSInterface::OS_updatesRunning(){ return (runCmd("pgrep -F /tmp/.updateInProgress")==0); }
+QString OSInterface::OS_updateLog(){ return QString(); } //Information about any currently-running update
+
+//Note: Because the second-stage updates on TrueOS actually happen on reboot, we never see a "finished" update
+bool OSInterface::OS_updatesFinished(){ return false; }
+QString OSInterface::OS_updateResults(){ return QString(); } //Information about any finished update
+
+void OSInterface::OS_startUpdates(){ runCmd("pc-updatemanager", QStringList() << "startupdate"); } //start stage 2 on reboot
+bool OSInterface::OS_updateOnlyOnReboot(){ return true; } //Should the startUpdates function be called only when rebooting the system?
+bool OSInterface::OS_updateCausesReboot(){ return true; }
+
+QDateTime OSInterface::OS_lastUpdate(){ return QDateTime(); } //The date/time of the previous updates
+QString OSInterface::OS_lastUpdateResults(){ return QString(); } //Information about the previously-finished update
+
+// = System Power =
+bool OSInterface::OS_canReboot(){
+ int ret = eaccess("/sbin/shutdown", X_OK);
+ return (ret==0);
+}
+void OSInterface::OS_startReboot(){ runCmd("/sbin/shutdown", QStringList() << "-ro" << "now"); }
+
+bool OSInterface::OS_canShutdown(){
+ int ret = eaccess("/sbin/shutdown", X_OK);
+ return (ret==0);
+}
+void OSInterface::OS_startShutdown(){ runCmd("/sbin/shutdown", QStringList() << "-po" << "now"); }
+
+bool OSInterface::OS_canSuspend(){
+ int ret = eaccess("/usr/sbin/acpiconf", X_OK);
+ return (ret==0);
+}
+void OSInterface::OS_startSuspend(){ runCmd("zzz"); } //zzz runs "acpiconf -s <suspend state>"
+
+// = Screen Brightness =
+bool OSInterface::OS_brightnessSupported(){
+//First run a quick check to ensure this is not a VirtualBox VM (no brightness control)
+ static int goodsys = -1; //This will not change over time - only check/set once
+ if(goodsys<0){
+ //Make sure we are not running in VirtualBox (does not work in a VM)
+ QStringList info = getCmdOutput("pciconf -lv");
+ if( info.filter("VirtualBox", Qt::CaseInsensitive).isEmpty() ){ goodsys = 1; }
+ else{ goodsys = 0; } //not a good system
+ }
+ if(goodsys!=1){ return false; } //go ahead and stop here - not a good system
+ QStringList tools; tools << "intel_backlight" << "xbrightness";
+ bool ok = false;
+ for(int i=0; i<tools.length() && !ok; i++){ ok = verifyAppOrBin(tools[i]); }
+ return ok;
+}
+
+int OSInterface::OS_brightness(){
+ //return percentage: 0-100 with -1 for errors
+ QStringList tools; tools << "intel_backlight" << "xbrightness";
+ //NOTE: xbacklight does not have a way to return the current brightness
+ int num = -1;
+ for(int i=0; i<tools.length() && num<0; i++){
+ if(!verifyAppOrBin(tools[i])){ continue; }
+ switch(i){
+ case 0: //intel_backlight
+ num = getCmdOutput("intel_backlight").join("").section("%",0,0).section(":",1,1).simplified().toInt();
+ break;
+ default:
+ num = -1;
+ }
+ }
+ if(num>100){ num=100; } //quick verification of upper limit
+ else if(num<-1){ num = -1; } //something really messed up - return the error code
+ return num;
+}
+
+bool OSInterface::OS_setBrightness(int percent){
+ QStringList tools; tools << "intel_backlight" << "xbrightness";
+ for(int i=0; i<tools.length(); i++){
+ if(!verifyAppOrBin(tools[i])){ continue; }
+ QStringList args;
+ switch(i){
+ case 0: //intel_backlight
+ args << QString::number(percent);
+ break;
+ case 1: //xbrightness
+ args << QString::number( qRound( (percent/100.0)*65535) ); //xbrightness has a scale of 0-65535
+ break;
+ }
+ return (0 == runCmd(tools[i], args) );
+ }
+ return false;
+}
+
+// = System Status Monitoring
+bool OSInterface::OS_cpuSupported(){ return false; }
+QList<int> OSInterface::OS_cpuPercentage(){ return QList<int>(); } // (one per CPU) percentage: 0-100 with empty list for errors
+QStringList OSInterface::OS_cpuTemperatures(){ return QStringList(); } // (one per CPU) Temperature of CPU ("50C" for example)
+
+bool OSInterface::OS_memorySupported(){ return false; }
+int OSInterface::OS_memoryUsedPercentage(){ return -1; } //percentage: 0-100 with -1 for errors
+QString OSInterface::OS_memoryTotal(){ return QString(); } //human-readable form - does not tend to change within a session
+QStringList OSInterface::OS_diskIO(){ return QStringList(); } //Returns list of current read/write stats for each device
+
+bool OSInterface::OS_diskSupported(){ return false; }
+int OSInterface::OS_fileSystemPercentage(QString dir){ return -1; } //percentage of capacity used: 0-100 with -1 for errors
+QString OSInterface::OS_fileSystemCapacity(QString dir){ return QString(); } //human-readable form - total capacity
+
+// = OS-Specific Utilities =
+QString OSInterface::controlPanelShortcut(){ return "pccontrol.desktop"; } //relative *.desktop shortcut name (Example: "some_utility.desktop")
+QString OSInterface::audioMixerShortcut(){ return "pc-mixer -notray"; } //relative *.desktop shortcut name (Example: "some_utility.desktop")
+QString OSInterface::appStoreShortcut(){ return "appcafe.desktop"; } //relative *.desktop shortcut name (Example: "some_utility.desktop")
+QString OSInterface::networkManagerUtility(){ return "pc-netmanager.desktop"; } //relative *.desktop shortcut name (Example: "some_utility.desktop")
+
+//FileSystemWatcher slots (optional - re-implement only if needed/used by this OS)
+void OSInterface::watcherFileChanged(QString){} //any additional parsing for files that are watched
+void OSInterface::watcherDirChanged(QString dir){ //any additional parsing for watched directories
+ if(handleMediaDirChange(dir)){ return; } //auto-handled media directories
+}
+
+//IO Device slots (optional - implement only if needed/used by this OS)
+void OSInterface::iodeviceReadyRead(){}
+void OSInterface::iodeviceAboutToClose(){}
+
+void OSInterface::netRequestFinished(QNetworkReply*){}
+void OSInterface::netSslErrors(QNetworkReply*, const QList<QSslError>&){}
diff --git a/src-qt5/src-cpp/framework-OSInterface-template.cpp b/src-qt5/src-cpp/framework-OSInterface-template.cpp
index 6d1a7e74..c9c7775a 100644
--- a/src-qt5/src-cpp/framework-OSInterface-template.cpp
+++ b/src-qt5/src-cpp/framework-OSInterface-template.cpp
@@ -4,6 +4,12 @@
// Available under the 3-clause BSD license
// See the LICENSE file for full details
//===========================================
+// USEFUL INTERNAL FUNCTIONS: (See framework-OSInterface.h for all possibilities);
+//----------------------------------------------
+// bool verifyAppOrBin(QString chk) : Returns true is the check is a valid binary or application (*.desktop)
+// int runCmd(QString command, QStringList arguments) : return code of command is returned
+// QStringList getCmdOutput(QString command, QStringList arguments) : returns standard output of command
+//===========================================
#include <framework-OSInterface.h>
// = Battery =
@@ -15,7 +21,7 @@ double OSInterface::OS_batterySecondsLeft(){ return -1; }
// = Volume =
bool OSInterface::OS_volumeSupported(){ return false; }
int OSInterface::OS_volume(){ return -1; }
-void OSInterface::OS_setVolume(int){}
+bool OSInterface::OS_setVolume(int){ return false;}
// = Network Information =
QString OSInterface::OS_networkTypeFromDeviceName(QString name){
@@ -56,7 +62,7 @@ void OSInterface::OS_startSuspend(){}
// = Screen Brightness =
bool OSInterface::OS_brightnessSupported(){ return false; }
int OSInterface::OS_brightness(){ return -1; } //percentage: 0-100 with -1 for errors
-void OSInterface::OS_setBrightness(int){}
+bool OSInterface::OS_setBrightness(int){ return false; }
// = System Status Monitoring
bool OSInterface::OS_cpuSupported(){ return false; }
diff --git a/src-qt5/src-cpp/framework-OSInterface.h b/src-qt5/src-cpp/framework-OSInterface.h
index 2f1795a1..2c4a4e0c 100644
--- a/src-qt5/src-cpp/framework-OSInterface.h
+++ b/src-qt5/src-cpp/framework-OSInterface.h
@@ -33,7 +33,7 @@
#include <QNetworkInterface>
//Lumina Utils class
-#include <LUtils.h>
+//#include <LUtils.h>
class OSInterface : public QObject{
Q_OBJECT
@@ -165,7 +165,7 @@ public:
// = Volume =
bool OS_volumeSupported();
int OS_volume();
- void OS_setVolume(int);
+ bool OS_setVolume(int);
// = Network Information =
QString OS_networkTypeFromDeviceName(QString name);
float OS_networkStrengthFromDeviceName(QString name);
@@ -194,7 +194,7 @@ public:
// = Screen Brightness =
bool OS_brightnessSupported();
int OS_brightness();
- void OS_setBrightness(int);
+ bool OS_setBrightness(int);
// = System Status Monitoring
bool OS_cpuSupported();
QList<int> OS_cpuPercentage();
@@ -219,10 +219,10 @@ private slots:
void iodeviceReadyRead();
void iodeviceAboutToClose();
//NetworkAccessManager slots
- void netAccessChanged(QNetworkAccessManager::NetworkAccessibility);
void netRequestFinished(QNetworkReply*);
void netSslErrors(QNetworkReply*, const QList<QSslError>&);
//Timer slots
+ void NetworkTimerUpdate();
void BatteryTimerUpdate();
void UpdateTimerUpdate();
void BrightnessTimerUpdate();
@@ -259,7 +259,7 @@ private:
//Network Access Manager (check network connectivity, etc)
QNetworkAccessManager *netman;
//Timer for regular probes/updates
- QTimer *batteryTimer, *updateTimer, *brightnessTimer, *volumeTimer, *cpuTimer, *memTimer, *diskTimer;
+ QTimer *networkTimer, *batteryTimer, *updateTimer, *brightnessTimer, *volumeTimer, *cpuTimer, *memTimer, *diskTimer;
// Internal implifications for connecting the various watcher objects to their respective slots
// (OS-agnostic - defined in the "OSInterface_private.cpp" file)
@@ -269,16 +269,19 @@ private:
//Internal simplification routines
bool verifyAppOrBin(QString chk);
+ QString runProcess(int &retcode, QString command, QStringList arguments, QString workdir = "", QStringList env = QStringList());
+ int runCmd(QString command, QStringList args = QStringList());
+ QStringList getCmdOutput(QString command, QStringList args = QStringList());
+ bool findInDirectory(QString file, QString dirpath, bool recursive=true);
+ QString readFile(QString path);
// 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();
-
- // Timer-based monitors
+ // Timer-based setups
+ void setupNetworkManager(int update_ms, int delay_ms);
void setupBatteryMonitor(int update_ms, int delay_ms);
void setupUpdateMonitor(int update_ms, int delay_ms);
void setupBrightnessMonitor(int update_ms, int delay_ms);
@@ -288,6 +291,7 @@ private:
void setupDiskMonitor(int update_ms, int delay_ms);
// Timer-based monitor update routines (NOTE: these are all run in a separate thread!!)
+ void syncNetworkInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer);
void syncBatteryInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer);
void syncUpdateInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer);
void syncBrightnessInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer);
diff --git a/src-qt5/src-cpp/framework-OSInterface.pri b/src-qt5/src-cpp/framework-OSInterface.pri
index fa6e966c..3a456382 100644
--- a/src-qt5/src-cpp/framework-OSInterface.pri
+++ b/src-qt5/src-cpp/framework-OSInterface.pri
@@ -1,11 +1,18 @@
-QT *= core network quick
+QT *= core network quick concurrent
+
+#include(../core/libLumina/LUtils.pri)
+#include(../core/libLumina/LuminaXDG.pri)
-include(../core/libLumina/LUtils.pri)
-include(../core/libLumina/LuminaXDG.pri)
HEADERS *= $${PWD}/framework-OSInterface.h
SOURCES *= $${PWD}/framework-OSInterface_private.cpp
-_os=template
-SOURCES *= $${PWD}/framework-OSInterface-$${_os}.cpp
+#Load the proper OS *.cpp file
+exists($${PWD}/framework-OSInterface-$${LINUX_DISTRO}.cpp){
+ SOURCES *= $${PWD}/framework-OSInterface-$${LINUX_DISTRO}.cpp
+}else:exists($${PWD}/framework-OSInterface-$${OS}.cpp){
+ SOURCES *= $${PWD}/framework-OSInterface-$${OS}.cpp
+}else{
+ SOURCES *= $${PWD}/framework-OSInterface-template.cpp
+}
INCLUDEPATH *= $${PWD}
diff --git a/src-qt5/src-cpp/framework-OSInterface_private.cpp b/src-qt5/src-cpp/framework-OSInterface_private.cpp
index 733fc61f..36da1bd4 100644
--- a/src-qt5/src-cpp/framework-OSInterface_private.cpp
+++ b/src-qt5/src-cpp/framework-OSInterface_private.cpp
@@ -50,7 +50,7 @@ void OSInterface::RegisterType(){
//Start/stop interface systems
void OSInterface::start(){
if(!mediaDirectories().isEmpty()){ setupMediaWatcher(); }//will create/connect the filesystem watcher automatically
- setupNetworkManager(); //will create/connect the network monitor automatically
+ setupNetworkManager(60000, 1); //will create/connect the network monitor automatically
if(batteryAvailable()){ setupBatteryMonitor(30000, 1); } //30 second updates, 1 ms init delay
if(brightnessSupported()){ setupBrightnessMonitor(60000, 1); } //1 minute updates, 1 ms init delay
if(volumeSupported()){ setupVolumeMonitor(60000, 2); } //1 minute updates, 2 ms init delay
@@ -87,22 +87,100 @@ void OSInterface::connectIodevice(){
void OSInterface::connectNetman(){
if(netman==0){ return; }
- connect(netman, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(netAccessChanged(QNetworkAccessManager::NetworkAccessibility)) );
+ connect(netman, SIGNAL(networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility)), this, SLOT(netAccessChanged()) );
connect(netman, SIGNAL(finished(QNetworkReply*)), this, SLOT(netRequestFinished(QNetworkReply*)) );
connect(netman, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(netSslErrors(QNetworkReply*, const QList<QSslError>&)) );
}
bool OSInterface::verifyAppOrBin(QString chk){
bool valid = !chk.isEmpty();
+ if(chk.contains(" ")){ chk = chk.section(" ",0,0); }
if(valid && chk.endsWith(".desktop")){
- chk = LUtils::AppToAbsolute(chk);
- valid = QFile::exists(chk);
+ if(chk.startsWith("/")){ return QFile::exists(chk); }
+ valid = false;
+ QStringList paths;
+ paths << QString(getenv("XDG_DATA_HOME")) << QString(getenv("XDG_DATA_DIRS")).split(":");
+ for(int i=0; i<paths.length() && !valid; i++){
+ if(QFile::exists(paths[i]+"/applications")){ valid = findInDirectory(chk, paths[i]+"/applications", true); }
+ }
}else if(valid){
- valid = LUtils::isValidBinary(chk);
+ //Find the absolute path for this binary
+ if(!chk.startsWith("/")){
+ QStringList paths = QString(getenv("PATH")).split(":");
+ for(int i=0; i<paths.length(); i++){
+ if(QFile::exists(paths[i]+"/"+chk)){ chk = paths[i]+"/"+chk; break; }
+ }
+ if(!chk.startsWith("/")){ return false; } //could not find the file
+ }else if(!QFile::exists(chk)){
+ return false; //file does not exist
+ }
+ //Make sure it is executable by the user
+ valid = QFileInfo(chk).isExecutable();
}
return valid;
}
+QString OSInterface::runProcess(int &retcode, QString command, QStringList arguments, QString workdir, QStringList env){
+ QProcess proc;
+ proc.setProcessChannelMode(QProcess::MergedChannels); //need output
+ //First setup the process environment as necessary
+ QProcessEnvironment PE = QProcessEnvironment::systemEnvironment();
+ if(!env.isEmpty()){
+ for(int i=0; i<env.length(); i++){
+ if(!env[i].contains("=")){ continue; }
+ PE.insert(env[i].section("=",0,0), env[i].section("=",1,100));
+ }
+ }
+ proc.setProcessEnvironment(PE);
+ //if a working directory is specified, check it and use it
+ if(!workdir.isEmpty()){
+ proc.setWorkingDirectory(workdir);
+ }
+ //Now run the command (with any optional arguments)
+ if(arguments.isEmpty()){ proc.start(command); }
+ else{ proc.start(command, arguments); }
+ //Wait for the process to finish (but don't block the event loop)
+ for(int i=0; i<10 && !proc.waitForFinished(500); i++){ //maximum of 5 seconds for command to finish
+ if(proc.state() == QProcess::NotRunning){ break; } //somehow missed the finished signal - go ahead and stop now
+ }
+ if(proc.state() != QProcess::NotRunning){ proc.terminate(); } //just in case - make sure to kill off the process
+ QString info = proc.readAllStandardOutput();
+ retcode = proc.exitCode(); //return success/failure
+ return info;
+}
+
+int OSInterface::runCmd(QString command, QStringList args){
+ int retcode;
+ runProcess(retcode, command, args);
+ return retcode;
+}
+
+QStringList OSInterface::getCmdOutput(QString command, QStringList args){
+ int retcode;
+ return runProcess(retcode, command, args).split("\n");
+}
+
+bool OSInterface::findInDirectory(QString file, QString dirpath, bool recursive){
+ bool found = QFile::exists(dirpath+"/"+file);
+ if(!found && recursive){
+ QDir dir(dirpath);
+ QStringList dirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
+ for(int i=0; i<dirs.length() && !found; i++){ found = findInDirectory(file, dir.absoluteFilePath(dirs[i]), recursive); }
+ }
+ return found;
+}
+
+QString OSInterface::readFile(QString path){
+ QFile file(path);
+ QString info;
+ if(file.open(QIODevice::ReadOnly)){
+ QTextStream out(&file);
+ info = out.readAll();
+ file.close();
+ }
+ return info;
+}
+
// ===========================
// OS SPECIFIC EXISTANCE CHECKS
// ===========================
@@ -162,13 +240,16 @@ QStringList OSInterface::autoHandledMediaFiles(){
// NETWORK INTERFACE FUNCTIONS
// =============================
// Qt-based NetworkAccessManager usage
-void OSInterface::setupNetworkManager(){
+void OSInterface::setupNetworkManager(int update_ms, int delay_ms){
if(netman==0){
netman = new QNetworkAccessManager(this);
connectNetman();
}
- //Load the initial state of the network accessibility
- netAccessChanged(netman->networkAccessible());
+ networkTimer = new QTimer(this);
+ networkTimer->setSingleShot(true);
+ networkTimer->setInterval(update_ms);
+ connect(networkTimer, SIGNAL(timeout()), this, SLOT(NetworkTimerUpdate()) );
+ QTimer::singleShot(delay_ms, this, SLOT(NetworkTimerUpdate()) );
}
bool OSInterface::networkAvailable(){
@@ -211,9 +292,9 @@ QString OSInterface::networkStatus(){
}
//NetworkAccessManager slots
-void OSInterface::netAccessChanged(QNetworkAccessManager::NetworkAccessibility stat){
+void OSInterface::syncNetworkInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer){
//qDebug() << "[DEBUG] Got Net Access Changed";
- INFO.insert("netaccess/available", stat== QNetworkAccessManager::Accessible);
+ hash->insert("netaccess/available", netman->networkAccessible()== QNetworkAccessManager::Accessible);
//Update all the other network status info at the same time
QNetworkConfiguration active = netman->activeConfiguration();
//Type of connection
@@ -226,10 +307,10 @@ void OSInterface::netAccessChanged(QNetworkAccessManager::NetworkAccessibility s
case QNetworkConfiguration::Bearer4G: type="cell-4G"; break;
default: type=OS_networkTypeFromDeviceName(active.name()); //could not be auto-determined - run the OS-specific routine
}
- INFO.insert("netaccess/type", type);
+ hash->insert("netaccess/type", type);
float strength = 100;
if(type!="wired"){ strength = OS_networkStrengthFromDeviceName(active.name()); }
- INFO.insert("netaccess/strength", strength);
+ hash->insert("netaccess/strength", strength);
//qDebug() << "Detected Device Status:" << active.identifier() << type << stat;
QNetworkInterface iface = QNetworkInterface::interfaceFromName(active.name());
@@ -243,7 +324,7 @@ void OSInterface::netAccessChanged(QNetworkAccessManager::NetworkAccessibility s
}
//qDebug() << " - IP Address:" << address;
//qDebug() << " - Hostname:" << networkHostname();
- INFO.insert("netaccess/address", address.join(", "));
+ hash->insert("netaccess/address", address.join(", "));
//Figure out the icon used for this type/strnegth
QString icon;
@@ -270,9 +351,10 @@ void OSInterface::netAccessChanged(QNetworkAccessManager::NetworkAccessibility s
}else{
icon = "network-workgroup"; //failover to a generic "network" icon
}
- INFO.insert("netaccess/icon",icon);
+ hash->insert("netaccess/icon",icon);
//qDebug() << "[DEBUG] Emit NetworkStatusChanged";
- emit networkStatusChanged();
+ os->emit networkStatusChanged();
+ timer->start();
}
@@ -280,6 +362,12 @@ void OSInterface::netAccessChanged(QNetworkAccessManager::NetworkAccessibility s
// TIMER-BASED MONITORS
// ========================
//Timer slots
+
+void OSInterface::NetworkTimerUpdate(){
+ if(networkTimer->isActive()){ networkTimer->stop(); } //just in case this was manually triggered
+ QtConcurrent::run(this, &OSInterface::syncNetworkInfo, this, &INFO, networkTimer);
+}
+
void OSInterface::BatteryTimerUpdate(){
if(batteryTimer->isActive()){ batteryTimer->stop(); } //just in case this was manually triggered
QtConcurrent::run(this, &OSInterface::syncBatteryInfo, this, &INFO, batteryTimer);
@@ -431,7 +519,7 @@ void OSInterface::syncBrightnessInfo(OSInterface *os, QHash<QString, QVariant> *
void OSInterface::syncVolumeInfo(OSInterface *os, QHash<QString, QVariant> *hash, QTimer *timer){
int oldvol = volume();
int newvol = OS_volume();
- if(oldvol!=newvol){
+ if(oldvol!=newvol && newvol>=0){
hash->insert("volume/current",newvol);
QString icon;
if(newvol>66){ icon = "audio-volume-high"; }
bgstack15