aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/core/libLumina/LuminaSingleApplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src-qt5/core/libLumina/LuminaSingleApplication.cpp')
-rw-r--r--src-qt5/core/libLumina/LuminaSingleApplication.cpp137
1 files changed, 137 insertions, 0 deletions
diff --git a/src-qt5/core/libLumina/LuminaSingleApplication.cpp b/src-qt5/core/libLumina/LuminaSingleApplication.cpp
new file mode 100644
index 00000000..30507b5e
--- /dev/null
+++ b/src-qt5/core/libLumina/LuminaSingleApplication.cpp
@@ -0,0 +1,137 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LuminaSingleApplication.h"
+#include <QDir>
+#include <QFile>
+#include <QLocalSocket>
+#include <QDebug>
+#include <QX11Info>
+
+#include <unistd.h> //for getlogin()
+
+LSingleApplication::LSingleApplication(int &argc, char **argv, QString appname) : QApplication(argc, argv){
+ //Load the proper translation systems
+ if(appname!="lumina-desktop"){ cTrans = LUtils::LoadTranslation(this, appname); }//save the translator for later
+ //Initialize a couple convenience internal variables
+ cfile = QDir::tempPath()+"/.LSingleApp-%1-%2-%3";
+ QString username = QString(getlogin());
+ //For locking the process use the official process name - not the user input (no masking)
+ appname = this->applicationName();
+ cfile = cfile.arg( username, appname, QString::number(QX11Info::appScreen()) );
+ lockfile = new QLockFile(cfile+"-lock");
+ lockfile->setStaleLockTime(0); //long-lived processes
+ for(int i=1; i<argc; i++){
+ QString path = QString::fromLocal8Bit(argv[i]);
+ //do few quick conversions for relative paths and such as necessary
+ // (Remember: this is only used for secondary processes, not the primary)
+ if(path=="."){
+ //Insert the current working directory instead
+ path = QDir::currentPath();
+ }else{
+ if(!path.startsWith("/") && !path.startsWith("-") ){ path.prepend(QDir::currentPath()+"/"); }
+ }
+ inputlist << path;
+ }
+ isActive = isBypass = false;
+ lserver = 0;
+ //Now check for the manual CLI flag to bypass single-instance forwarding (if necessary)
+ if(inputlist.contains("-new-instance")){
+ isBypass = true;
+ inputlist.removeAll("-new-instance");
+ }
+ PerformLockChecks();
+}
+
+LSingleApplication::~LSingleApplication(){
+ if(lserver != 0 && lockfile->isLocked() ){
+ //currently locked instance: remove the lock now
+ lserver->close();
+ QLocalServer::removeServer(cfile);
+ lockfile->unlock();
+ }
+}
+
+bool LSingleApplication::isPrimaryProcess(){
+ return (isActive || isBypass);
+}
+
+void LSingleApplication::PerformLockChecks(){
+ bool primary = lockfile->tryLock();
+ //qDebug() << "Try Lock: " << primary;
+ if(!primary){
+ //Pre-existing lock - check it for validity
+ QString appname, hostname;
+ qint64 pid;
+ lockfile->getLockInfo(&pid, &hostname, &appname); //PID already exists if it gets this far, ignore hostname
+ //qDebug() << " - Lock Info:" << pid << hostname << appname;
+ if( appname!=this->applicationName() || !QFile::exists(cfile) ){
+ //Some other process has the same PID or the server does not exist - stale lock
+ qDebug() << " - Cleaning stale single-instance lock:";
+ if(lockfile->removeStaleLockFile() ){
+ if(QFile::exists(cfile)){ QLocalServer::removeServer(cfile); } //also remove stale socket/server file
+ }else{
+ qDebug() << " -- Could not remove lock file";
+ }
+ //Now re-try to create the lock
+ primary = lockfile->tryLock();
+ //qDebug() << " - Try Lock Again:" << primary;
+ }
+ }
+ if(primary || !QFile::exists(cfile) ){
+ //Create the server socket
+ //qDebug() << "Create Local Server";
+ if(QFile::exists(cfile)){ QLocalServer::removeServer(cfile); } //stale socket/server file
+ lserver = new QLocalServer(this);
+ connect(lserver, SIGNAL(newConnection()), this, SLOT(newInputsAvailable()) );
+ if( lserver->listen(cfile) ){
+ qDebug() << " - Created new single-instance lock";
+ lserver->setSocketOptions(QLocalServer::UserAccessOption);
+ //qDebug() << " - Success";
+ isActive = true;
+ }else{
+ qDebug() << " - WARNING: Could not create single-instance framework";
+ qDebug() << " - Falling back on standard application startup";
+ lockfile->unlock();
+ isActive = true;
+ }
+
+ }else if(!isBypass){
+ //forward the current inputs to the locked process for processing and exit
+ //Check the connection to the local server first
+ qDebug() << "Single-instance lock found";
+ QLocalSocket socket(this);
+ socket.connectToServer(cfile);
+ socket.waitForConnected();
+ if(!socket.isValid() || socket.state()!=QLocalSocket::ConnectedState){
+ //error - could not forward info for some reason
+ qDebug() << " - Could not connect to locking process: exiting...";
+ exit(1);
+ }
+
+ qDebug() << " - Forwarding inputs to locking process and closing down this instance...";
+ socket.write( inputlist.join("::::").toLocal8Bit() );
+ socket.waitForDisconnected(500); //max out at 1/2 second (only hits this if no inputs)
+ }
+
+}
+
+//New messages detected
+void LSingleApplication::newInputsAvailable(){
+ while(lserver->hasPendingConnections()){
+ QLocalSocket *sock = lserver->nextPendingConnection();
+ QByteArray bytes;
+ sock->waitForReadyRead();
+ while(sock->bytesAvailable() > 0){ //if(sock->waitForReadyRead()){
+ //qDebug() << "Info Available";
+ bytes.append( sock->readAll() );
+ }
+ sock->disconnectFromServer();
+ QStringList inputs = QString::fromLocal8Bit(bytes).split("::::");
+ //qDebug() << " - New Inputs Detected:" << inputs;
+ emit InputsAvailable(inputs);
+ }
+} \ No newline at end of file
bgstack15