6734ed57295cfd96d984be4fc547671e0e01b9bc
[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 <algorithm>
21 #include <sstream>
22 #include <stdexcept>
23 #include <queue>
24
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>
30
31 #include <wayland-client.h>
32
33 #include "guilib/Resolution.h"
34 #include "guilib/gui3d.h"
35
36 #include "windowing/DllWaylandClient.h"
37 #include "windowing/DllXKBCommon.h"
38
39 #include "Callback.h"
40 #include "Compositor.h"
41 #include "Display.h"
42 #include "Output.h"
43 #include "Registry.h"
44 #include "Region.h"
45 #include "Shell.h"
46
47 #include "windowing/WaylandProtocol.h"
48 #include "XBMCConnection.h"
49
50 #include "windowing/wayland/Wayland11EventQueueStrategy.h"
51 #include "windowing/wayland/Wayland12EventQueueStrategy.h"
52
53 namespace xbmc
54 {
55 namespace wayland
56 {
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
62 {
63 public:
64
65   virtual ~RemoteGlobalInterface() {}
66   
67   struct Constructor
68   {
69     const char *interfaceName;
70     RemoteGlobalInterface *interface;
71   };
72   
73   virtual void OnObjectAvailable(uint32_t name, uint32_t version) = 0;
74 };
75
76 /* A GlobalInterface is a simple implementation of a
77  * RemoteGlobalInterface with OnObjectAvailable already implemented.
78  * 
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
87 {
88 public:
89
90   typedef boost::function<void(uint32_t version)> AvailabilityHook;
91
92 protected:
93
94   GlobalInterface(const AvailabilityHook &hook) :
95     m_hook(hook)
96   {
97   }
98   
99   GlobalInterface()
100   {
101   }
102
103   std::queue<uint32_t> & ObjectsAvailable(uint32_t minimum);
104
105 private:
106
107   virtual void OnObjectAvailable(uint32_t name, uint32_t version);
108
109   std::queue<uint32_t> m_availableNames;
110   uint32_t m_version;
111   AvailabilityHook m_hook;
112 };
113
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.
117  * 
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
124 {
125 public:
126
127   WaylandGlobalObject(uint32_t minimum,
128                       struct wl_interface **interface) :
129     GlobalInterface(),
130     m_minimum(minimum),
131     m_interface(interface)
132   {
133   }
134   
135   WaylandGlobalObject(uint32_t minimum,
136                       struct wl_interface **interface,
137                       const AvailabilityHook &hook) :
138     GlobalInterface(hook),
139     m_minimum(minimum),
140     m_interface(interface)
141   {
142   }
143   
144   Implementation * FetchPending(Registry &registry);
145
146 private:
147
148   uint32_t m_minimum;
149   struct wl_interface **m_interface;
150 };
151
152 /* A StoredGlobalInterface is an implementation of RemoteGlobalInterface
153  * which composes a WaylandGlobalObject internally.
154  * 
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.
161  */
162 template <typename Implementation, typename WaylandImplementation>
163 class StoredGlobalInterface :
164   public RemoteGlobalInterface
165 {
166 public:
167
168   typedef boost::function<Implementation * (WaylandImplementation *)> Factory;
169   typedef std::vector<boost::shared_ptr<Implementation> > Implementations;
170   
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,
175                         uint32_t minimum,
176                         struct wl_interface **interface) :
177     m_waylandObject(minimum, interface),
178     m_factory(factory)
179   {
180   }
181
182   StoredGlobalInterface(const Factory &factory,
183                         uint32_t minimum,
184                         struct wl_interface **interface,
185                         const GlobalInterface::AvailabilityHook &hook) :
186     m_waylandObject(minimum, interface, hook),
187     m_factory(factory)
188   {
189   }
190   
191   ~StoredGlobalInterface()
192   {
193   }
194
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.
199    * 
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 &registry);
204   Implementations & Get(Registry &registry);
205
206 private:
207
208   void OnObjectAvailable(uint32_t name,
209                          uint32_t version);
210
211   WaylandGlobalObject<WaylandImplementation> m_waylandObject;
212   Factory m_factory;
213   Implementations m_implementations;
214 };
215
216 class XBMCConnection::Private :
217   public IWaylandRegistration
218 {
219 public:
220
221   Private(IDllWaylandClient &clientLibrary,
222           IDllXKBCommon &xkbCommonLibrary,
223           EventInjector &eventInjector);
224   ~Private();
225
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.
235    * 
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();
241   
242   wayland::Display & Display();
243   wayland::Compositor & Compositor();
244   wayland::Shell & Shell();
245   wayland::Output & Output();
246   
247 private:
248
249   IDllWaylandClient &m_clientLibrary;
250   IDllXKBCommon &m_xkbCommonLibrary;
251   
252   EventInjector m_eventInjector;
253
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 */
258   void Synchronize();
259
260   /* Synchronization logic - these variables should not be touched
261    * outside the scope of WaitForSynchronize() */
262   bool synchronized;
263   boost::scoped_ptr<Callback> synchronizeCallback;
264   
265   bool OnGlobalInterfaceAvailable(uint32_t name,
266                                   const char *interface,
267                                   uint32_t version);
268
269   void InjectSeat();
270
271   boost::scoped_ptr<wayland::Display> m_display;
272   boost::scoped_ptr<wayland::Registry> m_registry;
273   
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;
278   
279   boost::scoped_ptr<events::IEventQueueStrategy> m_eventQueue;
280 };
281 }
282 }
283
284 namespace xw = xbmc::wayland;
285 namespace xwe = xbmc::wayland::events;
286 namespace xwe = xbmc::wayland::events;
287
288 void
289 xw::GlobalInterface::OnObjectAvailable(uint32_t name,
290                                        uint32_t version)
291 {
292   m_availableNames.push(name);
293   m_version = version;
294   
295   if (!m_hook.empty())
296     m_hook(m_version);
297 }
298
299 std::queue<uint32_t> &
300 xw::GlobalInterface::ObjectsAvailable(uint32_t minimum)
301 {
302   if (m_version < minimum)
303   {
304     std::stringstream ss;
305     ss << "Interface version at least "
306        << minimum
307        << " is not available"
308        << " (less than version: "
309        << m_version
310        << ")";
311     throw std::runtime_error(ss.str());
312   }
313   
314   return m_availableNames;
315 }
316
317 template<typename Implementation>
318 Implementation *
319 xw::WaylandGlobalObject<Implementation>::FetchPending(Registry &registry)
320 {
321   /* Pop any new names and bind them */
322   std::queue<uint32_t> &availableObjects(ObjectsAvailable(m_minimum));
323   if (!availableObjects.empty())
324   {
325     uint32_t name = availableObjects.front();
326     Implementation *proxy =
327       registry.Bind<Implementation *>(name,
328                                       m_interface,
329                                       m_minimum);
330     availableObjects.pop();
331     return proxy;
332   }
333   
334   return NULL;
335 }
336
337 template<typename Implementation, typename WaylandImplementation>
338 void
339 xw::StoredGlobalInterface<Implementation, WaylandImplementation>::OnObjectAvailable(uint32_t name, uint32_t version)
340 {
341   RemoteGlobalInterface &rgi =
342     static_cast<RemoteGlobalInterface &>(m_waylandObject);
343   rgi.OnObjectAvailable(name, version);
344 }
345
346 template <typename Implementation, typename WaylandImplementation>
347 typename xw::StoredGlobalInterface<Implementation, WaylandImplementation>::Implementations &
348 xw::StoredGlobalInterface<Implementation, WaylandImplementation>::Get(Registry &registry)
349 {
350   /* Instantiate any pending objects with this interface and then
351    * return the available implementations */
352   WaylandImplementation *proxy =
353     m_waylandObject.FetchPending(registry);
354   
355   while (proxy)
356   {
357     boost::shared_ptr<Implementation> instance(m_factory(proxy));
358     m_implementations.push_back(instance);
359     proxy = m_waylandObject.FetchPending(registry);
360   }
361
362   /* Calling Get() before we've received any notification that
363    * objects are available is a runtime_error and will be thrown as
364    * such.
365    * 
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
370    * Get(). */
371   if (m_implementations.empty())
372     throw std::runtime_error("Remote interface not available");
373   
374   return m_implementations;
375 }
376
377 template <typename Implementation, typename WaylandImplementation>
378 Implementation &
379 xw::StoredGlobalInterface<Implementation, WaylandImplementation>::GetFirst(xw::Registry &registry)
380 {
381   return *(Get(registry)[0]);
382 }
383
384 namespace
385 {
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");
390
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)
395 {
396   return new xw::Compositor(*clientLibrary, compositor);
397 }
398
399 xw::Output * CreateOutput(struct wl_output *output,
400                           IDllWaylandClient *clientLibrary)
401 {
402   return new xw::Output(*clientLibrary, output);
403 }
404
405 xw::Shell * CreateShell(struct wl_shell *shell,
406                         IDllWaylandClient *clientLibrary)
407 {
408   return new xw::Shell(*clientLibrary, shell);
409 }
410
411 bool ConstructorMatchesInterface(const xw::RemoteGlobalInterface::Constructor &constructor,
412                                  const char *interface)
413 {
414   return std::strcmp(constructor.interfaceName,
415                      interface) < 0;
416 }
417
418 const unsigned int RequestedCompositorVersion = 1;
419 const unsigned int RequestedShellVersion = 1;
420 const unsigned int RequestedOutputVersion = 1;
421 const unsigned int RequestedSeatVersion = 1;
422
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
426  * strategies.
427  * 
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.
437  * 
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.
446  * 
447  * The following table illustrates these differences:
448  * 
449  * ---------------------------------------------------------------------
450  * | Wayland | Thread that  | Thread that | Thread that   | Strategy   |
451  * | Version | Reads happen | wrappers    | flush happens | Object     |
452  * |         | in           | operate in  |               |            |
453  * |         |              | in          |               |            |
454  * ---------------------------------------------------------------------
455  * | <= 1.1  | Poll Thread  | Poll Thread | Main Thread   | xw::versio-|
456  * |         |              |             |               | n11::Event-|
457  * |         |              |             |               | QueueStrat-|
458  * |         |              |             |               | egy        |
459  * ---------------------------------------------------------------------
460  * | >= 1.2  | Poll Thread  | Main Thread | Main Thread   | xw::versio-|
461  * |         |              |             |               | n12::Event-|
462  * |         |              |             |               | QueueStrat-|
463  * |         |              |             |               | egy        |
464  * ---------------------------------------------------------------------
465  * 
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.
472  */
473 xwe::IEventQueueStrategy *
474 EventQueueForClientVersion(IDllWaylandClient &clientLibrary,
475                            struct wl_display *display)
476 {
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();
481   if (version12)
482     return new xw::version_12::EventQueueStrategy(clientLibrary,
483                                                   display);
484   else
485     return new xw::version_11::EventQueueStrategy(clientLibrary,
486                                                   display);
487 }
488 }
489
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
499  * bind to them.
500  * 
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
508  */
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(),
518                               *this)),
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()))
533 {
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()));
538         
539   /* Wait only for the globals to appear, we will wait for
540    * initialization upon binding them */
541   WaitForSynchronize();
542 }
543
544 void
545 xw::XBMCConnection::Private::InjectSeat()
546 {
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,
552                                     m_xkbCommonLibrary,
553                                     seat);
554 }
555
556 xw::XBMCConnection::Private::~Private()
557 {
558   (*m_eventInjector.destroyWaylandSeat)();
559   (*m_eventInjector.destroyEventQueue)();
560 }
561
562 xw::XBMCConnection::XBMCConnection(IDllWaylandClient &clientLibrary,
563                                    IDllXKBCommon &xkbCommonLibrary,
564                                    EventInjector &eventInjector) :
565   priv(new Private (clientLibrary, xkbCommonLibrary, eventInjector))
566 {
567 }
568
569 /* A defined destructor is required such that
570  * boost::scoped_ptr<Private>::~scoped_ptr is generated here */
571 xw::XBMCConnection::~XBMCConnection()
572 {
573 }
574
575 xw::Display &
576 xw::XBMCConnection::Private::Display()
577 {
578   return *m_display;
579 }
580
581 xw::Compositor &
582 xw::XBMCConnection::Private::Compositor()
583 {
584   return m_compositor.GetFirst(*m_registry);
585 }
586
587 xw::Shell &
588 xw::XBMCConnection::Private::Shell()
589 {
590   return m_shell.GetFirst(*m_registry);
591 }
592
593 xw::Output &
594 xw::XBMCConnection::Private::Output()
595 {
596   xw::Output &output(m_outputs.GetFirst(*m_registry));
597   
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())
602   {
603     std::stringstream ss;
604     ss << "No modes detected on first output";
605     throw std::runtime_error(ss.str());
606   }
607   return output;
608 }
609
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
614  * right away. */
615 bool
616 xw::XBMCConnection::Private::OnGlobalInterfaceAvailable(uint32_t name,
617                                                         const char *interface,
618                                                         uint32_t version)
619 {
620   /* A boost::array is effectively immutable so we can leave out
621    * const here */
622   typedef boost::array<RemoteGlobalInterface::Constructor, 4> ConstructorArray;
623
624   
625   /* Not static, as the pointers here may change in cases where
626    * Private is re-constructed.
627    * 
628    * These are sorted into alphabetical order so that we can do
629    * a simple binary search for them. */
630   ConstructorArray constructors =
631   {
632     {
633       { CompositorName.c_str(), &m_compositor },
634       { OutputName.c_str(), &m_outputs },
635       { SeatName.c_str(), &m_seat },
636       { ShellName.c_str(), &m_shell }
637     }
638   };
639
640   /* Simple binary search for a known object constructor that matches
641    * this interface */
642   ConstructorArray::iterator it(std::lower_bound(constructors.begin(),
643                                                  constructors.end(),
644                                                  interface,
645                                                  ConstructorMatchesInterface));
646   if (it != constructors.end() &&
647       strcmp(it->interfaceName, interface) == 0)
648   {
649     it->interface->OnObjectAvailable(name, version);
650     return true;
651   }
652   
653   return false;
654 }
655
656 void xw::XBMCConnection::Private::WaitForSynchronize()
657 {
658   boost::function<void(uint32_t)> func(boost::bind(&Private::Synchronize,
659                                                    this));
660   
661   synchronized = false;
662   synchronizeCallback.reset(new xw::Callback(m_clientLibrary,
663                                              m_display->Sync(),
664                                              func));
665
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)();
671 }
672
673 void xw::XBMCConnection::Private::Synchronize()
674 {
675   synchronized = true;
676   synchronizeCallback.reset();
677 }
678
679 namespace
680 {
681 void ResolutionInfoForMode(const xw::Output::ModeGeometry &mode,
682                            RESOLUTION_INFO &res)
683 {
684   res.iWidth = mode.width;
685   res.iHeight = mode.height;
686   
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;
691   res.iScreen = 0;
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",
698                      res.iScreenWidth,
699                      res.iScreenHeight,
700                      res.fRefreshRate);
701 }
702 }
703
704 void
705 xw::XBMCConnection::CurrentResolution(RESOLUTION_INFO &res) const
706 {
707   /* Supporting only the first output device at the moment */
708   const xw::Output::ModeGeometry &current(priv->Output().CurrentMode());
709   
710   ResolutionInfoForMode(current, res);
711 }
712
713 void
714 xw::XBMCConnection::PreferredResolution(RESOLUTION_INFO &res) const
715 {
716   /* Supporting only the first output device at the moment */
717   const xw::Output::ModeGeometry &preferred(priv->Output().PreferredMode());
718   ResolutionInfoForMode(preferred, res);
719 }
720
721 void
722 xw::XBMCConnection::AvailableResolutions(std::vector<RESOLUTION_INFO> &resolutions) const
723 {
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());
727
728   for (std::vector<xw::Output::ModeGeometry>::const_iterator it = m_modes.begin();
729        it != m_modes.end();
730        ++it)
731   {
732     resolutions.push_back(RESOLUTION_INFO());
733     RESOLUTION_INFO &back(resolutions.back());
734     
735     ResolutionInfoForMode(*it, back);
736   }
737 }
738
739 EGLNativeDisplayType *
740 xw::XBMCConnection::NativeDisplay() const
741 {
742   return priv->Display().GetEGLNativeDisplay();
743 }
744
745 xw::Compositor &
746 xw::XBMCConnection::GetCompositor()
747 {
748   return priv->Compositor();
749 }
750
751 xw::Shell &
752 xw::XBMCConnection::GetShell()
753 {
754   return priv->Shell();
755 }
756
757 xw::Output &
758 xw::XBMCConnection::GetFirstOutput()
759 {
760   return priv->Output();
761 }