diff options
Diffstat (limited to 'opentrack/main-window.cpp')
| -rw-r--r-- | opentrack/main-window.cpp | 920 | 
1 files changed, 920 insertions, 0 deletions
| diff --git a/opentrack/main-window.cpp b/opentrack/main-window.cpp new file mode 100644 index 00000000..b90aa3bd --- /dev/null +++ b/opentrack/main-window.cpp @@ -0,0 +1,920 @@ +/* Copyright (c) 2013-2016, Stanislaw Halik <sthalik@misaki.pl> + + * 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 "main-window.hpp" +#include "logic/pipeline.hpp" +#include "options/options.hpp" +#include "new_file_dialog.h" +#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 "compat/sysexits.hpp" + +#include <algorithm> +#include <utility> + +#include <QMessageBox> +#include <QDesktopServices> +#include <QDir> + +extern "C" const char* const opentrack_version; + +using namespace options::globals; +using namespace options; + +main_window::main_window() : State(OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH) +{ +    ui.setupUi(this); + +#if !defined _WIN32 && !defined __APPLE__ +    annoy_if_root(); +#endif + +    init_profiles(); +    init_buttons(); +    init_tray_menu(); +    init_dylibs(); +    init_shortcuts(); + +    setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | windowFlags()); +    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); +    adjustSize(); + +    if (!start_in_tray()) +    { +        setVisible(true); +        show(); +    } +    else +        setVisible(false); + +    connect(&pose_update_timer, &QTimer::timeout, +            this, &main_window::show_pose, Qt::DirectConnection); +    connect(&det_timer, &QTimer::timeout, +            this, &main_window::maybe_start_profile_from_executable); +    det_timer.start(1000); +} + +void main_window::init_shortcuts() +{ +    register_shortcuts(); + +    // ctrl+q exits +    connect(&kbd_quit, &QShortcut::activated, this, [this]() { main_window::exit(EXIT_SUCCESS); }, Qt::DirectConnection); +    kbd_quit.setEnabled(true); +} + +void main_window::init_dylibs() +{ +    using dylib_ptr = Modules::dylib_ptr; +    using dylib_list = Modules::dylib_list; + +    modules.filters().insert(modules.filters().begin(), +                             std::make_shared<dylib>("", dylib_type::Filter)); + +    for (dylib_ptr& x : modules.trackers()) +        ui.iconcomboTrackerSource->addItem(x->icon, x->name, x->module_name); + +    for (dylib_ptr& x : modules.protocols()) +        ui.iconcomboProtocol->addItem(x->icon, x->name, x->module_name); + +    for (dylib_ptr& x : modules.filters()) +        ui.iconcomboFilter->addItem(x->icon, x->name, x->module_name); + +    connect(ui.iconcomboTrackerSource, &QComboBox::currentTextChanged, +            this, [&](const QString&) { pTrackerDialog = nullptr; }); + +    connect(ui.iconcomboProtocol, &QComboBox::currentTextChanged, +            this, [&](const QString&) { pProtocolDialog = nullptr; }); + +    connect(ui.iconcomboFilter, &QComboBox::currentTextChanged, +            this, [&](const QString&) { pFilterDialog = nullptr; }); + +    connect(&m.tracker_dll, value_::value_changed<QString>(), +            this, &main_window::save_modules, +            Qt::DirectConnection); + +    connect(&m.protocol_dll, value_::value_changed<QString>(), +            this, &main_window::save_modules, +            Qt::DirectConnection); + +    connect(&m.filter_dll, value_::value_changed<QString>(), +            this, &main_window::save_modules, +            Qt::DirectConnection); + +    { +        struct list { +            dylib_list& libs; +            QComboBox* input; +            value<QString>& place; +        }; + +        list types[] { +            { modules.trackers(), ui.iconcomboTrackerSource, m.tracker_dll }, +            { modules.protocols(), ui.iconcomboProtocol, m.protocol_dll }, +            { modules.filters(), ui.iconcomboFilter, m.filter_dll }, +        }; + +        for (list& type : types) +        { +            list t = type; +            tie_setting(t.place, t.input, +                        [t](const QString& name) { +                            auto [ptr, idx] = module_by_name(name, t.libs); +                            return idx; +                        }, +                        [t](int, const QVariant& userdata) { +                            auto [ptr, idx] = module_by_name(userdata.toString(), t.libs); +                            if (ptr) +                                return ptr->module_name; +                            else +                                return QString(); +                        }); +        } +    } +} + +void main_window::init_profiles() +{ +    refresh_profile_list(); +    // implicitly created by `ini_directory()' +    if (ini_directory().isEmpty() || !QDir(ini_directory()).isReadable()) +        die_on_profile_not_writable(); + +    set_profile(ini_filename()); + +    // profile menu +    profile_menu.addAction(tr("Create new empty config"), this, &main_window::create_empty_profile); +    profile_menu.addAction(tr("Create new copied config"), this, &main_window::create_copied_profile); +    profile_menu.addAction(tr("Open configuration directory"), this, &main_window::open_profile_directory); +    ui.profile_button->setMenu(&profile_menu); + +    connect(&profile_list_timer, &QTimer::timeout, this, &main_window::refresh_profile_list); +    profile_list_timer.start(1000 * 5); + +    connect(ui.iconcomboProfile, &QComboBox::currentTextChanged, +            this, [this](const QString& x) { main_window::set_profile(x); }); +} + +void main_window::init_tray_menu() +{ +    tray_menu.clear(); + +    QString display_name(opentrack_version); +    if (display_name.startsWith("opentrack-")) +        display_name = tr("opentrack") + " " + display_name.mid(sizeof("opentrack-") - 1); +    if (display_name.endsWith("-DEBUG")) +        display_name.replace(display_name.size() - int(sizeof("DEBUG")), display_name.size(), tr(" (debug)")); + +    menu_action_header.setEnabled(false); +    menu_action_header.setText(display_name); +    menu_action_header.setIcon(QIcon(":/images/opentrack.png")); +    tray_menu.addAction(&menu_action_header); + +    menu_action_show.setIconVisibleInMenu(true); +    menu_action_show.setText(isHidden() ? tr("Show the Octopus") : tr("Hide the Octopus")); +    menu_action_show.setIcon(QIcon(":/images/opentrack.png")); +    QObject::connect(&menu_action_show, &QAction::triggered, this, [&] { toggle_restore_from_tray(QSystemTrayIcon::Trigger); }); +    tray_menu.addAction(&menu_action_show); + +    tray_menu.addSeparator(); + +    menu_action_tracker.setText(tr("Tracker settings")); +    menu_action_tracker.setIcon(QIcon(":/images/tools.png")); +    QObject::connect(&menu_action_tracker, &QAction::triggered, this, &main_window::show_tracker_settings); +    tray_menu.addAction(&menu_action_tracker); + +    menu_action_filter.setText(tr("Filter settings")); +    menu_action_filter.setIcon(QIcon(":/images/filter-16.png")); +    QObject::connect(&menu_action_filter, &QAction::triggered, this, &main_window::show_filter_settings); +    tray_menu.addAction(&menu_action_filter); + +    menu_action_proto.setText(tr("Protocol settings")); +    menu_action_proto.setIcon(QIcon(":/images/settings16.png")); +    QObject::connect(&menu_action_proto, &QAction::triggered, this, &main_window::show_proto_settings); +    tray_menu.addAction(&menu_action_proto); + +    tray_menu.addSeparator(); + +    menu_action_mappings.setIcon(QIcon(":/images/curves.png")); +    menu_action_mappings.setText(tr("Mappings")); +    QObject::connect(&menu_action_mappings, &QAction::triggered, this, &main_window::show_mapping_window); +    tray_menu.addAction(&menu_action_mappings); + +    menu_action_options.setIcon(QIcon(":/images/tools.png")); +    menu_action_options.setText(tr("Options")); +    QObject::connect(&menu_action_options, &QAction::triggered, this, &main_window::show_options_dialog); +    tray_menu.addAction(&menu_action_options); + +    tray_menu.addSeparator(); + +    menu_action_exit.setText(tr("Exit")); +    QObject::connect(&menu_action_exit, &QAction::triggered, this, &main_window::exit); +    tray_menu.addAction(&menu_action_exit); + +    connect(&s.tray_enabled, value_::value_changed<bool>(), +            this, &main_window::ensure_tray); + +    ensure_tray(); +} + +void main_window::init_buttons() +{ +    update_button_state(false, false); +    connect(ui.btnEditCurves, &QPushButton::clicked, this, &main_window::show_mapping_window); +    connect(ui.btnShortcuts, &QPushButton::clicked, this, &main_window::show_options_dialog); +    connect(ui.btnShowEngineControls, &QPushButton::clicked, this, &main_window::show_tracker_settings); +    connect(ui.btnShowServerControls, &QPushButton::clicked, this, &main_window::show_proto_settings); +    connect(ui.btnShowFilterControls, &QPushButton::clicked, this, &main_window::show_filter_settings); +    connect(ui.btnStartTracker, &QPushButton::clicked, this, &main_window::start_tracker_); +    connect(ui.btnStopTracker, &QPushButton::clicked, this, &main_window::stop_tracker_); +} + +void main_window::register_shortcuts() +{ +    global_shortcuts.reload({ +        { s.key_start_tracking1, [this](bool) { start_tracker(); }, true }, +        { s.key_start_tracking2, [this](bool) { start_tracker(); }, true }, + +        { s.key_stop_tracking1, [this](bool) { stop_tracker(); }, true }, +        { s.key_stop_tracking2, [this](bool) { stop_tracker(); }, true }, + +        { s.key_toggle_tracking1, [this](bool) { toggle_tracker(); }, true }, +        { s.key_toggle_tracking2, [this](bool) { toggle_tracker(); }, true }, + +        { s.key_restart_tracking1, [this](bool) { restart_tracker(); }, true }, +        { s.key_restart_tracking2, [this](bool) { restart_tracker(); }, true }, +    }); + +    if (work) +        work->reload_shortcuts(); +} + +void main_window::die_on_profile_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\nExiting now.").arg(ini_directory(), pad), +                          QMessageBox::Close, QMessageBox::NoButton); + +    exit(EX_OSFILE); +} + +bool main_window::profile_name_from_dialog(QString& ret) +{ +    new_file_dialog dlg; +    dlg.exec(); +    return dlg.is_ok(ret); +} + +main_window::~main_window() +{ +    // stupid ps3 eye has LED issues +    if (work && ui.video_frame->layout()) +    { +        hide(); +        stop_tracker_(); +        close(); + +        constexpr int inc = 25, max = 1000; + +        for (int k = 0; k < max; k += inc) +        { +            QEventLoop ev; +            ev.processEvents(); +            portable::sleep(inc); +        } +    } + +    exit(); +} + +void main_window::save_modules() +{ +    m.b->save(); +} + +void main_window::create_empty_profile() +{ +    QString name; +    if (profile_name_from_dialog(name)) +    { +        QFile(ini_combine(name)).open(QFile::ReadWrite); +        refresh_profile_list(); + +        if (profile_list.contains(name)) +        { +            QSignalBlocker q(ui.iconcomboProfile); + +            set_profile(name, false); +            mark_profile_as_not_needing_migration(); +        } +    } +} + +void main_window::create_copied_profile() +{ +    const QString cur = ini_pathname(); +    QString name; +    if (!cur.isEmpty() && profile_name_from_dialog(name)) +    { +        const QString new_name = ini_combine(name); +        (void) QFile::remove(new_name); +        QFile::copy(cur, new_name); + +        refresh_profile_list(); + +        if (profile_list.contains(name)) +        { +            QSignalBlocker q(ui.iconcomboProfile); + +            set_profile(name, false); +            mark_profile_as_not_needing_migration(); +        } +    } + +} + +void main_window::open_profile_directory() +{ +    QDesktopServices::openUrl("file:///" + QDir::toNativeSeparators(ini_directory())); +} + +void main_window::refresh_profile_list() +{ +    if (work) +        return; + +    QStringList list = ini_list(); +    QString current = ini_filename(); + +    if (list == profile_list) +        return; + +    if (!list.contains(current)) +        current = OPENTRACK_DEFAULT_PROFILE; + +    profile_list = list; + +    static const QIcon icon(":/images/settings16.png"); + +    QSignalBlocker l(ui.iconcomboProfile); + +    ui.iconcomboProfile->clear(); +    ui.iconcomboProfile->addItems(list); + +    for (int i = 0; i < list.size(); i++) +        ui.iconcomboProfile->setItemIcon(i, icon); + +    ui.iconcomboProfile->setCurrentText(current); +} + + + +void main_window::update_button_state(bool running, bool inertialp) +{ +    bool not_running = !running; +    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); +    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<Work>(pose, ev, ui.video_frame, current_tracker(), current_protocol(), current_filter()); + +    if (!work->is_ok()) +    { +        work = nullptr; +        return; +    } + +    { +        double p[6] = {0,0,0, 0,0,0}; +        show_pose_(p, p); +    } + +    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()); + +    pose_update_timer.start(50); + +    // 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; + +    force_is_visible(true); +    with_tracker_teardown sentinel; + +    pose_update_timer.stop(); +    ui.pose_display->present(0,0,0, 0,0,0); + +    if (pTrackerDialog) +        pTrackerDialog->unregister_tracker(); + +    if (pProtocolDialog) +        pProtocolDialog->unregister_protocol(); + +    if (pFilterDialog) +        pFilterDialog->unregister_filter(); + +    work = nullptr; + +    { +        double p[6] {}; +        show_pose_(p, p); +    } + +    update_button_state(false, false); +    set_title(); +    ui.btnStartTracker->setFocus(); +} + +void main_window::show_pose_(const double* mapped, const double* raw) +{ +    ui.pose_display->present(mapped[Yaw], mapped[Pitch], -mapped[Roll], +                             mapped[TX], mapped[TY], mapped[TZ]); + +    QLCDNumber* raw_[] = { +        ui.raw_x, ui.raw_y, ui.raw_z, +        ui.raw_yaw, ui.raw_pitch, ui.raw_roll, +    }; + +    QLCDNumber* mapped_[] = { +        ui.pose_x, ui.pose_y, ui.pose_z, +        ui.pose_yaw, ui.pose_pitch, ui.pose_roll, +    }; + +    for (int k = 0; k < 6; k++) +    { +        raw_[k]->display(iround(raw[k])); +        mapped_[k]->display(iround(mapped[k])); +    } + +    QString game_title; +    if (work && work->libs.pProtocol) +        game_title = work->libs.pProtocol->game_name(); +    set_title(game_title); +} + +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::show_pose() +{ +    set_is_visible(*this); + +    if (mapping_widget) +        mapping_widget->refresh_tab(); + +    if (!check_is_visible()) +        return; + +    double mapped[6], raw[6]; + +    work->pipeline_.raw_and_mapped_pose(mapped, raw); + +    show_pose_(mapped, raw); +} + +static void show_window(QWidget& d, bool fresh) +{ +    if (fresh) +    { +        d.setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | d.windowFlags()); +        d.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + +        d.show(); +        d.adjustSize(); +        d.raise(); +    } +    else +    { +        d.show(); +        d.raise(); +    } +} + +template<typename t, typename F> +static bool mk_window_common(std::unique_ptr<t>& d, F&& fun) +{ +    bool fresh = false; + +    if (!d) +        d = fun(), fresh = !!d; + +    if (d) +        show_window(*d, fresh); + +    return fresh; +} + +template<typename t, typename... Args> +static bool mk_window(std::unique_ptr<t>& place, Args&&... params) +{ +    return mk_window_common(place, [&] { +        return std::make_unique<t>(params...); +    }); +} + +template<typename t> +static bool mk_dialog(std::unique_ptr<t>& place, const std::shared_ptr<dylib>& lib) +{ +    using u = std::unique_ptr<t>; + +    return mk_window_common(place, [&] { +        if (lib && lib->Dialog) +            return u{ (t*)lib->Dialog() }; +        else +            return u{}; +    }); +} + +void main_window::show_tracker_settings() +{ +    if (mk_dialog(pTrackerDialog, current_tracker()) && work && work->libs.pTracker) +        pTrackerDialog->register_tracker(work->libs.pTracker.get()); +    if (pTrackerDialog) +        QObject::connect(pTrackerDialog.get(), &ITrackerDialog::closing, +                         this, [this] { pTrackerDialog = nullptr; }); +} + +void main_window::show_proto_settings() +{ +    if (mk_dialog(pProtocolDialog, current_protocol()) && work && work->libs.pProtocol) +        pProtocolDialog->register_protocol(work->libs.pProtocol.get()); +    if (pProtocolDialog) +        QObject::connect(pProtocolDialog.get(), &IProtocolDialog::closing, +                         this, [this] { pProtocolDialog = nullptr; }); +} + +void main_window::show_filter_settings() +{ +    if (mk_dialog(pFilterDialog, current_filter()) && work && work->libs.pFilter) +        pFilterDialog->register_filter(work->libs.pFilter.get()); +    if (pFilterDialog) +        QObject::connect(pFilterDialog.get(), &IFilterDialog::closing, +                         this, [this] { pFilterDialog = nullptr; }); +} + +void main_window::show_options_dialog() +{ +    if (mk_window(options_widget, [&](bool flag) { set_keys_enabled(!flag); })) +    { +        // XXX this should logically connect to a bundle +        // also doesn't work when switching profiles with options dialog open +        // move shortcuts to a separate bundle and add a migration -sh 20180218 +        connect(options_widget.get(), &options_dialog::closing, +                this, &main_window::register_shortcuts); +    } +} + +void main_window::show_mapping_window() +{ +    mk_window(mapping_widget, pose); +} + +void main_window::exit(int status) +{ +    // don't use std::call_once here, leads to freeze in Microsoft's CRT +    // this function never needs reentrancy anyway + +    // this is probably harmless, but better safe than sorry +    if (exiting_already) +        return; +    exiting_already = true; + +    qDebug() << "opentrack: exiting"; + +    if (tray) +        tray->hide(); +    tray = nullptr; + +    //close(); +    QApplication::setQuitOnLastWindowClosed(true); +    QApplication::exit(status); +} + +void main_window::set_profile(const QString& new_name_, bool migrate) +{ +    QSignalBlocker b(ui.iconcomboProfile); + +    QString new_name = new_name_; + +    if (!profile_list.contains(new_name)) +    { +        new_name = OPENTRACK_DEFAULT_PROFILE; +        if (!profile_list.contains(new_name)) +            migrate = false; +    } + +    const bool status = new_name != ini_filename(); + +    if (status) +        set_profile_in_registry(new_name); + +    using bundler = options::detail::bundler; + +    bundler::reload_no_notify(); + +    if (migrate) +        // migrations are for config layout changes and other user-visible +        // incompatibilities in future versions +        run_migrations(); +    else +        mark_profile_as_not_needing_migration(); + +    bundler::notify(); + +    set_title(); + +    if (status) +        ui.iconcomboProfile->setCurrentText(new_name); +} + +void main_window::ensure_tray() +{ +    if (!QSystemTrayIcon::isSystemTrayAvailable()) +    { +        QApplication::setQuitOnLastWindowClosed(true); +        return; +    } + +    if (s.tray_enabled) +    { +        if (!tray) +        { +            tray = std::make_unique<QSystemTrayIcon>(this); +            tray->setIcon(QIcon(":/images/opentrack.png")); +            tray->setContextMenu(&tray_menu); +            tray->show(); + +            connect(tray.get(), +                    &QSystemTrayIcon::activated, +                    this, +                    &main_window::toggle_restore_from_tray); +        } + +        QApplication::setQuitOnLastWindowClosed(false); +    } +    else +    { +        if (!isVisible()) +        { +            show(); +            setVisible(true); + +            raise(); // for OSX +            activateWindow(); // for Windows +        } + +        if (tray) +            tray->hide(); +        tray = nullptr; + +        QApplication::setQuitOnLastWindowClosed(true); +    } +} + +void main_window::toggle_restore_from_tray(QSystemTrayIcon::ActivationReason e) +{ +    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 +        break; +    default: +        return; +    } + +    ensure_tray(); + +    const bool is_minimized = isHidden() || !tray_enabled(); + +    menu_action_show.setText(!isHidden() ? tr("Show the Octopus") : tr("Hide the Octopus")); + +    setVisible(is_minimized); +    setHidden(!is_minimized); + +    setWindowState(is_minimized ? windowState() & ~Qt::WindowMinimized : Qt::WindowNoState); + +    if (is_minimized) +    { +        raise(); // for OSX +        activateWindow(); // for Windows +    } +    else +    { +        lower(); +        clearFocus(); +    } +} + +bool main_window::maybe_hide_to_tray(QEvent* e) +{ +    if (e->type() == QEvent::WindowStateChange && +        (windowState() & Qt::WindowMinimized) && +        tray_enabled()) +    { +        e->accept(); +        ensure_tray(); +        hide(); + +        return true; +    } + +    return false; +} + +void main_window::closeEvent(QCloseEvent*) +{ +    exit(); +} + +void main_window::maybe_start_profile_from_executable() +{ +    if (!work) +    { +        QString profile; +        if (det.profile_to_start(profile) && profile_list.contains(profile)) +        { +            set_profile(profile); +            start_tracker_(); +        } +    } +    else +    { +        if (det.should_stop()) +            stop_tracker_(); +    } +} + +void main_window::set_keys_enabled(bool flag) +{ +    if (!flag) +    { +        if (work) +            work->sc.reload({}); +        global_shortcuts.reload({}); +    } +    else +        register_shortcuts(); +} + +void main_window::changeEvent(QEvent* e) +{ +    if (!maybe_hide_to_tray(e)) +        e->ignore(); +} + +bool main_window::event(QEvent* event) +{ +    using t = QEvent::Type; + +    if (work) +    { +        switch (event->type()) +        { +        case t::Hide: +        case t::WindowActivate: +        case t::WindowDeactivate: +        case t::WindowStateChange: +        case t::FocusIn: +            set_is_visible(*this, true); +        break; +        default: +        break; +        } +    } +    return QMainWindow::event(event); +} + +bool main_window::tray_enabled() +{ +    return s.tray_enabled && QSystemTrayIcon::isSystemTrayAvailable(); +} + +bool main_window::start_in_tray() +{ +    return tray_enabled() && s.tray_start; +} + +void main_window::set_profile_in_registry(const QString &profile) +{ +    with_global_settings_object([&](QSettings& s) { +        s.setValue(OPENTRACK_PROFILE_FILENAME_KEY, profile); +    }); +} + +void main_window::restart_tracker_() +{ +    qDebug() << "restart tracker"; + +    stop_tracker_(); +    start_tracker_(); +} + +void main_window::toggle_tracker_() +{ +    qDebug() << "toggle tracker"; + +    if (work) +        stop_tracker_(); +    else +        start_tracker_(); +} + +#if !defined _WIN32 +#   include <unistd.h> +void main_window::annoy_if_root() +{ +    if (geteuid() == 0) +    { +        struct lst { +            QString caption; +            QString msg; +            int sleep_ms; +        }; + +        const lst list[] = { +            { +                tr("Running as root is bad"), +                tr("Do not run as root. Set correct device node permissions."), +                1000, +            }, +            { +                tr("Running as root is bad, seriously"), +                tr("Do not run as root. I'll keep whining at every startup."), +                3000, +            }, +            { +                tr("Be annoyed, comprehensively."), +                tr("Don't run as root to remove these annoying messages."), +                0 +            } +        }; + +        for (const auto& x : list) +        { +            QMessageBox::critical(this, x.caption, x.msg, QMessageBox::Ok); +            portable::sleep(x.sleep_ms); +        } +    } +} +#endif | 
