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/>.
25 #include <boost/array.hpp>
26 #include <boost/bind.hpp>
27 #include <boost/function.hpp>
28 #include <boost/scoped_ptr.hpp>
29 #include <boost/shared_ptr.hpp>
31 #include <wayland-client.h>
33 #include "guilib/Resolution.h"
34 #include "guilib/gui3d.h"
36 #include "windowing/DllWaylandClient.h"
37 #include "windowing/DllXKBCommon.h"
40 #include "Compositor.h"
47 #include "windowing/WaylandProtocol.h"
48 #include "XBMCConnection.h"
50 #include "windowing/wayland/Wayland11EventQueueStrategy.h"
51 #include "windowing/wayland/Wayland12EventQueueStrategy.h"
57 /* A RemoteGlobalInterface just describes a pure virtual class
58 * which is an observer for Private::OnGlobalInterfaceAvailable
59 * when a new global interface appears on the compositor for the
60 * client to bind to */
61 class RemoteGlobalInterface
65 virtual ~RemoteGlobalInterface() {}
69 const char *interfaceName;
70 RemoteGlobalInterface *interface;
73 virtual void OnObjectAvailable(uint32_t name, uint32_t version) = 0;
76 /* A GlobalInterface is a simple implementation of a
77 * RemoteGlobalInterface with OnObjectAvailable already implemented.
79 * Users of this class are able to inject a custom function to be
80 * observe whenever an object becomes avilable to this class and can
81 * get a queue of all names available for the particular interface
82 * this class is asked to observe. The object name is effectively
83 * just a number referring to the global object ID on the compositor
84 * side that can be bound to by a client. */
85 class GlobalInterface :
86 public RemoteGlobalInterface
90 typedef boost::function<void(uint32_t version)> AvailabilityHook;
94 GlobalInterface(const AvailabilityHook &hook) :
103 std::queue<uint32_t> & ObjectsAvailable(uint32_t minimum);
107 virtual void OnObjectAvailable(uint32_t name, uint32_t version);
109 std::queue<uint32_t> m_availableNames;
111 AvailabilityHook m_hook;
114 /* A WaylandGlobalObject is a more complete implementation of
115 * GlobalInterface. It observes for when objects become available
116 * and provides a method to fetch-and-bind names on-demand.
118 * Once FetchPending is called, the name is removed from the pending
119 * queue of GlobalInterface, bound to the interface provided and
120 * returned as an Implementation */
121 template <typename Implementation>
122 class WaylandGlobalObject :
123 public GlobalInterface
127 WaylandGlobalObject(uint32_t minimum,
128 struct wl_interface **interface) :
131 m_interface(interface)
135 WaylandGlobalObject(uint32_t minimum,
136 struct wl_interface **interface,
137 const AvailabilityHook &hook) :
138 GlobalInterface(hook),
140 m_interface(interface)
144 Implementation * FetchPending(Registry ®istry);
149 struct wl_interface **m_interface;
152 /* A StoredGlobalInterface is an implementation of RemoteGlobalInterface
153 * which composes a WaylandGlobalObject internally.
155 * This class takes a factory function to produce an Implementation *
156 * (usually a wrapper class of some sort) from a WaylandImplementation *
157 * (usually the defined wayland proxy object in the autogenerated
158 * protocol). It also has an alternate constructor that allows
159 * outside users to observe when an object has initially become available
160 * which is useful if it needs to be registered right away.
162 template <typename Implementation, typename WaylandImplementation>
163 class StoredGlobalInterface :
164 public RemoteGlobalInterface
168 typedef boost::function<Implementation * (WaylandImplementation *)> Factory;
169 typedef std::vector<boost::shared_ptr<Implementation> > Implementations;
171 /* Factory must be capable of returning a new Implementation *
172 * corresponding to a WaylandImplementation *. This is usually
173 * a wrapper class around that wayland object */
174 StoredGlobalInterface(const Factory &factory,
176 struct wl_interface **interface) :
177 m_waylandObject(minimum, interface),
182 StoredGlobalInterface(const Factory &factory,
184 struct wl_interface **interface,
185 const GlobalInterface::AvailabilityHook &hook) :
186 m_waylandObject(minimum, interface, hook),
191 ~StoredGlobalInterface()
195 /* These two functions always return constant values, although
196 * they might be required to create new Implementation objects
197 * by binding a global wayland object and wrapping it when they
198 * are initially called.
200 * The first function always returns the first-available interface,
201 * the second function always returns the list of available global
202 * objects which have that interface */
203 Implementation & GetFirst(Registry ®istry);
204 Implementations & Get(Registry ®istry);
208 void OnObjectAvailable(uint32_t name,
211 WaylandGlobalObject<WaylandImplementation> m_waylandObject;
213 Implementations m_implementations;
216 class XBMCConnection::Private :
217 public IWaylandRegistration
221 Private(IDllWaylandClient &clientLibrary,
222 IDllXKBCommon &xkbCommonLibrary,
223 EventInjector &eventInjector);
226 /* Synchronization entry point - call this function to issue a
227 * wl_display.sync request to the server. All this does is cause
228 * the server to send back an event that acknowledges the receipt
229 * of the request. However, it is useful in a number of circumstances
230 * - all request processing in wayland is sequential and guarunteed
231 * to be in the same order as requests were made. That means that
232 * once the event is received from the server, it is guarunteed
233 * that all requests made prior to the sync request have finished
234 * processing on the server and events have been issued to us.
236 * Do not call this from a non-main thread. The main thread may be
237 * waiting for a wl_display.sync event to be coming through and this
238 * function will merely spin until synchronized == true, for which
239 * a non-main thread may be responsible for setting as true */
240 void WaitForSynchronize();
242 wayland::Display & Display();
243 wayland::Compositor & Compositor();
244 wayland::Shell & Shell();
245 wayland::Output & Output();
249 IDllWaylandClient &m_clientLibrary;
250 IDllXKBCommon &m_xkbCommonLibrary;
252 EventInjector m_eventInjector;
254 /* Do not call this from a non-main thread. The main thread may be
255 * waiting for a wl_display.sync event to be coming through and this
256 * function will merely spin until synchronized == true, for which
257 * a non-main thread may be responsible for setting as true */
260 /* Synchronization logic - these variables should not be touched
261 * outside the scope of WaitForSynchronize() */
263 boost::scoped_ptr<Callback> synchronizeCallback;
265 bool OnGlobalInterfaceAvailable(uint32_t name,
266 const char *interface,
271 boost::scoped_ptr<wayland::Display> m_display;
272 boost::scoped_ptr<wayland::Registry> m_registry;
274 StoredGlobalInterface<wayland::Compositor, struct wl_compositor> m_compositor;
275 StoredGlobalInterface<wayland::Shell, struct wl_shell> m_shell;
276 WaylandGlobalObject<struct wl_seat> m_seat;
277 StoredGlobalInterface<wayland::Output, struct wl_output> m_outputs;
279 boost::scoped_ptr<events::IEventQueueStrategy> m_eventQueue;
284 namespace xw = xbmc::wayland;
285 namespace xwe = xbmc::wayland::events;
286 namespace xwe = xbmc::wayland::events;
289 xw::GlobalInterface::OnObjectAvailable(uint32_t name,
292 m_availableNames.push(name);
299 std::queue<uint32_t> &
300 xw::GlobalInterface::ObjectsAvailable(uint32_t minimum)
302 if (m_version < minimum)
304 std::stringstream ss;
305 ss << "Interface version at least "
307 << " is not available"
308 << " (less than version: "
311 throw std::runtime_error(ss.str());
314 return m_availableNames;
317 template<typename Implementation>
319 xw::WaylandGlobalObject<Implementation>::FetchPending(Registry ®istry)
321 /* Pop any new names and bind them */
322 std::queue<uint32_t> &availableObjects(ObjectsAvailable(m_minimum));
323 if (!availableObjects.empty())
325 uint32_t name = availableObjects.front();
326 Implementation *proxy =
327 registry.Bind<Implementation *>(name,
330 availableObjects.pop();
337 template<typename Implementation, typename WaylandImplementation>
339 xw::StoredGlobalInterface<Implementation, WaylandImplementation>::OnObjectAvailable(uint32_t name, uint32_t version)
341 RemoteGlobalInterface &rgi =
342 static_cast<RemoteGlobalInterface &>(m_waylandObject);
343 rgi.OnObjectAvailable(name, version);
346 template <typename Implementation, typename WaylandImplementation>
347 typename xw::StoredGlobalInterface<Implementation, WaylandImplementation>::Implementations &
348 xw::StoredGlobalInterface<Implementation, WaylandImplementation>::Get(Registry ®istry)
350 /* Instantiate any pending objects with this interface and then
351 * return the available implementations */
352 WaylandImplementation *proxy =
353 m_waylandObject.FetchPending(registry);
357 boost::shared_ptr<Implementation> instance(m_factory(proxy));
358 m_implementations.push_back(instance);
359 proxy = m_waylandObject.FetchPending(registry);
362 /* Calling Get() before we've received any notification that
363 * objects are available is a runtime_error and will be thrown as
366 * Calling code that wishes to avoid this error should either
367 * insert a synchronization point right after creating the object
368 * registry or register a callback using the second constructor
369 * to observe when the object has become available before calling
371 if (m_implementations.empty())
372 throw std::runtime_error("Remote interface not available");
374 return m_implementations;
377 template <typename Implementation, typename WaylandImplementation>
379 xw::StoredGlobalInterface<Implementation, WaylandImplementation>::GetFirst(xw::Registry ®istry)
381 return *(Get(registry)[0]);
386 const std::string CompositorName("wl_compositor");
387 const std::string ShellName("wl_shell");
388 const std::string SeatName("wl_seat");
389 const std::string OutputName("wl_output");
391 /* These are functions that satisfy the definition of a "Factory"
392 * for the purposes of StoredGlobalInterface */
393 xw::Compositor * CreateCompositor(struct wl_compositor *compositor,
394 IDllWaylandClient *clientLibrary)
396 return new xw::Compositor(*clientLibrary, compositor);
399 xw::Output * CreateOutput(struct wl_output *output,
400 IDllWaylandClient *clientLibrary)
402 return new xw::Output(*clientLibrary, output);
405 xw::Shell * CreateShell(struct wl_shell *shell,
406 IDllWaylandClient *clientLibrary)
408 return new xw::Shell(*clientLibrary, shell);
411 bool ConstructorMatchesInterface(const xw::RemoteGlobalInterface::Constructor &constructor,
412 const char *interface)
414 return std::strcmp(constructor.interfaceName,
418 const unsigned int RequestedCompositorVersion = 1;
419 const unsigned int RequestedShellVersion = 1;
420 const unsigned int RequestedOutputVersion = 1;
421 const unsigned int RequestedSeatVersion = 1;
423 /* A deficiency in the client library in wayland versions prior to
424 * 1.2 means that there is divergent behaviour between versions here
425 * and this is explicitly expressed and encapsulated in these two
428 * Because xbmc uses a game-loop, it is expected that no operation
429 * should block the main thread. This includes any operations to
430 * read the window system event queue. The main thread might be blocked
431 * for a prolonged period in the situation where the main xbmc surface
432 * is not visible, because the screen lock is active or another
433 * surface is obstructing it. When the main thread becomes blocked,
434 * it means that xbmc isn't able to start or stop any background jobs,
435 * which could interrupt library updates which occurr on idle or
436 * other such operations.
438 * However, wayland versions prior to 1.2 had the expectation that
439 * clients expected to block if there were no incoming compositor
440 * events because it is part of wayland's design that the compositor
441 * is responsible for sending the events to drive a client's render
442 * and input loop. As such, on wayland <= 1.1, the expectation is that
443 * compositor event read and dispatch occurrs in the same thread and
444 * on wayland >= 1.2 the expectation is that these operations can
445 * occurr in multiple threads.
447 * The following table illustrates these differences:
449 * ---------------------------------------------------------------------
450 * | Wayland | Thread that | Thread that | Thread that | Strategy |
451 * | Version | Reads happen | wrappers | flush happens | Object |
452 * | | in | operate in | | |
454 * ---------------------------------------------------------------------
455 * | <= 1.1 | Poll Thread | Poll Thread | Main Thread | xw::versio-|
456 * | | | | | n11::Event-|
457 * | | | | | QueueStrat-|
459 * ---------------------------------------------------------------------
460 * | >= 1.2 | Poll Thread | Main Thread | Main Thread | xw::versio-|
461 * | | | | | n12::Event-|
462 * | | | | | QueueStrat-|
464 * ---------------------------------------------------------------------
466 * The reason why it is different between the two versions it that it
467 * is generally desirable that the operation of all the wrapper objects
468 * occurr in the main thread, because there's less overhead in having
469 * to allocate temporary storage for their results in a queue so that
470 * they can be re-dispatched later. The plan is to eventually deprecate
471 * and remove support for wayland versions <= 1.1.
473 xwe::IEventQueueStrategy *
474 EventQueueForClientVersion(IDllWaylandClient &clientLibrary,
475 struct wl_display *display)
477 /* TODO: Test for wl_display_read_events / wl_display_prepare_read */
478 const bool version12 =
479 clientLibrary.wl_display_read_events_proc() &&
480 clientLibrary.wl_display_prepare_read_proc();
482 return new xw::version_12::EventQueueStrategy(clientLibrary,
485 return new xw::version_11::EventQueueStrategy(clientLibrary,
490 /* Creating a new xbmc::wayland::XBMCConnection effectively creates
491 * a new xbmc::wayland::Display object, which in turn will connect
492 * to the running wayland compositor and encapsulate the return value
493 * from the client library. Then it creates a new
494 * xbmc::wayland::Registry object which is responsible for managing
495 * all of the global objects on the wayland connection that we might
496 * want to use. On creation of this object, a request is sent to
497 * the compositor to send back an event for every available global
498 * object. Once we know which objects exist, we can easily
501 * The WaitForSynchronize call at the end of the constructor is
502 * important. Once we make a request to the server for all of the
503 * available global objects, we need to know what they all are
504 * by the time this constructor finishes running so that the
505 * object will be complete. The only way to do that is to know
506 * when our wl_registry.add_listener request has finished processing
507 * on both the server and client side
509 xw::XBMCConnection::Private::Private(IDllWaylandClient &clientLibrary,
510 IDllXKBCommon &xkbCommonLibrary,
511 EventInjector &eventInjector) :
512 m_clientLibrary(clientLibrary),
513 m_xkbCommonLibrary(xkbCommonLibrary),
514 m_eventInjector(eventInjector),
515 m_display(new xw::Display(clientLibrary)),
516 m_registry(new xw::Registry(clientLibrary,
517 m_display->GetWlDisplay(),
519 m_compositor(boost::bind(CreateCompositor, _1, &m_clientLibrary),
520 RequestedCompositorVersion,
521 clientLibrary.Get_wl_compositor_interface()),
522 m_shell(boost::bind(CreateShell, _1, &m_clientLibrary),
523 RequestedShellVersion,
524 clientLibrary.Get_wl_shell_interface()),
525 m_seat(RequestedSeatVersion,
526 clientLibrary.Get_wl_seat_interface(),
527 boost::bind(&Private::InjectSeat, this)),
528 m_outputs(boost::bind(CreateOutput, _1, &m_clientLibrary),
529 RequestedOutputVersion,
530 clientLibrary.Get_wl_output_interface()),
531 m_eventQueue(EventQueueForClientVersion(m_clientLibrary,
532 m_display->GetWlDisplay()))
534 /* Tell CWinEvents what our event queue is. That way
535 * CWinEvents::MessagePump is now able to dispatch events from
536 * the display whenever it is called */
537 (*m_eventInjector.setEventQueue)(*(m_eventQueue.get()));
539 /* Wait only for the globals to appear, we will wait for
540 * initialization upon binding them */
541 WaitForSynchronize();
545 xw::XBMCConnection::Private::InjectSeat()
547 /* When the seat becomes available and bound, let CWinEventsWayland
548 * know about it so that it can wrap it and query it for more
549 * information about input devices */
550 struct wl_seat *seat = m_seat.FetchPending(*m_registry);
551 (*m_eventInjector.setWaylandSeat)(m_clientLibrary,
556 xw::XBMCConnection::Private::~Private()
558 (*m_eventInjector.destroyWaylandSeat)();
559 (*m_eventInjector.destroyEventQueue)();
562 xw::XBMCConnection::XBMCConnection(IDllWaylandClient &clientLibrary,
563 IDllXKBCommon &xkbCommonLibrary,
564 EventInjector &eventInjector) :
565 priv(new Private (clientLibrary, xkbCommonLibrary, eventInjector))
569 /* A defined destructor is required such that
570 * boost::scoped_ptr<Private>::~scoped_ptr is generated here */
571 xw::XBMCConnection::~XBMCConnection()
576 xw::XBMCConnection::Private::Display()
582 xw::XBMCConnection::Private::Compositor()
584 return m_compositor.GetFirst(*m_registry);
588 xw::XBMCConnection::Private::Shell()
590 return m_shell.GetFirst(*m_registry);
594 xw::XBMCConnection::Private::Output()
596 xw::Output &output(m_outputs.GetFirst(*m_registry));
598 /* Wait for synchronize upon lazy-binding the first output
599 * and then check if we got any modes */
600 WaitForSynchronize();
601 if (output.AllModes().empty())
603 std::stringstream ss;
604 ss << "No modes detected on first output";
605 throw std::runtime_error(ss.str());
610 /* Once an object becomes available, we need to take note of that
611 * fact and store its interface information somewhere. We then
612 * call a function to indicate to any interested observer that the
613 * object is available and can be bound to. Callers might not do this
616 xw::XBMCConnection::Private::OnGlobalInterfaceAvailable(uint32_t name,
617 const char *interface,
620 /* A boost::array is effectively immutable so we can leave out
622 typedef boost::array<RemoteGlobalInterface::Constructor, 4> ConstructorArray;
625 /* Not static, as the pointers here may change in cases where
626 * Private is re-constructed.
628 * These are sorted into alphabetical order so that we can do
629 * a simple binary search for them. */
630 ConstructorArray constructors =
633 { CompositorName.c_str(), &m_compositor },
634 { OutputName.c_str(), &m_outputs },
635 { SeatName.c_str(), &m_seat },
636 { ShellName.c_str(), &m_shell }
640 /* Simple binary search for a known object constructor that matches
642 ConstructorArray::iterator it(std::lower_bound(constructors.begin(),
645 ConstructorMatchesInterface));
646 if (it != constructors.end() &&
647 strcmp(it->interfaceName, interface) == 0)
649 it->interface->OnObjectAvailable(name, version);
656 void xw::XBMCConnection::Private::WaitForSynchronize()
658 boost::function<void(uint32_t)> func(boost::bind(&Private::Synchronize,
661 synchronized = false;
662 synchronizeCallback.reset(new xw::Callback(m_clientLibrary,
666 /* For version 1.1 event queues the effect of this is going to be
667 * a spin-wait. That's not exactly ideal, but we do need to
668 * continuously flush the event queue */
669 while (!synchronized)
670 (*m_eventInjector.messagePump)();
673 void xw::XBMCConnection::Private::Synchronize()
676 synchronizeCallback.reset();
681 void ResolutionInfoForMode(const xw::Output::ModeGeometry &mode,
682 RESOLUTION_INFO &res)
684 res.iWidth = mode.width;
685 res.iHeight = mode.height;
687 /* The refresh rate is given as an integer in the second exponent
688 * so we need to divide by 100.0f to get a floating point value */
689 res.fRefreshRate = mode.refresh / 100.0f;
690 res.dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
692 res.bFullScreen = true;
693 res.iSubtitles = static_cast<int>(0.965 * res.iHeight);
694 res.fPixelRatio = 1.0f;
695 res.iScreenWidth = res.iWidth;
696 res.iScreenHeight = res.iHeight;
697 res.strMode.Format("%dx%d @ %.2fp",
705 xw::XBMCConnection::CurrentResolution(RESOLUTION_INFO &res) const
707 /* Supporting only the first output device at the moment */
708 const xw::Output::ModeGeometry ¤t(priv->Output().CurrentMode());
710 ResolutionInfoForMode(current, res);
714 xw::XBMCConnection::PreferredResolution(RESOLUTION_INFO &res) const
716 /* Supporting only the first output device at the moment */
717 const xw::Output::ModeGeometry &preferred(priv->Output().PreferredMode());
718 ResolutionInfoForMode(preferred, res);
722 xw::XBMCConnection::AvailableResolutions(std::vector<RESOLUTION_INFO> &resolutions) const
724 /* Supporting only the first output device at the moment */
725 xw::Output &output(priv->Output());
726 const std::vector<xw::Output::ModeGeometry> &m_modes(output.AllModes());
728 for (std::vector<xw::Output::ModeGeometry>::const_iterator it = m_modes.begin();
732 resolutions.push_back(RESOLUTION_INFO());
733 RESOLUTION_INFO &back(resolutions.back());
735 ResolutionInfoForMode(*it, back);
739 EGLNativeDisplayType *
740 xw::XBMCConnection::NativeDisplay() const
742 return priv->Display().GetEGLNativeDisplay();
746 xw::XBMCConnection::GetCompositor()
748 return priv->Compositor();
752 xw::XBMCConnection::GetShell()
754 return priv->Shell();
758 xw::XBMCConnection::GetFirstOutput()
760 return priv->Output();