Index: runtime/pgAdmin4.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/pgAdmin4.cpp	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/pgAdmin4.cpp	(date 1594828249516)
@@ -10,551 +10,72 @@
 //////////////////////////////////////////////////////////////////////////
 
 #include "pgAdmin4.h"
-
-// Must be before QT
-#include <Python.h>
-
-#if QT_VERSION >= 0x050000
-#include <QtWidgets>
-#include <QNetworkProxyFactory>
-#include <QNetworkRequest>
-#include <QNetworkReply>
-#else
-#include <QApplication>
-#include <QDebug>
-#include <QtNetwork>
-#include <QLineEdit>
-#include <QInputDialog>
-#include <QSplashScreen>
-#include <QUuid>
-#include <QNetworkProxyFactory>
-#endif
-
-// App headers
-#include "ConfigWindow.h"
-#include "Server.h"
-#include "TrayIcon.h"
-#include "MenuActions.h"
-#include "FloatingWindow.h"
-#include "Logger.h"
+#include "Runtime.h"
 
-#ifdef Q_OS_MAC
-#include "macos.h"
-#endif
+#include <stdlib.h>
 
-#include <QTime>
-
-QString logFileName;
-QString addrFileName;
+// Global vars for caching and avoing shutdown issues
+QString g_startupLogFile;
+QString g_serverLogFile;
+QString g_addressFile;
 
 int main(int argc, char * argv[])
 {
-    /*
-     * Before starting main application, need to set 'QT_X11_NO_MITSHM=1'
-     * to make the runtime work with IBM PPC machine.
-     */
-#if defined (Q_OS_LINUX)
-    QByteArray val("1");
-    qputenv("QT_X11_NO_MITSHM", val);
-#endif
-
-    // Create the QT application
-    QApplication app(argc, argv);
-    app.setQuitOnLastWindowClosed(false);
-
-    // Setup the styling
-#ifndef Q_OS_LINUX
-    QFile stylesheet;
-
-#ifdef Q_OS_WIN32
-    QSettings registry("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings::Registry64Format);
-    if (registry.value("AppsUseLightTheme", true).toBool())
-    {
-        qDebug( "Windows Light Mode...");
-        stylesheet.setFileName(":/light.qss");
-    }
-    else
-    {
-        qDebug( "Windows Dark Mode..." );
-        stylesheet.setFileName(":/dark.qss");
-    }
-#endif
-
-#ifdef Q_OS_MAC
-    if (IsDarkMode())
-    {
-        qDebug( "macOS Dark Mode...");
-        stylesheet.setFileName(":/dark.qss");
-    }
-    else
-    {
-        qDebug( "macOS Light Mode..." );
-        stylesheet.setFileName(":/light.qss");
-    }
-#endif
-
-    stylesheet.open(QFile::ReadOnly | QFile::Text);
-    QTextStream stream(&stylesheet);
-    app.setStyleSheet(stream.readAll());
-#endif
-
-    // Setup the settings management
-    QCoreApplication::setOrganizationName("pgadmin");
-    QCoreApplication::setOrganizationDomain("pgadmin.org");
-    QCoreApplication::setApplicationName(PGA_APP_NAME.toLower().replace(" ", ""));
-
-#if QT_VERSION >= 0x050000
-    // Set high DPI pixmap to display icons clear on Qt widget.
-    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
-#endif
-
-    // Create a hash of the executable path so we can run copies side-by-side
-    unsigned long exeHash = sdbm(reinterpret_cast<unsigned char *>(argv[0]));
-
-    // Create the address file, that will be used to store the appserver URL for this instance
+    // Make sure we can create logs etc.
     QDir workdir;
     workdir.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
-    addrFileName = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + (QString("/.%1.%2.addr").arg(PGA_APP_NAME).arg(exeHash)).remove(" ");
-    QFile addrFile(addrFileName);
-
-    // Create a system-wide semaphore keyed by app name, exe hash and the username
-    // to ensure instances are unique to the user and path
-    QString userName = qgetenv("USER"); // *nix
-    if (userName.isEmpty())
-        userName = qgetenv("USERNAME"); // Windows
-
-    QString semaName = QString("%1-%2-%3-sema").arg(PGA_APP_NAME).arg(userName).arg(exeHash);
-    QString shmemName = QString("%1-%2-%3-shmem").arg(PGA_APP_NAME).arg(userName).arg(exeHash);
-
-    QSystemSemaphore sema(semaName, 1);
-    sema.acquire();
-
-#ifndef Q_OS_WIN32
-    // We may need to clean up stale shmem segments on *nix. Attaching and detaching
-    // should remove the segment if it is orphaned.
-    QSharedMemory stale_shmem(shmemName);
-    if (stale_shmem.attach())
-        stale_shmem.detach();
-#endif
-
-    QSharedMemory shmem(shmemName);
-    bool is_running;
-    if (shmem.attach())
-    {
-        is_running = true;
-    }
-    else
-    {
-        shmem.create(1);
-        is_running = false;
-    }
-    sema.release();
-
-    QSettings settings;
-
-    if (is_running){
-        addrFile.open(QIODevice::ReadOnly | QIODevice::Text);
-        QTextStream in(&addrFile);
-        QString addr = in.readLine();
-
-        QString cmd = settings.value("BrowserCommand").toString();
-
-        if (!cmd.isEmpty())
-        {
-            cmd.replace("%URL%", addr);
-            QProcess::startDetached(cmd);
-        }
-        else
-        {
-            if (!QDesktopServices::openUrl(addr))
-            {
-                QString error(QWidget::tr("Failed to open the system default web browser. Is one installed?."));
-                QMessageBox::critical(NULL, QString(QWidget::tr("Fatal Error")), error);
-
-                exit(1);
-            }
-        }
-
-        return 0;
-    }
-
-    atexit(cleanup);
-
-    // In windows and linux, it is required to set application level proxy
-    // because socket bind logic to find free port gives socket creation error
-    // when system proxy is configured. We are also setting
-    // "setUseSystemConfiguration"=true to use the system proxy which will
-    // override this application level proxy. As this bug is fixed in Qt 5.9 so
-    // need to set application proxy for Qt version < 5.9.
-    //
-#if defined (Q_OS_WIN) && QT_VERSION <= 0x050800
-    // Give dummy URL required to find proxy server configured in windows.
-    QNetworkProxyQuery proxyQuery(QUrl("https://www.pgadmin.org"));
-    QNetworkProxy l_proxy;
-    QList<QNetworkProxy> listOfProxies = QNetworkProxyFactory::systemProxyForQuery(proxyQuery);
-
-    if (listOfProxies.size())
-    {
-        l_proxy = listOfProxies[0];
-
-        // If host name is not empty means proxy server is configured.
-        if (!l_proxy.hostName().isEmpty()) {
-            QNetworkProxy::setApplicationProxy(QNetworkProxy());
-        }
-    }
-#endif
-
-#if defined (Q_OS_LINUX) && QT_VERSION <= 0x050800
-    QByteArray proxy_env;
-    proxy_env = qgetenv("http_proxy");
-    // If http_proxy environment is defined in linux then proxy server is configured.
-    if (!proxy_env.isEmpty()) {
-        QNetworkProxy::setApplicationProxy(QNetworkProxy());
-    }
-#endif
-
-    // Display the spash screen
-    QSplashScreen *splash = new QSplashScreen();
-    splash->setPixmap(QPixmap(":/splash.png"));
-    splash->setWindowFlags(splash->windowFlags() | Qt::WindowStaysOnTopHint);
-    splash->show();
-    app.processEvents(QEventLoop::AllEvents);
-
-    quint16 port = 0L;
-
-    if (settings.value("FixedPort", false).toBool())
-    {
-        // Use the fixed port number
-        port = settings.value("PortNumber", 5050).toInt();
-    }
-    else
-    {
-        // Find an unused port number. Essentially, we're just reserving one
-        // here that Flask will use when we start up the server.
-#if QT_VERSION >= 0x050000
-        QTcpSocket socket;
-
-#if QT_VERSION >= 0x050900
-        socket.setProxy(QNetworkProxy::NoProxy);
-#endif
-
-        socket.bind(0, QTcpSocket::ShareAddress);
-#else
-        QUdpSocket socket;
-        socket.bind(0, QUdpSocket::ShareAddress);
-#endif
-        port = socket.localPort();
-    }
-
-    // Generate a random key to authenticate the client to the server
-    QString key = QUuid::createUuid().toString();
-    key = key.mid(1, key.length() - 2);
-
-    // Generate the filename for the log
-    logFileName = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + (QString("/.%1.%2.log").arg(PGA_APP_NAME).arg(exeHash)).remove(" ");
-
-    // Create Menu Actions
-    MenuActions *menuActions = new MenuActions();
-    if(menuActions != Q_NULLPTR)
-        menuActions->setLogFile(logFileName);
-
-    splash->showMessage(QString(QWidget::tr("Checking for system tray...")), Qt::AlignBottom | Qt::AlignCenter);
-    Logger::GetLogger()->Log("Checking for system tray...");
-
-    // Check system tray is available or not. If not then create one floating window.
-    FloatingWindow *floatingWindow = Q_NULLPTR;
-    TrayIcon *trayicon = Q_NULLPTR;
-    if (QSystemTrayIcon::isSystemTrayAvailable())
-    {
-        // Start the tray service
-        trayicon = new TrayIcon();
-
-        // Set the MenuActions object to connect to slot
-        if (trayicon != Q_NULLPTR)
-            trayicon->setMenuActions(menuActions);
-
-        trayicon->Init();
-    }
-    else
-    {
-        splash->showMessage(QString(QWidget::tr("System tray not found, creating floating window...")), Qt::AlignBottom | Qt::AlignCenter);
-        Logger::GetLogger()->Log("System tray not found, creating floating window...");
-        // Unable to find tray icon, so creating floting window
-        floatingWindow = new FloatingWindow();
-        if (floatingWindow == Q_NULLPTR)
-        {
-            QString error = QString(QWidget::tr("Unable to initialize either a tray icon or control window."));
-            QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
-            Logger::GetLogger()->Log(error);
-            Logger::ReleaseLogger();
-            exit(1);
-        }
-
-        // Set the MenuActions object to connect to slot
-        floatingWindow->setMenuActions(menuActions);
-        floatingWindow->Init();
-    }
-
-    // Fire up the webserver
-    Server *server;
-
-    bool done = false;
-
-    splash->showMessage(QString(QWidget::tr("Starting pgAdmin4 server...")), Qt::AlignBottom | Qt::AlignCenter);
-    Logger::GetLogger()->Log("Starting pgAdmin4 server...");
-    while (done != true)
-    {
-        QString msg = QString(QWidget::tr("Creating server object, port:%1, key:%2, logfile:%3")).arg(port).arg(key).arg(logFileName);
-        Logger::GetLogger()->Log(msg);
-        server = new Server(port, key, logFileName);
-
-        Logger::GetLogger()->Log("Initializing server...");
-        if (!server->Init())
-        {
-            splash->finish(Q_NULLPTR);
-
-            qDebug() << server->getError();
-
-            QString error = QString(QWidget::tr("An error occurred initialising the application server:\n\n%1")).arg(server->getError());
-            QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
-
-            Logger::GetLogger()->Log(error);
-            Logger::ReleaseLogger();
-
-            exit(1);
-        }
-
-        Logger::GetLogger()->Log("Server initialized.");
-        Logger::GetLogger()->Log("Starting Server Thread...");
-        server->start();
-
-        // This is a hack to give the server a chance to start and potentially fail. As
-        // the Python interpreter is a synchronous call, we can't check for proper startup
-        // easily in a more robust way - we have to rely on a clean startup not returning.
-        // It should always fail pretty quickly, and take longer to start if it succeeds, so
-        // we don't really get a visible delay here.
-        delay(1000);
-
-        // Any errors?
-        if (server->isFinished() || server->getError().length() > 0)
-        {
-            splash->finish(Q_NULLPTR);
 
-            qDebug() << server->getError();
-
-            QString error = QString(QWidget::tr("An error occurred initialising the application server:\n\n%1")).arg(server->getError());
-            QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
-            Logger::GetLogger()->Log(error);
-
-            // Allow the user to tweak the Python Path if needed
-            bool ok;
-
-            ConfigWindow *dlg = new ConfigWindow();
-            dlg->LoadSettings();
-            dlg->setModal(true);
-            ok = dlg->exec();
-
-            if (ok)
-                dlg->SaveSettings();
-            else
-            {
-                Logger::ReleaseLogger();
-                exit(1);
-            }
+    // Let's rock...
+    Runtime *runtime = new Runtime();
+    return runtime->go(argc, argv);
+}
 
-            delete server;
-        }
-        else
-            done = true;
-    }
 
-    // Ensure the server gets cleaned up later
-    QObject::connect(server, SIGNAL(finished()), server, SLOT(deleteLater()));
-
-    // Generate the app server URL
-    QString appServerUrl = QString("http://127.0.0.1:%1/?key=%2").arg(port).arg(key);
-    Logger::GetLogger()->Log(QString(QWidget::tr("Application Server URL: %1")).arg(appServerUrl));
-
-    // Read the server connection timeout from the registry or set the default timeout.
-    int timeout = settings.value("ConnectionTimeout", 90).toInt();
-
-    // Now the server should be up, we'll attempt to connect and get a response.
-    // We'll retry in a loop a few time before aborting if necessary.
-
-    QTime endTime = QTime::currentTime().addSecs(timeout);
-    QTime midTime1 = QTime::currentTime().addSecs(timeout/3);
-    QTime midTime2 = QTime::currentTime().addSecs(timeout*2/3);
-    bool alive = false;
-
-    Logger::GetLogger()->Log("The server should be up, we'll attempt to connect and get a response. Ping the server");
-    while(QTime::currentTime() <= endTime)
-    {
-        alive = pingServer(QUrl(appServerUrl));
-
-        if (alive)
-        {
-            break;
-        }
+// Get the filename for the startup log
+QString getStartupLogFile()
+{
+    if (g_startupLogFile == "")
+        g_startupLogFile = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + ("/pgadmin4.startup.log");
 
-        if(QTime::currentTime() >= midTime1)
-        {
-            if(QTime::currentTime() < midTime2) {
-                splash->showMessage(QString(QWidget::tr("Taking longer than usual...")), Qt::AlignBottom | Qt::AlignCenter);
-            }
-            else
-            {
-                splash->showMessage(QString(QWidget::tr("Almost there...")), Qt::AlignBottom | Qt::AlignCenter);
-            }
-        }
+    return g_startupLogFile;
+}
 
-        delay(200);
-    }
 
-    // Attempt to connect one more time in case of a long network timeout while looping
-    Logger::GetLogger()->Log("Attempt to connect one more time in case of a long network timeout while looping");
-    if (!alive && !pingServer(QUrl(appServerUrl)))
-    {
-        splash->finish(Q_NULLPTR);
-        QString error(QWidget::tr("The application server could not be contacted."));
-        QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
+// Get the filename for the server log
+QString getServerLogFile()
+{
+    if (g_serverLogFile == "")
+        g_serverLogFile = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + (QString("/pgadmin4.%1.log").arg(getExeHash()));
 
-        Logger::ReleaseLogger();
-        exit(1);
-    }
+    return g_serverLogFile;
+}
 
-    // Stash the URL for any duplicate processes to open
-    if (addrFile.open(QIODevice::WriteOnly))
-    {
-        addrFile.setPermissions(QFile::ReadOwner|QFile::WriteOwner);
-        QTextStream out(&addrFile);
-        out << appServerUrl << endl;
-    }
-
-    // Go!
-    menuActions->setAppServerUrl(appServerUrl);
 
-    // Enable the shutdown server menu as server started successfully.
-    if (trayicon != Q_NULLPTR)
-        trayicon->enableShutdownMenu();
-    if (floatingWindow != Q_NULLPTR)
-        floatingWindow->enableShutdownMenu();
-
-    if (settings.value("OpenTabAtStartup", true).toBool())
-    {
-        QString cmd = settings.value("BrowserCommand").toString();
+// Get the filename for the address file
+QString getAddressFile()
+{
+    if (g_addressFile == "")
+        g_addressFile = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + (QString("/pgadmin4.%1.addr").arg(getExeHash()));
 
-        if (!cmd.isEmpty())
-        {
-            cmd.replace("%URL%", appServerUrl);
-            QProcess::startDetached(cmd);
-        }
-        else
-        {
-            if (!QDesktopServices::openUrl(appServerUrl))
-            {
-                QString error(QWidget::tr("Failed to open the system default web browser. Is one installed?."));
-                QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
-
-                Logger::GetLogger()->Log(error);
-                Logger::ReleaseLogger();
-                exit(1);
-            }
-        }
-    }
+    return g_addressFile;
+}
 
-    QObject::connect(menuActions, SIGNAL(shutdownSignal(QUrl)), server, SLOT(shutdown(QUrl)));
-    splash->finish(Q_NULLPTR);
 
-    if (floatingWindow != Q_NULLPTR)
-        floatingWindow->show();
-
-    Logger::GetLogger()->Log("Everything works fine, successfully started pgAdmin4.");
-    Logger::ReleaseLogger();
-    return app.exec();
-}
-
-
-QString serverRequest(QUrl url, QString path)
-{
-    QNetworkAccessManager manager;
-    QEventLoop loop;
-    QNetworkReply *reply;
-    QVariant redirectUrl;
-
-
-    url.setPath(path);
-    QString requestUrl = url.toString();
-
-    do
-    {
-        reply = manager.get(QNetworkRequest(url));
-        QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
-        loop.exec();
-
-        redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
-        url = redirectUrl.toUrl();
-
-        if (!redirectUrl.isNull())
-            delete reply;
-
-    } while (!redirectUrl.isNull());
-
-    if (reply->error() != QNetworkReply::NoError)
-    {
-        qDebug() << "Failed to connect to the server:" << reply->errorString() << "( request URL:" << requestUrl << ").";
-        return QString();
-    }
-
-    QString response = reply->readAll();
-    qDebug() << "Server response:" << response << "( request URL:" << requestUrl << ").";
-
-    return response;
-}
-
-
-// Ping the application server to see if it's alive
-bool pingServer(QUrl url)
-{
-    return serverRequest(url, "/misc/ping") == "PING";
-}
-
-
-// Shutdown the application server
-bool shutdownServer(QUrl url)
-{
-    return serverRequest(url, "/misc/shutdown") == "SHUTDOWN";
-}
-
-
-void delay(int milliseconds)
-{
-    QTime endTime = QTime::currentTime().addMSecs(milliseconds);
-    while(QTime::currentTime() < endTime)
-    {
-        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
-    }
-}
-
-
+// Cleanup the address and log files
 void cleanup()
 {
-    // Remove the address file
-    QFile addrFile(addrFileName);
+    qDebug() << "Removing:" << getAddressFile();
+    QFile addrFile(getAddressFile());
     addrFile.remove();
 
-    // Remove the log file
-    QFile logFile(logFileName);
+    qDebug() << "Removing:" << getServerLogFile();
+    QFile logFile(getServerLogFile());
     logFile.remove();
 }
 
 
-unsigned long sdbm(unsigned char *str)
+// Get a hash of the executable name and path
+QString getExeHash()
 {
-    unsigned long hash = 0;
-    int c;
-
-    while ((c = *str++))
-        hash = c + (hash << 6) + (hash << 16) - hash;
-
-    return hash;
+    return QString(QCryptographicHash::hash(QCoreApplication::applicationFilePath().toUtf8(),QCryptographicHash::Md5).toHex());
 }
Index: runtime/MenuActions.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/MenuActions.h	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/MenuActions.h	(date 1594827323301)
@@ -12,9 +12,6 @@
 #ifndef MENUACTIONS_H
 #define MENUACTIONS_H
 
-#include "pgAdmin4.h"
-
-// App headers
 #include "LogWindow.h"
 #include "ConfigWindow.h"
 
@@ -25,13 +22,15 @@
     MenuActions();
 
     void setAppServerUrl(QString appServerUrl);
-    void setLogFile(QString logFile);
     QString getAppServerUrl() { return m_appServerUrl; }
 
 private:
     QString m_appServerUrl = "";
-    QString m_logFile = "";
     LogWindow *m_logWindow = Q_NULLPTR;
+    ConfigWindow *m_configWindow = Q_NULLPTR;
+
+public slots:
+    void onConfigDone(bool needRestart);
 
 protected slots:
     void onNew();
Index: runtime/Runtime.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/Runtime.cpp	(date 1594891687800)
+++ runtime/Runtime.cpp	(date 1594891687800)
@@ -0,0 +1,624 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2020, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// Runtime.cpp - Core of the runtime
+//
+//////////////////////////////////////////////////////////////////////////
+
+#include "pgAdmin4.h"
+#include "Runtime.h"
+#include "Server.h"
+#include "TrayIcon.h"
+#include "MenuActions.h"
+#include "ConfigWindow.h"
+#include "FloatingWindow.h"
+#include "Logger.h"
+
+#ifdef Q_OS_MAC
+#include "macos.h"
+#endif
+
+// Must be before QT
+#include <Python.h>
+
+#include <QtWidgets>
+#include <QNetworkProxyFactory>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QTime>
+
+
+Runtime::Runtime()
+{
+
+}
+
+
+bool Runtime::go(int argc, char *argv[])
+{
+    // Before starting main application, need to set 'QT_X11_NO_MITSHM=1'
+    // to make the runtime work with IBM PPC machines.
+#if defined (Q_OS_LINUX)
+    QByteArray val("1");
+    qputenv("QT_X11_NO_MITSHM", val);
+#endif
+
+    // Create the QT application
+    QApplication app(argc, argv);
+    app.setQuitOnLastWindowClosed(false);
+
+    // Setup look n feel
+    setupStyling(&app);
+
+    // Setup the settings management
+    QCoreApplication::setOrganizationName("pgadmin");
+    QCoreApplication::setOrganizationDomain("pgadmin.org");
+    QCoreApplication::setApplicationName("pgadmin4");
+
+    // Interlock
+    if (alreadyRunning())
+        exit(0);
+
+    // Proxy config
+    configureProxy();
+
+    // Display the spash screen
+    QSplashScreen *splash = displaySplash(&app);
+
+    // Get the port number to use
+    quint16 port = getPort();
+
+    // Generate a random key to authenticate the client to the server
+    QString key = QUuid::createUuid().toString();
+    key = key.mid(1, key.length() - 2);
+
+    // Create Menu Actions
+    MenuActions *menuActions = new MenuActions();
+
+    // Create the control object (tray icon or floating window
+    FloatingWindow *floatingWindow = Q_NULLPTR;
+    TrayIcon *trayIcon = Q_NULLPTR;
+
+    splash->showMessage(QString(QWidget::tr("Checking for system tray...")), Qt::AlignBottom | Qt::AlignCenter);
+
+    if (QSystemTrayIcon::isSystemTrayAvailable())
+        trayIcon = createTrayIcon(splash, menuActions);
+    else
+        floatingWindow = createFloatingWindow(splash, menuActions);
+
+    // Fire up the app server
+    Server *server = startServerLoop(splash, floatingWindow, trayIcon, port, key);
+
+    // Ensure we'll cleanup
+    QObject::connect(server, SIGNAL(finished()), server, SLOT(deleteLater()));
+    atexit(cleanup);
+
+    // Generate the app server URL
+    QString url = QString("http://127.0.0.1:%1/?key=%2").arg(port).arg(key);
+    Logger::GetLogger()->Log(QString(QWidget::tr("Application Server URL: %1")).arg(url));
+
+    // Check the server is running
+    checkServer(splash, url);
+
+    // Stash the URL for any duplicate processes to open
+    createAddressFile(url);
+
+    // Go!
+    menuActions->setAppServerUrl(url);
+
+    // Enable the shutdown server menu as server started successfully.
+    if (trayIcon != Q_NULLPTR)
+        trayIcon->enablePostStartOptions();
+    if (floatingWindow != Q_NULLPTR)
+        floatingWindow->enablePostStartOptions();
+
+    // Open the browser if needed
+    if (m_settings.value("OpenTabAtStartup", true).toBool())
+        openBrowserTab(url);
+
+    // Make sure the server is shutdown if the server is quit by the user
+    QObject::connect(menuActions, SIGNAL(shutdownSignal(QUrl)), server, SLOT(shutdown(QUrl)));
+
+    // Final cleanup
+    splash->finish(Q_NULLPTR);
+
+    if (floatingWindow != Q_NULLPTR)
+        floatingWindow->show();
+
+    Logger::GetLogger()->Log("Everything works fine, successfully started pgAdmin4.");
+    Logger::ReleaseLogger();
+    return app.exec();
+}
+
+
+// Setup the styling
+void Runtime::setupStyling(QApplication *app)
+{
+#ifndef Q_OS_LINUX
+    QFile stylesheet;
+
+#ifdef Q_OS_WIN32
+    QSettings registry("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings::Registry64Format);
+    if (registry.value("AppsUseLightTheme", true).toBool())
+    {
+        qDebug( "Windows Light Mode...");
+        stylesheet.setFileName(":/light.qss");
+    }
+    else
+    {
+        qDebug( "Windows Dark Mode..." );
+        stylesheet.setFileName(":/dark.qss");
+    }
+#endif
+
+#ifdef Q_OS_MAC
+    if (IsDarkMode())
+    {
+        qDebug( "macOS Dark Mode...");
+        stylesheet.setFileName(":/dark.qss");
+    }
+    else
+    {
+        qDebug( "macOS Light Mode..." );
+        stylesheet.setFileName(":/light.qss");
+    }
+#endif
+
+    stylesheet.open(QFile::ReadOnly | QFile::Text);
+    QTextStream stream(&stylesheet);
+    app->setStyleSheet(stream.readAll());
+#endif
+
+    // Set high DPI pixmap to display icons clear on Qt widget.
+    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
+}
+
+// Check if we're already running. If we are, open a new browser tab.
+bool Runtime::alreadyRunning()
+{
+    // Create a system-wide semaphore keyed by app name, exe hash and the username
+    // to ensure instances are unique to the user and path
+    QString userName = qgetenv("USER"); // *nix
+    if (userName.isEmpty())
+        userName = qgetenv("USERNAME"); // Windows
+
+    QString semaName = QString("pgadmin4-%1-%2-sema").arg(userName).arg(getExeHash());
+    QString shmemName = QString("pgadmin4-%1-%2-shmem").arg(userName).arg(getExeHash());
+    qDebug() << "Semaphore name:" << semaName;
+    qDebug() << "Shared memory segment name:" << shmemName;
+
+    QSystemSemaphore sema(semaName, 1);
+    sema.acquire();
+
+#ifndef Q_OS_WIN32
+    // We may need to clean up stale shmem segments on *nix. Attaching and detaching
+    // should remove the segment if it is orphaned.
+    QSharedMemory stale_shmem(shmemName);
+    if (stale_shmem.attach())
+        stale_shmem.detach();
+#endif
+
+    m_shmem = new QSharedMemory(shmemName);
+    bool is_running;
+    if (m_shmem->attach())
+        is_running = true;
+    else
+    {
+        m_shmem->create(1);
+        is_running = false;
+    }
+    sema.release();
+
+    if (is_running)
+    {
+        QFile addressFile(getAddressFile());
+        addressFile.open(QIODevice::ReadOnly | QIODevice::Text);
+        QTextStream in(&addressFile);
+        QString url = in.readLine();
+
+        qDebug() << "Already running. Opening browser tab to: " << url << "and exiting.";
+        openBrowserTab(url);
+        return true;
+    }
+
+    return false;
+}
+
+
+void Runtime::configureProxy()
+{
+    // In windows and linux, it is required to set application level proxy
+    // because socket bind logic to find free port gives socket creation error
+    // when system proxy is configured. We are also setting
+    // "setUseSystemConfiguration"=true to use the system proxy which will
+    // override this application level proxy. As this bug is fixed in Qt 5.9 so
+    // need to set application proxy for Qt version < 5.9.
+    //
+#if defined (Q_OS_WIN) && QT_VERSION <= 0x050800
+    // Give dummy URL required to find proxy server configured in windows.
+    QNetworkProxyQuery proxyQuery(QUrl("https://www.pgadmin.org"));
+    QNetworkProxy l_proxy;
+    QList<QNetworkProxy> listOfProxies = QNetworkProxyFactory::systemProxyForQuery(proxyQuery);
+
+    if (listOfProxies.size())
+    {
+        l_proxy = listOfProxies[0];
+
+        // If host name is not empty means proxy server is configured.
+        if (!l_proxy.hostName().isEmpty()) {
+            QNetworkProxy::setApplicationProxy(QNetworkProxy());
+        }
+    }
+#endif
+
+#if defined (Q_OS_LINUX) && QT_VERSION <= 0x050800
+    QByteArray proxy_env;
+    proxy_env = qgetenv("http_proxy");
+    // If http_proxy environment is defined in linux then proxy server is configured.
+    if (!proxy_env.isEmpty()) {
+        QNetworkProxy::setApplicationProxy(QNetworkProxy());
+    }
+#endif
+}
+
+
+// Display the splash screen
+QSplashScreen * Runtime::displaySplash(QApplication *app)
+{
+    QSplashScreen *splash = new QSplashScreen();
+    splash->setPixmap(QPixmap(":/splash.png"));
+    splash->setWindowFlags(splash->windowFlags() | Qt::WindowStaysOnTopHint);
+    splash->show();
+    app->processEvents(QEventLoop::AllEvents);
+
+    return splash;
+}
+
+
+// Get the port number we're going to use
+quint16 Runtime::getPort()
+{
+    quint16 port = 0L;
+
+    if (m_settings.value("FixedPort", false).toBool())
+    {
+        // Use the fixed port number
+        port = m_settings.value("PortNumber", 5050).toInt();
+    }
+    else
+    {
+        // Find an unused port number. Essentially, we're just reserving one
+        // here that Flask will use when we start up the server.
+        QTcpSocket socket;
+
+#if QT_VERSION >= 0x050900
+        socket.setProxy(QNetworkProxy::NoProxy);
+#endif
+
+        socket.bind(0, QTcpSocket::ShareAddress);
+        port = socket.localPort();
+    }
+
+    return port;
+}
+
+
+// Create a tray icon
+TrayIcon * Runtime::createTrayIcon(QSplashScreen *splash, MenuActions *menuActions)
+{
+    TrayIcon *trayIcon = Q_NULLPTR;
+
+    splash->showMessage(QString(QWidget::tr("Checking for system tray...")), Qt::AlignBottom | Qt::AlignCenter);
+    Logger::GetLogger()->Log("Checking for system tray...");
+
+    // Start the tray service
+    trayIcon = new TrayIcon();
+
+    // Set the MenuActions object to connect to slot
+    if (trayIcon != Q_NULLPTR)
+        trayIcon->setMenuActions(menuActions);
+
+    trayIcon->Init();
+
+    return trayIcon;
+}
+
+
+// Create a floating window
+FloatingWindow * Runtime::createFloatingWindow(QSplashScreen *splash, MenuActions *menuActions)
+{
+    FloatingWindow *floatingWindow = Q_NULLPTR;
+
+    splash->showMessage(QString(QWidget::tr("System tray not found, creating floating window...")), Qt::AlignBottom | Qt::AlignCenter);
+    Logger::GetLogger()->Log("System tray not found, creating floating window...");
+    floatingWindow = new FloatingWindow();
+    if (floatingWindow == Q_NULLPTR)
+    {
+        QString error = QString(QWidget::tr("Unable to initialize either a tray icon or floating window."));
+        QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
+        Logger::GetLogger()->Log(error);
+        Logger::ReleaseLogger();
+        exit(1);
+    }
+
+    // Set the MenuActions object to connect to slot
+    floatingWindow->setMenuActions(menuActions);
+    floatingWindow->Init();
+
+    return floatingWindow;
+}
+
+
+// Server startup loop
+Server * Runtime::startServerLoop(QSplashScreen *splash, FloatingWindow *floatingWindow, TrayIcon *trayIcon, int port, QString key)
+{
+    bool done = false;
+    Server *server;
+
+    while (!done)
+    {
+        server = startServer(splash, port, key);
+        if (server == NULL)
+        {
+            Logger::ReleaseLogger();
+            QApplication::quit();
+        }
+
+        // Check for server startup errors
+        if (server->isFinished() || server->getError().length() > 0)
+        {
+            splash->finish(Q_NULLPTR);
+
+            qDebug() << server->getError();
+
+            QString error = QString(QWidget::tr("An error occurred initialising the pgAdmin 4 server:\n\n%1")).arg(server->getError());
+            QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
+            Logger::GetLogger()->Log(error);
+
+            delete server;
+
+            // Enable the View Log option for diagnostics
+            if (floatingWindow)
+                floatingWindow->enableViewLogOption();
+            if (trayIcon)
+                trayIcon->enableViewLogOption();
+
+            // Allow the user to tweak the Python Path if needed
+            m_configDone = false;
+
+            ConfigWindow *dlg = new ConfigWindow();
+            dlg->setAttribute(Qt::WA_DeleteOnClose);
+            dlg->show();
+            dlg->raise();
+            dlg->activateWindow();
+            QObject::connect(dlg, SIGNAL(closing(bool)), this, SLOT(onConfigDone(bool)));
+
+            // Wait for configuration to be completed
+            while (!m_configDone)
+                delay(100);
+
+            // Disable the View Log option again
+            if (floatingWindow)
+                floatingWindow->disableViewLogOption();
+            if (trayIcon)
+                trayIcon->disableViewLogOption();
+        }
+        else
+        {
+            // Startup appears successful
+            done = true;
+        }
+    }
+
+    return server;
+}
+
+
+// Slot called when re-configuration is done.
+void Runtime::onConfigDone(bool accepted)
+{
+    if (accepted)
+        m_configDone = true;
+    else
+        exit(0);
+}
+
+
+// Start the server
+Server * Runtime::startServer(QSplashScreen *splash, int port, QString key)
+{
+    Server *server;
+
+    splash->showMessage(QString(QWidget::tr("Starting pgAdmin4 server...")), Qt::AlignBottom | Qt::AlignCenter);
+    Logger::GetLogger()->Log("Starting pgAdmin4 server...");
+
+    QString msg = QString(QWidget::tr("Creating server object, port:%1, key:%2, logfile:%3")).arg(port).arg(key).arg(getServerLogFile());
+    Logger::GetLogger()->Log(msg);
+    server = new Server(this, port, key, getServerLogFile());
+
+    Logger::GetLogger()->Log("Initializing server...");
+    if (!server->Init())
+    {
+        splash->finish(Q_NULLPTR);
+
+        qDebug() << server->getError();
+
+        QString error = QString(QWidget::tr("An error occurred initialising the pgAdmin 4 server:\n\n%1")).arg(server->getError());
+        QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
+
+        Logger::GetLogger()->Log(error);
+        Logger::ReleaseLogger();
+
+        exit(1);
+    }
+
+    Logger::GetLogger()->Log("Server initialized, starting server thread...");
+    server->start();
+
+    // This is a hack to give the server a chance to start and potentially fail. As
+    // the Python interpreter is a synchronous call, we can't check for proper startup
+    // easily in a more robust way - we have to rely on a clean startup not returning.
+    // It should always fail pretty quickly, and take longer to start if it succeeds, so
+    // we don't really get a visible delay here.
+    delay(1000);
+
+    return server;
+}
+
+
+// Check the server is running properly
+void Runtime::checkServer(QSplashScreen *splash, QString url)
+{
+    // Read the server connection timeout from the registry or set the default timeout.
+    int timeout = m_settings.value("ConnectionTimeout", 90).toInt();
+
+    // Now the server should be up, we'll attempt to connect and get a response.
+    // We'll retry in a loop a few time before aborting if necessary.
+
+    QTime endTime = QTime::currentTime().addSecs(timeout);
+    QTime midTime1 = QTime::currentTime().addSecs(timeout/3);
+    QTime midTime2 = QTime::currentTime().addSecs(timeout*2/3);
+    bool alive = false;
+
+    Logger::GetLogger()->Log("The server should be up. Attempting to connect and get a response.");
+    while(QTime::currentTime() <= endTime)
+    {
+        alive = pingServer(QUrl(url));
+
+        if (alive)
+        {
+            break;
+        }
+
+        if(QTime::currentTime() >= midTime1)
+        {
+            if(QTime::currentTime() < midTime2) {
+                splash->showMessage(QString(QWidget::tr("Taking longer than usual...")), Qt::AlignBottom | Qt::AlignCenter);
+            }
+            else
+            {
+                splash->showMessage(QString(QWidget::tr("Almost there...")), Qt::AlignBottom | Qt::AlignCenter);
+            }
+        }
+
+        delay(200);
+    }
+
+    // Attempt to connect one more time in case of a long network timeout while looping
+    Logger::GetLogger()->Log("Attempt to connect one more time in case of a long network timeout while looping");
+    if (!alive && !pingServer(QUrl(url)))
+    {
+        splash->finish(Q_NULLPTR);
+        QString error(QWidget::tr("The pgAdmin 4 server could not be contacted."));
+        QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
+
+        Logger::ReleaseLogger();
+        exit(1);
+    }
+}
+
+
+// Create the address file
+void Runtime::createAddressFile(QString url)
+{
+    QFile addressFile(getAddressFile());
+    if (addressFile.open(QIODevice::WriteOnly))
+    {
+        addressFile.setPermissions(QFile::ReadOwner|QFile::WriteOwner);
+        QTextStream out(&addressFile);
+        out << url << endl;
+    }
+}
+
+
+// Open a browser tab
+void Runtime::openBrowserTab(QString url)
+{
+    QString cmd = m_settings.value("BrowserCommand").toString();
+
+    if (!cmd.isEmpty())
+    {
+        cmd.replace("%URL%", url);
+        QProcess::startDetached(cmd);
+    }
+    else
+    {
+        if (!QDesktopServices::openUrl(url))
+        {
+            QString error(QWidget::tr("Failed to open the system default web browser. Is one installed?."));
+            QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
+
+            Logger::GetLogger()->Log(error);
+            Logger::ReleaseLogger();
+            exit(1);
+        }
+    }
+}
+
+
+// Make a request to the Python API server
+QString Runtime::serverRequest(QUrl url, QString path)
+{
+    QNetworkAccessManager manager;
+    QEventLoop loop;
+    QNetworkReply *reply;
+    QVariant redirectUrl;
+
+
+    url.setPath(path);
+    QString requestUrl = url.toString();
+
+    do
+    {
+        reply = manager.get(QNetworkRequest(url));
+        QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
+        loop.exec();
+
+        redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+        url = redirectUrl.toUrl();
+
+        if (!redirectUrl.isNull())
+            delete reply;
+
+    } while (!redirectUrl.isNull());
+
+    if (reply->error() != QNetworkReply::NoError)
+    {
+        qDebug() << "Failed to connect to the server:" << reply->errorString() << "- request URL:" << requestUrl << ".";
+        return QString();
+    }
+
+    QString response = reply->readAll();
+    qDebug() << "Server response:" << response << "- request URL:" << requestUrl << ".";
+
+    return response;
+}
+
+
+// Ping the application server to see if it's alive
+bool Runtime::pingServer(QUrl url)
+{
+    return serverRequest(url, "/misc/ping") == "PING";
+}
+
+
+// Shutdown the application server
+bool Runtime::shutdownServer(QUrl url)
+{
+    return serverRequest(url, "/misc/shutdown") == "SHUTDOWN";
+}
+
+
+void Runtime::delay(int milliseconds)
+{
+    QTime endTime = QTime::currentTime().addMSecs(milliseconds);
+    while(QTime::currentTime() < endTime)
+    {
+        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
+    }
+}
+
Index: runtime/Runtime.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/Runtime.h	(date 1594891454024)
+++ runtime/Runtime.h	(date 1594891454024)
@@ -0,0 +1,65 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2020, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// Runtime.h - Core of the runtime
+//
+//////////////////////////////////////////////////////////////////////////
+
+#ifndef RUNTIME_H
+#define RUNTIME_H
+
+// Include the Python header here as it needs to appear before any QT
+// headers anywhere in the app.
+#ifdef __MINGW32__
+#include <cmath>
+#endif
+#include <Python.h>
+
+#include "TrayIcon.h"
+#include "MenuActions.h"
+#include "FloatingWindow.h"
+
+// QT headers
+#include <QtWidgets>
+
+class Server;
+
+class Runtime: public QObject
+{
+    Q_OBJECT
+public:
+    Runtime();
+
+    bool alreadyRunning();
+    bool go(int argc, char *argv[]);
+    void delay(int milliseconds);
+    bool shutdownServer(QUrl url);
+
+private:
+    QSettings m_settings;
+    QSharedMemory *m_shmem;
+    bool m_configDone;
+
+    void setupStyling(QApplication *app);
+    void configureProxy();
+    QSplashScreen *displaySplash(QApplication *app);
+    quint16 getPort();
+    TrayIcon *createTrayIcon(QSplashScreen *splash, MenuActions *menuActions);
+    FloatingWindow *createFloatingWindow(QSplashScreen *splash, MenuActions *menuActions);
+    Server *startServerLoop(QSplashScreen *splash, FloatingWindow *floatingWindow, TrayIcon *trayIcon, int port, QString key);
+    Server *startServer(QSplashScreen *splash, int port, QString key);
+    void checkServer(QSplashScreen *splash, QString url);
+    void createAddressFile(QString url);
+    void openBrowserTab(QString url);
+    QString serverRequest(QUrl url, QString path);
+    bool pingServer(QUrl url);
+
+private slots:
+    void onConfigDone(bool accepted);
+};
+
+#endif // RUNTIME_H
Index: runtime/LogWindow.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/LogWindow.cpp	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/LogWindow.cpp	(date 1594660580030)
@@ -13,13 +13,13 @@
 #include "LogWindow.h"
 #include "ui_LogWindow.h"
 
+#include <QStandardPaths>
 #include <QTime>
 
 #include <stdio.h>
 
-LogWindow::LogWindow(QWidget *parent, QString serverLogFile) :
-    QDialog(parent),
-    m_serverLogFile(serverLogFile)
+LogWindow::LogWindow(QWidget *parent) :
+    QDialog(parent)
 {
     initLogWindow();
 }
@@ -35,15 +35,13 @@
     int startupLines;
     int serverLines;
 
-    QString startup_log = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + (QString("/.%1.startup.log").arg(PGA_APP_NAME)).remove(" ");
-
     ui->lblStatus->setText(tr("Loading logfiles..."));
 
-    ui->lblStartupLog->setText(tr("Startup Log (%1):").arg(startup_log));
-    ui->lblServerLog->setText(tr("Server Log (%1):").arg(m_serverLogFile));
+    ui->lblStartupLog->setText(tr("Startup Log (%1):").arg(getStartupLogFile()));
+    ui->lblServerLog->setText(tr("Server Log (%1):").arg(getServerLogFile()));
 
-    startupLines = this->readLog(startup_log, ui->textStartupLog);
-    serverLines = this->readLog(m_serverLogFile, ui->textServerLog);
+    startupLines = this->readLog(getStartupLogFile(), ui->textStartupLog);
+    serverLines = this->readLog(getServerLogFile(), ui->textServerLog);
 
     ui->lblStatus->setText(QString(tr("Loaded startup log (%1 lines) and server log (%2 lines).")).arg(startupLines).arg(serverLines));
 }
@@ -75,7 +73,7 @@
     log = fopen(logFile.toUtf8().data(), "r");
     if (log == Q_NULLPTR)
     {
-            logWidget->setPlainText(QString(tr("The log file (%1) could not be opened.")).arg(m_serverLogFile));
+            logWidget->setPlainText(QString(tr("The log file (%1) could not be opened.")).arg(getServerLogFile()));
             this->setDisabled(false);
             QApplication::restoreOverrideCursor();
             return 0;
Index: runtime/ConfigWindow.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/ConfigWindow.h	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/ConfigWindow.h	(date 1594826909291)
@@ -25,8 +25,11 @@
 public:
     explicit ConfigWindow(QWidget *parent = Q_NULLPTR);
 
-    void LoadSettings();
-    bool SaveSettings();
+    bool NeedRestart() { return m_needRestart; };
+
+signals:
+    void accepted(bool needRestart);
+    void closing(bool accepted);
 
 private slots:
     void on_buttonBox_accepted();
@@ -35,6 +38,8 @@
 
 private:
     Ui::ConfigWindow *ui;
+    bool m_needRestart;
+
     void initConfigWindow();
 };
 
Index: runtime/FloatingWindow.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/FloatingWindow.cpp	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/FloatingWindow.cpp	(date 1594891472612)
@@ -9,16 +9,20 @@
 //
 ////////////////////////////////////////////////////////////////////////////
 
-
+#include "pgAdmin4.h"
 #include "FloatingWindow.h"
 #include "ui_FloatingWindow.h"
 
+#include <QMenu>
+#include <QMenuBar>
+
 
 FloatingWindow::FloatingWindow(QWidget *parent) :
     QMainWindow(parent)
 {
 }
 
+
 bool FloatingWindow::Init()
 {
     ui = new Ui::FloatingWindow;
@@ -41,12 +45,13 @@
     return true;
 }
 
+
 // Create the menu
 void FloatingWindow::createMenu()
 {
     createActions();
 
-    m_floatingWindowMenu = menuBar()->addMenu(QString(tr("&%1")).arg(PGA_APP_NAME));
+    m_floatingWindowMenu = menuBar()->addMenu(tr("&pgAdmin 4"));
     m_floatingWindowMenu->addAction(m_newAction);
     m_floatingWindowMenu->addAction(m_copyUrlAction);
     m_floatingWindowMenu->addSeparator();
@@ -56,19 +61,24 @@
     m_floatingWindowMenu->addAction(m_quitAction);
 }
 
+
 // Create the menu actions
 void FloatingWindow::createActions()
 {
-    m_newAction = new QAction(QString(tr("&New %1 window...")).arg(PGA_APP_NAME), this);
+    m_newAction = new QAction(tr("&New pgAdmin 4 window..."), this);
+    m_newAction->setEnabled(false);
     connect(m_newAction, SIGNAL(triggered()), m_menuActions, SLOT(onNew()));
 
     m_copyUrlAction = new QAction(tr("&Copy server URL"), this);
+    m_copyUrlAction->setEnabled(false);
     connect(m_copyUrlAction, SIGNAL(triggered()), m_menuActions, SLOT(onCopyUrl()));
 
     m_configAction = new QAction(tr("C&onfigure..."), this);
+    m_configAction->setEnabled(false);
     connect(m_configAction, SIGNAL(triggered()), m_menuActions, SLOT(onConfig()));
 
     m_logAction = new QAction(tr("&View log..."), this);
+    m_logAction->setEnabled(false);
     connect(m_logAction, SIGNAL(triggered()), m_menuActions, SLOT(onLog()));
 
     m_quitAction = new QAction(tr("&Shut down server"), this);
@@ -76,19 +86,48 @@
     connect(m_quitAction, SIGNAL(triggered()), m_menuActions, SLOT(onQuit()));
 }
 
-void FloatingWindow::enableShutdownMenu()
+
+void FloatingWindow::enablePostStartOptions()
 {
+    if (m_newAction != Q_NULLPTR)
+        m_newAction->setEnabled(true);
+
+    if (m_copyUrlAction != Q_NULLPTR)
+        m_copyUrlAction->setEnabled(true);
+
+    if (m_configAction != Q_NULLPTR)
+        m_configAction->setEnabled(true);
+
+    if (m_logAction != Q_NULLPTR)
+        m_logAction->setEnabled(true);
+
     if (m_quitAction != Q_NULLPTR)
-    {
         m_quitAction->setEnabled(true);
-    }
+}
+
+
+// Enable the View Log option
+void FloatingWindow::enableViewLogOption()
+{
+    if (m_logAction != Q_NULLPTR)
+        m_logAction->setEnabled(true);
 }
+
+
+// Disable the View Log option
+void FloatingWindow::disableViewLogOption()
+{
+    if (m_logAction != Q_NULLPTR)
+        m_logAction->setEnabled(false);
+}
+
 
 void FloatingWindow::setMenuActions(MenuActions * menuActions)
 {
     m_menuActions = menuActions;
 }
 
+
 void FloatingWindow::closeEvent(QCloseEvent * event)
 {
     // Emit the signal to shut down the python server.
Index: runtime/pgAdmin4.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/pgAdmin4.h	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/pgAdmin4.h	(date 1594828249526)
@@ -12,34 +12,17 @@
 #ifndef PGADMIN4_H
 #define PGADMIN4_H
 
-// Include the Python header here as it needs to appear before any QT
-// headers anywhere in the app.
-#ifdef __MINGW32__
-#include <cmath>
-#endif
-#include <Python.h>
-
 // QT headers
-#include <QtGlobal>
-
-#if QT_VERSION >= 0x050000
-#include <QtWidgets>
-#else
-#include <QApplication>
-#include <QtGui>
-#include <Qt/qurl.h>
-#endif
-
-// Application name
-const QString PGA_APP_NAME = QString("pgAdmin 4");
+#include <QString>
 
 // Global function prototypes
 int main(int argc, char * argv[]);
-QString serverRequest(QUrl url, QString path);
-bool pingServer(QUrl url);
-bool shutdownServer(QUrl url);
-void delay(int milliseconds);
+
+QString getStartupLogFile();
+QString getServerLogFile();
+QString getAddressFile();
+QString getExeHash();
+
 void cleanup();
-unsigned long sdbm(unsigned char *str);
 
 #endif // PGADMIN4_H
Index: runtime/MenuActions.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/MenuActions.cpp	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/MenuActions.cpp	(date 1594828322758)
@@ -9,11 +9,16 @@
 //
 //////////////////////////////////////////////////////////////////////////
 
+#include "pgAdmin4.h"
 #include "MenuActions.h"
 
-// QT headers
+#include <QApplication>
 #include <QClipboard>
+#include <QDesktopServices>
+#include <QEventLoop>
 #include <QMessageBox>
+#include <QProcess>
+#include <QSettings>
 
 MenuActions::MenuActions()
 {
@@ -24,10 +29,6 @@
     m_appServerUrl = appServerUrl;
 }
 
-void MenuActions::setLogFile(QString logFile)
-{
-    m_logFile = logFile;
-}
 
 // Create a new application browser window on user request
 void MenuActions::onNew()
@@ -64,18 +65,24 @@
 // Show the config dialogue
 void MenuActions::onConfig()
 {
-    bool ok;
+    if (!m_configWindow)
+        m_configWindow = new ConfigWindow();
+
+    m_configWindow->show();
+    m_configWindow->raise();
+    m_configWindow->activateWindow();
+    connect(m_configWindow, SIGNAL(accepted(bool)), this, SLOT(onConfigDone(bool)));
+}
 
-    ConfigWindow *dlg = new ConfigWindow();
-    dlg->LoadSettings();
-    dlg->setModal(true);
-    ok = dlg->exec();
 
-    if (ok)
+void MenuActions::onConfigDone(bool needRestart)
+{
+    if (needRestart)
     {
-        bool needRestart = dlg->SaveSettings();
-
-        if (needRestart && QMessageBox::Yes == QMessageBox::question(Q_NULLPTR, tr("Shut down server?"), QString(tr("The %1 server must be restarted for changes to take effect. Do you want to shut down the server now?")).arg(PGA_APP_NAME), QMessageBox::Yes | QMessageBox::No))
+        if (QMessageBox::Yes == QMessageBox::question(Q_NULLPTR,
+                                                      tr("Shut down server?"),
+                                                      tr("The pgAdmin 4 server must be restarted for changes to take effect. Do you want to shut down the server now?"),
+                                                      QMessageBox::Yes | QMessageBox::No))
             exit(0);
     }
 }
@@ -87,16 +94,13 @@
     QSettings settings;
 
     if (!m_logWindow)
-    {
-        m_logWindow = new LogWindow(Q_NULLPTR, m_logFile);
-        m_logWindow->setWindowTitle(QString(tr("%1 Log")).arg(PGA_APP_NAME));
-    }
+        m_logWindow = new LogWindow();
 
     m_logWindow->show();
     m_logWindow->raise();
     m_logWindow->activateWindow();
 
-    QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
+    QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
 
     m_logWindow->LoadLog();
 }
@@ -105,10 +109,10 @@
 // Exit
 void MenuActions::onQuit()
 {
-    if (QMessageBox::Yes == QMessageBox::question(Q_NULLPTR, tr("Shut down server?"), QString(tr("Are you sure you want to shut down the %1 server?")).arg(PGA_APP_NAME), QMessageBox::Yes | QMessageBox::No))
+    if (QMessageBox::Yes == QMessageBox::question(Q_NULLPTR, tr("Shut down server?"), tr("Are you sure you want to shut down the pgAdmin 4 server?"), QMessageBox::Yes | QMessageBox::No))
     {
         // Emit the signal to shut down the python server.
         emit shutdownSignal(m_appServerUrl);
-        exit(0);
+        QApplication::quit();
     }
 }
Index: runtime/Server.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/Server.cpp	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/Server.cpp	(date 1594828249520)
@@ -10,19 +10,21 @@
 //////////////////////////////////////////////////////////////////////////
 
 #include "pgAdmin4.h"
-#include "Logger.h"
 
 // Must be before QT
 #include <Python.h>
 
+#include "Server.h"
+#include "Logger.h"
+
 // QT headers
+#include <QCoreApplication>
 #include <QDebug>
 #include <QDir>
 #include <QFile>
 #include <QMessageBox>
+#include <QSettings>
 
-// App headers
-#include "Server.h"
 
 static void add_to_path(QString &python_path, QString path, bool prepend=false)
 {
@@ -55,7 +57,8 @@
     }
 }
 
-Server::Server(quint16 port, QString key, QString logFileName):
+Server::Server(Runtime *runtime, quint16 port, QString key, QString logFileName):
+    m_runtime(runtime),
     m_port(port),
     m_key(key),
     m_logFileName(logFileName)
@@ -65,7 +68,7 @@
     Py_NoUserSiteDirectory=1;
     Py_DontWriteBytecodeFlag=1;
 
-    PGA_APP_NAME_UTF8 = PGA_APP_NAME.toUtf8();
+    PGA_APP_NAME_UTF8 = QString("pgAdmin 4").toUtf8();
 
     // Python3 requires conversion of char  * to wchar_t *, so...
     const char *appName = PGA_APP_NAME_UTF8.data();
@@ -349,7 +352,7 @@
 
 void Server::shutdown(QUrl url)
 {
-    if (!shutdownServer(url))
+    if (!m_runtime->shutdownServer(url))
         setError(tr("Failed to shut down application server thread."));
 
     QThread::quit();
@@ -357,7 +360,7 @@
     while(!this->isFinished())
     {
         Logger::GetLogger()->Log("Waiting for server to shut down.");
-        delay(250);
+        m_runtime->delay(250);
     }
 }
 
Index: runtime/LogWindow.ui
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/LogWindow.ui	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/LogWindow.ui	(date 1594828322753)
@@ -11,7 +11,7 @@
    </rect>
   </property>
   <property name="windowTitle">
-   <string>Dialog</string>
+   <string>pgAdmin 4 Log</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
Index: runtime/FloatingWindow.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/FloatingWindow.h	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/FloatingWindow.h	(date 1594891454013)
@@ -9,11 +9,9 @@
 //
 ////////////////////////////////////////////////////////////////////////////
 
-
 #ifndef FLOATINGWINDOW_H
 #define FLOATINGWINDOW_H
 
-#include "pgAdmin4.h"
 #include "MenuActions.h"
 
 #include <QMainWindow>
@@ -30,7 +28,9 @@
     explicit FloatingWindow(QWidget *parent = Q_NULLPTR);
 
     bool Init();
-    void enableShutdownMenu();
+    void enablePostStartOptions();
+    void enableViewLogOption();
+    void disableViewLogOption();
     void setMenuActions(MenuActions * menuActions);
 
 private:
Index: runtime/FloatingWindow.ui
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/FloatingWindow.ui	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/FloatingWindow.ui	(date 1594828322756)
@@ -17,7 +17,7 @@
    </sizepolicy>
   </property>
   <property name="windowTitle">
-   <string>MainWindow</string>
+   <string>pgAdmin 4</string>
   </property>
   <widget class="QWidget" name="centralwidget">
    <widget class="QWidget" name="verticalLayoutWidget">
Index: runtime/ConfigWindow.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/ConfigWindow.cpp	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/ConfigWindow.cpp	(date 1594828249514)
@@ -10,10 +10,11 @@
 //////////////////////////////////////////////////////////////////////////
 
 #include "pgAdmin4.h"
-
 #include "ConfigWindow.h"
 #include "ui_ConfigWindow.h"
 
+#include <QSettings>
+
 ConfigWindow::ConfigWindow(QWidget *parent) :
     QDialog(parent)
 {
@@ -22,33 +23,12 @@
 
 void ConfigWindow::initConfigWindow()
 {
+    QSettings settings;
+
     ui = new Ui::ConfigWindow;
     ui->setupUi(this);
-}
-
-void ConfigWindow::on_buttonBox_accepted()
-{
-    this->close();
-}
-
-void ConfigWindow::on_buttonBox_rejected()
-{
-    this->close();
-}
-
-void ConfigWindow::on_chkFixedPort_stateChanged(int state)
-{
-    if (state == Qt::Checked)
-        ui->spinPortNumber->setEnabled(true);
-    else
-        ui->spinPortNumber->setEnabled(false);
-}
 
-void ConfigWindow::LoadSettings()
-{
-    QSettings settings;
-
-    setWindowTitle(QString(tr("%1 Configuration")).arg(PGA_APP_NAME));
+    m_needRestart = false;
 
     ui->browserCommandLineEdit->setText(settings.value("BrowserCommand").toString());
 
@@ -78,7 +58,7 @@
     ui->applicationPathLineEdit->setText(settings.value("ApplicationPath").toString());
 }
 
-bool ConfigWindow::SaveSettings()
+void ConfigWindow::on_buttonBox_accepted()
 {
     QSettings settings;
 
@@ -90,10 +70,10 @@
     QString pythonpath = ui->pythonPathLineEdit->text();
     QString applicationpath = ui->applicationPathLineEdit->text();
 
-    bool needRestart = (settings.value("FixedPort").toBool() != fixedport ||
-                        settings.value("PortNumber").toInt() != portnumber ||
-                        settings.value("PythonPath").toString() != pythonpath ||
-                        settings.value("ApplicationPath").toString() != applicationpath);
+    m_needRestart = (settings.value("FixedPort").toBool() != fixedport ||
+                     settings.value("PortNumber").toInt() != portnumber ||
+                     settings.value("PythonPath").toString() != pythonpath ||
+                     settings.value("ApplicationPath").toString() != applicationpath);
 
     settings.setValue("BrowserCommand", browsercommand);
     settings.setValue("FixedPort", fixedport);
@@ -104,6 +84,23 @@
 
     settings.sync();
 
-    return needRestart;
+    emit accepted(m_needRestart);
+    emit closing(true);
+
+    this->close();
+}
+
+void ConfigWindow::on_buttonBox_rejected()
+{
+    emit closing(false);
+    this->close();
+}
+
+void ConfigWindow::on_chkFixedPort_stateChanged(int state)
+{
+    if (state == Qt::Checked)
+        ui->spinPortNumber->setEnabled(true);
+    else
+        ui->spinPortNumber->setEnabled(false);
 }
 
Index: runtime/TrayIcon.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/TrayIcon.h	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/TrayIcon.h	(date 1594891454014)
@@ -12,12 +12,11 @@
 #ifndef TRAYICON_H
 #define TRAYICON_H
 
-#include "pgAdmin4.h"
-
-// QT headers
-#include <QWidget>
 #include "MenuActions.h"
 
+#include <QWidget>
+#include <QSystemTrayIcon>
+
 class TrayIcon : public QWidget
 {
     Q_OBJECT
@@ -26,7 +25,9 @@
     TrayIcon();
 
     void Init();
-    void enableShutdownMenu();
+    void enablePostStartOptions();
+    void enableViewLogOption();
+    void disableViewLogOption();
     void setMenuActions(MenuActions * menuActions);
 
 private:
Index: runtime/ConfigWindow.ui
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/ConfigWindow.ui	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/ConfigWindow.ui	(date 1594828249531)
@@ -23,7 +23,7 @@
    </size>
   </property>
   <property name="windowTitle">
-   <string>Dialog</string>
+   <string>pgAdmin 4 Configuration</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
Index: runtime/Logger.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/Logger.cpp	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/Logger.cpp	(date 1594661019891)
@@ -11,8 +11,12 @@
 
 #include "pgAdmin4.h"
 #include "Logger.h"
+
+#include <QDateTime>
+#include <QTextStream>
+#include <QStandardPaths>
+
 Logger* Logger::m_pThis = Q_NULLPTR;
-QString Logger::m_sFileName = "";
 QFile* Logger::m_Logfile = Q_NULLPTR;
 
 Logger::Logger()
@@ -28,9 +32,8 @@
     if (m_pThis == Q_NULLPTR)
     {
         m_pThis = new Logger();
-        m_sFileName = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + (QString("/.%1.startup.log").arg(PGA_APP_NAME)).remove(" ");
         m_Logfile = new QFile;
-        m_Logfile->setFileName(m_sFileName);
+        m_Logfile->setFileName(getStartupLogFile());
         m_Logfile->open(QIODevice::WriteOnly | QIODevice::Text);
         m_Logfile->setPermissions(QFile::ReadOwner|QFile::WriteOwner);
     }
Index: runtime/Logger.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/Logger.h	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/Logger.h	(date 1594660896563)
@@ -27,7 +27,6 @@
     virtual ~Logger();
 
     static Logger* m_pThis;
-    static QString m_sFileName;
     static QFile *m_Logfile;
 };
 
Index: runtime/Server.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/Server.h	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/Server.h	(date 1594657203747)
@@ -12,18 +12,17 @@
 #ifndef SERVER_H
 #define SERVER_H
 
-#include "pgAdmin4.h"
+#include "Runtime.h"
 
-// QT headers
 #include <QThread>
-#include <QMessageBox>
+#include <QUrl>
 
 class Server : public QThread
 {
     Q_OBJECT
 
 public:
-    Server(quint16 port, QString key, QString logFileName);
+    Server(Runtime *runtime, quint16 port, QString key, QString logFileName);
     ~Server();
 
     bool Init();
@@ -41,7 +40,8 @@
     QString m_appfile;
     QString m_error;
 
-    quint16  m_port;
+    Runtime *m_runtime;
+    quint16 m_port;
     QString m_key;
     QString m_logFileName;
 
Index: runtime/pgAdmin4.pro
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/pgAdmin4.pro	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/pgAdmin4.pro	(date 1594890655540)
@@ -8,15 +8,15 @@
 message(Configuring the pgAdmin 4 runtime.)
 message(==================================)
 
+# Check for a suitable Qt version
+!versionAtLeast(QT_VERSION, 5.0.0) {
+    error("pgAdmin 4 cannot be built with Qt $${QT_VERSION}. Use Qt 5.0 or newer.")
+}
+message(Qt version: $${QT_VERSION})
+
 # Configure QT modules for the appropriate version of QT
-greaterThan(QT_MAJOR_VERSION, 4) {
-    message(Qt version:     5)
-    QT += network widgets
-} else { 
-    message(Qt version:     4)
-    QT += network
-    DEFINES += Q_NULLPTR=NULL
-}
+QT += network widgets
+
 win32 {
   RC_ICONS += pgAdmin4.ico
 }
@@ -94,6 +94,7 @@
 
 # Source code
 HEADERS =             Server.h \
+                      Runtime.h \
                       pgAdmin4.h \
                       ConfigWindow.h \
                       TrayIcon.h \
@@ -103,6 +104,7 @@
                       Logger.h
 
 SOURCES =             pgAdmin4.cpp \
+                      Runtime.cpp \
                       Server.cpp \
                       ConfigWindow.cpp \
                       TrayIcon.cpp \
Index: runtime/TrayIcon.cpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/TrayIcon.cpp	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/TrayIcon.cpp	(date 1594891472610)
@@ -9,13 +9,17 @@
 //
 //////////////////////////////////////////////////////////////////////////
 
-// App headers
+#include "pgAdmin4.h"
 #include "TrayIcon.h"
 
+#include <QMenu>
+
+
 TrayIcon::TrayIcon()
 {
 }
 
+
 void TrayIcon::Init()
 {
     createTrayIcon();
@@ -24,6 +28,7 @@
         m_trayIcon->show();
 }
 
+
 // Create the tray icon
 void TrayIcon::createTrayIcon()
 {
@@ -60,19 +65,24 @@
     setWindowIcon(icon);
 }
 
+
 // Create the menu actions
 void TrayIcon::createActions()
 {
-    m_newAction = new QAction(QString(tr("&New %1 window...")).arg(PGA_APP_NAME), this);
+    m_newAction = new QAction(tr("&New pgAdmin 4 window..."), this);
+    m_newAction->setEnabled(false);
     connect(m_newAction, SIGNAL(triggered()), m_menuActions, SLOT(onNew()));
 
     m_copyUrlAction = new QAction(tr("&Copy server URL"), this);
+    m_copyUrlAction->setEnabled(false);
     connect(m_copyUrlAction, SIGNAL(triggered()), m_menuActions, SLOT(onCopyUrl()));
 
     m_configAction = new QAction(tr("&Configure..."), this);
+    m_configAction->setEnabled(false);
     connect(m_configAction, SIGNAL(triggered()), m_menuActions, SLOT(onConfig()));
 
     m_logAction = new QAction(tr("&View log..."), this);
+    m_logAction->setEnabled(false);
     connect(m_logAction, SIGNAL(triggered()), m_menuActions, SLOT(onLog()));
 
     m_quitAction = new QAction(tr("&Shut down server"), this);
@@ -80,13 +90,41 @@
     connect(m_quitAction, SIGNAL(triggered()), m_menuActions, SLOT(onQuit()));
 }
 
-void TrayIcon::enableShutdownMenu()
+
+void TrayIcon::enablePostStartOptions()
 {
+    if (m_newAction != Q_NULLPTR)
+        m_newAction->setEnabled(true);
+
+    if (m_copyUrlAction != Q_NULLPTR)
+        m_copyUrlAction->setEnabled(true);
+
+    if (m_configAction != Q_NULLPTR)
+        m_configAction->setEnabled(true);
+
+    if (m_logAction != Q_NULLPTR)
+        m_logAction->setEnabled(true);
+
     if (m_quitAction != Q_NULLPTR)
-    {
         m_quitAction->setEnabled(true);
-    }
+}
+
+
+// Enable the View Log option
+void TrayIcon::enableViewLogOption()
+{
+    if (m_logAction != Q_NULLPTR)
+        m_logAction->setEnabled(true);
 }
+
+
+// Disable the View Log option
+void TrayIcon::disableViewLogOption()
+{
+    if (m_logAction != Q_NULLPTR)
+        m_logAction->setEnabled(false);
+}
+
 
 void TrayIcon::setMenuActions(MenuActions * menuActions)
 {
Index: runtime/LogWindow.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- runtime/LogWindow.h	(revision 911393206659482c9b7cdeaa190c72074f2252fe)
+++ runtime/LogWindow.h	(date 1594660529056)
@@ -24,7 +24,7 @@
     Q_OBJECT
 
 public:
-    explicit LogWindow(QWidget *parent = Q_NULLPTR, QString serverLogFile = "");
+    explicit LogWindow(QWidget *parent = Q_NULLPTR);
     void LoadLog();
 
 private slots:
@@ -33,9 +33,6 @@
 private:
     Ui::LogWindow *ui;
 
-    QString m_startupLogFile;
-    QString m_serverLogFile;
-
     void initLogWindow();
     int readLog(QString logFile, QPlainTextEdit *logWidget);
 };
