1 /*
2  *  Copyright (C) 2017-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #include "Connection.h"
12 #include "Output.h"
13 #include "Seat.h"
14 #include "SeatInputProcessing.h"
15 #include "ShellSurface.h"
16 #include "Signals.h"
17 #include "WindowDecorationHandler.h"
18 #include "threads/CriticalSection.h"
19 #include "threads/Event.h"
20 #include "utils/ActorProtocol.h"
21 #include "windowing/WinSystem.h"
22 
23 #include <atomic>
24 #include <ctime>
25 #include <list>
26 #include <map>
27 #include <set>
28 #include <time.h>
29 
30 #include <wayland-client.hpp>
31 #include <wayland-cursor.hpp>
32 #include <wayland-extra-protocols.hpp>
33 
34 class IDispResource;
35 
36 namespace KODI
37 {
38 namespace WINDOWING
39 {
40 namespace WAYLAND
41 {
42 
43 class CRegistry;
44 class CWindowDecorator;
45 
46 class CWinSystemWayland : public CWinSystemBase, IInputHandler, IWindowDecorationHandler, IShellSurfaceHandler
47 {
48 public:
49   CWinSystemWayland();
50   ~CWinSystemWayland() noexcept override;
51 
GetName()52   const std::string GetName() override { return "wayland"; }
53 
54   bool InitWindowSystem() override;
55   bool DestroyWindowSystem() override;
56 
57   bool CreateNewWindow(const std::string& name,
58                        bool fullScreen,
59                        RESOLUTION_INFO& res) override;
60 
61   bool DestroyWindow() override;
62 
63   bool ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) override;
64   bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays) override;
65   void FinishModeChange(RESOLUTION res) override;
66   void FinishWindowResize(int newWidth, int newHeight) override;
67 
68   bool UseLimitedColor() override;
69 
70   void UpdateResolutions() override;
71 
72   bool CanDoWindowed() override;
73   bool Minimize() override;
74 
75   bool HasCursor() override;
76   void ShowOSMouse(bool show) override;
77 
78   std::string GetClipboardText() override;
79 
80   float GetSyncOutputRefreshRate();
81   float GetDisplayLatency() override;
82   float GetFrameLatencyAdjustment() override;
83   std::unique_ptr<CVideoSync> GetVideoSync(void* clock) override;
84 
85   void Register(IDispResource* resource) override;
86   void Unregister(IDispResource* resource) override;
87 
88   using PresentationFeedbackHandler = std::function<void(timespec /* tv */, std::uint32_t /* refresh */, std::uint32_t /* sync output id */, float /* sync output fps */, std::uint64_t /* msc */)>;
89   CSignalRegistration RegisterOnPresentationFeedback(const PresentationFeedbackHandler& handler);
90 
91   // Like CWinSystemX11
92   void GetConnectedOutputs(std::vector<std::string>* outputs);
93 
94   // winevents override
95   bool MessagePump() override;
96 
97 protected:
98   std::unique_ptr<KODI::WINDOWING::IOSScreenSaver> GetOSScreenSaverImpl() override;
GetBufferSize()99   CSizeInt GetBufferSize() const
100   {
101     return m_bufferSize;
102   }
GetConnection()103   std::unique_ptr<CConnection> const& GetConnection()
104   {
105     return m_connection;
106   }
GetMainSurface()107   wayland::surface_t GetMainSurface()
108   {
109     return m_surface;
110   }
111 
112   void PrepareFramePresentation();
113   void FinishFramePresentation();
114   virtual void SetContextSize(CSizeInt size) = 0;
115 
116 private:
117   // IInputHandler
118   void OnEnter(InputType type) override;
119   void OnLeave(InputType type) override;
120   void OnEvent(InputType type, XBMC_Event& event) override;
121   void OnSetCursor(std::uint32_t seatGlobalName, std::uint32_t serial) override;
122 
123   // IWindowDecorationHandler
124   void OnWindowMove(const wayland::seat_t& seat, std::uint32_t serial) override;
125   void OnWindowResize(const wayland::seat_t& seat, std::uint32_t serial, wayland::shell_surface_resize edge) override;
126   void OnWindowShowContextMenu(const wayland::seat_t& seat, std::uint32_t serial, CPointInt position) override;
127   void OnWindowClose() override;
128   void OnWindowMaximize() override;
129   void OnWindowMinimize() override;
130 
131   // IShellSurfaceHandler
132   void OnConfigure(std::uint32_t serial, CSizeInt size, IShellSurface::StateBitset state) override;
133   void OnClose() override;
134 
135   // Registry handlers
136   void OnSeatAdded(std::uint32_t name, wayland::proxy_t&& seat);
137   void OnSeatRemoved(std::uint32_t name);
138   void OnOutputAdded(std::uint32_t name, wayland::proxy_t&& output);
139   void OnOutputRemoved(std::uint32_t name);
140 
141   void LoadDefaultCursor();
142   void SendFocusChange(bool focus);
143   bool SetResolutionExternal(bool fullScreen, RESOLUTION_INFO const& res);
144   void SetResolutionInternal(CSizeInt size, int scale, IShellSurface::StateBitset state, bool sizeIncludesDecoration, bool mustAck = false, std::uint32_t configureSerial = 0u);
145   struct Sizes
146   {
147     CSizeInt surfaceSize;
148     CSizeInt bufferSize;
149     CSizeInt configuredSize;
150   };
151   Sizes CalculateSizes(CSizeInt size, int scale, IShellSurface::StateBitset state, bool sizeIncludesDecoration);
152   struct SizeUpdateInformation
153   {
154     bool surfaceSizeChanged : 1;
155     bool bufferSizeChanged : 1;
156     bool configuredSizeChanged : 1;
157     bool bufferScaleChanged : 1;
158   };
159   SizeUpdateInformation UpdateSizeVariables(CSizeInt size, int scale, IShellSurface::StateBitset state, bool sizeIncludesDecoration);
160   void ApplySizeUpdate(SizeUpdateInformation update);
161   void ApplyNextState();
162 
163   std::string UserFriendlyOutputName(std::shared_ptr<COutput> const& output);
164   std::shared_ptr<COutput> FindOutputByUserFriendlyName(std::string const& name);
165   std::shared_ptr<COutput> FindOutputByWaylandOutput(wayland::output_t const& output);
166 
167   // Called when wl_output::done is received for an output, i.e. associated
168   // information like modes is available
169   void OnOutputDone(std::uint32_t name);
170   void UpdateBufferScale();
171   void ApplyBufferScale();
172   void ApplyOpaqueRegion();
173   void ApplyWindowGeometry();
174   void UpdateTouchDpi();
175   void ApplyShellSurfaceState(IShellSurface::StateBitset state);
176 
177   void ProcessMessages();
178   void AckConfigure(std::uint32_t serial);
179 
180   timespec GetPresentationClockTime();
181 
182   // Globals
183   // -------
184   std::unique_ptr<CConnection> m_connection;
185   std::unique_ptr<CRegistry> m_registry;
186   /**
187    * Registry used exclusively for wayland::seat_t
188    *
189    * Use extra registry because seats can only be registered after the surface
190    * has been created
191    */
192   std::unique_ptr<CRegistry> m_seatRegistry;
193   wayland::compositor_t m_compositor;
194   wayland::shm_t m_shm;
195   wayland::presentation_t m_presentation;
196 
197   std::unique_ptr<IShellSurface> m_shellSurface;
198 
199   // Frame callback handling
200   // -----------------------
201   wayland::callback_t m_frameCallback;
202   CEvent m_frameCallbackEvent;
203 
204   // Seat handling
205   // -------------
206   std::map<std::uint32_t, CSeat> m_seats;
207   CCriticalSection m_seatsMutex;
208   std::unique_ptr<CSeatInputProcessing> m_seatInputProcessing;
209   std::map<std::uint32_t, std::shared_ptr<COutput>> m_outputs;
210   /// outputs that did not receive their done event yet
211   std::map<std::uint32_t, std::shared_ptr<COutput>> m_outputsInPreparation;
212   CCriticalSection m_outputsMutex;
213 
214   // Windowed mode
215   // -------------
216   std::unique_ptr<CWindowDecorator> m_windowDecorator;
217 
218   // Cursor
219   // ------
220   bool m_osCursorVisible{true};
221   wayland::cursor_theme_t m_cursorTheme;
222   wayland::buffer_t m_cursorBuffer;
223   wayland::cursor_image_t m_cursorImage;
224   wayland::surface_t m_cursorSurface;
225 
226   // Presentation feedback
227   // ---------------------
228   clockid_t m_presentationClock;
229   struct SurfaceSubmission
230   {
231     timespec submissionTime;
232     float latency;
233     wayland::presentation_feedback_t feedback;
234     SurfaceSubmission(timespec const& submissionTime, wayland::presentation_feedback_t const& feedback);
235   };
236   std::list<SurfaceSubmission> m_surfaceSubmissions;
237   CCriticalSection m_surfaceSubmissionsMutex;
238   /// Protocol object ID of the sync output returned by wp_presentation
239   std::uint32_t m_syncOutputID;
240   /// Refresh rate of sync output returned by wp_presentation
241   std::atomic<float> m_syncOutputRefreshRate{0.0f};
242   static constexpr int LATENCY_MOVING_AVERAGE_SIZE{30};
243   std::atomic<float> m_latencyMovingAverage;
244   CSignalHandlerList<PresentationFeedbackHandler> m_presentationFeedbackHandlers;
245   std::int64_t m_frameStartTime{};
246 
247   // IDispResource
248   // -------------
249   std::set<IDispResource*> m_dispResources;
250   CCriticalSection m_dispResourcesMutex;
251 
252   // Surface state
253   // -------------
254   wayland::surface_t m_surface;
255   wayland::output_t m_lastSetOutput;
256   /// Set of outputs that show some part of our main surface as indicated by
257   /// compositor
258   std::set<std::shared_ptr<COutput>> m_surfaceOutputs;
259   CCriticalSection m_surfaceOutputsMutex;
260   /// Size of our surface in "surface coordinates" (i.e. without scaling applied)
261   /// and without window decorations
262   CSizeInt m_surfaceSize;
263   /// Size of the buffer that should back the surface (i.e. with scaling applied)
264   CSizeInt m_bufferSize;
265   /// Size of the whole window including window decorations as given by configure
266   CSizeInt m_configuredSize;
267   /// Scale in use for main surface buffer
268   int m_scale{1};
269   /// Shell surface state last acked
270   IShellSurface::StateBitset m_shellSurfaceState;
271   /// Whether the shell surface is waiting for initial configure
272   bool m_shellSurfaceInitializing{false};
273   struct
274   {
275     bool mustBeAcked{false};
276     std::uint32_t configureSerial{};
277     CSizeInt configuredSize;
278     int scale{1};
279     IShellSurface::StateBitset shellSurfaceState;
280   } m_next;
281   bool m_waitingForApply{false};
282 
283   // Internal communication
284   // ----------------------
285   /// Protocol for communicating events to the main thread
286   Actor::Protocol m_protocol;
287 
288   // Configure state
289   // ---------------
290   bool m_firstSerialAcked{false};
291   std::uint32_t m_lastAckedSerial{0u};
292   /// Whether this is the first call to SetFullScreen
293   bool m_isInitialSetFullScreen{true};
294 };
295 
296 
297 }
298 }
299 }
300