1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef UI_GFX_X_CONNECTION_H_
6 #define UI_GFX_X_CONNECTION_H_
7 
8 #include <queue>
9 
10 #include "base/component_export.h"
11 #include "base/containers/circular_deque.h"
12 #include "base/sequence_checker.h"
13 #include "ui/events/platform/platform_event_source.h"
14 #include "ui/gfx/x/event.h"
15 #include "ui/gfx/x/extension_manager.h"
16 #include "ui/gfx/x/xlib_support.h"
17 #include "ui/gfx/x/xproto.h"
18 
19 typedef struct xcb_connection_t xcb_connection_t;
20 
21 namespace x11 {
22 
23 class KeyboardState;
24 
25 // Represents a socket to the X11 server.
COMPONENT_EXPORT(X11)26 class COMPONENT_EXPORT(X11) Connection : public XProto,
27                                          public ExtensionManager {
28  public:
29   using ErrorHandler = base::RepeatingCallback<void(const Error*, const char*)>;
30   using IOErrorHandler = base::OnceClosure;
31 
32   class Delegate {
33    public:
34     virtual bool ShouldContinueStream() const = 0;
35     virtual void DispatchXEvent(x11::Event* event) = 0;
36 
37    protected:
38     virtual ~Delegate() = default;
39   };
40 
41   struct VisualInfo {
42     const Format* format;
43     const VisualType* visual_type;
44   };
45 
46   // Gets or creates the thread local connection instance.
47   static Connection* Get();
48 
49   // Sets the thread local connection instance.
50   static void Set(std::unique_ptr<x11::Connection> connection);
51 
52   explicit Connection(const std::string& address = "");
53   ~Connection();
54 
55   Connection(const Connection&) = delete;
56   Connection(Connection&&) = delete;
57 
58   xcb_connection_t* XcbConnection();
59 
60   // Obtain an Xlib display that's connected to the same server as |this|.  This
61   // is meant to be used only for compatibility with components like GLX,
62   // Vulkan, and VAAPI.  The underlying socket is not shared, so synchronization
63   // with |this| may be necessary.  The |type| parameter can be used to achieve
64   // synchronization.  The returned wrapper should not be saved.
65   XlibDisplayWrapper GetXlibDisplay(
66       XlibDisplayType type = XlibDisplayType::kNormal);
67 
68   uint32_t extended_max_request_length() const {
69     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
70     return extended_max_request_length_;
71   }
72 
73   const Setup& setup() const {
74     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
75     return setup_;
76   }
77   const Screen& default_screen() const {
78     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
79     return *default_screen_;
80   }
81   x11::Window default_root() const {
82     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
83     return default_screen().root;
84   }
85   const Depth& default_root_depth() const {
86     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
87     return *default_root_depth_;
88   }
89   const VisualType& default_root_visual() const {
90     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
91     return *default_root_visual_;
92   }
93 
94   // Returns the underlying socket's FD if the connection is valid, or -1
95   // otherwise.
96   int GetFd();
97 
98   const std::string& DisplayString() const;
99 
100   std::string GetConnectionHostname() const;
101 
102   int DefaultScreenId() const;
103 
104   template <typename T>
105   T GenerateId() {
106     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
107     return static_cast<T>(GenerateIdImpl());
108   }
109 
110   // Is the connection up and error-free?
111   bool Ready() const;
112 
113   // Write all requests to the socket.
114   void Flush();
115 
116   // Flush and block until the server has responded to all requests.
117   void Sync();
118 
119   // If |synchronous| is true, this makes all requests Sync().
120   void SynchronizeForTest(bool synchronous);
121 
122   bool synchronous() const { return synchronous_; }
123 
124   // Read all responses from the socket without blocking.
125   void ReadResponses();
126 
127   Event WaitForNextEvent();
128 
129   // Are there any events, errors, or replies already buffered?
130   bool HasPendingResponses();
131 
132   // Dispatch any buffered events, errors, or replies.
133   void Dispatch(Delegate* delegate);
134 
135   // Returns the old error handler.
136   ErrorHandler SetErrorHandler(ErrorHandler new_handler);
137 
138   void SetIOErrorHandler(IOErrorHandler new_handler);
139 
140   // Returns the visual data for |id|, or nullptr if the visual with that ID
141   // doesn't exist or only exists on a non-default screen.
142   const VisualInfo* GetVisualInfoFromId(VisualId id) const;
143 
144   KeyCode KeysymToKeycode(uint32_t keysym) const;
145 
146   uint32_t KeycodeToKeysym(KeyCode keycode, uint32_t modifiers) const;
147 
148   // Access the event buffer.  Clients may modify the queue, including
149   // "deleting" events by setting events[i] = x11::Event(), which will
150   // guarantee all calls to x11::Event::As() will return nullptr.
151   base::circular_deque<Event>& events() {
152     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
153     return events_;
154   }
155 
156   std::unique_ptr<Connection> Clone() const;
157 
158   // Releases ownership of this connection to a different thread.
159   void DetachFromSequence();
160 
161   // The viz compositor thread hangs a PlatformEventSource off the connection so
162   // that it gets destroyed at the appropriate time.
163   // TODO(thomasanderson): This is a layering violation and this should be moved
164   // somewhere else.
165   std::unique_ptr<ui::PlatformEventSource> platform_event_source;
166 
167  private:
168   friend class FutureBase;
169 
170   struct Request {
171     Request(unsigned int sequence, FutureBase::ResponseCallback callback);
172     Request(Request&& other);
173     ~Request();
174 
175     const unsigned int sequence;
176     FutureBase::ResponseCallback callback;
177     bool have_response = false;
178     FutureBase::RawReply reply;
179     FutureBase::RawError error;
180   };
181 
182   void InitRootDepthAndVisual();
183 
184   void AddRequest(unsigned int sequence, FutureBase::ResponseCallback callback);
185 
186   bool HasNextResponse();
187 
188   bool HasNextEvent();
189 
190   void PreDispatchEvent(const Event& event);
191 
192   int ScreenIndexFromRootWindow(x11::Window root) const;
193 
194   // This function is implemented in the generated read_error.cc.
195   void InitErrorParsers();
196 
197   std::unique_ptr<Error> ParseError(FutureBase::RawError error_bytes);
198 
199   uint32_t GenerateIdImpl();
200 
201   xcb_connection_t* connection_ = nullptr;
202   std::unique_ptr<XlibDisplay> xlib_display_;
203 
204   bool synchronous_ = false;
205   bool syncing_ = false;
206 
207   uint32_t extended_max_request_length_ = 0;
208 
209   std::string display_string_;
210   int default_screen_id_ = 0;
211   Setup setup_;
212   Screen* default_screen_ = nullptr;
213   Depth* default_root_depth_ = nullptr;
214   VisualType* default_root_visual_ = nullptr;
215 
216   std::unordered_map<VisualId, VisualInfo> default_screen_visuals_;
217 
218   std::unique_ptr<KeyboardState> keyboard_state_;
219 
220   base::circular_deque<Event> events_;
221 
222   std::queue<Request> requests_;
223 
224   using ErrorParser =
225       std::unique_ptr<Error> (*)(FutureBase::RawError error_bytes);
226   std::array<ErrorParser, 256> error_parsers_{};
227 
228   ErrorHandler error_handler_;
229   IOErrorHandler io_error_handler_;
230 
231   SEQUENCE_CHECKER(sequence_checker_);
232 };
233 
234 }  // namespace x11
235 
236 #endif  // UI_GFX_X_CONNECTION_H_
237