2 * Copyright (C) 2011-2013 Team XBMC
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)
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.
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/>.
22 #if defined(HAVE_WAYLAND)
24 #define WL_EGL_PLATFORM
30 #include <boost/noncopyable.hpp>
31 #include <boost/function.hpp>
32 #include <boost/bind.hpp>
33 #include <boost/scoped_ptr.hpp>
34 #include <boost/shared_ptr.hpp>
38 #include <wayland-client.h>
39 #include <wayland-version.h>
41 #include "windowing/DllWaylandClient.h"
42 #include "windowing/DllWaylandEgl.h"
43 #include "windowing/DllXKBCommon.h"
44 #include "windowing/WaylandProtocol.h"
46 #include "guilib/gui3d.h"
47 #include "utils/log.h"
48 #include "windowing/WinEvents.h"
49 #include "windowing/WinEventsWayland.h"
51 #include "wayland/WaylandLibraries.h"
52 #include "wayland/XBMCConnection.h"
53 #include "wayland/XBMCSurface.h"
57 #include "EGLNativeTypeWayland.h"
59 #if defined(HAVE_WAYLAND)
60 namespace xw = xbmc::wayland;
62 class CEGLNativeTypeWayland::Private
66 boost::scoped_ptr<xw::Libraries> m_libraries;
67 boost::scoped_ptr<xw::XBMCConnection> m_connection;
68 boost::scoped_ptr<xw::XBMCSurface> m_surface;
70 bool LoadWaylandLibraries();
71 void UnloadWaylandLibraries();
74 bool CEGLNativeTypeWayland::Private::LoadWaylandLibraries()
78 m_libraries.reset(new xw::Libraries());
80 catch (const std::runtime_error &err)
82 CLog::Log(LOGWARNING, "%s: %s\n",
83 __FUNCTION__, err.what());
90 void CEGLNativeTypeWayland::Private::UnloadWaylandLibraries()
96 class CEGLNativeTypeWayland::Private
101 CEGLNativeTypeWayland::CEGLNativeTypeWayland() :
106 CEGLNativeTypeWayland::~CEGLNativeTypeWayland()
110 bool CEGLNativeTypeWayland::CheckCompatibility()
112 #if defined(HAVE_WAYLAND)
113 if (!getenv("WAYLAND_DISPLAY"))
115 CLog::Log(LOGWARNING, "%s:, WAYLAND_DISPLAY is not set",
121 * There appears to be a bug in DllDynamic::CanLoad() which causes
122 * it to always return false. We are just loading the library
123 * directly at CheckCompatibility time now */
124 if (!priv->LoadWaylandLibraries())
133 void CEGLNativeTypeWayland::Initialize()
137 void CEGLNativeTypeWayland::Destroy()
139 #if defined(HAVE_WAYLAND)
140 priv->UnloadWaylandLibraries();
144 bool CEGLNativeTypeWayland::CreateNativeDisplay()
146 #if defined(HAVE_WAYLAND)
148 /* On CreateNativeDisplay we connect to the running wayland
149 * compositor on our current socket (as specified by WAYLAND_DISPLAY)
150 * and then do some initial set up like registering event handlers.
152 * xbmc::wayland::XBMCConnection is an encapsulation of all of our
153 * current global state with regards to a wayland connection. We
154 * need to give it access to the wayland client libraries and
155 * libxkbcommon for it to do its work.
157 * We also inject an xbmc::wayland::XBMCConnection::EventInjector
158 * which is basically just a table of function pointers to functions
159 * in CWinEventsWayland, which are all static. CWinEvents is still
160 * effectively a static, singleton class, and depending on it
161 * means that testing becomes substantially more difficult. As such
162 * we just inject the bits that we need here so that they can be
163 * stubbed out later in testing environments if need be.
165 * xbmc::wayland::XBMCConnection's constructor will throw an
166 * std::runtime_error in case it runs into any trouble in connecting
167 * to the wayland compositor or getting the initial global objects.
169 * The best we can do when that happens is just report the error
170 * and bail out, possibly to try another (fallback) windowing system.
174 xw::XBMCConnection::EventInjector injector =
176 CWinEventsWayland::SetWaylandDisplay,
177 CWinEventsWayland::DestroyWaylandDisplay,
178 CWinEvents::MessagePump
181 priv->m_connection.reset(new xw::XBMCConnection(priv->m_libraries->ClientLibrary(),
182 priv->m_libraries->XKBCommonLibrary(),
185 catch (const std::runtime_error &err)
187 CLog::Log(LOGERROR, "%s: %s", __FUNCTION__, err.what());
197 bool CEGLNativeTypeWayland::CreateNativeWindow()
199 #if defined(HAVE_WAYLAND)
201 /* CreateNativeWindow is where we allocate a new wayland surface
202 * using libwayland-egl and ask the compositor to display it by
203 * creating a new remote surface object.
205 * xbmc::wayland::XBMCSurface encapsulates all of this information. It
206 * needs access to various client libraries, as well as the compositor
207 * and shell global interfaces from xbmc::wayland::XBMCConnection
208 * in order to actually create the internal "surface" and "shell
209 * surface" representations.
211 * Once xbmc::wayland::XBMCSurface is created, an EGL bindable
212 * surface will be available for later use.
214 * The last two parameters are the requested width and height of
217 * If any problems are encountered in creating the surface
218 * an std::runtime_error is thrown. Like above, we catch it and
219 * report the error, since there's not much we can do about it.
223 priv->m_surface.reset(new xw::XBMCSurface(priv->m_libraries->ClientLibrary(),
224 priv->m_libraries->EGLLibrary(),
225 priv->m_connection->GetCompositor(),
226 priv->m_connection->GetShell(),
230 catch (const std::runtime_error &err)
232 CLog::Log(LOGERROR, "%s: %s", __FUNCTION__, err.what());
242 bool CEGLNativeTypeWayland::GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const
244 #if defined(HAVE_WAYLAND)
245 /* We need to return a pointer to the wl_display * (eg wl_display **),
246 * as EGLWrapper needs to dereference our return value to get the
247 * actual display and not its first member */
249 reinterpret_cast <XBNativeDisplayType *>(priv->m_connection->NativeDisplay());
256 bool CEGLNativeTypeWayland::GetNativeWindow(XBNativeDisplayType **nativeWindow) const
258 #if defined(HAVE_WAYLAND)
260 reinterpret_cast <XBNativeWindowType *>(priv->m_surface->EGLNativeWindow());
267 /* DestroyNativeDisplay and DestroyNativeWindow simply just call
268 * reset on the relevant scoped_ptr. This will effectively destroy
269 * the encapsulating objects which cleans up all of the relevant
270 * connections and surfaces */
271 bool CEGLNativeTypeWayland::DestroyNativeDisplay()
273 #if defined(HAVE_WAYLAND)
274 priv->m_connection.reset();
281 bool CEGLNativeTypeWayland::DestroyNativeWindow()
283 #if defined(HAVE_WAYLAND)
284 priv->m_surface.reset();
291 /* The connection knowns about the resolution size, so we ask it
292 * about it. This information is all cached locally, but stored in
293 * the xbmc::wayland::XBMCConnection object */
294 bool CEGLNativeTypeWayland::GetNativeResolution(RESOLUTION_INFO *res) const
296 #if defined(HAVE_WAYLAND)
297 priv->m_connection->CurrentResolution(*res);
305 bool CEGLNativeTypeWayland::SetNativeResolution(const RESOLUTION_INFO &res)
307 #if defined(HAVE_WAYLAND)
308 priv->m_surface->Resize(res.iScreenWidth, res.iScreenHeight);
315 bool CEGLNativeTypeWayland::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
317 #if defined(HAVE_WAYLAND)
318 priv->m_connection->AvailableResolutions(resolutions);
325 bool CEGLNativeTypeWayland::GetPreferredResolution(RESOLUTION_INFO *res) const
327 #if defined(HAVE_WAYLAND)
328 priv->m_connection->PreferredResolution(*res);
335 bool CEGLNativeTypeWayland::ShowWindow(bool show)
337 #if defined(HAVE_WAYLAND)
339 priv->m_surface->Show();