/* Copyright (c) 2013-2018, Stanislaw Halik * Permission to use, copy, modify, and/or distribute this * software for any purpose with or without fee is hereby granted, * provided that the above copyright notice and this permission * notice appear in all copies. */ #include "window.hpp" #include "options/options.hpp" #include "migration/migration.hpp" #include "compat/check-visible.hpp" #include "compat/sleep.hpp" #include "compat/macros.hpp" #include "compat/library-path.hpp" #include "compat/math.hpp" #include #include #include #include #include #include #include #include #include #include extern "C" const char* const opentrack_version; using namespace options::globals; using namespace options; #if !defined EXIT_SUCCESS # define EXIT_SUCCESS 0 #endif #if !defined EXIT_FAILURE # define EXIT_FAILURE 1 #endif /* FreeBSD sysexits(3) * * The input data was incorrect in some way. This * should only be used for user's data and not system * files. */ #if !defined EX_OSFILE # define EX_OSFILE 72 #endif void force_trackmouse_settings(); main_window::main_window() : State(OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH) { ui.setupUi(this); update_button_state(false, false); // ctrl+q exits connect(&kbd_quit, SIGNAL(activated()), this, SLOT(exit())); if (!set_profile()) { die_on_config_not_writable(); exit(EX_OSFILE); return; } // only tie and connect main screen options after migrations are done // below is fine, set_profile() is called already connect(this, &main_window::start_tracker, this, [&] { qDebug() << "start tracker"; start_tracker_(); }, Qt::QueuedConnection); connect(this, &main_window::stop_tracker, this, [&] { qDebug() << "stop tracker"; stop_tracker_(); }, Qt::QueuedConnection); connect(this, &main_window::toggle_tracker, this, [&] { qDebug() << "toggle tracker"; toggle_tracker_(); }, Qt::QueuedConnection); connect(ui.btnStartTracker, SIGNAL(clicked()), this, SLOT(start_tracker_())); connect(ui.btnStopTracker, SIGNAL(clicked()), this, SLOT(stop_tracker_())); { tie_setting(mouse.sensitivity_x, ui.sensitivity_slider); tie_setting(mouse.sensitivity_x, ui.sensitivity_label, [](double x) { return QString::number(x) + QStringLiteral("%"); }); // one-way only tie_setting(mouse.sensitivity_x, this, [this](double x) { mouse.sensitivity_y = *mouse.sensitivity_x; }); // no "ok" button, gotta save on timer auto save = [this] { qDebug() << "trackmouse: saving settings"; mouse.b->save(); save_settings_timer.stop(); }; auto start_save_timer = [this](double) { save_settings_timer.start(); }; save_settings_timer.setInterval(save_settings_interval_ms); save_settings_timer.setSingleShot(true); ui.sensitivity_slider->setTracking(false); connect(&save_settings_timer, &QTimer::timeout, this, save, Qt::DirectConnection); #if 1 // this doesn't fire the timer on application load connect(ui.sensitivity_slider, &QSlider::valueChanged, this, start_save_timer, Qt::DirectConnection); #else // but this does so let's not not use it tie_setting(mouse.sensitivity_x, this, start_save_timer); #endif } force_trackmouse_settings(); register_shortcuts(); kbd_quit.setEnabled(true); setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | windowFlags()); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); adjustSize(); setVisible(true); show(); } void main_window::register_shortcuts() { global_shortcuts.reload({ { s.key_toggle_tracking1, [this](bool) { main_window::toggle_tracker(); }, true }, }); if (work) work->reload_shortcuts(); } void main_window::die_on_config_not_writable() { stop_tracker_(); static const QString pad(16, QChar(' ')); QMessageBox::critical(this, tr("The Octopus is sad"), tr("Check permissions for your .ini directory:\n\n%1\"%2\n\n" "Exiting now." ).arg(ini_directory(), pad), QMessageBox::Close, QMessageBox::NoButton); exit(EX_OSFILE); } bool main_window::maybe_die_on_config_not_writable(const QString& current) { const bool writable = with_settings_object([&](QSettings& s) { return s.isWritable(); }); if (writable) return false; if (!QFile(ini_combine(current)).open(QFile::ReadWrite)) { die_on_config_not_writable(); return true; } return false; } main_window::~main_window() { // stupid ps3 eye has LED issues if (work) { stop_tracker_(); QEventLoop ev; ev.processEvents(); portable::sleep(2000); } exit(); } void main_window::set_working_directory() { QDir::setCurrent(OPENTRACK_BASE_PATH); } void main_window::save_modules() { m.b->save(); } std::tuple main_window::module_by_name(const QString& name, Modules::dylib_list& list) { auto it = std::find_if(list.cbegin(), list.cend(), [&name](const dylib_ptr& lib) { if (!lib) return name.isEmpty(); else return name == lib->module_name; }); if (it == list.cend()) return { nullptr, -1 }; else return { *it, std::distance(list.cbegin(), it) }; } main_window::dylib_ptr main_window::current_tracker() { auto [ptr, idx] = module_by_name(m.tracker_dll, modules.trackers()); return ptr; } main_window::dylib_ptr main_window::current_protocol() { auto [ptr, idx] = module_by_name(m.protocol_dll, modules.protocols()); return ptr; } main_window::dylib_ptr main_window::current_filter() { auto [ptr, idx] = module_by_name(m.filter_dll, modules.filters()); return ptr; } void main_window::update_button_state(bool running, bool inertialp) { bool not_running = !running; #if 0 ui.iconcomboProfile->setEnabled(not_running); ui.btnStartTracker->setEnabled(not_running); ui.btnStopTracker->setEnabled(running); ui.iconcomboProtocol->setEnabled(not_running); ui.iconcomboFilter->setEnabled(not_running); ui.iconcomboTrackerSource->setEnabled(not_running); ui.profile_button->setEnabled(not_running); #endif ui.video_frame_label->setVisible(not_running || inertialp); if(not_running) { ui.video_frame_label->setPixmap(QPixmap(":/images/tracking-not-started.png")); } else { ui.video_frame_label->setPixmap(QPixmap(":/images/no-feed.png")); } } void main_window::start_tracker_() { if (work) return; work = std::make_shared(pose, ev, ui.video_frame, current_tracker(), current_protocol(), current_filter()); if (!work->is_ok()) { work = nullptr; return; } if (pTrackerDialog) pTrackerDialog->register_tracker(work->libs.pTracker.get()); if (pFilterDialog) pFilterDialog->register_filter(work->libs.pFilter.get()); if (pProtocolDialog) pProtocolDialog->register_protocol(work->libs.pProtocol.get()); // NB check valid since SelectedLibraries ctor called // trackers take care of layout state updates const bool is_inertial = ui.video_frame->layout() == nullptr; update_button_state(true, is_inertial); ui.btnStopTracker->setFocus(); } void main_window::stop_tracker_() { if (!work) return; with_tracker_teardown sentinel; if (pTrackerDialog) pTrackerDialog->unregister_tracker(); if (pProtocolDialog) pProtocolDialog->unregister_protocol(); if (pFilterDialog) pFilterDialog->unregister_filter(); work = nullptr; update_button_state(false, false); set_title(); ui.btnStartTracker->setFocus(); // ps3 eye issues portable::sleep(1000); } void main_window::set_title(const QString& game_title) { static const QString version{opentrack_version}; static const QString sep { tr(" :: ") }; static const QString pat1{ version + sep + "%1" + sep + "%2" }; static const QString pat2{ version + sep + "%1" }; const QString current = ini_filename(); if (game_title.isEmpty()) setWindowTitle(pat2.arg(current)); else setWindowTitle(pat1.arg(current, game_title)); } void main_window::exit(int status) { if (exiting_already) return; exiting_already = true; qDebug() << "trackmouse: saving settings on app exit"; save_settings_timer.stop(); mouse.b->save(); //close(); QApplication::setQuitOnLastWindowClosed(true); QApplication::exit(status); } bool main_window::set_profile() { if (maybe_die_on_config_not_writable(OPENTRACK_DEFAULT_CONFIG)) return false; set_profile_in_registry(); options::detail::bundler::refresh_all_bundles(); // migrations are for config layout changes and other user-visible // incompatibilities in future versions run_migrations(); set_title(); return true; } void main_window::closeEvent(QCloseEvent*) { exit(); } void main_window::set_profile_in_registry() { with_global_settings_object([&](QSettings& s) { s.setValue(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG); }); } void main_window::toggle_tracker_() { qDebug() << "toggle tracker"; if (work) stop_tracker_(); else start_tracker_(); }