<commit_before>#include <xcb/xcb_icccm.h>
#include <algorithm>
#include <string>

#include "components/bar.hpp"
#include "components/config.hpp"
#include "components/parser.hpp"
#include "components/screen.hpp"
#include "events/signal.hpp"
#include "events/signal_emitter.hpp"
#include "utils/bspwm.hpp"
#include "utils/color.hpp"
#include "utils/factory.hpp"
#include "utils/math.hpp"
#include "utils/string.hpp"
#include "x11/atoms.hpp"
#include "x11/connection.hpp"
#include "x11/fonts.hpp"
#include "x11/tray_manager.hpp"
#include "x11/wm.hpp"
#include "x11/xutils.hpp"

#if ENABLE_I3
#include "utils/i3.hpp"
#endif

POLYBAR_NS

using namespace signals::ui;
using namespace wm_util;

/**
 * Create instance
 */
bar::make_type bar::make() {
  // clang-format off
  return factory_util::unique<bar>(
        connection::make(),
        signal_emitter::make(),
        config::make(),
        logger::make(),
        screen::make(),
        tray_manager::make());
  // clang-format on
}

/**
 * Construct bar instance
 *
 * TODO: Break out all tray handling
 */
bar::bar(connection& conn, signal_emitter& emitter, const config& config, const logger& logger,
    unique_ptr<screen> screen, unique_ptr<tray_manager> tray_manager)
    : m_connection(conn)
    , m_sig(emitter)
    , m_conf(config)
    , m_log(logger)
    , m_screen(move(screen))
    , m_tray(move(tray_manager)) {
  string bs{m_conf.section()};

  // Get available RandR outputs
  auto monitor_name = m_conf.get<string>(bs, "monitor", "");
  auto monitor_strictmode = m_conf.get<bool>(bs, "monitor-strict", false);
  auto monitors = randr_util::get_monitors(m_connection, m_connection.screen()->root, monitor_strictmode);

  if (monitors.empty()) {
    throw application_error("No monitors found");
  } else if (monitor_name.empty()) {
    monitor_name = monitors[0]->name;
    m_log.warn("No monitor specified, using \"%s\"", monitor_name);
  }

  // Match against the defined monitor name
  for (auto&& monitor : monitors) {
    if (monitor->match(monitor_name, monitor_strictmode)) {
      m_opts.monitor = move(monitor);
      break;
    }
  }

  if (!m_opts.monitor) {
    throw application_error("Monitor \"" + monitor_name + "\" not found or disconnected");
  }

  m_log.trace("bar: Loaded monitor %s (%ix%i+%i+%i)", m_opts.monitor->name, m_opts.monitor->w, m_opts.monitor->h,
      m_opts.monitor->x, m_opts.monitor->y);

  try {
    m_opts.override_redirect = m_conf.get<bool>(bs, "dock");
    m_conf.warn_deprecated(bs, "dock", "override-redirect");
  } catch (const key_error& err) {
    m_opts.override_redirect = m_conf.get<bool>(bs, "override-redirect", m_opts.override_redirect);
  }

  m_opts.dimvalue = m_conf.get<double>(bs, "dim-value", 1.0);
  m_opts.dimvalue = math_util::cap(m_opts.dimvalue, 0.0, 1.0);

  // Build WM_NAME
  m_opts.wmname = m_conf.get<string>(bs, "wm-name", "polybar-" + bs.substr(4) + "_" + m_opts.monitor->name);
  m_opts.wmname = string_util::replace(m_opts.wmname, " ", "-");

  // Load configuration values
  m_opts.origin = m_conf.get<bool>(bs, "bottom", false) ? edge::BOTTOM : edge::TOP;
  m_opts.spacing = m_conf.get<decltype(m_opts.spacing)>(bs, "spacing", m_opts.spacing);
  m_opts.padding.left = m_conf.get<decltype(m_opts.padding.left)>(bs, "padding-left", m_opts.padding.left);
  m_opts.padding.right = m_conf.get<decltype(m_opts.padding.right)>(bs, "padding-right", m_opts.padding.right);
  m_opts.module_margin.left =
      m_conf.get<decltype(m_opts.module_margin.left)>(bs, "module-margin-left", m_opts.module_margin.left);<commit_msg>feat(monitor): Add monitor-fallback option #243<commit_after>#include <xcb/xcb_icccm.h>
#include <algorithm>
#include <string>

#include "components/bar.hpp"
#include "components/config.hpp"
#include "components/parser.hpp"
#include "components/screen.hpp"
#include "events/signal.hpp"
#include "events/signal_emitter.hpp"
#include "utils/bspwm.hpp"
#include "utils/color.hpp"
#include "utils/factory.hpp"
#include "utils/math.hpp"
#include "utils/string.hpp"
#include "x11/atoms.hpp"
#include "x11/connection.hpp"
#include "x11/fonts.hpp"
#include "x11/tray_manager.hpp"
#include "x11/wm.hpp"
#include "x11/xutils.hpp"

#if ENABLE_I3
#include "utils/i3.hpp"
#endif

POLYBAR_NS

using namespace signals::ui;
using namespace wm_util;

/**
 * Create instance
 */
bar::make_type bar::make() {
  // clang-format off
  return factory_util::unique<bar>(
        connection::make(),
        signal_emitter::make(),
        config::make(),
        logger::make(),
        screen::make(),
        tray_manager::make());
  // clang-format on
}

/**
 * Construct bar instance
 *
 * TODO: Break out all tray handling
 */
bar::bar(connection& conn, signal_emitter& emitter, const config& config, const logger& logger,
    unique_ptr<screen> screen, unique_ptr<tray_manager> tray_manager)
    : m_connection(conn)
    , m_sig(emitter)
    , m_conf(config)
    , m_log(logger)
    , m_screen(move(screen))
    , m_tray(move(tray_manager)) {
  string bs{m_conf.section()};

  // Get available RandR outputs
  auto monitor_name = m_conf.get<string>(bs, "monitor", "");
  auto monitor_name_fallback = m_conf.get<string>(bs, "monitor-fallback", "");
  auto monitor_strictmode = m_conf.get<bool>(bs, "monitor-strict", false);
  auto monitors = randr_util::get_monitors(m_connection, m_connection.screen()->root, monitor_strictmode);

  if (monitors.empty()) {
    throw application_error("No monitors found");
  }

  if (monitor_name.empty()) {
    monitor_name = monitors[0]->name;
    m_log.warn("No monitor specified, using \"%s\"", monitor_name);
  }

  bool name_found{false};
  bool fallback_found{monitor_name_fallback.empty()};
  monitor_t fallback{};

  for (auto&& monitor : monitors) {
    if (!name_found && (name_found = monitor->match(monitor_name, monitor_strictmode))) {
      m_opts.monitor = move(monitor);
    } else if (!fallback_found && (fallback_found = monitor->match(monitor_name_fallback, monitor_strictmode))) {
      fallback = move(monitor);
    }

    if (name_found && fallback_found) {
      break;
    }
  }

  if (!m_opts.monitor) {
    if (fallback) {
      m_opts.monitor = move(fallback);
      m_log.warn("Monitor \"%s\" not found, reverting to fallback \"%s\"", monitor_name, monitor_name_fallback);
    } else {
      throw application_error("Monitor \"" + monitor_name + "\" not found or disconnected");
    }
  }

  m_log.trace("bar: Loaded monitor %s (%ix%i+%i+%i)", m_opts.monitor->name, m_opts.monitor->w, m_opts.monitor->h,
      m_opts.monitor->x, m_opts.monitor->y);

  try {
    m_opts.override_redirect = m_conf.get<bool>(bs, "dock");
    m_conf.warn_deprecated(bs, "dock", "override-redirect");
  } catch (const key_error& err) {
    m_opts.override_redirect = m_conf.get<bool>(bs, "override-redirect", m_opts.override_redirect);
  }

  m_opts.dimvalue = m_conf.get<double>(bs, "dim-value", 1.0);
  m_opts.dimvalue = math_util::cap(m_opts.dimvalue, 0.0, 1.0);

  // Build WM_NAME
  m_opts.wmname = m_conf.get<string>(bs, "wm-name", "polybar-" + bs.substr(4) + "_" + m_opts.monitor->name);
  m_opts.wmname = string_util::replace(m_opts.wmname, " ", "-");

  // Load configuration values
  m_opts.origin = m_conf.get<bool>(bs, "bottom", false) ? edge::BOTTOM : edge::TOP;
  m_opts.spacing = m_conf.get<decltype(m_opts.spacing)>(bs, "spacing", m_opts.spacing);
  m_opts.padding.left = m_conf.get<decltype(m_opts.padding.left)>(bs, "padding-left", m_opts.padding.left);
  m_opts.padding.right = m_conf.get<decltype(m_opts.padding.right)>(bs, "padding-right", m_opts.padding.right);
  m_opts.module_margin.left =
      m_conf.get<decltype(m_opts.module_margin.left)>(bs, "module-margin-left", m_opts.module_margin.left);
{'fraction_non_alphanumeric': 0.16433021806853582, 'fraction_numerical': 0.006100726895119419, 'mean_word_length': 4.410814606741573, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 57, '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': '5683699', 'n_tokens_mistral': 2823, 'n_tokens_neox': 2747, 'n_words': 488}