diff --git a/quickinstall b/quickinstall index 41e4f8f0..4ec7f7ad 100755 --- a/quickinstall +++ b/quickinstall @@ -63,7 +63,6 @@ if [[ ! -d $BINDIR ]]; then echo "There is nothing to do." finish 0 fi - # Offer to install ckb at a standard location shopt -s nocasematch read -rp "Install ckb system-wide [Y/n]? " doinstall @@ -191,8 +190,11 @@ sleep 1 echo "" read -rp "Start ckb now [Y/n]? " dolaunch [[ $dolaunch =~ no? ]] && exit 0 -sleep 0.5 APP=$PREFIX/ckb [[ "$OSTYPE" == "darwin"* ]] && APP=$APP.app/Contents/MacOS/ckb +# Ask ckb to close if there's an instance already running +$APP --close >/dev/null 2>&1 +sleep 0.5 +# Launch nohup $APP >/dev/null 2>&1 & exit 0 diff --git a/src/ckb/main.cpp b/src/ckb/main.cpp index a064fdce..236505a0 100644 --- a/src/ckb/main.cpp +++ b/src/ckb/main.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include QSharedMemory appShare("ckb"); @@ -12,17 +15,64 @@ QSharedMemory appShare("ckb"); extern "C" void disableAppNap(); #endif -bool isRunning(bool showWindow){ - if(!appShare.create(16)){ - if(!appShare.attach() || !appShare.lock()) - return false; - if(showWindow){ - void* data = appShare.data(); - snprintf((char*)data, 16, "Open"); +// Shared memory sizes +#define SHMEM_SIZE 128 * 1024 +#define SHMEM_SIZE_V015 16 + +// Scan shared memory for an active PID +static bool pidActive(const QStringList& lines){ + foreach(const QString& line, lines){ + if(line.startsWith("PID ")){ + bool ok; + pid_t pid; + // Valid PID found? + if((pid = line.split(" ")[1].toLong(&ok)) > 0 && ok){ + // kill -0 does nothing to the application, but checks if it's running + return (kill(pid, 0) == 0 || errno != ESRCH); + } } - appShare.unlock(); - return true; } + // If the PID wasn't listed in the shmem, assume it is running + return true; +} + +// Check if the application is running. Optionally write something to its shared memory. +static bool isRunning(const char* command){ + // Try to create shared memory (if successful, application was not already running) + if(!appShare.create(SHMEM_SIZE) || !appShare.lock()){ + // Lock existing shared memory + if(!appShare.attach() || !appShare.lock()) + return true; + bool running = false; + if(appShare.size() == SHMEM_SIZE_V015){ + // Old shmem - no PID listed so assume the process is running, and print the command directly to the buffer + if(command){ + void* data = appShare.data(); + snprintf((char*)data, SHMEM_SIZE_V015, "%s", command); + } + running = true; + } else { + // New shmem. Scan the contents of the shared memory for a PID + QStringList lines = QString((const char*)appShare.constData()).split("\n"); + if(pidActive(lines)){ + running = true; + // Append the command + if(command){ + lines.append(QString("Option ") + command); + QByteArray newMem = lines.join("\n").left(SHMEM_SIZE).toLatin1(); + // Copy the NUL byte as well as the string + memcpy(appShare.data(), newMem.constData(), newMem.length() + 1); + } + } + } + if(running){ + appShare.unlock(); + return true; + } + } + // Not already running. Initialize the shared memory with our PID + snprintf((char*)appShare.data(), appShare.size(), "PID %ld", (long)getpid()); + appShare.unlock(); return false; } @@ -40,8 +90,24 @@ int main(int argc, char *argv[]){ qApp->setAttribute(Qt::AA_UseHighDpiPixmaps); #endif + // If launched with --version, print version info and then quit + if(qApp->arguments().contains("--version")){ + printf("ckb %s\n", CKB_VERSION_STR); + return 0; + } + + // Kill existing app when launched with --close + if(qApp->arguments().contains("--close")){ + if(isRunning("Close")) + printf("Asking existing instance to close.\n"); + else + printf("ckb is not running.\n"); + return 0; + } + + // Launch in background if requested bool background = qApp->arguments().contains("--background"); - if(isRunning(!background)){ + if(isRunning(background ? 0 : "Open")){ printf("ckb is already running. Exiting.\n"); return 0; } diff --git a/src/ckb/mainwindow.cpp b/src/ckb/mainwindow.cpp index e1bdeed5..6f1a0d8a 100644 --- a/src/ckb/mainwindow.cpp +++ b/src/ckb/mainwindow.cpp @@ -6,6 +6,7 @@ #include #include #include +#include extern QSharedMemory appShare; @@ -204,14 +205,29 @@ void MainWindow::closeEvent(QCloseEvent *event){ } void MainWindow::timerTick(){ - // Check if another instance requested this in the foreground + // Check shared memory for changes if(appShare.lock()){ void* data = appShare.data(); - if((QString)QByteArray((const char*)data) == "Open") - showWindow(); - // Remove the request - *(char*)data = 0; + QStringList commands = QString((const char*)data).split("\n"); + // Restore PID, remove all other data + snprintf((char*)appShare.data(), appShare.size(), "PID %ld", (long)getpid()); appShare.unlock(); + // Parse commands + foreach(const QString& line, commands){ + // Old ckb option line - bring application to foreground + if(line == "Open") + showWindow(); + if(line.startsWith("Option ")){ + // New ckb option line + QString option = line.split(" ")[1]; + if(option == "Open") + // Bring to foreground + showWindow(); + else if(option == "Close") + // Quit application + qApp->quit(); + } + } } // Check for firmware updates (when appropriate) if(!CkbSettings::get("Program/DisableAutoFWCheck").toBool())