summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2016-09-16 17:39:15 +0200
committerStanislaw Halik <sthalik@misaki.pl>2016-09-16 17:54:12 +0200
commitaf8d6f769c26d4d260d6fc430165b51aebbd0733 (patch)
tree2129d44b18bc919b339d7bfd9de9da6b3c921669
parenta781170550b4354e0f5551e0b20560d84e4108ce (diff)
gui/main-window: exit program when config not writable
Note, it opens the config in read-write mode to check if it's writable. This might present a race condition when config is saved. However, we're expecting all config saving to be done in the user interface thread. Add a check for it however.
-rw-r--r--gui/main-window.cpp319
-rw-r--r--gui/main-window.hpp10
-rw-r--r--gui/main.cpp18
-rw-r--r--options/bundle.cpp6
-rw-r--r--options/group.cpp13
-rw-r--r--options/group.hpp1
6 files changed, 195 insertions, 172 deletions
diff --git a/gui/main-window.cpp b/gui/main-window.cpp
index 52494ff8..89235720 100644
--- a/gui/main-window.cpp
+++ b/gui/main-window.cpp
@@ -16,9 +16,11 @@
#include <QFileDialog>
#include <QDesktopServices>
#include <QCoreApplication>
+#include <QApplication>
#include <QIcon>
#include <QString>
#include <QChar>
+#include <QSignalBlocker>
#ifdef _WIN32
# include <windows.h>
@@ -43,7 +45,14 @@ MainWindow::MainWindow() :
setFixedSize(size());
updateButtonState(false, false);
- refresh_config_list(true);
+ if (group::ini_directory().size() == 0)
+ {
+ die_on_config_not_writable();
+ return;
+ }
+
+ if (!refresh_config_list())
+ return;
connect(ui.btnEditCurves, SIGNAL(clicked()), this, SLOT(showCurveConfiguration()));
connect(ui.btnShortcuts, SIGNAL(clicked()), this, SLOT(show_options_dialog()));
@@ -52,7 +61,7 @@ MainWindow::MainWindow() :
connect(ui.btnShowFilterControls, SIGNAL(clicked()), this, SLOT(showFilterSettings()));
connect(ui.btnStartTracker, SIGNAL(clicked()), this, SLOT(startTracker()));
connect(ui.btnStopTracker, SIGNAL(clicked()), this, SLOT(stopTracker()));
- connect(ui.iconcomboProfile, SIGNAL(currentTextChanged(QString)), this, SLOT(profile_selected(QString)));
+ connect(ui.iconcomboProfile, &QComboBox::currentTextChanged, this, [&](const QString& x) { set_profile(x); });
// fill dylib comboboxen
{
@@ -69,7 +78,7 @@ MainWindow::MainWindow() :
}
// timers
- connect(&config_list_timer, &QTimer::timeout, this, [this]() { refresh_config_list(false); });
+ connect(&config_list_timer, &QTimer::timeout, this, [this]() { refresh_config_list(); });
connect(&pose_update_timer, SIGNAL(timeout()), this, SLOT(showHeadPose()));
connect(&det_timer, SIGNAL(timeout()), this, SLOT(maybe_start_profile_from_executable()));
@@ -84,18 +93,14 @@ MainWindow::MainWindow() :
ui.profile_button->setMenu(&profile_menu);
}
- if (!QFile(group::ini_pathname()).exists())
- {
- set_profile(OPENTRACK_DEFAULT_CONFIG);
- const auto pathname = group::ini_pathname();
- if (!QFile(pathname).exists())
- {
- QFile file(pathname);
- (void) file.open(QFile::ReadWrite);
- }
- }
- else
- set_profile(group::ini_filename());
+ if (!progn(
+ const QString cur = group::ini_filename();
+ if (is_config_listed(cur))
+ return set_profile(cur);
+ else
+ return set_profile(OPENTRACK_DEFAULT_CONFIG);
+ ))
+ return;
// only tie and connect main screen options after migrations are done
// below is fine, set_profile() is called already
@@ -149,12 +154,6 @@ MainWindow::MainWindow() :
ensure_tray();
}
- if (group::ini_directory() == "")
- QMessageBox::warning(this,
- "Configuration not saved.",
- "Can't create configuration directory! Expect major malfunction.",
- QMessageBox::Ok, QMessageBox::NoButton);
-
register_shortcuts();
det_timer.start(1000);
config_list_timer.start(1000 * 5);
@@ -237,19 +236,44 @@ void MainWindow::register_shortcuts()
work->reload_shortcuts();
}
-bool MainWindow::warn_on_config_not_writable()
+void MainWindow::die_on_config_not_writable()
{
- QString current_file = group::ini_pathname();
- QFile f(current_file);
- f.open(QFile::ReadWrite);
+ stopTracker();
+
+ static const QString pad(16, QChar(' '));
+
+ QMessageBox::critical(this,
+ "The Octopus is sad",
+ QStringLiteral("Check permissions for your .ini directory:\n\n\"%1\"%2\n\nExiting now.").arg(group::ini_directory()).arg(pad),
+ QMessageBox::Close, QMessageBox::NoButton);
+
+ // signals main() to short-circuit
+ if (!isVisible())
+ setEnabled(false);
+
+ setVisible(false);
+
+ // tray related
+ qApp->setQuitOnLastWindowClosed(true);
- if (!f.isOpen())
+ close();
+}
+
+bool MainWindow::maybe_die_on_config_not_writable(const QString& current, QStringList* ini_list_)
+{
+ const bool open = QFile(group::ini_combine(current)).open(QFile::ReadWrite);
+ const QStringList ini_list = group::ini_list();
+
+ if (!ini_list.contains(current) || !open)
{
- QMessageBox::warning(this, "Something went wrong", "Check permissions and ownership for your .ini file!", QMessageBox::Ok, QMessageBox::NoButton);
- return false;
+ die_on_config_not_writable();
+ return true;
}
- return true;
+ if (ini_list_ != nullptr)
+ *ini_list_ = ini_list;
+
+ return false;
}
bool MainWindow::get_new_config_name_from_dialog(QString& ret)
@@ -279,135 +303,101 @@ void MainWindow::save_modules()
void MainWindow::make_empty_config()
{
QString name;
- const QString dir = group::ini_directory();
- if (dir != "" && get_new_config_name_from_dialog(name))
+ if (get_new_config_name_from_dialog(name))
{
- QFile filename(dir + "/" + name);
- (void) filename.open(QFile::ReadWrite);
- refresh_config_list(true);
- ui.iconcomboProfile->setCurrentText(name);
- mark_config_as_not_needing_migration();
+ QFile(group::ini_combine(name)).open(QFile::ReadWrite);
+
+ if (!refresh_config_list())
+ return;
+
+ if (is_config_listed(name))
+ {
+ QSignalBlocker q(ui.iconcomboProfile);
+
+ if (!set_profile(name))
+ return;
+ mark_config_as_not_needing_migration();
+ }
}
}
void MainWindow::make_copied_config()
{
- const QString dir = group::ini_directory();
const QString cur = group::ini_pathname();
QString name;
- if (cur != "" && dir != "" && get_new_config_name_from_dialog(name))
+ if (cur != "" && get_new_config_name_from_dialog(name))
{
- const QString new_name = dir + "/" + name;
+ const QString new_name = group::ini_combine(name);
(void) QFile::remove(new_name);
- (void) QFile::copy(cur, new_name);
- refresh_config_list(true);
- ui.iconcomboProfile->setCurrentText(name);
- mark_config_as_not_needing_migration();
+ QFile::copy(cur, new_name);
+
+ if (!refresh_config_list())
+ return;
+
+ if (is_config_listed(name))
+ {
+ QSignalBlocker q(ui.iconcomboProfile);
+
+ if (!set_profile(name))
+ return;
+ mark_config_as_not_needing_migration();
+ }
}
+
}
void MainWindow::open_config_directory()
{
- const QString path = group::ini_directory();
- if (path != "")
- {
- QDesktopServices::openUrl("file:///" + QDir::toNativeSeparators(path));
- }
+ QDesktopServices::openUrl("file:///" + QDir::toNativeSeparators(group::ini_directory()));
}
-void MainWindow::refresh_config_list(bool warn)
+bool MainWindow::refresh_config_list()
{
if (work)
- return;
+ return true;
QStringList ini_list = group::ini_list();
- if (ini_list.size() == 0)
- {
- QFile filename(group::ini_directory() + "/" OPENTRACK_DEFAULT_CONFIG);
- (void) filename.open(QFile::ReadWrite);
- ini_list.append(OPENTRACK_DEFAULT_CONFIG);
- }
-
- if (progn(
- if (ini_list.size() == ui.iconcomboProfile->count())
- {
- const int sz = ini_list.size();
- for (int i = 0; i < sz; i++)
- {
- if (ini_list[i] != ui.iconcomboProfile->itemText(i))
- return false;
- }
- return true;
- }
-
- return false;
- ))
- {
- // don't even warn on non-writable.
- // it'd happen all the time since refresh is on a timer.
- return;
- }
-
- bool file_ok = false;
-
- QString current = group::ini_filename();
- QIcon icon(":/images/settings16.png");
-
- {
+ // check for sameness
+ const bool exact_same = ini_list.size() > 0 && progn(
+ if (ini_list.size() == ui.iconcomboProfile->count())
{
- inhibit_qt_signals l(*ui.iconcomboProfile);
-
- ui.iconcomboProfile->clear();
- ui.iconcomboProfile->addItems(ini_list);
-
+ const int sz = ini_list.size();
+ for (int i = 0; i < sz; i++)
{
- const int sz = ini_list.size();
-
- for (int i = 0; i < sz; i++)
- ui.iconcomboProfile->setItemIcon(i, icon);
+ if (ini_list[i] != ui.iconcomboProfile->itemText(i))
+ return false;
}
-
- ui.iconcomboProfile->setCurrentText(current);
+ return true;
}
- const QString pathname = group::ini_pathname();
+ return false;
+ );
- if (!QFile(pathname).exists())
- {
- {
- QFile file(pathname);
- (void) file.open(QFile::ReadWrite);
- }
+ QString current = group::ini_filename();
- const QStringList ini_list = group::ini_list();
+ if (!ini_list.contains(current))
+ current = OPENTRACK_DEFAULT_CONFIG_Q;
- if (ini_list.contains(current))
- {
- {
- inhibit_qt_signals q(ui.iconcomboProfile);
+ if (maybe_die_on_config_not_writable(current, &ini_list))
+ return false;
- ui.iconcomboProfile->clear();
- ui.iconcomboProfile->addItems(ini_list);
- for (int i = 0; i < ini_list.size(); i++)
- ui.iconcomboProfile->setItemIcon(i, icon);
- ui.iconcomboProfile->setCurrentText(current);
- }
+ if (exact_same)
+ return true;
- options::detail::bundler::refresh_all_bundles();
- }
- }
- else
- {
- file_ok = true;
- ui.iconcomboProfile->setCurrentText(current);
- }
- }
+ const QIcon icon(":/images/settings16.png");
- set_title();
+ QSignalBlocker l(ui.iconcomboProfile);
+
+ ui.iconcomboProfile->clear();
+ ui.iconcomboProfile->addItems(ini_list);
- if (warn)
- warn_on_config_not_writable();
+ for (int i = 0; i < ini_list.size(); i++)
+ ui.iconcomboProfile->setItemIcon(i, icon);
+
+ ui.iconcomboProfile->setCurrentText(current);
+
+ return true;
}
void MainWindow::updateButtonState(bool running, bool inertialp)
@@ -649,21 +639,30 @@ void MainWindow::exit()
QCoreApplication::exit(0);
}
-void MainWindow::profile_selected(const QString& name)
+bool MainWindow::set_profile(const QString& new_name_)
{
- const auto old_name = group::ini_filename();
- const auto new_name = name;
+ if (!refresh_config_list())
+ return false;
- if (name == "")
- return;
+ QString new_name = new_name_;
- if (old_name != new_name)
- {
- save_modules();
- set_profile(new_name);
- set_title();
- options::detail::bundler::refresh_all_bundles();
- }
+ if (!is_config_listed(new_name))
+ new_name = OPENTRACK_DEFAULT_CONFIG_Q;
+
+ if (maybe_die_on_config_not_writable(new_name, nullptr))
+ return false;
+
+ ui.iconcomboProfile->setCurrentText(new_name);
+ set_profile_in_registry(new_name);
+
+ // migrations are for config layout changes and other user-visible
+ // incompatibilities in future versions
+ run_migrations();
+
+ set_title();
+ options::detail::bundler::refresh_all_bundles();
+
+ return true;
}
void MainWindow::ensure_tray()
@@ -704,17 +703,20 @@ void MainWindow::ensure_tray()
void MainWindow::toggle_restore_from_tray(QSystemTrayIcon::ActivationReason e)
{
- if (progn(switch (e)
- {
- // if we enable double click also then it causes
- // toggle back to the original state
- //case QSystemTrayIcon::DoubleClick:
- case QSystemTrayIcon::Trigger: // single click
- return false;
- default:
- return true;
- }))
+ if (progn(
+ switch (e)
+ {
+ // if we enable double click also then it causes
+ // toggle back to the original state
+ //case QSystemTrayIcon::DoubleClick:
+ case QSystemTrayIcon::Trigger: // single click
+ return false;
+ default:
+ return true;
+ }))
+ {
return;
+ }
ensure_tray();
@@ -731,7 +733,7 @@ void MainWindow::toggle_restore_from_tray(QSystemTrayIcon::ActivationReason e)
return ws(windowState() & (~Qt::WindowMinimized));
else
return ws(Qt::WindowNoState);
- ));
+ ));
if (is_minimized)
{
@@ -791,7 +793,15 @@ void MainWindow::set_keys_enabled(bool flag)
{
register_shortcuts();
}
- qDebug() << "keybindings set to" << flag;
+}
+
+bool MainWindow::is_config_listed(const QString& name)
+{
+ const int sz = ui.iconcomboProfile->count();
+ for (int i = 0; i < sz; i++)
+ if (ui.iconcomboProfile->itemText(i) == name)
+ return true;
+ return false;
}
void MainWindow::changeEvent(QEvent* e)
@@ -814,15 +824,8 @@ bool MainWindow::is_tray_enabled()
return s.tray_enabled && QSystemTrayIcon::isSystemTrayAvailable();
}
-void MainWindow::set_profile(const QString &profile)
+void MainWindow::set_profile_in_registry(const QString &profile)
{
- {
- QSettings settings(OPENTRACK_ORG);
- settings.setValue(OPENTRACK_CONFIG_FILENAME_KEY, profile);
- }
- const bool ok = warn_on_config_not_writable();
- if (ok)
- // migrations are for config layout changes and other user-visible
- // incompatibilities in future versions
- run_migrations();
+ QSettings settings(OPENTRACK_ORG);
+ settings.setValue(OPENTRACK_CONFIG_FILENAME_KEY, profile);
}
diff --git a/gui/main-window.hpp b/gui/main-window.hpp
index 7cd94e93..b33b22fe 100644
--- a/gui/main-window.hpp
+++ b/gui/main-window.hpp
@@ -85,9 +85,10 @@ class MainWindow : public QMainWindow, private State
void ensure_tray();
void set_title(const QString& game_title = QStringLiteral(""));
static bool get_new_config_name_from_dialog(QString &ret);
- void set_profile(const QString& profile);
+ void set_profile_in_registry(const QString& profile);
void register_shortcuts();
void set_keys_enabled(bool flag);
+ bool is_config_listed(const QString& name);
void init_tray_menu();
@@ -98,7 +99,7 @@ class MainWindow : public QMainWindow, private State
private slots:
void save_modules();
void exit();
- void profile_selected(const QString& name);
+ bool set_profile(const QString& new_name);
void showTrackerSettings();
void showProtocolSettings();
@@ -112,7 +113,7 @@ private slots:
void make_empty_config();
void make_copied_config();
void open_config_directory();
- void refresh_config_list(bool warn);
+ bool refresh_config_list();
void startTracker();
void stopTracker();
@@ -128,6 +129,7 @@ public:
MainWindow();
~MainWindow();
static void set_working_directory();
- bool warn_on_config_not_writable();
+ bool maybe_die_on_config_not_writable(const QString& current, QStringList* ini_list);
+ void die_on_config_not_writable();
bool is_tray_enabled();
};
diff --git a/gui/main.cpp b/gui/main.cpp
index c3e3999a..47999212 100644
--- a/gui/main.cpp
+++ b/gui/main.cpp
@@ -137,34 +137,36 @@ main(int argc, char** argv)
add_win32_path();
#endif
- {
+ do
+ {
mem<MainWindow> w = std::make_shared<MainWindow>();
+ if (!w->isEnabled())
+ break;
+
if (!w->is_tray_enabled())
{
- w->setHidden(false);
+ w->setVisible(true);
w->show();
}
else
- {
w->setVisible(false);
- w->setHidden(true);
- }
app.setQuitOnLastWindowClosed(false);
app.exec();
qDebug() << "exit: window";
}
+ while (false);
- qDebug() << "exit: main()";
-
- // msvc crashes again in some destructor
+ // msvc crashes in some destructor
#if defined(_MSC_VER)
qDebug() << "exit: terminating";
TerminateProcess(GetCurrentProcess(), 0);
#endif
+ qDebug() << "exit: main()";
+
return 0;
}
diff --git a/options/bundle.cpp b/options/bundle.cpp
index e4c0ffbd..482e46d1 100644
--- a/options/bundle.cpp
+++ b/options/bundle.cpp
@@ -1,6 +1,9 @@
#include "bundle.hpp"
#include "value.hpp"
+#include <QThread>
+#include <QApplication>
+
using options::base_value;
namespace options
@@ -58,6 +61,9 @@ bool bundle::contains(const QString &name) const
void bundle::save_deferred(QSettings& s)
{
+ if (QThread::currentThread() != qApp->thread())
+ qCritical() << "group::save - current thread not ui thread";
+
if (group_name.size() == 0)
return;
diff --git a/options/group.cpp b/options/group.cpp
index 94e111aa..a17f185c 100644
--- a/options/group.cpp
+++ b/options/group.cpp
@@ -2,6 +2,7 @@
#include "defs.hpp"
#include <QStandardPaths>
#include <QDir>
+
#include <QDebug>
namespace options {
@@ -48,7 +49,7 @@ void group::put(const QString &s, const QVariant &d)
bool group::contains(const QString &s) const
{
- return kvs.count(s) != 0;
+ return kvs.find(s) != kvs.cend();
}
QString group::ini_directory()
@@ -64,7 +65,10 @@ QString group::ini_directory()
QString group::ini_filename()
{
QSettings settings(OPENTRACK_ORG);
- return settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString();
+ const QString ret = settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString();
+ if (ret.size() == 0)
+ return OPENTRACK_DEFAULT_CONFIG;
+ return ret;
}
QString group::ini_pathname()
@@ -75,6 +79,11 @@ QString group::ini_pathname()
return dir + "/" + ini_filename();
}
+QString group::ini_combine(const QString& filename)
+{
+ return ini_directory() + QStringLiteral("/") + filename;
+}
+
QStringList group::ini_list()
{
const auto dirname = ini_directory();
diff --git a/options/group.hpp b/options/group.hpp
index f5b3e523..82b508af 100644
--- a/options/group.hpp
+++ b/options/group.hpp
@@ -26,6 +26,7 @@ public:
static QString ini_directory();
static QString ini_filename();
static QString ini_pathname();
+ static QString ini_combine(const QString& filename);
static QStringList ini_list();
static std::shared_ptr<QSettings> ini_file();