<commit_before>// Clip Library
// Copyright (c) 2018 <NAME>

#include "clip.h"
#include "clip_lock_impl.h"

#include <xcb/xcb.h>

#include <algorithm>
#include <condition_variable>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <map>
#include <memory>
#include <mutex>
#include <thread>
#include <vector>

#ifdef HAVE_PNG_H
  #include "clip_x11_png.h"
#endif

namespace clip {

namespace {

enum CommonAtom {
  ATOM,
  INCR,
  TARGETS,
  CLIPBOARD,
#ifdef HAVE_PNG_H
  MIME_IMAGE_PNG,
#endif
};

const char* kCommonAtomNames[] = {
  "ATOM",
  "INCR",
  "TARGETS",
  "CLIPBOARD",
#ifdef HAVE_PNG_H
  "image/png",
#endif
};

const int kBaseForCustomFormats = 100;

class Manager {
public:
  typedef std::shared_ptr<std::vector<uint8_t>> buffer_ptr;
  typedef std::vector<xcb_atom_t> atoms;
  typedef std::function<bool()> notify_callback;

  Manager()
    : m_connection(xcb_connect(nullptr, nullptr))
    , m_incr_process(false)
    , m_reply(nullptr) {
    xcb_screen_t* screen =
      xcb_setup_roots_iterator(xcb_get_setup(m_connection)).data;


    uint32_t event_mask =
      // Just in case that some program reports SelectionNotify events
      // with XCB_EVENT_MASK_PROPERTY_CHANGE mask.
      XCB_EVENT_MASK_PROPERTY_CHANGE |
      // To receive DestroyNotify event and stop the message loop.
      XCB_EVENT_MASK_STRUCTURE_NOTIFY;

    m_window = xcb_generate_id(m_connection);
    xcb_create_window(m_connection, 0,
                      m_window,
                      screen->root,
                      0, 0, 1, 1, 0,
                      XCB_WINDOW_CLASS_INPUT_OUTPUT,
                      screen->root_visual,
                      XCB_CW_EVENT_MASK,
                      &event_mask);

    m_thread = std::thread(
      [this]{
        process_x11_events();
      });
  }

  ~Manager() {
    if (!m_data.empty() &&
        m_window &&
        m_window == get_x11_selection_owner()) {
      // TODO create some method to keep the clipboard alive.
    }

    if (m_window) {
      xcb_destroy_window(m_connection, m_window);
      xcb_flush(m_connection);
    }

    m_thread.join();

    xcb_disconnect(m_connection);
  }

  bool try_lock() {
    return m_mutex.try_lock();
  }

  void unlock() {
    m_mutex.unlock();
  }

  void clear() {
    m_data.clear();
  }

  bool is_convertible(format f) const {
    const atoms atoms = get_format_atoms(f);
    const xcb_window_t owner = get_x11_selection_owner();

    // If we are the owner, we just can check the m_data map
    if (owner == m_window) {
      for (xcb_atom_t atom : atoms) {
        auto it = m_data.find(atom);
        if (it != m_data.end())
          return true;
      }
    }
    // Ask to the selection owner the available formats/atoms/targets.
    else if (owner) {
      bool result =
        get_data_from_selection_owner(
          { get_atom(TARGETS) },
          [this, &atoms]() -> bool {
            xcb_atom_t* sel_atoms = (xcb_atom_t*)xcb_get_property_value(m_reply);
            int sel_natoms = xcb_get_property_value_length(m_reply);
            auto atoms_begin = atoms.begin();
            auto atoms_end = atoms.end();
            for (int i=0; i<sel_natoms; ++i) {
              if (std::find(atoms_begin,
                            atoms_end,<commit_msg>A little more of const-correctness<commit_after>// Clip Library
// Copyright (c) 2018 <NAME>

#include "clip.h"
#include "clip_lock_impl.h"

#include <xcb/xcb.h>

#include <algorithm>
#include <condition_variable>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <map>
#include <memory>
#include <mutex>
#include <thread>
#include <vector>

#ifdef HAVE_PNG_H
  #include "clip_x11_png.h"
#endif

namespace clip {

namespace {

enum CommonAtom {
  ATOM,
  INCR,
  TARGETS,
  CLIPBOARD,
#ifdef HAVE_PNG_H
  MIME_IMAGE_PNG,
#endif
};

const char* kCommonAtomNames[] = {
  "ATOM",
  "INCR",
  "TARGETS",
  "CLIPBOARD",
#ifdef HAVE_PNG_H
  "image/png",
#endif
};

const int kBaseForCustomFormats = 100;

class Manager {
public:
  typedef std::shared_ptr<std::vector<uint8_t>> buffer_ptr;
  typedef std::vector<xcb_atom_t> atoms;
  typedef std::function<bool()> notify_callback;

  Manager()
    : m_connection(xcb_connect(nullptr, nullptr))
    , m_incr_process(false)
    , m_reply(nullptr) {
    xcb_screen_t* screen =
      xcb_setup_roots_iterator(xcb_get_setup(m_connection)).data;


    uint32_t event_mask =
      // Just in case that some program reports SelectionNotify events
      // with XCB_EVENT_MASK_PROPERTY_CHANGE mask.
      XCB_EVENT_MASK_PROPERTY_CHANGE |
      // To receive DestroyNotify event and stop the message loop.
      XCB_EVENT_MASK_STRUCTURE_NOTIFY;

    m_window = xcb_generate_id(m_connection);
    xcb_create_window(m_connection, 0,
                      m_window,
                      screen->root,
                      0, 0, 1, 1, 0,
                      XCB_WINDOW_CLASS_INPUT_OUTPUT,
                      screen->root_visual,
                      XCB_CW_EVENT_MASK,
                      &event_mask);

    m_thread = std::thread(
      [this]{
        process_x11_events();
      });
  }

  ~Manager() {
    if (!m_data.empty() &&
        m_window &&
        m_window == get_x11_selection_owner()) {
      // TODO create some method to keep the clipboard alive.
    }

    if (m_window) {
      xcb_destroy_window(m_connection, m_window);
      xcb_flush(m_connection);
    }

    m_thread.join();

    xcb_disconnect(m_connection);
  }

  bool try_lock() {
    return m_mutex.try_lock();
  }

  void unlock() {
    m_mutex.unlock();
  }

  void clear() {
    m_data.clear();
  }

  bool is_convertible(format f) const {
    const atoms atoms = get_format_atoms(f);
    const xcb_window_t owner = get_x11_selection_owner();

    // If we are the owner, we just can check the m_data map
    if (owner == m_window) {
      for (xcb_atom_t atom : atoms) {
        auto it = m_data.find(atom);
        if (it != m_data.end())
          return true;
      }
    }
    // Ask to the selection owner the available formats/atoms/targets.
    else if (owner) {
      bool result =
        get_data_from_selection_owner(
          { get_atom(TARGETS) },
          [this, &atoms]() -> bool {
            const xcb_atom_t* sel_atoms = (const xcb_atom_t*)xcb_get_property_value(m_reply);
            int sel_natoms = xcb_get_property_value_length(m_reply);
            auto atoms_begin = atoms.begin();
            auto atoms_end = atoms.end();
            for (int i=0; i<sel_natoms; ++i) {
              if (std::find(atoms_begin,
                            atoms_end,
{'fraction_non_alphanumeric': 0.10902198635329795, 'fraction_numerical': 0.0075815011372251705, 'mean_word_length': 2.5272727272727273, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 41, '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': '560807', 'n_tokens_mistral': 2336, 'n_tokens_neox': 2263, 'n_words': 483}