<commit_before>#pragma once

#include <thread>

#include "common.hpp"
#include "components/bar.hpp"
#include "components/config.hpp"
#include "components/logger.hpp"
#include "components/x11/connection.hpp"
#include "components/x11/randr.hpp"
#include "components/x11/tray.hpp"
#include "components/x11/types.hpp"
#include "config.hpp"
#include "utils/command.hpp"
#include "utils/inotify.hpp"
#include "utils/process.hpp"
#include "utils/socket.hpp"
#include "utils/throttle.hpp"

#include "modules/backlight.hpp"
#include "modules/battery.hpp"
#include "modules/bspwm.hpp"
#include "modules/counter.hpp"
#include "modules/cpu.hpp"
#include "modules/date.hpp"
#include "modules/memory.hpp"
#include "modules/menu.hpp"
#include "modules/script.hpp"
#include "modules/text.hpp"
#include "modules/unsupported.hpp"
#if ENABLE_I3
#include "modules/i3.hpp"
#endif
#if ENABLE_MPD
#include "modules/mpd.hpp"
#endif
#if ENABLE_NETWORK
#include "modules/network.hpp"
#endif
#if ENABLE_ALSA
#include "modules/volume.hpp"
#endif

LEMONBUDDY_NS

using namespace modules;
using module_t = unique_ptr<module_interface>;

class controller {
 public:
  /**
   * Construct controller
   */
  explicit controller(connection& conn, const logger& logger, const config& config,
      unique_ptr<bar> bar, unique_ptr<traymanager> tray, inotify_watch_t& confwatch)
      : m_connection(conn)
      , m_log(logger)
      , m_conf(config)
      , m_bar(forward<decltype(bar)>(bar))
      , m_traymanager(forward<decltype(tray)>(tray))
      , m_confwatch(confwatch) {}

  /**
   * Stop modules and cleanup X components,
   * threads and spawned processes
   */
  ~controller() noexcept {
    if (!m_mutex.try_lock_for(3s)) {
      m_log.warn("Failed to acquire lock for 3s... Forcing shutdown using SIGKILL");
      raise(SIGKILL);
    }

    std::lock_guard<std::timed_mutex> guard(m_mutex, std::adopt_lock);

    m_log.trace("controller: Stop modules");
    for (auto&& block : m_modules) {
      for (auto&& module : block.second) {
        module->on_update.disconnect(this, &controller::on_module_update);
        module->on_stop.disconnect(this, &controller::on_module_stop);
        module->stop();
      }
    }

    m_log.trace("controller: Deconstruct bar instance");
    bar_signals::action_click.disconnect(this, &controller::on_module_click);
    m_bar.reset();

    if (m_traymanager) {
      m_log.trace("controller: Deactivate tray manager");
      m_traymanager->deactivate();
    }

    m_log.trace("controller: Interrupt X event loop");
    m_connection.send_dummy_event(m_connection.root());

    if (m_confwatch) {
      try {
        m_log.trace("controller: Remove config watch");
        m_confwatch->remove();
      } catch (const system_error& err) {
      }
    }
<commit_msg>fix(tray): Deactivate the tray before removing the bar<commit_after>#pragma once

#include <thread>

#include "common.hpp"
#include "components/bar.hpp"
#include "components/config.hpp"
#include "components/logger.hpp"
#include "components/x11/connection.hpp"
#include "components/x11/randr.hpp"
#include "components/x11/tray.hpp"
#include "components/x11/types.hpp"
#include "config.hpp"
#include "utils/command.hpp"
#include "utils/inotify.hpp"
#include "utils/process.hpp"
#include "utils/socket.hpp"
#include "utils/throttle.hpp"

#include "modules/backlight.hpp"
#include "modules/battery.hpp"
#include "modules/bspwm.hpp"
#include "modules/counter.hpp"
#include "modules/cpu.hpp"
#include "modules/date.hpp"
#include "modules/memory.hpp"
#include "modules/menu.hpp"
#include "modules/script.hpp"
#include "modules/text.hpp"
#include "modules/unsupported.hpp"
#if ENABLE_I3
#include "modules/i3.hpp"
#endif
#if ENABLE_MPD
#include "modules/mpd.hpp"
#endif
#if ENABLE_NETWORK
#include "modules/network.hpp"
#endif
#if ENABLE_ALSA
#include "modules/volume.hpp"
#endif

LEMONBUDDY_NS

using namespace modules;
using module_t = unique_ptr<module_interface>;

class controller {
 public:
  /**
   * Construct controller
   */
  explicit controller(connection& conn, const logger& logger, const config& config,
      unique_ptr<bar> bar, unique_ptr<traymanager> tray, inotify_watch_t& confwatch)
      : m_connection(conn)
      , m_log(logger)
      , m_conf(config)
      , m_bar(forward<decltype(bar)>(bar))
      , m_traymanager(forward<decltype(tray)>(tray))
      , m_confwatch(confwatch) {}

  /**
   * Stop modules and cleanup X components,
   * threads and spawned processes
   */
  ~controller() noexcept {
    if (!m_mutex.try_lock_for(3s)) {
      m_log.warn("Failed to acquire lock for 3s... Forcing shutdown using SIGKILL");
      raise(SIGKILL);
    }

    std::lock_guard<std::timed_mutex> guard(m_mutex, std::adopt_lock);

    m_log.trace("controller: Stop modules");
    for (auto&& block : m_modules) {
      for (auto&& module : block.second) {
        module->on_update.disconnect(this, &controller::on_module_update);
        module->on_stop.disconnect(this, &controller::on_module_stop);
        module->stop();
      }
    }

    if (m_traymanager) {
      m_log.trace("controller: Deactivate tray manager");
      m_traymanager->deactivate();
    }

    m_log.trace("controller: Deconstruct bar instance");
    bar_signals::action_click.disconnect(this, &controller::on_module_click);
    m_bar.reset();

    m_log.trace("controller: Interrupt X event loop");
    m_connection.send_dummy_event(m_connection.root());

    if (m_confwatch) {
      try {
        m_log.trace("controller: Remove config watch");
        m_confwatch->remove();
      } catch (const system_error& err) {
      }
    }

{'fraction_non_alphanumeric': 0.13882437019832053, 'fraction_numerical': 0.004288011434697159, 'mean_word_length': 4.192949907235621, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5504747', 'n_tokens_mistral': 1913, 'n_tokens_neox': 1894, 'n_words': 373}