Added initial support for displaying on Wayland compositors.
[vuplus_xbmc] / xbmc / windowing / egl / wayland / XBMCConnection.cpp
1 /*
2  *      Copyright (C) 2011-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20 #include <sstream>
21 #include <stdexcept>
22
23 #include <boost/bind.hpp>
24 #include <boost/function.hpp>
25 #include <boost/scoped_ptr.hpp>
26
27 #include <wayland-client.h>
28
29 #include "guilib/Resolution.h"
30 #include "guilib/gui3d.h"
31
32 #include "windowing/DllWaylandClient.h"
33 #include "windowing/DllXKBCommon.h"
34
35 #include "Callback.h"
36 #include "Compositor.h"
37 #include "Display.h"
38 #include "Registry.h"
39 #include "Region.h"
40 #include "Shell.h"
41
42 #include "windowing/WaylandProtocol.h"
43 #include "XBMCConnection.h"
44
45 namespace xbmc
46 {
47 namespace wayland
48 {
49 class XBMCConnection::Private :
50   public IWaylandRegistration
51 {
52 public:
53
54   Private(IDllWaylandClient &clientLibrary,
55           IDllXKBCommon &xkbCommonLibrary,
56           EventInjector &eventInjector);
57   ~Private();
58
59   IDllWaylandClient &m_clientLibrary;
60   IDllXKBCommon &m_xkbCommonLibrary;
61   
62   EventInjector &m_eventInjector;
63
64   boost::scoped_ptr<Display> m_display;
65   boost::scoped_ptr<Registry> m_registry;
66   boost::scoped_ptr<Compositor> m_compositor;
67   boost::scoped_ptr<Shell> m_shell;
68
69   /* Synchronization logic - these variables should not be touched
70    * outside the scope of WaitForSynchronize() */
71   bool synchronized;
72   boost::scoped_ptr<Callback> synchronizeCallback;
73
74   /* Synchronization entry point - call this function to issue a
75    * wl_display.sync request to the server. All this does is cause
76    * the server to send back an event that acknowledges the receipt
77    * of the request. However, it is useful in a number of circumstances
78    * - all request processing in wayland is sequential and guarunteed
79    * to be in the same order as requests were made. That means that
80    * once the event is received from the server, it is guarunteed
81    * that all requests made prior to the sync request have finished
82    * processing on the server and events have been issued to us. */
83   void WaitForSynchronize();
84   
85   /* Callback function for synchronize event, do not call directly */
86   void Synchronize();
87
88   bool OnCompositorAvailable(struct wl_compositor *);
89   bool OnShellAvailable(struct wl_shell *);
90   bool OnSeatAvailable(struct wl_seat *);
91   bool OnOutputAvailable(struct wl_output *);
92 };
93 }
94 }
95
96 namespace xw = xbmc::wayland;
97
98 /* Creating a new xbmc::wayland::XBMCConnection effectively creates
99  * a new xbmc::wayland::Display object, which in turn will connect
100  * to the running wayland compositor and encapsulate the return value
101  * from the client library. Then it creates a new
102  * xbmc::wayland::Registry object which is responsible for managing
103  * all of the global objects on the wayland connection that we might
104  * want to use. On creation of this object, a request is sent to
105  * the compositor to send back an event for every available global
106  * object. Once we know which objects exist, we can easily
107  * bind to them.
108  * 
109  * The WaitForSynchronize call at the end of the constructor is
110  * important. Once we make a request to the server for all of the
111  * available global objects, we need to know what they all are
112  * by the time this constructor finishes running so that the
113  * object will be complete. The only way to do that is to know
114  * when our wl_registry.add_listener request has finished processing
115  * on both the server and client side
116  */
117 xw::XBMCConnection::Private::Private(IDllWaylandClient &clientLibrary,
118                                      IDllXKBCommon &xkbCommonLibrary,
119                                      EventInjector &eventInjector) :
120   m_clientLibrary(clientLibrary),
121   m_xkbCommonLibrary(xkbCommonLibrary),
122   m_eventInjector(eventInjector),
123   m_display(new xw::Display(clientLibrary)),
124   m_registry(new xw::Registry(clientLibrary,
125                               m_display->GetWlDisplay(),
126                               *this))
127 {
128   /* Tell CWinEvents what our display is. That way
129    * CWinEvents::MessagePump is now able to dispatch events from
130    * the display whenever it is called */ 
131   (*m_eventInjector.setDisplay)(&clientLibrary,
132                                 m_display->GetWlDisplay());
133         
134   WaitForSynchronize();
135 }
136
137 xw::XBMCConnection::Private::~Private()
138 {
139   (*m_eventInjector.destroyDisplay)();
140 }
141
142 xw::XBMCConnection::XBMCConnection(IDllWaylandClient &clientLibrary,
143                                    IDllXKBCommon &xkbCommonLibrary,
144                                    EventInjector &eventInjector) :
145   priv(new Private (clientLibrary, xkbCommonLibrary, eventInjector))
146 {
147 }
148
149 /* A defined destructor is required such that
150  * boost::scoped_ptr<Private>::~scoped_ptr is generated here */
151 xw::XBMCConnection::~XBMCConnection()
152 {
153 }
154
155 /* These are all registry callbacks. Once an object becomes available
156  * (generally speaking at construction time) then we need to
157  * create an internal representation for it so that we can use it
158  * later */
159 bool xw::XBMCConnection::Private::OnCompositorAvailable(struct wl_compositor *c)
160 {
161   m_compositor.reset(new xw::Compositor(m_clientLibrary, c));
162   return true;
163 }
164
165 bool xw::XBMCConnection::Private::OnShellAvailable(struct wl_shell *s)
166 {
167   m_shell.reset(new xw::Shell(m_clientLibrary, s));
168   return true;
169 }
170
171 bool xw::XBMCConnection::Private::OnSeatAvailable(struct wl_seat *s)
172 {
173   return true;
174 }
175
176 void xw::XBMCConnection::Private::WaitForSynchronize()
177 {
178   boost::function<void(uint32_t)> func(boost::bind(&Private::Synchronize,
179                                                    this));
180   
181   synchronized = false;
182   synchronizeCallback.reset(new xw::Callback(m_clientLibrary,
183                                              m_display->Sync(),
184                                              func));
185   while (!synchronized)
186     (*m_eventInjector.messagePump)();
187 }
188
189 void xw::XBMCConnection::Private::Synchronize()
190 {
191   synchronized = true;
192   synchronizeCallback.reset();
193 }
194
195 void
196 xw::XBMCConnection::CurrentResolution(RESOLUTION_INFO &res) const
197 {
198   res.iWidth = 640;
199   res.iHeight = 480;
200   res.fRefreshRate = 60;
201   res.dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
202   res.iScreen = 0;
203   res.bFullScreen = true;
204   res.iSubtitles = static_cast<int>(0.965 * res.iHeight);
205   res.fPixelRatio = 1.0f;
206   res.iScreenWidth = res.iWidth;
207   res.iScreenHeight = res.iHeight;
208   res.strMode.Format("%dx%d @ %.2fp",
209                      res.iScreenWidth,
210                      res.iScreenHeight,
211                      res.fRefreshRate);
212 }
213
214 void
215 xw::XBMCConnection::PreferredResolution(RESOLUTION_INFO &res) const
216 {
217   CurrentResolution(res);
218 }
219
220 void
221 xw::XBMCConnection::AvailableResolutions(std::vector<RESOLUTION_INFO> &res) const
222 {
223   RESOLUTION_INFO resolution;
224   CurrentResolution(resolution);
225   res.push_back(resolution);
226 }
227
228 EGLNativeDisplayType *
229 xw::XBMCConnection::NativeDisplay() const
230 {
231   return priv->m_display->GetEGLNativeDisplay();
232 }
233
234 const boost::scoped_ptr<xw::Compositor> &
235 xw::XBMCConnection::GetCompositor() const
236 {
237   return priv->m_compositor;
238 }
239
240 const boost::scoped_ptr<xw::Shell> &
241 xw::XBMCConnection::GetShell() const
242 {
243   return priv->m_shell;
244 }