1 #pragma once
2 
3 #include <xcb/xcb.h>
4 #include <cstdlib>
5 #include <xpp/core.hpp>
6 #include <xpp/generic/factory.hpp>
7 #include <xpp/proto/x.hpp>
8 
9 #include "common.hpp"
10 #include "components/screen.hpp"
11 #include "x11/extensions/all.hpp"
12 #include "x11/registry.hpp"
13 #include "x11/types.hpp"
14 
15 POLYBAR_NS
16 
17 namespace detail {
18   template <typename Connection, typename... Extensions>
19   class interfaces : public xpp::x::extension::interface<interfaces<Connection, Extensions...>, Connection>,
20                      public Extensions::template interface<interfaces<Connection, Extensions...>, Connection>... {
21    public:
connection() const22     const Connection& connection() const {
23       return static_cast<const Connection&>(*this);
24     }
25   };
26 
27   template <typename Derived, typename... Extensions>
28   class connection_base : public xpp::core,
29                           public xpp::generic::error_dispatcher,
30                           public detail::interfaces<connection_base<Derived, Extensions...>, Extensions...>,
31                           private xpp::x::extension,
32                           private xpp::x::extension::error_dispatcher,
33                           private Extensions...,
34                           private Extensions::error_dispatcher... {
35    public:
connection_base(xcb_connection_t * c,int s)36     explicit connection_base(xcb_connection_t* c, int s)
37         : xpp::core(c)
38         , interfaces<connection_base<Derived, Extensions...>, Extensions...>(*this)
39         , Extensions(m_c.get())...
40         , Extensions::error_dispatcher(static_cast<Extensions&>(*this).get())... {
41       core::m_screen = s;
42       m_root_window = screen_of_display(default_screen())->root;
43     }
44 
~connection_base()45     virtual ~connection_base() {}
46 
operator ()(const shared_ptr<xcb_generic_error_t> & error) const47     void operator()(const shared_ptr<xcb_generic_error_t>& error) const {
48       check<xpp::x::extension, Extensions...>(error);
49     }
50 
51     template <typename Extension>
extension() const52     const Extension& extension() const {
53       return static_cast<const Extension&>(*this);
54     }
55 
56     template <typename WindowType = xcb_window_t>
root() const57     WindowType root() const {
58       using make = xpp::generic::factory::make<connection_base, xcb_window_t, WindowType>;
59       return make()(*this, m_root_window);
60     }
61 
wait_for_event() const62     shared_ptr<xcb_generic_event_t> wait_for_event() const {
63       try {
64         return core::wait_for_event();
65       } catch (const shared_ptr<xcb_generic_error_t>& error) {
66         check<xpp::x::extension, Extensions...>(error);
67       }
68       throw;  // re-throw exception
69     }
70 
wait_for_special_event(xcb_special_event_t * se) const71     shared_ptr<xcb_generic_event_t> wait_for_special_event(xcb_special_event_t* se) const {
72       try {
73         return core::wait_for_special_event(se);
74       } catch (const shared_ptr<xcb_generic_error_t>& error) {
75         check<xpp::x::extension, Extensions...>(error);
76       }
77       throw;  // re-throw exception
78     }
79 
80    private:
81     xcb_window_t m_root_window;
82 
83     template <typename Extension, typename Next, typename... Rest>
check(const shared_ptr<xcb_generic_error_t> & error) const84     void check(const shared_ptr<xcb_generic_error_t>& error) const {
85       check<Extension>(error);
86       check<Next, Rest...>(error);
87     }
88 
89     template <typename Extension>
check(const shared_ptr<xcb_generic_error_t> & error) const90     void check(const shared_ptr<xcb_generic_error_t>& error) const {
91       using error_dispatcher = typename Extension::error_dispatcher;
92       auto& dispatcher = static_cast<const error_dispatcher&>(*this);
93       dispatcher(error);
94     }
95   };
96 }
97 
98 class connection : public detail::connection_base<connection&, XPP_EXTENSION_LIST> {
99  public:
100   using base_type = detail::connection_base<connection&, XPP_EXTENSION_LIST>;
101 
102   using make_type = connection&;
103   static make_type make(xcb_connection_t* conn = nullptr, int default_screen = 0);
104 
105   explicit connection(xcb_connection_t* c, int default_screen);
106   ~connection();
107 
operator =(const connection & o)108   const connection& operator=(const connection& o) {
109     return o;
110   }
111 
112   static void pack_values(unsigned int mask, const unsigned int* src, unsigned int* dest);
113   static void pack_values(unsigned int mask, const xcb_params_cw_t* src, unsigned int* dest);
114   static void pack_values(unsigned int mask, const xcb_params_gc_t* src, unsigned int* dest);
115   static void pack_values(unsigned int mask, const xcb_params_configure_window_t* src, unsigned int* dest);
116 
117   xcb_screen_t* screen(bool realloc = false);
118 
119   string id(xcb_window_t w) const;
120 
121   void ensure_event_mask(xcb_window_t win, unsigned int event);
122   void clear_event_mask(xcb_window_t win);
123 
124   shared_ptr<xcb_client_message_event_t> make_client_message(xcb_atom_t type, xcb_window_t target) const;
125   void send_client_message(const shared_ptr<xcb_client_message_event_t>& message, xcb_window_t target,
126       unsigned int event_mask = 0xFFFFFF, bool propagate = false) const;
127 
128   xcb_visualtype_t* visual_type(xcb_screen_t* screen, int match_depth = 32);
129   xcb_visualtype_t* visual_type_for_id(xcb_screen_t* screen, xcb_visualid_t visual_id);
130 
131   bool root_pixmap(xcb_pixmap_t* pixmap, int* depth, xcb_rectangle_t* rect);
132 
133   static string error_str(int error_code);
134 
135   void dispatch_event(const shared_ptr<xcb_generic_event_t>& evt) const;
136 
137   template <typename Event, unsigned int ResponseType>
wait_for_response(function<bool (const Event *)> check_event)138   void wait_for_response(function<bool(const Event*)> check_event) {
139     int fd = get_file_descriptor();
140     shared_ptr<xcb_generic_event_t> evt{};
141     while (!connection_has_error()) {
142       fd_set fds;
143       FD_ZERO(&fds);
144       FD_SET(fd, &fds);
145 
146       if (!select(fd + 1, &fds, nullptr, nullptr, nullptr)) {
147         continue;
148       } else if ((evt = shared_ptr<xcb_generic_event_t>(xcb_poll_for_event(*this), free)) == nullptr) {
149         continue;
150       } else if (evt->response_type != ResponseType) {
151         continue;
152       } else if (check_event(reinterpret_cast<const Event*>(&*evt))) {
153         break;
154       }
155     }
156   }
157 
158   template <typename Sink>
attach_sink(Sink && sink,registry::priority prio=0)159   void attach_sink(Sink&& sink, registry::priority prio = 0) {
160     m_registry.attach(prio, forward<Sink>(sink));
161   }
162 
163   template <typename Sink>
detach_sink(Sink && sink,registry::priority prio=0)164   void detach_sink(Sink&& sink, registry::priority prio = 0) {
165     m_registry.detach(prio, forward<Sink>(sink));
166   }
167 
168  protected:
169   registry m_registry{*this};
170   xcb_screen_t* m_screen{nullptr};
171 };
172 
173 POLYBAR_NS_END
174