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