Merge pull request #3408 from Karlson2k/win32_fix_path_slashes_small
authorjmarshallnz <jcmarsha@gmail.com>
Sun, 13 Oct 2013 09:27:32 +0000 (02:27 -0700)
committerjmarshallnz <jcmarsha@gmail.com>
Sun, 13 Oct 2013 09:27:32 +0000 (02:27 -0700)
Win32: fix path slashes (diet version)

137 files changed:
.gitignore
Makefile.in
addons/skin.confluence/720p/script-NextAired-TVGuide.xml
addons/skin.confluence/720p/script-XBMC_Lyrics-main.xml
configure.in
project/Win32BuildSetup/BuildSetup.bat
tools/buildsteps/README
tools/buildsteps/androidx86/configure-depends [new file with mode: 0644]
tools/buildsteps/androidx86/configure-xbmc [new file with mode: 0644]
tools/buildsteps/androidx86/make-depends [new file with mode: 0644]
tools/buildsteps/androidx86/make-xbmc [new file with mode: 0644]
tools/buildsteps/androidx86/package [new file with mode: 0644]
tools/buildsteps/androidx86/prepare-depends [new file with mode: 0644]
tools/buildsteps/androidx86/prepare-xbmc [new file with mode: 0644]
tools/buildsteps/defaultenv
tools/depends/target/Makefile
tools/depends/target/libass/Makefile
xbmc/DllPaths_generated.h.in
xbmc/DynamicDll.h
xbmc/android/jni/Context.cpp
xbmc/android/jni/jutils/jutils-details.hpp
xbmc/android/jni/jutils/jutils.hpp
xbmc/cores/dvdplayer/DVDInputStreams/DVDInputStreamPVRManager.cpp
xbmc/cores/dvdplayer/DVDPlayer.cpp
xbmc/cores/paplayer/PAPlayer.cpp
xbmc/dbwrappers/Database.cpp
xbmc/dbwrappers/dataset.cpp
xbmc/dbwrappers/dataset.h
xbmc/dbwrappers/mysqldataset.cpp
xbmc/filesystem/PVRFile.cpp
xbmc/guilib/GUIControlFactory.cpp
xbmc/guilib/GUIRadioButtonControl.cpp
xbmc/guilib/GUIRadioButtonControl.h
xbmc/input/linux/Keymap.h [new file with mode: 0644]
xbmc/input/linux/Makefile [deleted file]
xbmc/input/linux/Makefile.in [new file with mode: 0644]
xbmc/input/linux/XKBCommonKeymap.cpp [new file with mode: 0644]
xbmc/input/linux/XKBCommonKeymap.h [new file with mode: 0644]
xbmc/interfaces/json-rpc/ServiceDescription.h
xbmc/interfaces/json-rpc/types.json
xbmc/interfaces/legacy/Control.cpp
xbmc/interfaces/legacy/Control.h
xbmc/music/MusicThumbLoader.cpp
xbmc/network/upnp/UPnP.cpp
xbmc/network/upnp/UPnP.h
xbmc/network/upnp/UPnPInternal.cpp
xbmc/network/upnp/UPnPPlayer.cpp
xbmc/pvr/PVRManager.cpp
xbmc/settings/AdvancedSettings.cpp
xbmc/settings/AdvancedSettings.h
xbmc/utils/StringUtils.cpp
xbmc/windowing/DllWaylandClient.h [new file with mode: 0644]
xbmc/windowing/DllWaylandEgl.h [new file with mode: 0644]
xbmc/windowing/DllXKBCommon.h [new file with mode: 0644]
xbmc/windowing/Makefile [deleted file]
xbmc/windowing/Makefile.in [new file with mode: 0644]
xbmc/windowing/WaylandProtocol.h [new file with mode: 0644]
xbmc/windowing/WinEvents.cpp
xbmc/windowing/WinEvents.h
xbmc/windowing/WinEventsWayland.cpp [new file with mode: 0644]
xbmc/windowing/WinEventsWayland.h [new file with mode: 0644]
xbmc/windowing/egl/EGLNativeTypeWayland.cpp [new file with mode: 0644]
xbmc/windowing/egl/EGLNativeTypeWayland.h [new file with mode: 0644]
xbmc/windowing/egl/EGLQuirks.h
xbmc/windowing/egl/EGLWrapper.cpp
xbmc/windowing/egl/EGLWrapper.h
xbmc/windowing/egl/Makefile [deleted file]
xbmc/windowing/egl/Makefile.in [new file with mode: 0644]
xbmc/windowing/egl/WinSystemEGL.cpp
xbmc/windowing/egl/wayland/Callback.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/Callback.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/Compositor.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/Compositor.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/Display.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/Display.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/OpenGLSurface.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/OpenGLSurface.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/Output.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/Output.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/Region.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/Region.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/Registry.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/Registry.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/Shell.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/Shell.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/ShellSurface.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/ShellSurface.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/Surface.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/Surface.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/WaylandLibraries.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/WaylandLibraries.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/XBMCConnection.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/XBMCConnection.h [new file with mode: 0644]
xbmc/windowing/egl/wayland/XBMCSurface.cpp [new file with mode: 0644]
xbmc/windowing/egl/wayland/XBMCSurface.h [new file with mode: 0644]
xbmc/windowing/tests/wayland/Makefile.in [new file with mode: 0644]
xbmc/windowing/tests/wayland/StubCursorManager.cpp [new file with mode: 0644]
xbmc/windowing/tests/wayland/StubCursorManager.h [new file with mode: 0644]
xbmc/windowing/tests/wayland/StubEventListener.cpp [new file with mode: 0644]
xbmc/windowing/tests/wayland/StubEventListener.h [new file with mode: 0644]
xbmc/windowing/tests/wayland/TestEGLNativeTypeWayland.cpp [new file with mode: 0644]
xbmc/windowing/tests/wayland/TestWaylandInputUnit.cpp [new file with mode: 0644]
xbmc/windowing/tests/wayland/TestXBMCWaylandInputAcceptance.cpp [new file with mode: 0644]
xbmc/windowing/tests/wayland/TmpEnv.cpp [new file with mode: 0644]
xbmc/windowing/tests/wayland/TmpEnv.h [new file with mode: 0644]
xbmc/windowing/tests/wayland/WestonProcess.cpp [new file with mode: 0644]
xbmc/windowing/tests/wayland/WestonProcess.h [new file with mode: 0644]
xbmc/windowing/tests/wayland/WestonTest.cpp [new file with mode: 0644]
xbmc/windowing/tests/wayland/WestonTest.h [new file with mode: 0644]
xbmc/windowing/tests/wayland/XBMCWayland.cpp [new file with mode: 0644]
xbmc/windowing/tests/wayland/XBMCWayland.h [new file with mode: 0644]
xbmc/windowing/tests/wayland/XBMCWaylandTestExtension.cpp [new file with mode: 0644]
xbmc/windowing/tests/wayland/protocol.xml [new file with mode: 0644]
xbmc/windowing/wayland/CursorManager.h [new file with mode: 0644]
xbmc/windowing/wayland/EventListener.h [new file with mode: 0644]
xbmc/windowing/wayland/EventLoop.cpp [new file with mode: 0644]
xbmc/windowing/wayland/EventLoop.h [new file with mode: 0644]
xbmc/windowing/wayland/EventQueueStrategy.h [new file with mode: 0644]
xbmc/windowing/wayland/InputFactory.cpp [new file with mode: 0644]
xbmc/windowing/wayland/InputFactory.h [new file with mode: 0644]
xbmc/windowing/wayland/Keyboard.cpp [new file with mode: 0644]
xbmc/windowing/wayland/Keyboard.h [new file with mode: 0644]
xbmc/windowing/wayland/KeyboardProcessor.cpp [new file with mode: 0644]
xbmc/windowing/wayland/KeyboardProcessor.h [new file with mode: 0644]
xbmc/windowing/wayland/Pointer.cpp [new file with mode: 0644]
xbmc/windowing/wayland/Pointer.h [new file with mode: 0644]
xbmc/windowing/wayland/PointerProcessor.cpp [new file with mode: 0644]
xbmc/windowing/wayland/PointerProcessor.h [new file with mode: 0644]
xbmc/windowing/wayland/PollThread.cpp [new file with mode: 0644]
xbmc/windowing/wayland/PollThread.h [new file with mode: 0644]
xbmc/windowing/wayland/Seat.cpp [new file with mode: 0644]
xbmc/windowing/wayland/Seat.h [new file with mode: 0644]
xbmc/windowing/wayland/TimeoutManager.h [new file with mode: 0644]
xbmc/windowing/wayland/Wayland11EventQueueStrategy.cpp [new file with mode: 0644]
xbmc/windowing/wayland/Wayland11EventQueueStrategy.h [new file with mode: 0644]
xbmc/windowing/wayland/Wayland12EventQueueStrategy.cpp [new file with mode: 0644]
xbmc/windowing/wayland/Wayland12EventQueueStrategy.h [new file with mode: 0644]

index 3c805ee..60df6a8 100644 (file)
@@ -596,6 +596,9 @@ lib/cmyth/Makefile
 /xbmc/guilib/Profile
 /xbmc/guilib/Profile_FastCap
 
+# /xbmc/input
+/xbmc/input/linux/Makefile
+
 # /xbmc/interfaces/
 /xbmc/interfaces/Makefile
 /xbmc/interfaces/python/Makefile
@@ -722,6 +725,14 @@ lib/cmyth/Makefile
 # no longer used
 /xbmc/win32/git_rev.h
 
+# /xbmc/windowing/
+/xbmc/windowing/Makefile
+/xbmc/windowing/egl/Makefile
+/xbmc/windowing/tests/wayland/xbmc_wayland_test_client_protocol.h
+/xbmc/windowing/tests/wayland/xbmc_wayland_test_protocol.c
+/xbmc/windowing/tests/wayland/xbmc_wayland_test_server_protocol.h
+/xbmc/windowing/tests/wayland/Makefile
+
 # /lib/ffmpeg/
 /lib/ffmpeg/config.h
 /lib/ffmpeg/config.err
index 3b21d50..77cf789 100644 (file)
@@ -307,10 +307,20 @@ CHECK_LIBS = xbmc/filesystem/test/filesystemTest.a \
              xbmc/utils/test/utilsTest.a \
              xbmc/threads/test/threadTest.a \
              xbmc/interfaces/python/test/pythonSwigTest.a \
+             xbmc/windowing/tests/wayland/test_wayland.a \
              xbmc/test/xbmc-test.a
+
+ifeq (@USE_WAYLAND_TEST_EXTENSION@,1)
+WAYLAND_TEST_MODULE = xbmc/windowing/tests/wayland/xbmc-wayland-test-extension.so
+$(WAYLAND_TEST_MODULE): force
+       $(MAKE) -C $(@D) $(@F)
+CHECK_EXTENSIONS = $(WAYLAND_TEST_MODULE)
+CHECK_LIBADD=@WAYLAND_TEST_LIBS@
+endif
+
 CHECK_PROGRAMS = xbmc-test
 
-CLEAN_FILES += $(CHECK_PROGRAMS)
+CLEAN_FILES += $(CHECK_PROGRAMS) $(CHECK_EXTENSIONS)
 
 all : $(FINAL_TARGETS)
        @echo '-----------------------'
@@ -674,7 +684,7 @@ ifeq (1,@GTEST_CONFIGURED@)
 check: testsuite
        for check_program in $(CHECK_PROGRAMS); do $(CURDIR)/$$check_program; done
 
-testsuite: $(CHECK_PROGRAMS)
+testsuite: $(CHECK_EXTENSIONS) $(CHECK_PROGRAMS)
 
 testframework: $(GTEST_LIBS)
 
@@ -688,9 +698,9 @@ $(CHECK_LIBS): force
 
 xbmc-test: $(CHECK_LIBS) $(OBJSXBMC) $(DYNOBJSXBMC) $(NWAOBJSXBMC) $(GTEST_LIBS)
 ifeq ($(findstring osx,@ARCH@), osx)
-       $(SILENT_LD) $(CXX) $(LDFLAGS) $(GTEST_INCLUDES) -o $@ -Wl,-all_load,-ObjC $(CHECK_LIBS) $(DYNOBJSXBMC) $(NWAOBJSXBMC) $(OBJSXBMC) $(GTEST_LIBS) $(LIBS) -rdynamic
+       $(SILENT_LD) $(CXX) $(LDFLAGS) $(GTEST_INCLUDES) -o $@ -Wl,-all_load,-ObjC $(DYNOBJSXBMC) $(NWAOBJSXBMC) $(OBJSXBMC) $(GTEST_LIBS) $(CHECK_LIBS) $(LIBS) $(CHECK_LIBADD) -rdynamic
 else
-       $(SILENT_LD) $(CXX) $(CXXFLAGS) $(LDFLAGS) $(GTEST_INCLUDES) -o $@ -Wl,--whole-archive $(CHECK_LIBS) $(DYNOBJSXBMC) $(OBJSXBMC) -Wl,--no-whole-archive $(NWAOBJSXBMC) $(GTEST_LIBS) $(LIBS) -rdynamic
+       $(SILENT_LD) $(CXX) $(CXXFLAGS) $(LDFLAGS) $(GTEST_INCLUDES) -o $@ -Wl,--whole-archive $(DYNOBJSXBMC) $(OBJSXBMC) $(GTEST_LIBS) $(CHECK_LIBS) -Wl,--no-whole-archive $(NWAOBJSXBMC) $(LIBS) $(CHECK_LIBADD) -rdynamic
 endif
 else
 # Give a message that the framework is not configured, but don't fail.
index e0a8aa3..34e4d82 100644 (file)
                        <itemgap>5</itemgap>
                        <control type="label">
                                <include>WindowTitleCommons</include>
-                               <label>$LOCALIZE[SCRIPT450]</label>
+                               <label>$ADDON[script.tv.show.next.aired 450]</label>
                        </control>
                        <control type="label">
                                <include>WindowTitleCommons</include>
index 44c32f5..22463c8 100644 (file)
@@ -45,7 +45,7 @@
                                <width>550</width>
                                <height>30</height>
                                <font>font30_title</font>
-                               <label>$LOCALIZE[SCRIPT0]</label>
+                               <label>$ADDON[script.cu.lrclyrics 0]</label>
                                <align>right</align>
                                <aligny>center</aligny>
                                <textcolor>white</textcolor>
                <!-- ** Required ** Do not change <id> or <type> -->
                <!-- ** Required ** Do not change <id> or <type> -->
        </controls>
-</window>
\ No newline at end of file
+</window>
index 9d635d4..521bd38 100644 (file)
@@ -131,6 +131,8 @@ fishbmc_enabled="== FishBMC enabled. =="
 fishbmc_disabled="== FishBMC disabled. =="
 projectm_enabled="== ProjectM enabled. =="
 projectm_disabled="== ProjectM disabled. =="
+wayland_enabled="== Wayland enabled. =="
+wayland_disabled="== Wayland disabled. =="
 x11_enabled="== X11 enabled. =="
 x11_disabled="== X11 disabled. =="
 pulse_not_found="== Could not find libpulse. PulseAudio support disabled. =="
@@ -342,6 +344,12 @@ AC_ARG_ENABLE([projectm],
   [use_projectm=$enableval],
   [use_projectm=yes])
 
+AC_ARG_ENABLE([wayland],
+  [AS_HELP_STRING([--enable-wayland],
+  [enable wayland (default is no) 'Linux Only'])],
+  [use_wayland=$enableval],
+  [use_wayland=no])
+
 AC_ARG_ENABLE([x11],
   [AS_HELP_STRING([--enable-x11],
   [enable x11 (default is yes) 'Linux Only'])],
@@ -593,6 +601,7 @@ AC_PROG_LIBTOOL
 AC_PROG_AWK
 AC_PROG_LN_S
 AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
 MAKE="${MAKE:-make}"
 OBJDUMP="${OBJDUMP:-objdump}"
 
@@ -686,6 +695,7 @@ case $host in
      use_gles=yes
      use_sdl=no
      use_x11=no
+     use_wayland=no
      ;;
   arm*-*linux-android*)
      target_platform=target_android
@@ -699,6 +709,7 @@ case $host in
      use_optical_drive=no
      use_sdl=no
      use_x11=no
+     use_wayland=no
      build_shared_lib=yes
      ;;
   *)
@@ -953,6 +964,65 @@ else
   AC_MSG_NOTICE([Using Python $PYTHON_VERSION])
 fi
 
+# Wayland
+if test "$use_wayland" = "yes" && test "$host_vendor" != "apple"; then
+  AC_MSG_NOTICE($wayland_enabled)
+  PKG_CHECK_MODULES([WAYLAND_CLIENT],    [wayland-client],
+    [INCLUDES="$INCLUDES $WAYLAND_CLIENT_CFLAGS";
+     WAYLAND_CLIENT_LIBRARY_LINE=`LIBRARY=\`${PKG_CONFIG} --libs-only-l wayland-client\`; echo ${LIBRARY:2}`;
+     XB_FIND_SONAME([WAYLAND_CLIENT_LIBRARY], ${WAYLAND_CLIENT_LIBRARY_LINE})],
+     AC_MSG_ERROR($missing_library))
+  PKG_CHECK_MODULES([WAYLAND_EGL],    [wayland-egl],
+    [INCLUDES="$INCLUDES $WAYLAND_EGL_CFLAGS";
+     WAYLAND_EGL_LIBRARY_LINE=`LIBRARY=\`${PKG_CONFIG} --libs-only-l wayland-egl\`; echo ${LIBRARY:2}`
+     XB_FIND_SONAME([WAYLAND_EGL_LIBRARY], ${WAYLAND_EGL_LIBRARY_LINE})],
+    AC_MSG_ERROR($missing_library))
+  PKG_CHECK_MODULES([XKBCOMMON],    [xkbcommon],
+    [INCLUDES="$INCLUDES $XKBCOMMON_CFLAGS";
+     XKBCOMMON_LIBRARY_LINE=`LIBRARY=\`${PKG_CONFIG} --libs-only-l xkbcommon\`; echo ${LIBRARY:2}`;
+     XB_FIND_SONAME([XKBCOMMON_LIBRARY], $XKBCOMMON_LIBRARY_LINE)],
+    AC_MSG_ERROR($missing_library))
+  AC_DEFINE([HAVE_WAYLAND], [1], [Define to 1 if you have Wayland libs installed.])
+  AC_DEFINE([HAVE_XKBCOMMON], [1], [Define to 1 if you have libxkbcommon installed.])
+
+  # If we are also building with tests then we want to build
+  # wayland tests as well
+  if test "$configure_gtest" = "yes"; then
+    have_weston_sdk=no;
+    PKG_CHECK_MODULES([PIXMAN],
+                      [pixman-1],have_pixman=yes,
+                      [AC_MSG_WARN($missing_library); have_pixman=no])
+    PKG_CHECK_MODULES([WESTON],
+                      [weston >= 1.1.90],[have_weston_sdk=yes],
+                      [have_weston_sdk=no; AC_MSG_WARN($missing_library)])
+
+    AC_CHECK_PROG(WAYLAND_SCANNER, wayland-scanner, "wayland-scanner", "no")
+    if test "x$WAYLAND_SCANNER" == "xno"; then
+      AC_MSG_WARN($missing_program)
+    else
+      if test "x$have_weston_sdk" == "xyes" && test "x$have_pixman" = "xyes"; then
+        AC_SUBST(WAYLAND_TEST_INCLUDES,"$WAYLAND_CLIENT_CFLAGS $XKBCOMMON_CFLAGS $PIXMAN_CFLAGS $WESTON_CFLAGS")
+        AC_SUBST(WAYLAND_TEST_LIBS,"$WAYLAND_CLIENT_LIBS $XKBCOMMON_LIBS $PIXMAN_LIBS $WESTON_LIBS")
+        AC_DEFINE([HAVE_WESTON_SDK], [1], [Define to 1 if Weston SDK is installed.])
+        AC_SUBST(USE_WAYLAND_TEST_EXTENSION, 1)
+      fi
+      AC_SUBST(WAYLAND_SCANNER)
+      AC_DEFINE([HAVE_WAYLAND_XBMC_PROTO],[1],["Define to 1 if the wayland test-protocol will be built"])
+    fi
+  fi
+
+  # Disable SDL and X11 builds
+  use_sdl=no
+  use_joystick=no
+  use_x11=no
+
+  # Wayland requires the EGL "window system" which in turn only supports
+  # the OpenGL ES API, so enable gles support
+  use_gles=yes
+else
+  AC_MSG_RESULT($wayland_disabled)
+fi
+
 # Checks for platforms libraries.
 if test "$use_gles" = "yes"; then
   use_gl="no"
@@ -2116,6 +2186,14 @@ else
   final_message="$final_message\n  X11:\t\tNo"
 fi
 
+if test "$use_wayland" = "yes"; then
+  final_message="$final_message\n  Wayland:\tYes"
+  USE_WAYLAND=1
+  USE_XKBCOMMON=1
+else
+  final_message="$final_message\n  Wayland:\tNo"
+fi
+
 if test "$use_libbluray" = "yes"; then
   final_message="$final_message\n  Bluray:\tYes"
 else
@@ -2436,6 +2514,7 @@ OUTPUT_FILES="Makefile \
     xbmc/music/karaoke/Makefile \
     xbmc/osx/Makefile \
     xbmc/guilib/Makefile \
+    xbmc/input/linux/Makefile \
     xbmc/interfaces/Makefile \
     xbmc/network/Makefile \
     xbmc/network/upnp/Makefile \
@@ -2458,6 +2537,8 @@ OUTPUT_FILES="Makefile \
     xbmc/visualizations/OpenGLSpectrum/Makefile \
     xbmc/visualizations/fishBMC/Makefile \
     xbmc/visualizations/WaveForm/Makefile \
+    xbmc/windowing/Makefile \
+    xbmc/windowing/egl/Makefile \
     lib/addons/library.xbmc.addon/Makefile \
     lib/addons/library.xbmc.codec/Makefile \
     lib/addons/library.xbmc.gui/Makefile \
@@ -2474,6 +2555,7 @@ OUTPUT_FILES="Makefile \
     xbmc/android/jni/Makefile \
     xbmc/utils/Makefile \
     xbmc/main/Makefile \
+    xbmc/windowing/tests/wayland/Makefile \
     project/cmake/xbmc-config.cmake"
 
 if test "$use_skin_touched" = "yes"; then
@@ -2545,8 +2627,10 @@ AC_SUBST(USE_LIBUDEV)
 AC_SUBST(USE_LIBUSB)
 AC_SUBST(USE_LIBCEC)
 AC_SUBST(USE_MYSQL)
+AC_SUBST(USE_WAYLAND)
 AC_SUBST(USE_WEB_SERVER)
 AC_SUBST(USE_UPNP)
+AC_SUBST(USE_XKBCOMMON)
 AC_SUBST(USE_OMXLIB)
 AC_SUBST(USE_ANDROID)
 AC_SUBST(GTEST_CONFIGURED)
index 6b23fe1..54eab2a 100644 (file)
@@ -134,7 +134,7 @@ IF %comp%==vs2010 (
   %NET% %CLEAN_EXE%
   ECHO Compiling XBMC branch %BRANCH%...
   %NET% %OPTS_EXE%
-  IF NOT EXIST %EXE% (
+  IF %errorlevel%==1 (
        set DIETEXT="XBMC.EXE failed to build!  See %CD%\..\vs2010express\XBMC\%buildconfig%\objs\XBMC.log"
        IF %promptlevel%==noprompt (
                type "%CD%\..\vs2010express\XBMC\%buildconfig%\objs\XBMC.log"
@@ -151,7 +151,7 @@ IF %comp%==vs2010 (
   ECHO ------------------------------------------------------------
   ECHO Compiling XBMC branch %BRANCH%...
   %NET% %OPTS_EXE%
-  IF NOT EXIST %EXE% (
+  IF %errorlevel%==1 (
        set DIETEXT="XBMC.EXE failed to build!  See %CD%\..\vs2010express\XBMC\%buildconfig%\objs\XBMC.log"
        IF %promptlevel%==noprompt (
                type "%CD%\..\vs2010express\XBMC\%buildconfig%\objs\XBMC.log"
@@ -345,6 +345,7 @@ IF %comp%==vs2010 (
   echo %DIETEXT%
   SET exitcode=1
   ECHO ------------------------------------------------------------
+  GOTO END
 
 :VIEWLOG_EXE
   SET log="%CD%\..\vs2010express\XBMC\%buildconfig%\objs\XBMC.log"
index 68c5354..782e2c4 100644 (file)
@@ -11,5 +11,6 @@ $XBMC_DEPENDS_ROOT - root for installing the xbmc build depends and toolchain he
 Additional ENV variables might be specified by the buildnodes. For android buildslaves these are:
 
 TOOLCHAIN - the used toolchain dir
+TOOLCHAIN_X86 - this is the toolchain dir for x86 toolchain of android. This needs this extra var for beeing able to specify both toolchains (arm & x86) at the same slave.
 NDK_PATH  - the path to the android native ndk
-SDK_PATH  - the path to the android sdk
\ No newline at end of file
+SDK_PATH  - the path to the android sdk
diff --git a/tools/buildsteps/androidx86/configure-depends b/tools/buildsteps/androidx86/configure-depends
new file mode 100644 (file)
index 0000000..4213455
--- /dev/null
@@ -0,0 +1,15 @@
+WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )}
+XBMC_PLATFORM_DIR=android
+. $WORKSPACE/tools/buildsteps/defaultenv
+
+if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ]
+then
+  cd $WORKSPACE/tools/depends;./configure \
+    --with-tarballs=$TARBALLS \
+    --host=i686-linux-android \
+    --with-sdk-path=$SDK_PATH \
+    --with-ndk=$NDK_PATH \
+    $(if [ "$SDK_VERSION" != "Default" ]; then echo --with-sdk=android-$SDK_VERSION;fi) \
+    --with-toolchain=$TOOLCHAIN_X86 \
+    --prefix=$XBMC_DEPENDS_ROOT
+fi
diff --git a/tools/buildsteps/androidx86/configure-xbmc b/tools/buildsteps/androidx86/configure-xbmc
new file mode 100644 (file)
index 0000000..afdd82a
--- /dev/null
@@ -0,0 +1,5 @@
+WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )}
+XBMC_PLATFORM_DIR=android
+. $WORKSPACE/tools/buildsteps/defaultenv
+
+make -C $WORKSPACE/tools/depends/target/xbmc
diff --git a/tools/buildsteps/androidx86/make-depends b/tools/buildsteps/androidx86/make-depends
new file mode 100644 (file)
index 0000000..2deb44a
--- /dev/null
@@ -0,0 +1,9 @@
+WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )}
+XBMC_PLATFORM_DIR=android
+. $WORKSPACE/tools/buildsteps/defaultenv
+
+if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ]
+then
+  cd $WORKSPACE/tools/depends;make -j $BUILDTHREADS && tagSuccessFulBuild .
+fi
+
diff --git a/tools/buildsteps/androidx86/make-xbmc b/tools/buildsteps/androidx86/make-xbmc
new file mode 100644 (file)
index 0000000..738656f
--- /dev/null
@@ -0,0 +1,5 @@
+WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )}
+XBMC_PLATFORM_DIR=android
+. $WORKSPACE/tools/buildsteps/defaultenv
+
+cd $WORKSPACE;make -j$BUILDTHREADS
diff --git a/tools/buildsteps/androidx86/package b/tools/buildsteps/androidx86/package
new file mode 100644 (file)
index 0000000..d95392b
--- /dev/null
@@ -0,0 +1,10 @@
+WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )}
+XBMC_PLATFORM_DIR=android
+. $WORKSPACE/tools/buildsteps/defaultenv
+
+cd $WORKSPACE;make apk
+
+#rename for upload
+#e.x. xbmc-20130314-8c2fb31-Frodo-x86.apk
+UPLOAD_FILENAME="xbmc-$(getBuildRevDateStr)-x86.apk"
+mv xbmcapp-x86-*.apk $UPLOAD_FILENAME
diff --git a/tools/buildsteps/androidx86/prepare-depends b/tools/buildsteps/androidx86/prepare-depends
new file mode 100644 (file)
index 0000000..8aabe48
--- /dev/null
@@ -0,0 +1,13 @@
+WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )}
+XBMC_PLATFORM_DIR=android
+. $WORKSPACE/tools/buildsteps/defaultenv
+
+#clean without depends for skipping depends build if possible
+cd $WORKSPACE;git clean -xfd -e "tools/depends"
+
+if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ]
+then
+  #clean up the rest too
+  cd $WORKSPACE;git clean -xfd
+  cd $WORKSPACE/tools/depends/;./bootstrap
+fi
diff --git a/tools/buildsteps/androidx86/prepare-xbmc b/tools/buildsteps/androidx86/prepare-xbmc
new file mode 100644 (file)
index 0000000..020bc03
--- /dev/null
@@ -0,0 +1,5 @@
+WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )}
+XBMC_PLATFORM_DIR=android
+. $WORKSPACE/tools/buildsteps/defaultenv
+
+#nothing on android
index 5d75149..eb67fef 100644 (file)
@@ -67,14 +67,14 @@ fi
 
 #helper functions
 
-#hash a dir based on the git revision, SDK_PATH, NDK_PATH, SDK_VERSION, TOOLCHAIN and XBMC_DEPENDS_ROOT
+#hash a dir based on the git revision, SDK_PATH, NDK_PATH, SDK_VERSION, TOOLCHAIN TOOLCHAIN_X86 (for droidx86) and XBMC_DEPENDS_ROOT
 function getBuildHash ()
 {
   local checkPath
   checkPath="$1"
   local hashStr
   hashStr="$(git rev-list HEAD --max-count=1  -- $checkPath)"
-  hashStr="$hashStr $SDK_PATH $NDK_PATH $SDK_VERSION $TOOLCHAIN $XBMC_DEPENDS_ROOT"
+  hashStr="$hashStr $SDK_PATH $NDK_PATH $SDK_VERSION $TOOLCHAIN $TOOLCHAIN_X86 $XBMC_DEPENDS_ROOT"
   echo $hashStr
 }
 
index eae2dcc..2081b49 100644 (file)
@@ -35,6 +35,7 @@ endif
 
 ifeq ($(OS),android)
   DEPENDS += mdnsresponder android-sources-ics
+  EXCLUDED_DEPENDS = gmp nettle gnutls
 endif
 
 DEPENDS := $(filter-out $(EXCLUDED_DEPENDS),$(DEPENDS))
index 87e810f..8df2cec 100644 (file)
@@ -3,7 +3,7 @@ DEPS= ../../Makefile.include Makefile
 
 # lib name, version
 LIBNAME=libass
-VERSION=0.9.13
+VERSION=0.10.1
 SOURCE=$(LIBNAME)-$(VERSION)
 ARCHIVE=$(SOURCE).tar.gz
 
index fca6ac9..d35ea97 100644 (file)
 /* libbluray */
 #define DLL_PATH_LIBBLURAY     "@BLURAY_SONAME@"
 
+/* wayland */
+#define DLL_PATH_WAYLAND_CLIENT "@WAYLAND_CLIENT_LIBRARY_SONAME@"
+#define DLL_PATH_WAYLAND_EGL "@WAYLAND_EGL_LIBRARY_SONAME@"
+
+/* xkbcommon */
+#define DLL_PATH_XKBCOMMON "@XKBCOMMON_LIBRARY_SONAME@"
+
 #endif
index b641fbf..3cf4e9b 100644 (file)
@@ -1,5 +1,4 @@
 #pragma once
-
 /*
  *      Copyright (C) 2005-2013 Team XBMC
  *      http://xbmc.org
@@ -356,12 +355,10 @@ public: \
 #define BEGIN_METHOD_RESOLVE() \
   protected: \
   virtual bool ResolveExports() \
-  { \
-    return (
+  {
 
 #define END_METHOD_RESOLVE() \
-              1 \
-              ); \
+    return true; \
   }
 
 ///////////////////////////////////////////////////////////
@@ -374,10 +371,33 @@ public: \
 //          or DEFINE_METHOD_LINKAGE
 //
 #define RESOLVE_METHOD(method) \
-  m_dll->ResolveExport( #method , & m_##method##_ptr ) &&
+  if (!m_dll->ResolveExport( #method , & m_##method##_ptr )) \
+    return false;
 
 #define RESOLVE_METHOD_FP(method) \
-  m_dll->ResolveExport( #method , & method##_ptr ) &&
+  if (!m_dll->ResolveExport( #method , & method##_ptr )) \
+    return false;
+
+
+///////////////////////////////////////////////////////////
+//
+//  RESOLVE_METHOD_OPTIONAL
+//
+//  Resolves a method from a dll. does not abort if the
+//  method is missing
+//
+//  method: Name of the method defined with DEFINE_METHOD
+//          or DEFINE_METHOD_LINKAGE
+//
+
+#define RESOLVE_METHOD_OPTIONAL(method) \
+   m_dll->ResolveExport( #method , & m_##method##_ptr );
+
+#define RESOLVE_METHOD_OPTIONAL_FP(method) \
+   method##_ptr = NULL; \
+   m_dll->ResolveExport( #method , & method##_ptr );
+
+
 
 ///////////////////////////////////////////////////////////
 //
@@ -390,10 +410,12 @@ public: \
 //          or DEFINE_METHOD_LINKAGE
 //
 #define RESOLVE_METHOD_RENAME(dllmethod, method) \
-  m_dll->ResolveExport( #dllmethod , & m_##method##_ptr ) &&
+  if (!m_dll->ResolveExport( #dllmethod , & m_##method##_ptr )) \
+    return false;
 
 #define RESOLVE_METHOD_RENAME_FP(dllmethod, method) \
-  m_dll->ResolveExport( #dllmethod , & method##_ptr ) &&
+  if (!m_dll->ResolveExport( #dllmethod , & method##_ptr )) \
+    return false;
 
 
 ////////////////////////////////////////////////////////////////////
index defa2be..70e26e9 100644 (file)
@@ -63,7 +63,6 @@ CJNIContext::CJNIContext(const ANativeActivity *nativeActivity)
 CJNIContext::~CJNIContext()
 {
   m_appInstance = NULL;
-  m_context.release();
   xbmc_jni_on_unload();
 }
 
index 542a32c..9c3e833 100644 (file)
@@ -94,7 +94,7 @@ struct jcast_helper<std::string, jhstring>
 {
     static std::string cast(jhstring const &v)
     {
-        return jcast_helper<std::string, jstring>::cast(v);
+        return jcast_helper<std::string, jstring>::cast(v.get());
     }
 };
 
@@ -103,7 +103,7 @@ struct jcast_helper<std::vector<std::string>, jhobjectArray>
 {
     static std::vector<std::string> cast(jhobjectArray const &v)
     {
-        return jcast_helper<std::vector<std::string>, jobjectArray>::cast(v);
+        return jcast_helper<std::vector<std::string>, jobjectArray>::cast(v.get());
     }
 };
 
@@ -112,7 +112,7 @@ struct jcast_helper<std::vector<T>, jhobjectArray>
 {
     static std::vector<T> cast(jhobjectArray const &v)
     {
-        return jcast_helper<std::vector<T>, jobjectArray>::cast(v);
+        return jcast_helper<std::vector<T>, jobjectArray>::cast(v.get());
     }
 };
 
@@ -130,7 +130,7 @@ std::vector<T> jcast_helper<std::vector<T>, jobjectArray>::cast(jobjectArray con
 
   for (int i = 0; i < size; i++)
   {
-    jhobject element = (jhobject)env->GetObjectArrayElement(v, i);
+    T element((jhobject)env->GetObjectArrayElement(v, i));
     vec.emplace_back(element);
   }
   return vec;
index 1b9e55c..059a2c0 100644 (file)
@@ -57,99 +57,208 @@ JNIEnv *xbmc_jnienv();
 
 namespace jni
 {
+
 template <typename T>
 class jholder
 {
-    typedef void (jholder::*safe_bool_type)();
-    void non_null_object() {}
+/* A native jni types wrapper class.
+
+  This templated class is used as a container for native jni types: jobject,
+  jclass, etc. It maintains scope and references so that parent objects don't
+  have to bother.
+
+  Here, a jobject will be used as an example.
+
+  Background: JNI uses reference-counted objects to facilitate
+  garbage-collection. A jobject is really just a pointer to some shared memory.
+  When a jobject is given to native code, it has a local
+  reference. When this local reference is removed, the JVM is free to
+  garbage-collect its contents. Local references are destroyed when the jobject
+  is destroyed (or loses scope) or when Java execution resumes, or they can be
+  destroyed manually. Objects which hold local references also cannot be shared
+  between threads. To get around these limitations, the local reference can be
+  upgraded to a global one.
+
+  This class handles this logic for the user. A jobject can be moved into a
+  jhobject via the jhobject constructor. After doing so, the original jobject's
+  state is undefined because the jhobject will unref it automatically.
+
+  Scope of copies is handled as well, so no extra care needs to be taken. When
+  a copy is made, the copy inherits the scope of the original object. The
+  class tries to operate in the safest possible way when assigning objects of
+  differing scope by choosing the widest possible scope.
+
+  Example:
+
+  jhobject somefunction(jobject androidObject)
+  {
+    jhobject foo(androidObject);
+    // store androidObject in foo. androidObject should not be used again.
+    // foo has a local ref.
+
+    jhobject bar(foo);
+    // copy foo to bar. foo and bar are both local. They can both be used
+    // on this thread until returning to java. It would not be safe to return
+    // them because the caller cannot be trusted to obey the local-ref rules.
+    //
+    // Note: This copy makes no practical sense, it's only used for
+    // demonstrating scope copies. This is effectively making a copy of a
+    // pointer.
+
+    bar.setGlobal();
+    // Now foo has a local ref and bar has a global ref.
+
+    foo = bar;
+    // foo's local ref is destroyed. it's value is set to bar's and the widest
+    // possible scope is chosen. foo and bar now both have global refs.
+
+    return foo;
+  } // bar's global is unref'd and it is destroyed. global foo is returned.
+
+*/
+
+typedef void (jholder::*safe_bool_type)();
+void non_null_object() {}
 
 public:
-    explicit jholder(T obj = 0)
-        :object(obj)
-        ,global(false)
-    {
-    }
 
-    jholder(jholder const &c)
-        :object(c.object ? (T)xbmc_jnienv()->NewLocalRef(c.object) : 0)
-        ,global(false)
-    {
-    }
+/*! \brief constructor for jholder().
+   Object is null, type is invalid
+*/
+  jholder()
+  :m_refType(JNIInvalidRefType)
+  ,m_object(0)
+  {
+  }
 
+/*! \brief jholder copy constructor.
+   Object is copied, scope matches the original
+*/
+  jholder(jholder<T> const &c)
+  :m_refType(JNIInvalidRefType)
+  ,m_object(c.get())
+  {
+    setscope(c.m_refType);
+  }
 
-    template <typename U>
-    explicit jholder(jholder<U> const &c)
-        :object(c.object ? (T)xbmc_jnienv()->NewLocalRef(c.object) : 0)
-        ,global(false)
-    {
-    }
+/*! \brief jholder assignment operator
+   Object takes on the widest scope of the two, local at a minimum
+*/
+  jholder &operator=(jholder const &c)
+  {
+    jobjectRefType newtype = JNILocalRefType;
+    if(c.m_refType == JNIGlobalRefType || m_refType == JNIGlobalRefType)
+      newtype = JNIGlobalRefType;
 
-    ~jholder()
-    {
-      reset();
-    }
+    reset(c.get());
+    setscope(newtype);
+    return *this;
+  }
 
-    jholder &operator=(jholder const &c)
-    {
-        jholder tmp(c);
-        swap(tmp);
-        return *this;
-    }
+/*! \brief jholder constructor from a native jni object
+   Incoming objects already hold a local ref.
+*/
+  explicit jholder(const T& obj)
+  :m_refType(JNILocalRefType)
+  ,m_object(obj)
+  {
+    setscope(JNILocalRefType);
+  }
 
-    void reset(T obj = 0)
-    {
-        if (object)
-        {
-          if(global)
-            xbmc_jnienv()->DeleteGlobalRef(object);
-          else
-            xbmc_jnienv()->DeleteLocalRef(object);
-        }
-        object = obj;
-        global = false;
-    }
+/*! \brief jholder dtor.
+   Held objects are deref'd and destroyed.
+*/
+  ~jholder()
+  {
+    reset();
+  }
 
-    const T& get() const {return object;}
+/*! \brief cast operator for native types
+   Grr, no explicit operator casts without c++11.
+   This enables automatic down-casting to native types.
+*/
+  operator const T&() const
+  {
+    return get();
+  }
 
-    T release()
-    {
-        T ret = object;
-        object = 0;
-        global = false;
-        return ret;
-    }
+/*! \brief get native type
+   Same as the above, mainly for internal usage for readability and explicitness
+*/
+  const T& get() const
+  {
+    return m_object;
+  }
 
-    void setGlobal()
-    {
-      if(object)
-      {
-        T globalRef = (T)xbmc_jnienv()->NewGlobalRef(object);
-        reset(globalRef);
-        global = true;
-      }
-    }
+/*! \brief set an object to global scope. Has no effect if it's already global
+*/
+  void setGlobal()
+  {
+    setscope(JNIGlobalRefType);
+  }
 
-    bool operator!() const {return !object;}
-    operator safe_bool_type () const
-    {
-        return object ? &jholder::non_null_object : 0;
-    }
+/*! \brief not operator.
+     queries whether the jholder contains a valid object
+*/
+  bool operator!() const {return !m_object;}
+  operator safe_bool_type () const
+  {
+    return m_object ? &jholder::non_null_object : 0;
+  }
 
-    operator const T&() const
+/*! \brief Change the internal object
+  Unref the original object. The new ref type is invalid.
+
+  This should almost never be used outside of this class. Use it only to
+  maintain static objects that should never be unref'd, such as
+  nativeActivity->clazz.
+  Repeat: Usage of reset() is almost definitely wrong!
+*/
+  void reset(const T &obj = 0)
+  {
+    if(m_object)
     {
-      return object;
+      if(m_refType == JNIGlobalRefType)
+        xbmc_jnienv()->DeleteGlobalRef(m_object);
+      else if (m_refType == JNILocalRefType)
+        xbmc_jnienv()->DeleteLocalRef(m_object);
     }
+    m_refType = JNIInvalidRefType;
+    m_object = obj;
+  }
 
 private:
-    void swap(jholder &c)
+
+/*! \brief Set an object to local/global scope
+    New refs will be created as needed.
+    If the scope is being set to invalid, its ref will be destroyed as needed.
+*/
+  void setscope(const jobjectRefType type)
+  {
+    // Don't attempt anything on a bad object. Update its status to invalid.
+    if (!m_object)
     {
-        T tmp = object;
-        object = c.object;
-        c.object = tmp;
+      m_refType = JNIInvalidRefType;
+      return;
     }
 
-    T object;
-    bool global;
+    // Don't bother if the scope isn't actually changing
+    if (m_refType == type)
+      return;
+
+    if(type == JNIGlobalRefType)
+      reset((T)xbmc_jnienv()->NewGlobalRef(m_object));
+
+    else if (type == JNILocalRefType)
+      reset((T)xbmc_jnienv()->NewLocalRef(m_object));
+
+    else if (type == JNIInvalidRefType)
+      reset();
+    m_refType = type;
+  }
+
+  jobjectRefType m_refType;
+  T m_object;
 };
 
 typedef jholder<jclass> jhclass;
index fe585cd..aff267e 100644 (file)
@@ -189,15 +189,15 @@ int64_t CDVDInputStreamPVRManager::Seek(int64_t offset, int whence)
   if (!m_pFile)
     return -1;
 
-  if (whence == SEEK_POSSIBLE)
-    return m_pFile->IoControl(IOCTRL_SEEK_POSSIBLE, NULL);
-
   if (m_pOtherStream)
   {
     return m_pOtherStream->Seek(offset, whence);
   }
   else
   {
+    if (whence == SEEK_POSSIBLE)
+      return m_pFile->IoControl(IOCTRL_SEEK_POSSIBLE, NULL);
+
     int64_t ret = m_pFile->Seek(offset, whence);
 
     /* if we succeed, we are not eof anymore */
index 5e75372..7881f98 100644 (file)
@@ -501,9 +501,6 @@ bool CDVDPlayer::CloseFile()
 {
   CLog::Log(LOGNOTICE, "CDVDPlayer::CloseFile()");
 
-  // unpause the player
-  SetPlaySpeed(DVD_PLAYSPEED_NORMAL);
-
   // set the abort request so that other threads can finish up
   m_bAbortRequest = true;
 
index 473e745..75e0dd5 100644 (file)
@@ -674,7 +674,7 @@ inline void PAPlayer::ProcessStreams(double &delay, double &buffer)
     }
 
     /* it is time to start playing the next stream? */
-    if (si->m_playNextAtFrame > 0 && !si->m_playNextTriggered && si->m_framesSent >= si->m_playNextAtFrame)
+    if (si->m_playNextAtFrame > 0 && !si->m_playNextTriggered && !m_continueStream && si->m_framesSent >= si->m_playNextAtFrame)
     {
       if (!si->m_prepareTriggered)
       {
index c60d2ce..7c51a9c 100644 (file)
@@ -465,6 +465,9 @@ bool CDatabase::Connect(const CStdString &dbName, const DatabaseSettings &dbSett
   // database name is always required
   m_pDB->setDatabase(dbName.c_str());
 
+  // set SSL configuration regardless if any are empty (all empty means no SSL).
+  m_pDB->setSSLConfig(dbSettings.key.c_str(), dbSettings.cert.c_str(), dbSettings.ca.c_str(), dbSettings.capath.c_str(), dbSettings.ciphers.c_str());
+
   // create the datasets
   m_pDS.reset(m_pDB->CreateDataset());
   m_pDS2.reset(m_pDB->CreateDataset());
index d5a4515..35e8a6d 100644 (file)
@@ -54,12 +54,18 @@ Database::~Database() {
   disconnect();                // Disconnect if connected to database
 }
 
-int Database::connectFull(const char *newHost, const char *newPort, const char *newDb, const char *newLogin, const char *newPasswd) {
+int Database::connectFull(const char *newHost, const char *newPort, const char *newDb, const char *newLogin, const char *newPasswd,
+                        const char *newKey, const char *newCert, const char *newCA, const char *newCApath, const char *newCiphers) {
   host = newHost;
   port = newPort;
   db = newDb;
   login = newLogin;
   passwd = newPasswd;
+  key = newKey;
+  cert = newCert;
+  ca = newCA;
+  capath = newCApath;
+  ciphers = newCiphers;
   return connect(true);
 }
 
index 279a770..96e8d2c 100644 (file)
@@ -71,7 +71,8 @@ protected:
   std::string error, // Error description
     host, port, db, login, passwd, //Login info
     sequence_table, //Sequence table for nextid
-    default_charset; //Default character set
+    default_charset, //Default character set
+    key, cert, ca, capath, ciphers; //SSL - Encryption info
 
 public:
 /* constructor */
@@ -107,6 +108,14 @@ public:
   const char *getSequenceTable(void) { return sequence_table.c_str(); }
 /* Get the default character set */
   const char *getDefaultCharset(void) { return default_charset.c_str(); }
+/* Sets SSL configuration */
+  virtual void setSSLConfig(const char *newKey, const char *newCert, const char *newCA, const char *newCApath, const char *newCiphers) {
+    key = newKey;
+    cert = newCert;
+    ca = newCA;
+    capath = newCApath;
+    ciphers = newCiphers;
+  }
 
 /* virtual methods that must be overloaded in derived classes */
 
@@ -117,7 +126,9 @@ public:
        
   virtual int connect(bool create) { return DB_COMMAND_OK; }
   virtual int connectFull( const char *newDb, const char *newHost=NULL,
-                      const char *newLogin=NULL, const char *newPasswd=NULL,const char *newPort=NULL);
+                      const char *newLogin=NULL, const char *newPasswd=NULL,const char *newPort=NULL,
+                      const char *newKey=NULL, const char *newCert=NULL, const char *newCA=NULL, 
+                      const char *newCApath=NULL, const char *newCiphers=NULL);
   virtual void disconnect(void) { active = false; }
   virtual int reset(void) { return DB_COMMAND_OK; }
   virtual int create(void) { return DB_COMMAND_OK; }
index 85632b8..b29975f 100644 (file)
@@ -117,8 +117,16 @@ int MysqlDatabase::connect(bool create_new) {
   {
     disconnect();
 
-    if (conn == NULL)
+    if (conn == NULL) {
       conn = mysql_init(conn);
+      mysql_ssl_set(
+        conn, 
+        key.empty() ? NULL : key.c_str(), 
+        cert.empty() ? NULL : cert.c_str(), 
+        ca.empty() ? NULL : ca.c_str(), 
+        capath.empty() ? NULL : capath.c_str(), 
+        ciphers.empty() ? NULL : ciphers.c_str());
+    }
 
     CWakeOnAccess::Get().WakeUpHost(host, "MySQL : " + db);
 
index 4df5448..d223a4d 100644 (file)
@@ -308,7 +308,7 @@ int CPVRFile::IoControl(EIoControl request, void *param)
   {
     if (!g_PVRManager.IsStarted())
       return 0;
-    else if (g_PVRClients->GetStreamLength() && g_PVRClients->SeekStream(0, SEEK_CUR) >= 0)
+    else if (g_PVRClients->CanSeekStream())
       return 1;
     else
       return 0;
index 39a98fa..ab5290e 100644 (file)
@@ -617,7 +617,8 @@ CGUIControl* CGUIControlFactory::Create(int parentID, const CRect &rect, TiXmlEl
   CTextureInfo textureCheckMark, textureCheckMarkNF;
   CTextureInfo textureFocus, textureNoFocus;
   CTextureInfo textureAltFocus, textureAltNoFocus;
-  CTextureInfo textureRadioOn, textureRadioOff;
+  CTextureInfo textureRadioOnFocus, textureRadioOnNoFocus;
+  CTextureInfo textureRadioOffFocus, textureRadioOffNoFocus;
   CTextureInfo imageNoFocus, imageFocus;
   CGUIInfoLabel texturePath;
   CRect borderSize;
@@ -819,10 +820,18 @@ CGUIControl* CGUIControlFactory::Create(int parentID, const CRect &rect, TiXmlEl
   XMLUtils::GetFloat(pControlNode, "sliderheight", sliderHeight);
   GetTexture(pControlNode, "texturecheckmark", textureCheckMark);
   GetTexture(pControlNode, "texturecheckmarknofocus", textureCheckMarkNF);
-  GetTexture(pControlNode, "textureradiofocus", textureRadioOn);    // backward compatibility
-  GetTexture(pControlNode, "textureradionofocus", textureRadioOff);
-  GetTexture(pControlNode, "textureradioon", textureRadioOn);
-  GetTexture(pControlNode, "textureradiooff", textureRadioOff);
+  if (!GetTexture(pControlNode, "textureradioonfocus", textureRadioOnFocus) || !GetTexture(pControlNode, "textureradioonnofocus", textureRadioOnNoFocus))
+  {
+    GetTexture(pControlNode, "textureradiofocus", textureRadioOnFocus);    // backward compatibility
+    GetTexture(pControlNode, "textureradioon", textureRadioOnFocus);
+    textureRadioOnNoFocus = textureRadioOnFocus;
+  }
+  if (!GetTexture(pControlNode, "textureradioofffocus", textureRadioOffFocus) || !GetTexture(pControlNode, "textureradiooffnofocus", textureRadioOffNoFocus))
+  {
+    GetTexture(pControlNode, "textureradionofocus", textureRadioOffFocus);    // backward compatibility
+    GetTexture(pControlNode, "textureradiooff", textureRadioOffFocus);
+    textureRadioOffNoFocus = textureRadioOffFocus;
+  }
 
   GetTexture(pControlNode, "texturesliderbackground", textureBackground);
   GetTexture(pControlNode, "texturesliderbar", textureBar);
@@ -1114,7 +1123,7 @@ CGUIControl* CGUIControlFactory::Create(int parentID, const CRect &rect, TiXmlEl
       parentID, id, posX, posY, width, height,
       textureFocus, textureNoFocus,
       labelInfo,
-      textureRadioOn, textureRadioOff);
+      textureRadioOnFocus, textureRadioOnNoFocus, textureRadioOffFocus, textureRadioOffNoFocus);
 
     ((CGUIRadioButtonControl *)control)->SetLabel(strLabel);
     ((CGUIRadioButtonControl *)control)->SetRadioDimensions(radioPosX, radioPosY, radioWidth, radioHeight);
index c073e22..3c40400 100644 (file)
 CGUIRadioButtonControl::CGUIRadioButtonControl(int parentID, int controlID, float posX, float posY, float width, float height,
     const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus,
     const CLabelInfo& labelInfo,
-    const CTextureInfo& radioOn, const CTextureInfo& radioOff)
+    const CTextureInfo& radioOnFocus, const CTextureInfo& radioOnNoFocus,
+    const CTextureInfo& radioOffFocus, const CTextureInfo& radioOffNoFocus)
     : CGUIButtonControl(parentID, controlID, posX, posY, width, height, textureFocus, textureNoFocus, labelInfo)
-    , m_imgRadioOn(posX, posY, 16, 16, radioOn)
-    , m_imgRadioOff(posX, posY, 16, 16, radioOff)
+    , m_imgRadioOnFocus(posX, posY, 16, 16, radioOnFocus)
+    , m_imgRadioOnNoFocus(posX, posY, 16, 16, radioOnNoFocus)
+    , m_imgRadioOffFocus(posX, posY, 16, 16, radioOffFocus)
+    , m_imgRadioOffNoFocus(posX, posY, 16, 16, radioOffNoFocus)
 {
   m_radioPosX = 0;
   m_radioPosY = 0;
   m_toggleSelect = 0;
-  m_imgRadioOn.SetAspectRatio(CAspectRatio::AR_KEEP);\
-  m_imgRadioOff.SetAspectRatio(CAspectRatio::AR_KEEP);
+  m_imgRadioOnFocus.SetAspectRatio(CAspectRatio::AR_KEEP);
+  m_imgRadioOnNoFocus.SetAspectRatio(CAspectRatio::AR_KEEP);
+  m_imgRadioOffFocus.SetAspectRatio(CAspectRatio::AR_KEEP);
+  m_imgRadioOffNoFocus.SetAspectRatio(CAspectRatio::AR_KEEP);
   ControlType = GUICONTROL_RADIO;
 }
 
@@ -47,9 +52,19 @@ void CGUIRadioButtonControl::Render()
   CGUIButtonControl::Render();
 
   if ( IsSelected() && !IsDisabled() )
-    m_imgRadioOn.Render();
+  {
+    if (HasFocus())
+      m_imgRadioOnFocus.Render();
+    else
+      m_imgRadioOnNoFocus.Render();
+  }
   else
-    m_imgRadioOff.Render();
+  {
+    if (HasFocus())
+      m_imgRadioOffFocus.Render();
+    else
+      m_imgRadioOffNoFocus.Render();
+  }
 }
 
 void CGUIRadioButtonControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions)
@@ -65,9 +80,11 @@ void CGUIRadioButtonControl::Process(unsigned int currentTime, CDirtyRegionList
       m_bSelected = selected;
     }
   }
-
-  m_imgRadioOn.Process(currentTime);
-  m_imgRadioOff.Process(currentTime);
+  
+  m_imgRadioOnFocus.Process(currentTime);
+  m_imgRadioOnNoFocus.Process(currentTime);
+  m_imgRadioOffFocus.Process(currentTime);
+  m_imgRadioOffNoFocus.Process(currentTime);
 
   CGUIButtonControl::Process(currentTime, dirtyregions);
 }
@@ -90,40 +107,49 @@ bool CGUIRadioButtonControl::OnMessage(CGUIMessage& message)
 void CGUIRadioButtonControl::AllocResources()
 {
   CGUIButtonControl::AllocResources();
-  m_imgRadioOn.AllocResources();
-  m_imgRadioOff.AllocResources();
-
+  m_imgRadioOnFocus.AllocResources();
+  m_imgRadioOnNoFocus.AllocResources();
+  m_imgRadioOffFocus.AllocResources();
+  m_imgRadioOffNoFocus.AllocResources();
   SetPosition(m_posX, m_posY);
 }
 
 void CGUIRadioButtonControl::FreeResources(bool immediately)
 {
   CGUIButtonControl::FreeResources(immediately);
-  m_imgRadioOn.FreeResources(immediately);
-  m_imgRadioOff.FreeResources(immediately);
+  m_imgRadioOnFocus.FreeResources(immediately);
+  m_imgRadioOnNoFocus.FreeResources(immediately);
+  m_imgRadioOffFocus.FreeResources(immediately);
+  m_imgRadioOffNoFocus.FreeResources(immediately);
 }
 
 void CGUIRadioButtonControl::DynamicResourceAlloc(bool bOnOff)
 {
   CGUIControl::DynamicResourceAlloc(bOnOff);
-  m_imgRadioOn.DynamicResourceAlloc(bOnOff);
-  m_imgRadioOff.DynamicResourceAlloc(bOnOff);
+  m_imgRadioOnFocus.DynamicResourceAlloc(bOnOff);
+  m_imgRadioOnNoFocus.DynamicResourceAlloc(bOnOff);
+  m_imgRadioOffFocus.DynamicResourceAlloc(bOnOff);
+  m_imgRadioOffNoFocus.DynamicResourceAlloc(bOnOff);
 }
 
 void CGUIRadioButtonControl::SetInvalid()
 {
   CGUIButtonControl::SetInvalid();
-  m_imgRadioOn.SetInvalid();
-  m_imgRadioOff.SetInvalid();
+  m_imgRadioOnFocus.SetInvalid();
+  m_imgRadioOnNoFocus.SetInvalid();
+  m_imgRadioOffFocus.SetInvalid();
+  m_imgRadioOffNoFocus.SetInvalid();
 }
 
 void CGUIRadioButtonControl::SetPosition(float posX, float posY)
 {
   CGUIButtonControl::SetPosition(posX, posY);
-  float radioPosX = m_radioPosX ? m_posX + m_radioPosX : (m_posX + m_width - 8) - m_imgRadioOn.GetWidth();
-  float radioPosY = m_radioPosY ? m_posY + m_radioPosY : m_posY + (m_height - m_imgRadioOn.GetHeight()) / 2;
-  m_imgRadioOn.SetPosition(radioPosX, radioPosY);
-  m_imgRadioOff.SetPosition(radioPosX, radioPosY);
+  float radioPosX = m_radioPosX ? m_posX + m_radioPosX : (m_posX + m_width - 8) - m_imgRadioOnFocus.GetWidth();
+  float radioPosY = m_radioPosY ? m_posY + m_radioPosY : m_posY + (m_height - m_imgRadioOnFocus.GetHeight()) / 2;
+  m_imgRadioOnFocus.SetPosition(radioPosX, radioPosY);
+  m_imgRadioOnNoFocus.SetPosition(radioPosX, radioPosY);
+  m_imgRadioOffFocus.SetPosition(radioPosX, radioPosY);
+  m_imgRadioOffNoFocus.SetPosition(radioPosX, radioPosY);
 }
 
 void CGUIRadioButtonControl::SetRadioDimensions(float posX, float posY, float width, float height)
@@ -132,13 +158,17 @@ void CGUIRadioButtonControl::SetRadioDimensions(float posX, float posY, float wi
   m_radioPosY = posY;
   if (width)
   {
-    m_imgRadioOn.SetWidth(width);
-    m_imgRadioOff.SetWidth(width);
+    m_imgRadioOnFocus.SetWidth(width);
+    m_imgRadioOnNoFocus.SetWidth(width);
+    m_imgRadioOffFocus.SetWidth(width);
+    m_imgRadioOffNoFocus.SetWidth(width);
   }
   if (height)
   {
-    m_imgRadioOn.SetHeight(height);
-    m_imgRadioOff.SetHeight(height);
+    m_imgRadioOnFocus.SetHeight(height);
+    m_imgRadioOnNoFocus.SetHeight(height);
+    m_imgRadioOffFocus.SetHeight(height);
+    m_imgRadioOffNoFocus.SetHeight(height);
   }
   SetPosition(GetXPosition(), GetYPosition());
 }
@@ -168,9 +198,10 @@ CStdString CGUIRadioButtonControl::GetDescription() const
 bool CGUIRadioButtonControl::UpdateColors()
 {
   bool changed = CGUIButtonControl::UpdateColors();
-  changed |= m_imgRadioOn.SetDiffuseColor(m_diffuseColor);
-  changed |= m_imgRadioOff.SetDiffuseColor(m_diffuseColor);
-
+  changed |= m_imgRadioOnFocus.SetDiffuseColor(m_diffuseColor);
+  changed |= m_imgRadioOnNoFocus.SetDiffuseColor(m_diffuseColor);
+  changed |= m_imgRadioOffFocus.SetDiffuseColor(m_diffuseColor);
+  changed |= m_imgRadioOffNoFocus.SetDiffuseColor(m_diffuseColor);
   return changed;
 }
 
index 5452de2..65315d2 100644 (file)
@@ -39,7 +39,8 @@ public:
                          float posX, float posY, float width, float height,
                          const CTextureInfo& textureFocus, const CTextureInfo& textureNoFocus,
                          const CLabelInfo& labelInfo,
-                         const CTextureInfo& radioOn, const CTextureInfo& radioOff);
+                         const CTextureInfo& radioOnFocus, const CTextureInfo& radioOnNoFocus,
+                         const CTextureInfo& radioOffFocus, const CTextureInfo& radioOffNoFocus);
 
   virtual ~CGUIRadioButtonControl(void);
   virtual CGUIRadioButtonControl *Clone() const { return new CGUIRadioButtonControl(*this); };
@@ -61,8 +62,10 @@ public:
   bool IsSelected() const { return m_bSelected; };
 protected:
   virtual bool UpdateColors();
-  CGUITexture m_imgRadioOn;
-  CGUITexture m_imgRadioOff;
+  CGUITexture m_imgRadioOnFocus;
+  CGUITexture m_imgRadioOnNoFocus;
+  CGUITexture m_imgRadioOffFocus;
+  CGUITexture m_imgRadioOffNoFocus;
   float m_radioPosX;
   float m_radioPosY;
   unsigned int m_toggleSelect;
diff --git a/xbmc/input/linux/Keymap.h b/xbmc/input/linux/Keymap.h
new file mode 100644 (file)
index 0000000..4fe9952
--- /dev/null
@@ -0,0 +1,36 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "system.h"
+
+class ILinuxKeymap
+{
+public:
+
+  virtual ~ILinuxKeymap() {};
+  
+  virtual uint32_t KeysymForKeycode(uint32_t code) const = 0;
+  virtual void     UpdateMask(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) = 0;
+  virtual uint32_t CurrentModifiers() const = 0;
+  
+  virtual uint32_t XBMCKeysymForKeycode(uint32_t code) const = 0;
+  virtual uint32_t ActiveXBMCModifiers() const = 0;
+};
diff --git a/xbmc/input/linux/Makefile b/xbmc/input/linux/Makefile
deleted file mode 100644 (file)
index 33885a5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-SRCS=LIRC.cpp \
-  LinuxInputDevices.cpp
-
-LIB=input_linux.a
-
-include ../../../Makefile.include
--include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/input/linux/Makefile.in b/xbmc/input/linux/Makefile.in
new file mode 100644 (file)
index 0000000..56b428e
--- /dev/null
@@ -0,0 +1,12 @@
+SRCS=LIRC.cpp \
+  LinuxInputDevices.cpp
+
+# xkbcommon detail
+ifeq (@USE_XKBCOMMON@,1)
+SRCS += XKBCommonKeymap.cpp
+endif
+
+LIB=input_linux.a
+
+include ../../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/input/linux/XKBCommonKeymap.cpp b/xbmc/input/linux/XKBCommonKeymap.cpp
new file mode 100644 (file)
index 0000000..2b720ea
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/scope_exit.hpp>
+
+#include <sys/mman.h>
+
+#include <xkbcommon/xkbcommon.h>
+
+#include "Application.h"
+
+#include "windowing/DllXKBCommon.h"
+#include "XKBCommonKeymap.h"
+
+struct xkb_context *
+CXKBKeymap::CreateXKBContext(IDllXKBCommon &xkbCommonLibrary)
+{
+  enum xkb_context_flags flags =
+    static_cast<enum xkb_context_flags>(0);
+
+  struct xkb_context *context = xkbCommonLibrary.xkb_context_new(flags);
+  
+  /* It is the object who wants to create an XKBKeymap and not
+   * XKBKeymap itself that owns the xkb_context. The
+   * xkb_context is merely just a detail for construction of the
+   * more interesting xkb_state and xkb_keymap objects.
+   * 
+   * Failure to create the context effectively means that that object
+   * will be unable to create a keymap or serve any useful purpose in
+   * processing key events. As such, it makes this an incomplete
+   * object and a runtime_error will be thrown */
+  if (!context)
+    throw std::runtime_error("Failed to create xkb context");
+  
+  return context;
+}
+
+/* Opens a shared memory region and parses the data in it to an
+ * xkbcommon keymap.
+ * 
+ * Generally a keymap is determined by the compositor by evaluating
+ * the currently available hardware and compiling a keymap
+ * most appropriate for that hardware. The compositor simply
+ * sends keycodes and modifier bits in the wire protocol. It is the
+ * client's responsibility to handle transformation of those hardware
+ * specific keycodes and modifier bits into a common keyboard
+ * representation. The compositor provides a serialized keymap
+ * in shared memory to allow clients to perform these transformations.
+ * 
+ * This function does not own the file descriptor. The fact that it
+ * is sent as a const & is a reminder of that. It must not be closed
+ * from this function.
+ */
+struct xkb_keymap *
+CXKBKeymap::ReceiveXKBKeymapFromSharedMemory(IDllXKBCommon &xkbCommonLibrary, struct xkb_context *context, const int &fd, uint32_t size)
+{
+  const char *keymapString = static_cast<const char *>(mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
+  if (keymapString == MAP_FAILED)
+  {
+    std::stringstream ss;
+    ss << "mmap: " << strerror(errno);
+    throw std::runtime_error(ss.str());
+  }
+
+  /* In every exit path, the keymap string memory region must be
+   * unmapped */
+  BOOST_SCOPE_EXIT((keymapString)(size))
+  {
+    munmap(const_cast<void *>(static_cast<const void *>(keymapString)),
+                              size);
+  } BOOST_SCOPE_EXIT_END
+
+  enum xkb_keymap_compile_flags flags =
+    static_cast<enum xkb_keymap_compile_flags>(0);
+  struct xkb_keymap *keymap =
+    xkbCommonLibrary.xkb_keymap_new_from_string(context, keymapString, XKB_KEYMAP_FORMAT_TEXT_V1, flags);
+
+  /* Failure to compile a keymap is a runtime error and the caller
+   * should handle it */
+  if (!keymap)
+    throw std::runtime_error("Failed to compile keymap");
+
+  return keymap;
+}
+
+struct xkb_keymap *
+CXKBKeymap::CreateXKBKeymapFromNames(IDllXKBCommon &xkbCommonLibrary, struct xkb_context *context, const std::string &rules, const std::string &model, const std::string &layout, const std::string &variant, const std::string &options)
+{
+  enum xkb_keymap_compile_flags flags =
+    static_cast<enum xkb_keymap_compile_flags>(0);
+  
+  struct xkb_rule_names names =
+  {
+    rules.c_str(),
+    model.c_str(),
+    layout.c_str(),
+    variant.c_str(),
+    options.c_str()
+  };
+  
+  struct xkb_keymap *keymap =
+    xkbCommonLibrary.xkb_keymap_new_from_names(context, &names, flags);
+
+  if (!keymap)
+    throw std::runtime_error("Failed to compile keymap");
+
+  return keymap;
+}
+
+struct xkb_state *
+CXKBKeymap::CreateXKBStateFromKeymap(IDllXKBCommon &xkbCommonLibrary, struct xkb_keymap *keymap)
+{
+  struct xkb_state *state = xkbCommonLibrary.xkb_state_new(keymap);
+
+  if (!state)
+    throw std::runtime_error("Failed to create keyboard state");
+
+  return state;
+}
+
+/* A wrapper class around an xkbcommon keymap and state tracker.
+ * 
+ * This class knows about some common modifier combinations and keeps
+ * track of the currently pressed keys and modifiers. It also has
+ * some utility functions to transform hardware keycodes into
+ * a common representation.
+ * 
+ * Since this class is keeping track of all the pressed and depressed
+ * modifiers, IT MUST ALWAYS BE KEPT UP TO DATE WITH ANY NEWLY
+ * PRESSED MODIFIERS. Undefined behaviour will result if it is not
+ * kept up to date.
+ */
+CXKBKeymap::CXKBKeymap(IDllXKBCommon &xkbCommonLibrary,
+                       struct xkb_keymap *keymap) :
+  m_xkbCommonLibrary(xkbCommonLibrary),
+  m_keymap(keymap),
+  m_state(CreateXKBStateFromKeymap(xkbCommonLibrary,
+                                   keymap)),
+  m_internalLeftControlIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                         XKB_MOD_NAME_CTRL)),
+  m_internalLeftShiftIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                       XKB_MOD_NAME_SHIFT)),
+  m_internalLeftSuperIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                       XKB_MOD_NAME_LOGO)),
+  m_internalLeftAltIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                     XKB_MOD_NAME_ALT)),
+  m_internalLeftMetaIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                      "Meta")),
+  m_internalRightControlIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                          "RControl")),
+  m_internalRightShiftIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                        "RShift")),
+  m_internalRightSuperIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                        "Hyper")),
+  m_internalRightAltIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                      "AltGr")),
+  m_internalRightMetaIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                       "Meta")),
+  m_internalCapsLockIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                      XKB_LED_NAME_CAPS)),
+  m_internalNumLockIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                     XKB_LED_NAME_NUM)),
+  m_internalModeIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
+                                                                  XKB_LED_NAME_SCROLL))
+{
+}
+
+CXKBKeymap::~CXKBKeymap()
+{
+  m_xkbCommonLibrary.xkb_state_unref(m_state);
+  m_xkbCommonLibrary.xkb_keymap_unref(m_keymap);
+}
+
+uint32_t
+CXKBKeymap::KeysymForKeycode(uint32_t code) const
+{
+  const xkb_keysym_t *syms;
+  uint32_t numSyms;
+
+  /* Key the keysyms for a particular keycode. Generally each
+   * keycode should only have one symbol, but if it has more than
+   * one then we're unable to just get one symbol for it, so that's
+   * a runtime_error which the client needs to handle.
+   * 
+   * Codes sent generally have an offset of 8 */
+  numSyms = m_xkbCommonLibrary.xkb_state_key_get_syms(m_state, code + 8, &syms);
+
+  if (numSyms == 1)
+    return static_cast<uint32_t>(syms[0]);
+
+  std::stringstream ss;
+  ss << "Pressed key "
+     << std::hex
+     << code
+     << std::dec
+     << " is unspported";
+
+  throw std::runtime_error(ss.str());
+}
+
+/* Gets the currently depressed, latched and locked modifiers
+ * for the keyboard */
+uint32_t CXKBKeymap::CurrentModifiers() const
+{
+  enum xkb_state_component components =
+    static_cast <xkb_state_component>(XKB_STATE_DEPRESSED |
+                                      XKB_STATE_LATCHED |
+                                      XKB_STATE_LOCKED);
+  xkb_mod_mask_t mask = m_xkbCommonLibrary.xkb_state_serialize_mods(m_state,
+                                                                    components);
+  return mask;
+}
+
+/* Updates the currently depressed, latched, locked and group
+ * modifiers for a keyboard being tracked.
+ * 
+ * THIS FUNCTION MUST BE CALLED WHENEVER MODIFIERS CHANGE */
+void CXKBKeymap::UpdateMask(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group)
+{
+  m_xkbCommonLibrary.xkb_state_update_mask(m_state, depressed, latched, locked, 0, 0, group);
+}
+
+uint32_t CXKBKeymap::ActiveXBMCModifiers() const
+{
+  xkb_mod_mask_t mask(CurrentModifiers());
+  XBMCMod xbmcModifiers = XBMCKMOD_NONE;
+  
+  struct ModTable
+  {
+    xkb_mod_index_t xkbMod;
+    XBMCMod xbmcMod;
+  } modTable[] =
+  {
+    { m_internalLeftShiftIndex, XBMCKMOD_LSHIFT },
+    { m_internalRightShiftIndex, XBMCKMOD_RSHIFT },
+    { m_internalLeftShiftIndex, XBMCKMOD_LSUPER },
+    { m_internalRightSuperIndex, XBMCKMOD_RSUPER },
+    { m_internalLeftControlIndex, XBMCKMOD_LCTRL },
+    { m_internalRightControlIndex, XBMCKMOD_RCTRL },
+    { m_internalLeftAltIndex, XBMCKMOD_LALT },
+    { m_internalRightAltIndex, XBMCKMOD_RALT },
+    { m_internalLeftMetaIndex, XBMCKMOD_LMETA },
+    { m_internalRightMetaIndex, XBMCKMOD_RMETA },
+    { m_internalNumLockIndex, XBMCKMOD_NUM },
+    { m_internalCapsLockIndex, XBMCKMOD_CAPS },
+    { m_internalModeIndex, XBMCKMOD_MODE }
+  };
+
+  size_t modTableSize = sizeof(modTable) / sizeof(modTable[0]);
+
+  for (size_t i = 0; i < modTableSize; ++i)
+  {
+    if (mask & (1 << modTable[i].xkbMod))
+      xbmcModifiers = static_cast<XBMCMod>(xbmcModifiers | modTable[i].xbmcMod);
+  }
+
+  return static_cast<uint32_t>(xbmcModifiers);
+}
+
+uint32_t CXKBKeymap::XBMCKeysymForKeycode(uint32_t code) const
+{
+  uint32_t sym =  KeysymForKeycode(code);
+
+  /* Strip high bits from functional keys */
+  if ((sym & ~(0xff00)) <= 0x1b)
+    sym = sym & ~(0xff00);
+  else if ((sym & ~(0xff00)) == 0xff)
+    sym = static_cast<uint32_t>(XBMCK_DELETE);
+  
+  /* We only support keys within certain ranges */
+  const bool isNavigationKey = (sym >= 0xff50 && sym <= 0xff58);
+  const bool isModifierKey = (sym >= 0xffe1 && sym <= 0xffee);
+  const bool isKeyPadKey = (sym >= 0xffb1 && sym <= 0xffb9);
+  const bool isFKey = (sym >= 0xffbe && sym <= 0xffcc);
+  const bool isMediaKey = (sym >= 0x1008ff26 && sym <= 0x1008ffa2);
+
+  if (isNavigationKey ||
+      isModifierKey ||
+      isKeyPadKey ||
+      isFKey ||
+      isMediaKey)
+  {
+    /* Navigation keys are not in line, so we need to
+     * look them up */
+    static const struct NavigationKeySyms
+    {
+      uint32_t xkb;
+      XBMCKey xbmc;
+    } navigationKeySyms[] =
+    {
+      { XKB_KEY_Home, XBMCK_HOME },
+      { XKB_KEY_Left, XBMCK_LEFT },
+      { XKB_KEY_Right, XBMCK_RIGHT },
+      { XKB_KEY_Down, XBMCK_DOWN },
+      { XKB_KEY_Up, XBMCK_UP },
+      { XKB_KEY_Page_Up, XBMCK_PAGEUP },
+      { XKB_KEY_Page_Down, XBMCK_PAGEDOWN },
+      { XKB_KEY_End, XBMCK_END },
+      { XKB_KEY_Insert, XBMCK_INSERT },
+      { XKB_KEY_KP_0, XBMCK_KP0 },
+      { XKB_KEY_KP_1, XBMCK_KP1 },
+      { XKB_KEY_KP_2, XBMCK_KP2 },
+      { XKB_KEY_KP_3, XBMCK_KP3 },
+      { XKB_KEY_KP_4, XBMCK_KP4 },
+      { XKB_KEY_KP_5, XBMCK_KP5 },
+      { XKB_KEY_KP_6, XBMCK_KP6 },
+      { XKB_KEY_KP_7, XBMCK_KP7 },
+      { XKB_KEY_KP_8, XBMCK_KP8 },
+      { XKB_KEY_KP_9, XBMCK_KP9 },
+      { XKB_KEY_KP_Decimal, XBMCK_KP_PERIOD },
+      { XKB_KEY_KP_Divide, XBMCK_KP_DIVIDE },
+      { XKB_KEY_KP_Multiply, XBMCK_KP_MULTIPLY },
+      { XKB_KEY_KP_Add, XBMCK_KP_PLUS },
+      { XKB_KEY_KP_Separator, XBMCK_KP_MINUS },
+      { XKB_KEY_KP_Equal, XBMCK_KP_EQUALS },
+      { XKB_KEY_F1, XBMCK_F1 },
+      { XKB_KEY_F2, XBMCK_F2 },
+      { XKB_KEY_F3, XBMCK_F3 },
+      { XKB_KEY_F4, XBMCK_F4 },
+      { XKB_KEY_F5, XBMCK_F5 },
+      { XKB_KEY_F6, XBMCK_F6 },
+      { XKB_KEY_F7, XBMCK_F7 },
+      { XKB_KEY_F8, XBMCK_F8 },
+      { XKB_KEY_F9, XBMCK_F9 },
+      { XKB_KEY_F10, XBMCK_F10 },
+      { XKB_KEY_F11, XBMCK_F11 },
+      { XKB_KEY_F12, XBMCK_F12 },
+      { XKB_KEY_F13, XBMCK_F13 },
+      { XKB_KEY_F14, XBMCK_F14 },
+      { XKB_KEY_F15, XBMCK_F15 },
+      { XKB_KEY_Caps_Lock, XBMCK_CAPSLOCK },
+      { XKB_KEY_Shift_Lock, XBMCK_SCROLLOCK },
+      { XKB_KEY_Shift_R, XBMCK_RSHIFT },
+      { XKB_KEY_Shift_L, XBMCK_LSHIFT },
+      { XKB_KEY_Alt_R, XBMCK_RALT },
+      { XKB_KEY_Alt_L, XBMCK_LALT },
+      { XKB_KEY_Control_R, XBMCK_RCTRL },
+      { XKB_KEY_Control_L, XBMCK_LCTRL },
+      { XKB_KEY_Meta_R, XBMCK_RMETA },
+      { XKB_KEY_Meta_L, XBMCK_LMETA },
+      { XKB_KEY_Super_R, XBMCK_RSUPER },
+      { XKB_KEY_Super_L, XBMCK_LSUPER },
+      { XKB_KEY_XF86Eject, XBMCK_EJECT },
+      { XKB_KEY_XF86AudioStop, XBMCK_STOP },
+      { XKB_KEY_XF86AudioRecord, XBMCK_RECORD },
+      { XKB_KEY_XF86AudioRewind, XBMCK_REWIND },
+      { XKB_KEY_XF86AudioPlay, XBMCK_PLAY },
+      { XKB_KEY_XF86AudioRandomPlay, XBMCK_SHUFFLE },
+      { XKB_KEY_XF86AudioForward, XBMCK_FASTFORWARD }
+    };
+  
+    static const size_t navigationKeySymsSize = sizeof(navigationKeySyms) /
+                                                sizeof(navigationKeySyms[0]);
+
+    for (size_t i = 0; i < navigationKeySymsSize; ++i)
+    {
+      if (navigationKeySyms[i].xkb == sym)
+      {
+        sym = navigationKeySyms[i].xbmc;
+        break;
+      }
+    }
+  }
+
+  return sym;
+}
diff --git a/xbmc/input/linux/XKBCommonKeymap.h b/xbmc/input/linux/XKBCommonKeymap.h
new file mode 100644 (file)
index 0000000..118ebb5
--- /dev/null
@@ -0,0 +1,78 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+
+#include "input/linux/Keymap.h"
+
+struct xkb_keymap;
+struct xkb_state;
+
+typedef uint32_t xkb_mod_index_t;
+typedef uint32_t xkb_mask_index_t;
+
+class IDllXKBCommon;
+
+class CXKBKeymap : public ILinuxKeymap
+{
+public:
+
+  CXKBKeymap(IDllXKBCommon &m_xkbCommonLibrary,
+             struct xkb_keymap *keymap);
+  ~CXKBKeymap();
+
+  static struct xkb_context * CreateXKBContext(IDllXKBCommon &xkbCommonLibrary);
+  /* ReceiveXKBKeymapFromSharedMemory does not own the file descriptor, as such it takes a const reference to it */ 
+  static struct xkb_keymap * ReceiveXKBKeymapFromSharedMemory(IDllXKBCommon &xkbCommonLibrary, struct xkb_context *, const int &fd, uint32_t size);
+  static struct xkb_state * CreateXKBStateFromKeymap(IDllXKBCommon &xkbCommonLibrary, struct xkb_keymap *keymap);
+  static struct xkb_keymap * CreateXKBKeymapFromNames(IDllXKBCommon &xkbCommonLibrary, struct xkb_context *context,  const std::string &rules, const std::string &model, const std::string &layout, const std::string &variant, const std::string &options);
+private:
+
+  uint32_t KeysymForKeycode(uint32_t code) const;
+  void UpdateMask(uint32_t depressed,
+                  uint32_t latched,
+                  uint32_t locked,
+                  uint32_t group);
+  uint32_t CurrentModifiers() const;
+  uint32_t XBMCKeysymForKeycode(uint32_t code) const;
+  uint32_t ActiveXBMCModifiers() const;
+
+  IDllXKBCommon &m_xkbCommonLibrary;
+
+  struct xkb_keymap *m_keymap;
+  struct xkb_state *m_state;
+
+  xkb_mod_index_t m_internalLeftControlIndex;
+  xkb_mod_index_t m_internalLeftShiftIndex;
+  xkb_mod_index_t m_internalLeftSuperIndex;
+  xkb_mod_index_t m_internalLeftAltIndex;
+  xkb_mod_index_t m_internalLeftMetaIndex;
+
+  xkb_mod_index_t m_internalRightControlIndex;
+  xkb_mod_index_t m_internalRightShiftIndex;
+  xkb_mod_index_t m_internalRightSuperIndex;
+  xkb_mod_index_t m_internalRightAltIndex;
+  xkb_mod_index_t m_internalRightMetaIndex;
+
+  xkb_mod_index_t m_internalCapsLockIndex;
+  xkb_mod_index_t m_internalNumLockIndex;
+  xkb_mod_index_t m_internalModeIndex;
+};
index b4afd3a..6d3e611 100644 (file)
@@ -1271,18 +1271,16 @@ namespace JSONRPC
       "\"enum\": [ \"media\", \"window\", \"script\", \"unknown\" ]"
     "}",
     "\"Favourite.Details.Favourite\": {"
-      "\"type\": \"array\","
-      "\"items\": { \"type\": \"object\","
-        "\"properties\": {"
-          "\"title\": { \"type\": \"string\", \"required\": true },"
-          "\"type\": { \"$ref\": \"Favourite.Type\", \"required\": true },"
-          "\"path\": { \"type\": \"string\" },"
-          "\"window\": { \"type\": \"string\" },"
-          "\"windowparameter\": { \"type\": \"string\" },"
-          "\"thumbnail\": { \"type\": \"string\" }"
-        "},"
-        "\"additionalProperties\": false"
-      "}"
+      "\"type\": \"object\","
+      "\"properties\": {"
+        "\"title\": { \"type\": \"string\", \"required\": true },"
+        "\"type\": { \"$ref\": \"Favourite.Type\", \"required\": true },"
+        "\"path\": { \"type\": \"string\" },"
+        "\"window\": { \"type\": \"string\" },"
+        "\"windowparameter\": { \"type\": \"string\" },"
+        "\"thumbnail\": { \"type\": \"string\" }"
+      "},"
+      "\"additionalProperties\": false"
     "}"
   };
 
index 460b864..f134bb2 100644 (file)
     "enum": [ "media", "window", "script", "unknown" ]
   },
   "Favourite.Details.Favourite": {
-    "type": "array",
-    "items": { "type": "object",
-      "properties": {
-        "title": { "type": "string", "required": true },
-        "type": { "$ref": "Favourite.Type", "required": true },
-        "path": { "type": "string" },
-        "window": { "type": "string" },
-        "windowparameter": { "type": "string" },
-        "thumbnail": { "type": "string" }
-      },
-      "additionalProperties": false
-    }
+    "type": "object",
+    "properties": {
+      "title": { "type": "string", "required": true },
+      "type": { "$ref": "Favourite.Type", "required": true },
+      "path": { "type": "string" },
+      "window": { "type": "string" },
+      "windowparameter": { "type": "string" },
+      "thumbnail": { "type": "string" }
+    },
+    "additionalProperties": false
   }
 }
index 585f7d0..a4eea05 100644 (file)
@@ -583,7 +583,9 @@ namespace XBMCAddon
     // ============================================================
     // ============================================================
     ControlRadioButton::ControlRadioButton(long x, long y, long width, long height, const String& label,
-                                           const char* focusTexture, const char* noFocusTexture, 
+                                           const char* focusOnTexture,  const char* noFocusOnTexture,
+                                           const char* focusOffTexture, const char* noFocusOffTexture,
+                                           const char* focusTexture,    const char* noFocusTexture, 
                                            long _textOffsetX, long _textOffsetY, 
                                            long alignment, const char* font, const char* _textColor,
                                            const char* _disabledColor, long angle,
@@ -605,11 +607,29 @@ namespace XBMCAddon
         XBMCAddonUtils::getDefaultImage((char*)"button", (char*)"texturefocus", (char*)"button-focus.png");
       strTextureNoFocus = noFocusTexture ? noFocusTexture :
         XBMCAddonUtils::getDefaultImage((char*)"button", (char*)"texturenofocus", (char*)"button-nofocus.jpg");
-      strTextureRadioFocus = TextureRadioFocus ? TextureRadioFocus :
-        XBMCAddonUtils::getDefaultImage((char*)"radiobutton", (char*)"textureradiofocus", (char*)"radiobutton-focus.png");
-      strTextureRadioNoFocus = TextureRadioNoFocus ? TextureRadioNoFocus :
-        XBMCAddonUtils::getDefaultImage((char*)"radiobutton", (char*)"textureradionofocus", (char*)"radiobutton-nofocus.jpg");
-      
+
+      if (focusOnTexture && noFocusOnTexture)
+      {
+        strTextureRadioOnFocus = focusOnTexture;
+        strTextureRadioOnNoFocus = noFocusOnTexture;
+      }
+      else
+      {
+        strTextureRadioOnFocus = strTextureRadioOnNoFocus = focusTexture ? focusTexture :
+          XBMCAddonUtils::getDefaultImage((char*)"radiobutton", (char*)"textureradiofocus", (char*)"radiobutton-focus.png");
+      }
+
+      if (focusOffTexture && noFocusOffTexture)
+      {
+        strTextureRadioOffFocus = focusOffTexture;
+        strTextureRadioOffNoFocus = noFocusOffTexture;
+      }
+      else
+      {
+        strTextureRadioOffFocus = strTextureRadioOffNoFocus = noFocusTexture ? noFocusTexture :
+          XBMCAddonUtils::getDefaultImage((char*)"radiobutton", (char*)"textureradiofocus", (char*)"radiobutton-focus.png");
+      }
+
       if (font) strFont = font;
       if (_textColor) sscanf( _textColor, "%x", &textColor );
       if (_disabledColor) sscanf( _disabledColor, "%x", &disabledColor );
@@ -697,8 +717,10 @@ namespace XBMCAddon
         (CStdString)strTextureFocus,
         (CStdString)strTextureNoFocus,
         label,
-        (CStdString)strTextureRadioFocus,
-        (CStdString)strTextureRadioNoFocus);
+        (CStdString)strTextureRadioOnFocus,
+        (CStdString)strTextureRadioOnNoFocus,
+        (CStdString)strTextureRadioOffFocus,
+        (CStdString)strTextureRadioOffNoFocus);
 
       CGUIRadioButtonControl* pGuiButtonControl =
         (CGUIRadioButtonControl*)pGUIControl;
index 2766f5f..4a30d04 100644 (file)
@@ -1493,10 +1493,45 @@ namespace XBMCAddon
 #endif
     };
 
+    // ControlRadioButton class
+    /**
+     * ControlRadioButton class.
+     * 
+     * ControlRadioButton(x, y, width, height, label[, focusOnTexture, noFocusOnTexture,
+     *                   focusOffTexture, noFocusOffTexture, focusTexture, noFocusTexture,
+     *                   textOffsetX, textOffsetY, alignment, font, textColor, disabledColor])
+     * 
+     * x                 : integer - x coordinate of control.
+     * y                 : integer - y coordinate of control.
+     * width             : integer - width of control.
+     * height            : integer - height of control.
+     * label             : string or unicode - text string.
+     * focusOnTexture    : [opt] string - filename for radio ON focused texture.
+     * noFocusOnTexture  : [opt] string - filename for radio ON not focused texture.
+     * focusOfTexture    : [opt] string - filename for radio OFF focused texture.
+     * noFocusOffTexture : [opt] string - filename for radio OFF not focused texture.
+     * focusTexture      : [opt] string - filename for radio ON texture (deprecated, use focusOnTexture and noFocusOnTexture).
+     * noFocusTexture    : [opt] string - filename for radio OFF texture (deprecated, use focusOffTexture and noFocusOffTexture).
+     * textOffsetX       : [opt] integer - horizontal text offset
+     * textOffsetY       : [opt] integer - vertical text offset
+     * alignment         : [opt] integer - alignment of label - *Note, see xbfont.h
+     * font              : [opt] string - font used for label text. (e.g. 'font13')
+     * textColor         : [opt] hexstring - color of enabled checkmark's label. (e.g. '0xFFFFFFFF')
+     * disabledColor     : [opt] hexstring - color of disabled checkmark's label. (e.g. '0xFFFF3300')
+     * 
+     * *Note, You can use the above as keywords for arguments and skip certain optional arguments.
+     *        Once you use a keyword, all following arguments require the keyword.
+     *        After you create the control, you need to add it to the window with addControl().
+     * 
+     * example:
+     *   - self.radiobutton = xbmcgui.ControlRadioButton(100, 250, 200, 50, 'Enable', font='font14')
+     */
     class ControlRadioButton : public Control
     {
     public:
       ControlRadioButton(long x, long y, long width, long height, const String& label,
+                         const char* focusOnTexture = NULL, const char* noFocusOnTexture = NULL,
+                         const char* focusOffTexture = NULL, const char* noFocusOffTexture = NULL,
                          const char* focusTexture = NULL, const char* noFocusTexture = NULL, 
                          long textOffsetX = CONTROL_TEXT_OFFSET_X, 
                          long textOffsetY = CONTROL_TEXT_OFFSET_Y, 
@@ -1579,8 +1614,10 @@ namespace XBMCAddon
       std::string strText;
       std::string strTextureFocus;
       std::string strTextureNoFocus;
-      std::string strTextureRadioFocus;
-      std::string strTextureRadioNoFocus;
+      std::string strTextureRadioOnFocus;
+      std::string strTextureRadioOnNoFocus;
+      std::string strTextureRadioOffFocus;
+      std::string strTextureRadioOffNoFocus;
       color_t textColor;
       color_t disabledColor;
       int textOffsetX;
index f476871..4473aaa 100644 (file)
@@ -110,6 +110,23 @@ bool CMusicThumbLoader::LoadItemCached(CFileItem* pItem)
           pItem->SetArt("artist.fanart", fanart);
           pItem->SetArtFallback("fanart", "artist.fanart");
         }
+        else if (!pItem->GetMusicInfoTag()->GetAlbumArtist().empty() &&
+                 pItem->GetMusicInfoTag()->GetAlbumArtist()[0] != artist)
+        {
+          // If no artist fanart and the album artist is different to the artist,
+          // try to get fanart from the album artist
+          artist = pItem->GetMusicInfoTag()->GetAlbumArtist()[0];
+          idArtist = m_musicDatabase->GetArtistByName(artist);
+          if (idArtist >= 0)
+          {
+            fanart = m_musicDatabase->GetArtForItem(idArtist, "artist", "fanart");
+            if (!fanart.empty())
+            {
+              pItem->SetArt("albumartist.fanart", fanart);
+              pItem->SetArtFallback("fanart", "albumartist.fanart");
+            }
+          }
+        }
       }
       m_musicDatabase->Close();
     }
@@ -203,6 +220,16 @@ bool CMusicThumbLoader::FillLibraryArt(CFileItem &item)
         item.SetArt("artist.fanart", fanart);
         item.SetArtFallback("fanart", "artist.fanart");
       }
+      else if (tag.GetType() == "song")
+      {
+        // If no artist fanart, try for album artist fanart
+        fanart = m_musicDatabase->GetArtistArtForItem(tag.GetAlbumId(), "album", "fanart");
+        if (!fanart.empty())
+        {
+          item.SetArt("albumartist.fanart", fanart);
+          item.SetArtFallback("fanart", "albumartist.fanart");
+        }
+      }
     }
     m_musicDatabase->Close();
   }
index 61be9ee..9fce935 100644 (file)
@@ -108,6 +108,8 @@ namespace UPNP
 |   static
 +---------------------------------------------------------------------*/
 CUPnP* CUPnP::upnp = NULL;
+static NPT_List<void*> g_UserData;
+static NPT_Mutex       g_UserDataLock;
 
 /*----------------------------------------------------------------------
 |   CDeviceHostReferenceHolder class
@@ -288,39 +290,65 @@ public:
   {
   }
 
+#define CHECK_USERDATA_RETURN(userdata) do {     \
+  if (!g_UserData.Contains(userdata))            \
+      return;                                    \
+  } while(0)
+
   virtual void OnStopResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnStopResult(res, device, userdata); }
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnStopResult(res, device, userdata);
+  }
 
   virtual void OnSetPlayModeResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnSetPlayModeResult(res, device, userdata); }
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnSetPlayModeResult(res, device, userdata);
+  }
 
   virtual void OnSetAVTransportURIResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnSetAVTransportURIResult(res, device, userdata); }
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnSetAVTransportURIResult(res, device, userdata);
+  }
 
   virtual void OnSeekResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnSeekResult(res, device, userdata); }
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnSeekResult(res, device, userdata);
+  }
 
   virtual void OnPreviousResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnPreviousResult(res, device, userdata); }
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnPreviousResult(res, device, userdata);
+  }
 
   virtual void OnPlayResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnPlayResult(res, device, userdata); }
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnPlayResult(res, device, userdata);
+  }
 
   virtual void OnPauseResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnPauseResult(res, device, userdata); }
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnPauseResult(res, device, userdata);
+  }
 
   virtual void OnNextResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnNextResult(res, device, userdata); }
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnNextResult(res, device, userdata);
+  }
 
   virtual void OnGetMediaInfoResult(NPT_Result res, PLT_DeviceDataReference& device, PLT_MediaInfo* info, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnGetMediaInfoResult(res, device, info, userdata); }
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnGetMediaInfoResult(res, device, info, userdata);
+  }
 
   virtual void OnGetPositionInfoResult(NPT_Result res, PLT_DeviceDataReference& device, PLT_PositionInfo* info, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnGetPositionInfoResult(res, device, info, userdata); }
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnGetPositionInfoResult(res, device, info, userdata);
+  }
 
   virtual void OnGetTransportInfoResult(NPT_Result res, PLT_DeviceDataReference& device, PLT_TransportInfo* info, void* userdata)
-  { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnGetTransportInfoResult(res, device, info, userdata); }
-
+  { CHECK_USERDATA_RETURN(userdata);
+    static_cast<PLT_MediaControllerDelegate*>(userdata)->OnGetTransportInfoResult(res, device, info, userdata);
+  }
 
   virtual bool OnMRAdded(PLT_DeviceDataReference& device )
   {
@@ -652,4 +680,16 @@ void CUPnP::UpdateState()
       ((CUPnPRenderer*)m_RendererHolder->m_Device.AsPointer())->UpdateState();
 }
 
+void CUPnP::RegisterUserdata(void* ptr)
+{
+  NPT_AutoLock lock(g_UserDataLock);
+  g_UserData.Add(ptr);
+}
+
+void CUPnP::UnregisterUserdata(void* ptr)
+{
+  NPT_AutoLock lock(g_UserDataLock);
+  g_UserData.Remove(ptr);
+}
+
 } /* namespace UPNP */
index c96dac2..4a4fd5a 100644 (file)
@@ -74,6 +74,9 @@ public:
     static bool SaveFileState(const CFileItem& item,
                               const CBookmark& bookmark,
                               const bool updatePlayCount);
+
+    static void RegisterUserdata(void* ptr);
+    static void UnregisterUserdata(void* ptr);
 private:
     // methods
     CUPnPRenderer* CreateRenderer(int port = 0);
index 02d7876..f1ec1ca 100644 (file)
@@ -38,6 +38,7 @@
 #include "music/tags/MusicInfoTag.h"
 #include "TextureCache.h"
 #include "ThumbLoader.h"
+#include "utils/URIUtils.h"
 
 using namespace MUSIC_INFO;
 using namespace XFILE;
@@ -809,6 +810,48 @@ CFileItemPtr BuildObject(PLT_MediaObject* entry)
   return pItem;
 }
 
+struct ResourcePrioritySort
+{
+  ResourcePrioritySort(const PLT_MediaObject* entry)
+  {
+    if (entry->m_ObjectClass.type.StartsWith("object.item.audioItem"))
+        m_content = "audio";
+    else if (entry->m_ObjectClass.type.StartsWith("object.item.imageItem"))
+        m_content = "image";
+    else if (entry->m_ObjectClass.type.StartsWith("object.item.videoItem"))
+        m_content = "video";
+  }
+
+  int  GetPriority(const PLT_MediaItemResource& res) const
+  {
+    int prio = 0;
+
+    if (m_content != "" && res.m_ProtocolInfo.GetContentType().StartsWith(m_content))
+        prio += 400;
+
+    NPT_Url url(res.m_Uri);
+    if (URIUtils::IsHostOnLAN((const char*)url.GetHost(), false))
+        prio += 300;
+
+    if (res.m_ProtocolInfo.GetProtocol() == "xbmc-get")
+        prio += 200;
+    else if (res.m_ProtocolInfo.GetProtocol() == "http-get")
+        prio += 100;
+
+    return prio;
+  }
+
+  int operator()(const PLT_MediaItemResource& lh, const PLT_MediaItemResource& rh) const
+  {
+    if(GetPriority(lh) < GetPriority(rh))
+        return 1;
+    else
+        return 0;
+  }
+
+  NPT_String m_content;
+};
+
 bool GetResource(const PLT_MediaObject* entry, CFileItem& item)
 {
   PLT_MediaItemResource resource;
@@ -817,30 +860,17 @@ bool GetResource(const PLT_MediaObject* entry, CFileItem& item)
   item.SetProperty("original_listitem_url",  item.GetPath());
   item.SetProperty("original_listitem_mime", item.GetMimeType());
 
-  // look for a resource with "xbmc-get" protocol
-  // if we can't find one, try to find a valid resource
-  if(NPT_FAILED(NPT_ContainerFind(entry->m_Resources,
-                                  CResourceFinder("xbmc-get"), resource))) {
-    const char* content = NULL;
-    if (entry->m_ObjectClass.type.StartsWith("object.item.audioItem"))
-      content = "audio";
-    else if (entry->m_ObjectClass.type.StartsWith("object.item.imageItem"))
-      content = "image";
-    else if (entry->m_ObjectClass.type.StartsWith("object.item.videoItem"))
-      content = "video";
-
-    if(NPT_FAILED(NPT_ContainerFind(entry->m_Resources,
-                                    CResourceFinder("http-get", content), resource))) {
-      if(entry->m_Resources.GetItemCount()) {
-        // last attempt to find something suitable
-        resource = entry->m_Resources[0];
-      }
-      else {
-        CLog::Log(LOGERROR, "CUPnPDirectory::GetResource - no resources available for object %s", (const char*)entry->m_ObjectID);
-        return false;
-      }
-    }
+  // get a sorted list based on our preference
+  NPT_List<PLT_MediaItemResource> sorted;
+  for (NPT_Cardinal i = 0; i < entry->m_Resources.GetItemCount(); ++i) {
+      sorted.Add(entry->m_Resources[i]);
   }
+  sorted.Sort(ResourcePrioritySort(entry));
+
+  if(sorted.GetItemCount() == 0)
+    return false;
+
+  resource = *sorted.GetFirstItem();
 
   // if it's an item, path is the first url to the item
   // we hope the server made the first one reachable for us
index 7b42df0..b78f97b 100644 (file)
@@ -166,7 +166,10 @@ CUPnPPlayer::CUPnPPlayer(IPlayerCallback& callback, const char* uuid)
 
   PLT_DeviceDataReference device;
   if(NPT_SUCCEEDED(m_control->FindRenderer(uuid, device)))
+  {
     m_delegate = new CUPnPPlayerController(m_control, device, callback);
+    CUPnP::RegisterUserdata(m_delegate);
+  }
   else
     CLog::Log(LOGERROR, "UPNP: CUPnPPlayer couldn't find device as %s", uuid);
 }
@@ -174,6 +177,7 @@ CUPnPPlayer::CUPnPPlayer(IPlayerCallback& callback, const char* uuid)
 CUPnPPlayer::~CUPnPPlayer()
 {
   CloseFile();
+  CUPnP::UnregisterUserdata(m_delegate);
   delete m_delegate;
 }
 
index 23c255f..a4545bc 100644 (file)
@@ -674,7 +674,8 @@ void CPVRManager::ResetDatabase(bool bResetEPGOnly /* = false */)
   pDlgProgress->Progress();
 
   /* reset the EPG pointers */
-  m_database->ResetEPG();
+  if (m_database)
+    m_database->ResetEPG();
 
   /* stop the thread */
   Stop();
index 4e1a28c..ac18c02 100644 (file)
@@ -1118,6 +1118,11 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
     XMLUtils::GetString(pDatabase, "user", m_databaseVideo.user);
     XMLUtils::GetString(pDatabase, "pass", m_databaseVideo.pass);
     XMLUtils::GetString(pDatabase, "name", m_databaseVideo.name);
+    XMLUtils::GetString(pDatabase, "key", m_databaseVideo.key);
+    XMLUtils::GetString(pDatabase, "cert", m_databaseVideo.cert);
+    XMLUtils::GetString(pDatabase, "ca", m_databaseVideo.ca);
+    XMLUtils::GetString(pDatabase, "capath", m_databaseVideo.capath);
+    XMLUtils::GetString(pDatabase, "ciphers", m_databaseVideo.ciphers);
   }
 
   pDatabase = pRootElement->FirstChildElement("musicdatabase");
@@ -1129,6 +1134,11 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
     XMLUtils::GetString(pDatabase, "user", m_databaseMusic.user);
     XMLUtils::GetString(pDatabase, "pass", m_databaseMusic.pass);
     XMLUtils::GetString(pDatabase, "name", m_databaseMusic.name);
+    XMLUtils::GetString(pDatabase, "key", m_databaseMusic.key);
+    XMLUtils::GetString(pDatabase, "cert", m_databaseMusic.cert);
+    XMLUtils::GetString(pDatabase, "ca", m_databaseMusic.ca);
+    XMLUtils::GetString(pDatabase, "capath", m_databaseMusic.capath);
+    XMLUtils::GetString(pDatabase, "ciphers", m_databaseMusic.ciphers);
   }
 
   pDatabase = pRootElement->FirstChildElement("tvdatabase");
@@ -1140,6 +1150,11 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
     XMLUtils::GetString(pDatabase, "user", m_databaseTV.user);
     XMLUtils::GetString(pDatabase, "pass", m_databaseTV.pass);
     XMLUtils::GetString(pDatabase, "name", m_databaseTV.name);
+    XMLUtils::GetString(pDatabase, "key", m_databaseTV.key);
+    XMLUtils::GetString(pDatabase, "cert", m_databaseTV.cert);
+    XMLUtils::GetString(pDatabase, "ca", m_databaseTV.ca);
+    XMLUtils::GetString(pDatabase, "capath", m_databaseTV.capath);
+    XMLUtils::GetString(pDatabase, "ciphers", m_databaseTV.ciphers);
   }
 
   pDatabase = pRootElement->FirstChildElement("epgdatabase");
@@ -1151,6 +1166,11 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
     XMLUtils::GetString(pDatabase, "user", m_databaseEpg.user);
     XMLUtils::GetString(pDatabase, "pass", m_databaseEpg.pass);
     XMLUtils::GetString(pDatabase, "name", m_databaseEpg.name);
+    XMLUtils::GetString(pDatabase, "key", m_databaseEpg.key);
+    XMLUtils::GetString(pDatabase, "cert", m_databaseEpg.cert);
+    XMLUtils::GetString(pDatabase, "ca", m_databaseEpg.ca);
+    XMLUtils::GetString(pDatabase, "capath", m_databaseEpg.capath);
+    XMLUtils::GetString(pDatabase, "ciphers", m_databaseEpg.ciphers);
   }
 
   pElement = pRootElement->FirstChildElement("enablemultimediakeys");
index 05e670b..e6e02ad 100644 (file)
@@ -43,6 +43,11 @@ public:
     user.clear();
     pass.clear();
     name.clear();
+    key.clear();
+    cert.clear();
+    ca.clear();
+    capath.clear();
+    ciphers.clear();
   };
   CStdString type;
   CStdString host;
@@ -50,6 +55,11 @@ public:
   CStdString user;
   CStdString pass;
   CStdString name;
+  CStdString key;
+  CStdString cert;
+  CStdString ca;
+  CStdString capath;
+  CStdString ciphers;
 };
 
 struct TVShowRegexp
index 21456bf..c7ad96d 100644 (file)
@@ -168,15 +168,22 @@ std::string& StringUtils::Trim(std::string &str)
   return TrimRight(str);
 }
 
+// hack to ensure that std::string::iterator will be dereferenced as _unsigned_ char
+// without this hack "TrimX" functions failed on Win32 with UTF-8 strings
+static int isspace_c(char c)
+{
+  return ::isspace((unsigned char)c);
+}
+
 std::string& StringUtils::TrimLeft(std::string &str)
 {
-  str.erase(str.begin(), ::find_if(str.begin(), str.end(), ::not1(::ptr_fun<int, int>(::isspace))));
+  str.erase(str.begin(), ::find_if(str.begin(), str.end(), ::not1(::ptr_fun(isspace_c))));
   return str;
 }
 
 std::string& StringUtils::TrimRight(std::string &str)
 {
-  str.erase(::find_if(str.rbegin(), str.rend(), ::not1(::ptr_fun<int, int>(::isspace))).base(), str.end());
+  str.erase(::find_if(str.rbegin(), str.rend(), ::not1(::ptr_fun(isspace_c))).base(), str.end());
   return str;
 }
 
diff --git a/xbmc/windowing/DllWaylandClient.h b/xbmc/windowing/DllWaylandClient.h
new file mode 100644 (file)
index 0000000..b4b275b
--- /dev/null
@@ -0,0 +1,193 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2005-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
+  #include "config.h"
+#endif
+
+#include <cstdarg>
+
+#include "utils/log.h"
+#include "DynamicDll.h"
+
+struct wl_proxy;
+struct wl_interface;
+
+struct wl_display;
+struct wl_registry;
+struct wl_callback;
+struct wl_compositor;
+struct wl_shell;
+struct wl_shell_surface;
+struct wl_surface;
+struct wl_seat;
+struct wl_pointer;
+struct wl_keyboard;
+struct wl_output;
+struct wl_region;
+
+extern const struct wl_interface wl_display_interface;
+extern const struct wl_interface wl_registry_interface;
+extern const struct wl_interface wl_callback_interface;
+extern const struct wl_interface wl_compositor_interface;
+extern const struct wl_interface wl_shell_interface;
+extern const struct wl_interface wl_shell_surface_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_keyboard_interface;
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_region_interface;
+
+class IDllWaylandClient
+{
+public:
+  typedef void(*wl_proxy_marshal_func)(struct wl_proxy *,
+                                       uint32_t,
+                                       ...);
+  typedef void(*wl_proxy_listener_func)(void);
+  typedef int(*wl_display_read_events_func)(struct wl_display *);
+  typedef int(*wl_display_prepare_read_func)(struct wl_display *);
+
+  virtual struct wl_interface ** Get_wl_display_interface() = 0;
+  virtual struct wl_interface ** Get_wl_registry_interface() = 0;
+  virtual struct wl_interface ** Get_wl_callback_interface() = 0;
+  virtual struct wl_interface ** Get_wl_compositor_interface() = 0;
+  virtual struct wl_interface ** Get_wl_shell_interface() = 0;
+  virtual struct wl_interface ** Get_wl_shell_surface_interface() = 0;
+  virtual struct wl_interface ** Get_wl_surface_interface() = 0;
+  virtual struct wl_interface ** Get_wl_seat_interface() = 0;
+  virtual struct wl_interface ** Get_wl_pointer_interface() = 0;
+  virtual struct wl_interface ** Get_wl_keyboard_interface() = 0;
+  virtual struct wl_interface ** Get_wl_output_interface() = 0;
+  virtual struct wl_interface ** Get_wl_region_interface() = 0;
+
+  virtual struct wl_display * wl_display_connect(const char *) = 0;
+  virtual void wl_display_disconnect(struct wl_display *) = 0;
+  virtual int wl_display_get_fd(struct wl_display *) = 0;
+  virtual wl_display_prepare_read_func wl_display_prepare_read_proc() = 0;
+  virtual wl_display_read_events_func wl_display_read_events_proc() = 0;
+  virtual int wl_display_dispatch_pending(struct wl_display *) = 0;
+  virtual int wl_display_dispatch(struct wl_display *) = 0;
+  virtual int wl_display_flush(struct wl_display *) = 0;
+  
+  virtual wl_proxy_marshal_func wl_proxy_marshaller() = 0;
+
+  virtual struct wl_proxy * wl_proxy_create(struct wl_proxy *,
+                                            const struct wl_interface *) = 0;
+  virtual void wl_proxy_destroy(struct wl_proxy *) = 0;
+  virtual int wl_proxy_add_listener(struct wl_proxy *,
+                                    wl_proxy_listener_func *,
+                                    void *) = 0;
+
+  virtual ~IDllWaylandClient() {}
+};
+
+class DllWaylandClient : public DllDynamic, public IDllWaylandClient
+{
+  DECLARE_DLL_WRAPPER(DllWaylandClient, DLL_PATH_WAYLAND_CLIENT)
+  
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_display_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_registry_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_callback_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_compositor_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_shell_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_shell_surface_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_surface_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_seat_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_pointer_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_keyboard_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_output_interface);
+  DEFINE_GLOBAL_PTR(struct wl_interface *, wl_region_interface);
+  
+  DEFINE_METHOD1(struct wl_display *, wl_display_connect, (const char *p1));
+  DEFINE_METHOD1(void, wl_display_disconnect, (struct wl_display *p1));
+  DEFINE_METHOD1(int, wl_display_get_fd, (struct wl_display *p1));
+  DEFINE_METHOD_FP(int, wl_display_prepare_read, (struct wl_display *p1));
+  DEFINE_METHOD_FP(int, wl_display_read_events, (struct wl_display *p1));
+  DEFINE_METHOD1(int, wl_display_dispatch_pending, (struct wl_display *p1));
+  DEFINE_METHOD1(int, wl_display_dispatch, (struct wl_display *p1));
+  DEFINE_METHOD1(int, wl_display_flush, (struct wl_display *p1));
+  
+  /* We need to resolve wl_proxy_marshal as a function pointer as it
+   * takes varargs */
+  DEFINE_METHOD_FP(void,
+                   wl_proxy_marshal,
+                   (struct wl_proxy *p1, uint32_t p2, ...));
+
+  DEFINE_METHOD2(struct wl_proxy *,
+                 wl_proxy_create,
+                 (struct wl_proxy *p1, const struct wl_interface *p2));
+  DEFINE_METHOD1(void, wl_proxy_destroy, (struct wl_proxy *p1));
+  DEFINE_METHOD3(int,
+                 wl_proxy_add_listener,
+                 (struct wl_proxy *p1,
+                  wl_proxy_listener_func *p2,
+                  void *p3));
+  
+  BEGIN_METHOD_RESOLVE()
+    RESOLVE_METHOD(wl_display_interface)
+    RESOLVE_METHOD(wl_registry_interface)
+    RESOLVE_METHOD(wl_callback_interface)
+    RESOLVE_METHOD(wl_compositor_interface)
+    RESOLVE_METHOD(wl_shell_interface)
+    RESOLVE_METHOD(wl_shell_surface_interface)
+    RESOLVE_METHOD(wl_surface_interface)
+    RESOLVE_METHOD(wl_seat_interface)
+    RESOLVE_METHOD(wl_pointer_interface)
+    RESOLVE_METHOD(wl_keyboard_interface)
+    RESOLVE_METHOD(wl_output_interface)
+    RESOLVE_METHOD(wl_region_interface)
+  
+    RESOLVE_METHOD(wl_display_connect)
+    RESOLVE_METHOD(wl_display_disconnect)
+    RESOLVE_METHOD(wl_display_get_fd)
+    RESOLVE_METHOD_OPTIONAL_FP(wl_display_prepare_read)
+    RESOLVE_METHOD_OPTIONAL_FP(wl_display_read_events)
+    RESOLVE_METHOD(wl_display_dispatch_pending)
+    RESOLVE_METHOD(wl_display_dispatch)
+    RESOLVE_METHOD(wl_display_flush)
+    RESOLVE_METHOD_FP(wl_proxy_marshal)
+    RESOLVE_METHOD(wl_proxy_create)
+    RESOLVE_METHOD(wl_proxy_destroy)
+    RESOLVE_METHOD(wl_proxy_add_listener)
+  END_METHOD_RESOLVE()
+  
+public:
+
+  /* This overload returns the function pointer to wl_proxy_marshal
+   * so that clients can call it directly */
+  wl_proxy_marshal_func wl_proxy_marshaller()
+  {
+    return DllWaylandClient::wl_proxy_marshal;
+  }
+  
+  wl_display_prepare_read_func wl_display_prepare_read_proc()
+  {
+    return DllWaylandClient::wl_display_prepare_read;
+  }
+  
+  wl_display_read_events_func wl_display_read_events_proc()
+  {
+    return DllWaylandClient::wl_display_read_events;
+  }
+};
diff --git a/xbmc/windowing/DllWaylandEgl.h b/xbmc/windowing/DllWaylandEgl.h
new file mode 100644 (file)
index 0000000..1919cfa
--- /dev/null
@@ -0,0 +1,65 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2005-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
+  #include "config.h"
+#endif
+#include "utils/log.h"
+#include "DynamicDll.h"
+
+struct wl_surface;
+struct wl_egl_window;
+
+class IDllWaylandEGL
+{
+public:
+  virtual ~IDllWaylandEGL() {}
+  virtual struct wl_egl_window * wl_egl_window_create(struct wl_surface *,
+                                                      int width,
+                                                      int height) = 0;
+  virtual void wl_egl_window_destroy(struct wl_egl_window *) = 0;
+  virtual void wl_egl_window_resize(struct wl_egl_window *,
+                                    int width, int height,
+                                    int dx, int dy) = 0;
+};
+
+class DllWaylandEGL : public DllDynamic, public IDllWaylandEGL
+{
+  DECLARE_DLL_WRAPPER(DllWaylandEGL, DLL_PATH_WAYLAND_EGL)
+  
+  DEFINE_METHOD3(struct wl_egl_window *,
+                 wl_egl_window_create,
+                 (struct wl_surface *p1, int p2, int p3));
+  DEFINE_METHOD1(void, wl_egl_window_destroy, (struct wl_egl_window *p1));
+  DEFINE_METHOD5(void,
+                 wl_egl_window_resize,
+                 (struct wl_egl_window *p1,
+                  int p2,
+                  int p3,
+                  int p4,
+                  int p5));
+  BEGIN_METHOD_RESOLVE()
+    RESOLVE_METHOD(wl_egl_window_create)
+    RESOLVE_METHOD(wl_egl_window_destroy)
+    RESOLVE_METHOD(wl_egl_window_resize)
+  END_METHOD_RESOLVE()
+};
diff --git a/xbmc/windowing/DllXKBCommon.h b/xbmc/windowing/DllXKBCommon.h
new file mode 100644 (file)
index 0000000..5bf12b7
--- /dev/null
@@ -0,0 +1,92 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2005-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
+  #include "config.h"
+#endif
+#include <xkbcommon/xkbcommon.h>
+#include "utils/log.h"
+#include "DynamicDll.h"
+
+class IDllXKBCommon
+{
+public:
+  virtual ~IDllXKBCommon() {}
+  
+  virtual struct xkb_context * xkb_context_new(enum xkb_context_flags) = 0;
+  virtual void xkb_context_unref(struct xkb_context *) = 0;
+  virtual struct xkb_keymap * xkb_keymap_new_from_string(struct xkb_context *,
+                                                         const char *,
+                                                         enum xkb_keymap_format,
+                                                         enum xkb_keymap_compile_flags) = 0;
+  virtual struct xkb_keymap * xkb_keymap_new_from_names(struct xkb_context *,
+                                                        const struct xkb_rule_names *,
+                                                        enum xkb_keymap_compile_flags) = 0;
+  virtual xkb_mod_index_t xkb_keymap_mod_get_index(struct xkb_keymap *, 
+                                                   const char *) = 0;
+  virtual void xkb_keymap_unref(struct xkb_keymap *) = 0;
+  virtual struct xkb_state * xkb_state_new(struct xkb_keymap *) = 0;
+  virtual xkb_mod_mask_t xkb_state_serialize_mods(struct xkb_state *,
+                                                  enum xkb_state_component) = 0;
+  virtual enum xkb_state_component xkb_state_update_mask (struct xkb_state *,
+                                                          xkb_mod_mask_t,
+                                                          xkb_mod_mask_t,
+                                                          xkb_mod_mask_t,
+                                                          xkb_layout_index_t,
+                                                          xkb_layout_index_t,
+                                                          xkb_layout_index_t) = 0;
+  virtual uint32_t xkb_state_key_get_syms(struct xkb_state *,
+                                          uint32_t,
+                                          const xkb_keysym_t **) = 0;
+  virtual void xkb_state_unref(struct xkb_state *) = 0;
+};
+
+class DllXKBCommon : public DllDynamic, public IDllXKBCommon
+{
+  DECLARE_DLL_WRAPPER(DllXKBCommon, DLL_PATH_XKBCOMMON)
+  
+  DEFINE_METHOD1(struct xkb_context *, xkb_context_new, (enum xkb_context_flags p1));
+  DEFINE_METHOD1(void, xkb_context_unref, (struct xkb_context *p1));
+  DEFINE_METHOD4(struct xkb_keymap *, xkb_keymap_new_from_string, (struct xkb_context *p1, const char *p2, enum xkb_keymap_format p3, enum xkb_keymap_compile_flags p4));
+  DEFINE_METHOD3(struct xkb_keymap *, xkb_keymap_new_from_names, (struct xkb_context *p1, const struct xkb_rule_names *p2, enum xkb_keymap_compile_flags p3));
+  DEFINE_METHOD2(xkb_mod_index_t, xkb_keymap_mod_get_index, (struct xkb_keymap *p1, const char *p2));
+  DEFINE_METHOD1(void, xkb_keymap_unref, (struct xkb_keymap *p1));
+  DEFINE_METHOD1(struct xkb_state *, xkb_state_new, (struct xkb_keymap *p1));
+  DEFINE_METHOD2(xkb_mod_mask_t, xkb_state_serialize_mods, (struct xkb_state *p1, enum xkb_state_component p2));
+  DEFINE_METHOD7(enum xkb_state_component, xkb_state_update_mask, (struct xkb_state *p1, xkb_mod_mask_t p2, xkb_mod_mask_t p3, xkb_mod_mask_t p4, xkb_layout_index_t p5, xkb_layout_index_t p6, xkb_layout_index_t p7));
+  DEFINE_METHOD3(uint32_t, xkb_state_key_get_syms, (struct xkb_state *p1, uint32_t p2, const xkb_keysym_t **p3));
+  DEFINE_METHOD1(void, xkb_state_unref, (struct xkb_state *p1));
+  
+  BEGIN_METHOD_RESOLVE()
+    RESOLVE_METHOD(xkb_context_new)
+    RESOLVE_METHOD(xkb_context_unref)
+    RESOLVE_METHOD(xkb_keymap_new_from_string)
+    RESOLVE_METHOD(xkb_keymap_new_from_names)
+    RESOLVE_METHOD(xkb_keymap_mod_get_index)
+    RESOLVE_METHOD(xkb_keymap_unref)
+    RESOLVE_METHOD(xkb_state_new)
+    RESOLVE_METHOD(xkb_state_serialize_mods)
+    RESOLVE_METHOD(xkb_state_update_mask)
+    RESOLVE_METHOD(xkb_state_key_get_syms)
+    RESOLVE_METHOD(xkb_state_unref)
+  END_METHOD_RESOLVE()
+};
diff --git a/xbmc/windowing/Makefile b/xbmc/windowing/Makefile
deleted file mode 100644 (file)
index b52d16c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-SRCS=WinEventsSDL.cpp \
-     WinEventsLinux.cpp \
-     WinSystem.cpp \
-     WinEvents.cpp
-     
-LIB=windowing.a
-
-include ../../Makefile.include
--include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/windowing/Makefile.in b/xbmc/windowing/Makefile.in
new file mode 100644 (file)
index 0000000..6704967
--- /dev/null
@@ -0,0 +1,24 @@
+SRCS=WinEventsSDL.cpp \
+     WinEventsLinux.cpp \
+     WinEventsWayland.cpp \
+     WinSystem.cpp \
+     WinEvents.cpp
+
+# Wayland implementation detail
+ifeq (@USE_WAYLAND@,1)
+SRCS += wayland/EventLoop.cpp \
+        wayland/Seat.cpp \
+        wayland/Pointer.cpp \
+        wayland/PointerProcessor.cpp \
+        wayland/InputFactory.cpp \
+        wayland/Keyboard.cpp \
+        wayland/KeyboardProcessor.cpp \
+        wayland/PollThread.cpp \
+        wayland/Wayland11EventQueueStrategy.cpp \
+        wayland/Wayland12EventQueueStrategy.cpp
+endif
+
+LIB=windowing.a
+
+include ../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/windowing/WaylandProtocol.h b/xbmc/windowing/WaylandProtocol.h
new file mode 100644 (file)
index 0000000..424754b
--- /dev/null
@@ -0,0 +1,244 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2005-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <iomanip>
+#include <stdexcept>
+#include <sstream>
+
+#include "DllWaylandClient.h"
+
+/* These functions are wrappers around using the wayland protocol
+ * directly. Unfortunately, since most of the protocol has autogenerated
+ * binding code, and that binding code assumes that we're directly
+ * linked to the client library (we're not), we can't use it. So
+ * we need to use wl_proxy_create, wl_proxy_marshal and wl_proxy_destory
+ * directly.
+ * 
+ * These functions effectively exist to reduce some of the duplication
+ * that surrounds using these functions directly. You should look
+ * at the autogenerated binding code to determine how wl_proxy_marshal
+ * should be used to call a particular method.
+ * 
+ * Also note that there may be some cases where additional constructor
+ * or destructor functions might need to be called before or after
+ * CreateWaylandObject and DestroyWaylandObject.
+ * 
+ * If you need to call a method with more than six arguments,
+ * you'll need to add a new overload here */
+namespace xbmc
+{
+namespace wayland
+{
+namespace protocol
+{
+/* These functions call a method on a specifed wayland object
+ * (you should use the pointer provided by the client library
+ *  and not the wrapper) with the specified opcode and
+ * arguments.
+ * 
+ * THERE IS NO TYPE CHECKING so you should be especially sure that
+ * you're calling it with the right arguments. Failure to do so
+ * will result in very strange behaviour
+ */
+template <typename Object>
+void CallMethodOnWaylandObject(IDllWaylandClient &clientLibrary,
+                               Object object,
+                               uint32_t opcode)
+{
+  struct wl_proxy *proxy =
+    reinterpret_cast<struct wl_proxy *>(object);
+  clientLibrary.wl_proxy_marshaller()(proxy,
+                                      opcode);
+}
+template <typename Object,
+          typename A1>
+void CallMethodOnWaylandObject(IDllWaylandClient &clientLibrary,
+                               Object object,
+                               uint32_t opcode,
+                               A1 arg1)
+{
+  struct wl_proxy *proxy =
+    reinterpret_cast<struct wl_proxy *>(object);
+  clientLibrary.wl_proxy_marshaller()(proxy,
+                                      opcode,
+                                      arg1);
+}
+
+template <typename Object,
+          typename A1,
+          typename A2>
+void CallMethodOnWaylandObject(IDllWaylandClient &clientLibrary,
+                               Object object,
+                               uint32_t opcode,
+                               A1 arg1,
+                               A2 arg2)
+{
+  struct wl_proxy *proxy =
+    reinterpret_cast<struct wl_proxy *>(object);
+  clientLibrary.wl_proxy_marshaller()(proxy,
+                                      opcode,
+                                      arg1,
+                                      arg2);
+}
+
+template <typename Object,
+          typename A1,
+          typename A2,
+          typename A3>
+void CallMethodOnWaylandObject(IDllWaylandClient &clientLibrary,
+                               Object object,
+                               uint32_t opcode,
+                               A1 arg1,
+                               A2 arg2,
+                               A3 arg3)
+{
+  struct wl_proxy *proxy =
+    reinterpret_cast<struct wl_proxy *>(object);
+  clientLibrary.wl_proxy_marshaller()(proxy,
+                                      opcode,
+                                      arg1,
+                                      arg2,
+                                      arg3);
+}
+
+template <typename Object,
+          typename A1,
+          typename A2,
+          typename A3,
+          typename A4>
+void CallMethodOnWaylandObject(IDllWaylandClient &clientLibrary,
+                               Object object,
+                               uint32_t opcode,
+                               A1 arg1,
+                               A2 arg2,
+                               A3 arg3,
+                               A4 arg4)
+{
+  struct wl_proxy *proxy =
+    reinterpret_cast<struct wl_proxy *>(object);
+  clientLibrary.wl_proxy_marshaller()(proxy,
+                                      opcode,
+                                      arg1,
+                                      arg2,
+                                      arg3,
+                                      arg4);
+}
+
+template <typename Object,
+          typename A1,
+          typename A2,
+          typename A3,
+          typename A4,
+          typename A5>
+void CallMethodOnWaylandObject(IDllWaylandClient &clientLibrary,
+                               Object object,
+                               uint32_t opcode,
+                               A1 arg1,
+                               A2 arg2,
+                               A3 arg3,
+                               A4 arg4,
+                               A5 arg5)
+{
+  struct wl_proxy *proxy =
+    reinterpret_cast<struct wl_proxy *>(object);
+  clientLibrary.wl_proxy_marshaller()(proxy,
+                                      opcode,
+                                      arg1,
+                                      arg2,
+                                      arg3,
+                                      arg4,
+                                      arg5);
+}
+
+/* This function template returns a new unmanaged object pointer
+ * as specified by Create with the RPC interface as specified
+ * as a child in the server ownership hierarchy of factory.
+ * 
+ * Create must be castable to struct wl_proxy *, which
+ * means that struct wl_proxy should be its first member. Generally
+ * all wayland library proxy objects satisfy this criteria
+ */ 
+template <typename Create, typename Factory>
+Create CreateWaylandObject(IDllWaylandClient &clientLibrary,
+                           Factory factory,
+                           struct wl_interface **interface)
+{
+  struct wl_proxy *pfactory =
+    reinterpret_cast<struct wl_proxy *>(factory);
+  struct wl_proxy *proxy =
+    clientLibrary.wl_proxy_create(pfactory,
+                                  reinterpret_cast<struct wl_interface *>(interface));
+
+  if (!proxy)
+  {
+    std::stringstream ss;
+    ss << "Failed to create "
+       << typeid(Create).name()
+       << " from factory "
+       << typeid(Factory).name()
+       << " at 0x"
+       << std::hex
+       << reinterpret_cast<void *>(pfactory)
+       << std::dec;
+    throw std::runtime_error(ss.str());
+  }
+
+  return reinterpret_cast<Create>(proxy);
+}
+
+/* This function adds a new "listener" to the object specified.
+ * A "listener" is generally a struct of function pointers as specified
+ * by the object's RPC interface for each event it can generate. These
+ * can usually be found in the protocol header. "data" is passed
+ * to each callback to make it a full closure. */
+template <typename Object, typename Listener>
+int AddListenerOnWaylandObject(IDllWaylandClient &clientLibrary,
+                               Object object,
+                               Listener listener,
+                               void *data)
+{
+  struct wl_proxy *proxy =
+    reinterpret_cast<struct wl_proxy *>(object);
+  
+  /* C-style casts are bad, but there is no equavilent to
+   * std::remove_const in C++98 and we are reinterpret_cast'ing
+   * anyways */
+  IDllWaylandClient::wl_proxy_listener_func *listenerFunc =
+    (IDllWaylandClient::wl_proxy_listener_func *)((void *)listener);
+  return clientLibrary.wl_proxy_add_listener(proxy, listenerFunc, data);
+}
+
+/* This function destroys the proxy object and releases its resources
+ * on the client side. There may be an additional destroy request to
+ * release resources on the server side. That must be called
+ * prior to this. */
+template <typename Object>
+void DestroyWaylandObject(IDllWaylandClient &clientLibrary,
+                          Object *object)
+{
+  struct wl_proxy *proxy =
+    reinterpret_cast<struct wl_proxy *>(object);
+  clientLibrary.wl_proxy_destroy(proxy);
+}
+}
+}
+}
index d47784c..1022ad2 100644 (file)
 #include "WinEventsSDL.h"
 #define WinEventsType CWinEventsSDL
 
+#elif defined(HAVE_WAYLAND)
+#include "WinEventsWayland.h"
+#define WinEventsType CWinEventsWayland
+
 #elif defined(TARGET_LINUX) && defined(HAS_LINUX_EVENTS)
 #include "WinEventsLinux.h"
 #define WinEventsType CWinEventsLinux
index 8ae126a..e04631f 100644 (file)
@@ -45,5 +45,4 @@ class CWinEvents
     static size_t GetQueueSize();
 };
 
-
 #endif // WINDOW_EVENTS_H
diff --git a/xbmc/windowing/WinEventsWayland.cpp b/xbmc/windowing/WinEventsWayland.cpp
new file mode 100644 (file)
index 0000000..0e5be52
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include "system.h"
+
+#if defined (HAVE_WAYLAND)
+
+#include <boost/scoped_ptr.hpp>
+
+#include "Application.h"
+#include "xbmc/windowing/WindowingFactory.h"
+#include "WinEventsWayland.h"
+
+#include "wayland/EventListener.h"
+#include "wayland/InputFactory.h"
+#include "wayland/EventLoop.h"
+
+namespace xwe = xbmc::wayland::events;
+
+namespace
+{
+class XBMCListener :
+  public xbmc::IEventListener
+{
+public:
+
+  virtual void OnEvent(XBMC_Event &event);
+  virtual void OnFocused();
+  virtual void OnUnfocused();
+};
+
+XBMCListener g_listener;
+boost::scoped_ptr <xbmc::InputFactory> g_inputInstance;
+boost::scoped_ptr <xwe::Loop> g_eventLoop;
+}
+
+void XBMCListener::OnEvent(XBMC_Event &e)
+{
+  g_application.OnEvent(e);
+}
+
+void XBMCListener::OnFocused()
+{
+  g_application.m_AppFocused = true;
+  g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
+}
+
+void XBMCListener::OnUnfocused()
+{
+  g_application.m_AppFocused = false;
+  g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
+}
+
+CWinEventsWayland::CWinEventsWayland()
+{
+}
+
+void CWinEventsWayland::RefreshDevices()
+{
+}
+
+bool CWinEventsWayland::IsRemoteLowBattery()
+{
+  return false;
+}
+
+/* This function reads the display connection and dispatches
+ * any events through the specified object listeners */
+bool CWinEventsWayland::MessagePump()
+{
+  if (!g_eventLoop.get())
+    return false;
+
+  g_eventLoop->Dispatch();
+
+  return true;
+}
+
+size_t CWinEventsWayland::GetQueueSize()
+{
+  /* We can't query the size of the queue */
+  return 0;
+}
+
+void CWinEventsWayland::SetEventQueueStrategy(xwe::IEventQueueStrategy &strategy)
+{
+  g_eventLoop.reset(new xwe::Loop(g_listener, strategy));
+}
+
+void CWinEventsWayland::DestroyEventQueueStrategy()
+{
+  g_eventLoop.reset();
+}
+
+/* Once we know about a wayland seat, we can just create our manager
+ * object to encapsulate all of that state. When the seat goes away
+ * we just unset the manager object and it is all cleaned up at that
+ * point */
+void CWinEventsWayland::SetWaylandSeat(IDllWaylandClient &clientLibrary,
+                                       IDllXKBCommon &xkbCommonLibrary,
+                                       struct wl_seat *s)
+{
+  if (!g_eventLoop.get())
+    throw std::logic_error("Must have a wl_display set before setting "
+                           "the wl_seat in CWinEventsWayland ");
+
+  g_inputInstance.reset(new xbmc::InputFactory(clientLibrary,
+                                               xkbCommonLibrary,
+                                               s,
+                                               *g_eventLoop,
+                                               *g_eventLoop));
+}
+
+void CWinEventsWayland::DestroyWaylandSeat()
+{
+  g_inputInstance.reset();
+}
+
+/* When a surface becomes available, this function should be called
+ * to register it as the current one for processing input events on.
+ * 
+ * It is a precondition violation to call this function before
+ * a seat has been registered */
+void CWinEventsWayland::SetXBMCSurface(struct wl_surface *s)
+{
+  if (!g_inputInstance.get())
+    throw std::logic_error("Must have a wl_seat set before setting "
+                           "the wl_surface in CWinEventsWayland");
+  
+  g_inputInstance->SetXBMCSurface(s);
+}
+
+#endif
diff --git a/xbmc/windowing/WinEventsWayland.h b/xbmc/windowing/WinEventsWayland.h
new file mode 100644 (file)
index 0000000..e15e767
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+
+#ifndef WINDOW_EVENTS_WAYLAND_H
+#define WINDOW_EVENTS_WAYLAND_H
+
+#pragma once
+#include "windowing/WinEvents.h"
+
+struct wl_display;
+struct wl_seat;
+struct wl_surface;
+
+class IDllWaylandClient;
+class IDllXKBCommon;
+
+namespace xbmc
+{
+namespace wayland
+{
+namespace events
+{
+class IEventQueueStrategy;
+}
+}
+}
+
+class CWinEventsWayland : public IWinEvents
+{
+public:
+  CWinEventsWayland();
+  bool MessagePump();
+  size_t GetQueueSize();
+  static void RefreshDevices();
+  static bool IsRemoteLowBattery();
+
+  static void SetEventQueueStrategy(xbmc::wayland::events::IEventQueueStrategy &strategy);
+  static void DestroyEventQueueStrategy();
+
+  static void SetWaylandSeat(IDllWaylandClient &clientLibrary,
+                             IDllXKBCommon &xkbCommonLibrary,
+                             struct wl_seat *seat);
+  static void DestroyWaylandSeat();
+  
+  static void SetXBMCSurface(struct wl_surface *surf);
+};
+
+#endif
diff --git a/xbmc/windowing/egl/EGLNativeTypeWayland.cpp b/xbmc/windowing/egl/EGLNativeTypeWayland.cpp
new file mode 100644 (file)
index 0000000..fe77ab0
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "system.h"
+
+#if defined(HAVE_WAYLAND)
+
+#define WL_EGL_PLATFORM
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/noncopyable.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <cstdlib>
+
+#include <wayland-client.h>
+#include <wayland-version.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/DllWaylandEgl.h"
+#include "windowing/DllXKBCommon.h"
+#include "windowing/WaylandProtocol.h"
+
+#include "guilib/gui3d.h"
+#include "utils/log.h"
+#include "windowing/WinEvents.h"
+#include "windowing/WinEventsWayland.h"
+
+#include "wayland/WaylandLibraries.h"
+#include "wayland/XBMCConnection.h"
+#include "wayland/XBMCSurface.h"
+
+#endif
+
+#include "EGLNativeTypeWayland.h"
+
+#if defined(HAVE_WAYLAND)
+namespace xw = xbmc::wayland;
+
+class CEGLNativeTypeWayland::Private
+{
+public:
+
+  boost::scoped_ptr<xw::Libraries> m_libraries;
+  boost::scoped_ptr<xw::XBMCConnection> m_connection;
+  boost::scoped_ptr<xw::XBMCSurface> m_surface;
+
+  bool LoadWaylandLibraries();
+  void UnloadWaylandLibraries();
+};
+
+bool CEGLNativeTypeWayland::Private::LoadWaylandLibraries()
+{
+  try
+  {
+    m_libraries.reset(new xw::Libraries());
+  }
+  catch (const std::runtime_error &err)
+  {
+    CLog::Log(LOGWARNING, "%s: %s\n",
+              __FUNCTION__, err.what());
+    return false;
+  }
+  
+  return true;
+}
+
+void CEGLNativeTypeWayland::Private::UnloadWaylandLibraries()
+{
+  m_libraries.reset();
+}
+
+#else
+class CEGLNativeTypeWayland::Private
+{
+};
+#endif
+
+CEGLNativeTypeWayland::CEGLNativeTypeWayland() :
+  priv(new Private())
+{
+}
+
+CEGLNativeTypeWayland::~CEGLNativeTypeWayland()
+{
+} 
+
+bool CEGLNativeTypeWayland::CheckCompatibility()
+{
+#if defined(HAVE_WAYLAND)
+  if (!getenv("WAYLAND_DISPLAY"))
+  {
+    CLog::Log(LOGWARNING, "%s:, WAYLAND_DISPLAY is not set",
+              __FUNCTION__);
+    return false;
+  }
+  
+  /* FIXME:
+   * There appears to be a bug in DllDynamic::CanLoad() which causes
+   * it to always return false. We are just loading the library 
+   * directly at CheckCompatibility time now */
+  if (!priv->LoadWaylandLibraries())
+    return false;
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+void CEGLNativeTypeWayland::Initialize()
+{
+}
+
+void CEGLNativeTypeWayland::Destroy()
+{
+#if defined(HAVE_WAYLAND)
+  priv->UnloadWaylandLibraries();
+#endif
+}
+
+int CEGLNativeTypeWayland::GetQuirks()
+{
+  return EGL_QUIRK_DONT_TRUST_SURFACE_SIZE;
+}
+
+bool CEGLNativeTypeWayland::CreateNativeDisplay()
+{
+#if defined(HAVE_WAYLAND)
+
+  /* On CreateNativeDisplay we connect to the running wayland
+   * compositor on our current socket (as specified by WAYLAND_DISPLAY)
+   * and then do some initial set up like registering event handlers.
+   * 
+   * xbmc::wayland::XBMCConnection is an encapsulation of all of our
+   * current global state with regards to a wayland connection. We
+   * need to give it access to the wayland client libraries and
+   * libxkbcommon for it to do its work.
+   * 
+   * We also inject an xbmc::wayland::XBMCConnection::EventInjector
+   * which is basically just a table of function pointers to functions
+   * in CWinEventsWayland, which are all static. CWinEvents is still
+   * effectively a static, singleton class, and depending on it
+   * means that testing becomes substantially more difficult. As such
+   * we just inject the bits that we need here so that they can be
+   * stubbed out later in testing environments if need be.
+   * 
+   * xbmc::wayland::XBMCConnection's constructor will throw an
+   * std::runtime_error in case it runs into any trouble in connecting
+   * to the wayland compositor or getting the initial global objects.
+   * 
+   * The best we can do when that happens is just report the error
+   * and bail out, possibly to try another (fallback) windowing system.
+   */
+  try
+  {
+    xw::XBMCConnection::EventInjector injector =
+    {
+      CWinEventsWayland::SetEventQueueStrategy,
+      CWinEventsWayland::DestroyEventQueueStrategy,
+      CWinEventsWayland::SetWaylandSeat,
+      CWinEventsWayland::DestroyWaylandSeat,
+      CWinEvents::MessagePump
+    };
+      
+    priv->m_connection.reset(new xw::XBMCConnection(priv->m_libraries->ClientLibrary(),
+                                                    priv->m_libraries->XKBCommonLibrary(),
+                                                    injector));
+  }
+  catch (const std::runtime_error &err)
+  {
+    CLog::Log(LOGERROR, "%s: %s", __FUNCTION__, err.what());
+    return false;
+  }
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeWayland::CreateNativeWindow()
+{
+#if defined(HAVE_WAYLAND)
+
+  /* CreateNativeWindow is where we allocate a new wayland surface
+   * using libwayland-egl and ask the compositor to display it by
+   * creating a new remote surface object.
+   * 
+   * xbmc::wayland::XBMCSurface encapsulates all of this information. It
+   * needs access to various client libraries, as well as the compositor
+   * and shell global interfaces from xbmc::wayland::XBMCConnection
+   * in order to actually create the internal "surface" and "shell
+   * surface" representations.
+   * 
+   * Once xbmc::wayland::XBMCSurface is created, an EGL bindable
+   * surface will be available for later use.
+   * 
+   * The last two parameters are the requested width and height of
+   * the surface.
+   * 
+   * If any problems are encountered in creating the surface
+   * an std::runtime_error is thrown. Like above, we catch it and
+   * report the error, since there's not much we can do about it.
+   */
+  try
+  {
+    RESOLUTION_INFO info;
+    priv->m_connection->CurrentResolution(info);
+
+    xw::XBMCSurface::EventInjector injector =
+    {
+      CWinEventsWayland::SetXBMCSurface
+    };
+
+    priv->m_surface.reset(new xw::XBMCSurface(priv->m_libraries->ClientLibrary(),
+                                              priv->m_libraries->EGLLibrary(),
+                                              injector,
+                                              priv->m_connection->GetCompositor(),
+                                              priv->m_connection->GetShell(),
+                                              info.iScreenWidth,
+                                              info.iScreenHeight));
+  }
+  catch (const std::runtime_error &err)
+  {
+    CLog::Log(LOGERROR, "%s: %s", __FUNCTION__, err.what());
+    return false;
+  }
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeWayland::GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const
+{
+#if defined(HAVE_WAYLAND)
+  /* We need to return a pointer to the wl_display * (eg wl_display **),
+   * as EGLWrapper needs to dereference our return value to get the
+   * actual display and not its first member */
+  *nativeDisplay =
+      reinterpret_cast <XBNativeDisplayType *>(priv->m_connection->NativeDisplay());
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeWayland::GetNativeWindow(XBNativeDisplayType **nativeWindow) const
+{
+#if defined(HAVE_WAYLAND)
+  *nativeWindow =
+      reinterpret_cast <XBNativeWindowType *>(priv->m_surface->EGLNativeWindow());
+  return true;
+#else
+  return false;
+#endif
+}
+
+/* DestroyNativeDisplay and DestroyNativeWindow simply just call
+ * reset on the relevant scoped_ptr. This will effectively destroy
+ * the encapsulating objects which cleans up all of the relevant
+ * connections and surfaces */
+bool CEGLNativeTypeWayland::DestroyNativeDisplay()
+{
+#if defined(HAVE_WAYLAND)
+  priv->m_connection.reset();
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeWayland::DestroyNativeWindow()
+{
+#if defined(HAVE_WAYLAND)
+  priv->m_surface.reset();
+  return true;  
+#else
+  return false;
+#endif
+}
+
+/* The connection knowns about the resolution size, so we ask it
+ * about it. This information is all cached locally, but stored in
+ * the xbmc::wayland::XBMCConnection object */
+bool CEGLNativeTypeWayland::GetNativeResolution(RESOLUTION_INFO *res) const
+{
+#if defined(HAVE_WAYLAND)
+  priv->m_connection->CurrentResolution(*res);
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeWayland::SetNativeResolution(const RESOLUTION_INFO &res)
+{
+#if defined(HAVE_WAYLAND)
+  priv->m_surface->Resize(res.iScreenWidth, res.iScreenHeight);
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeWayland::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
+{
+#if defined(HAVE_WAYLAND)
+  priv->m_connection->AvailableResolutions(resolutions);
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeWayland::GetPreferredResolution(RESOLUTION_INFO *res) const
+{
+#if defined(HAVE_WAYLAND)
+  priv->m_connection->PreferredResolution(*res);
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool CEGLNativeTypeWayland::ShowWindow(bool show)
+{
+#if defined(HAVE_WAYLAND)
+
+  /* XBMC lacks a way to select the output it should appear on,
+   * so we always appear on the first output */
+  if (show)
+    priv->m_surface->Show(priv->m_connection->GetFirstOutput());
+  else
+    return false;
+
+  return true;
+#else
+  return false;
+#endif
+}
diff --git a/xbmc/windowing/egl/EGLNativeTypeWayland.h b/xbmc/windowing/egl/EGLNativeTypeWayland.h
new file mode 100644 (file)
index 0000000..e3813a0
--- /dev/null
@@ -0,0 +1,58 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <boost/scoped_ptr.hpp>
+
+#include <EGL/egl.h>
+#include "EGLNativeType.h"
+
+class CEGLNativeTypeWayland : public CEGLNativeType
+{
+public:
+  CEGLNativeTypeWayland();
+  virtual ~CEGLNativeTypeWayland();
+  virtual std::string GetNativeName() const { return "wayland"; };
+  virtual bool  CheckCompatibility();
+  virtual void  Initialize();
+  virtual void  Destroy();
+  virtual int   GetQuirks();
+
+  virtual bool  CreateNativeDisplay();
+  virtual bool  CreateNativeWindow();
+  virtual bool  GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const;
+  virtual bool  GetNativeWindow(XBNativeWindowType **nativeWindow) const;
+
+  virtual bool  DestroyNativeWindow();
+  virtual bool  DestroyNativeDisplay();
+
+  virtual bool  GetNativeResolution(RESOLUTION_INFO *res) const;
+  virtual bool  SetNativeResolution(const RESOLUTION_INFO &res);
+  virtual bool  ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions);
+  virtual bool  GetPreferredResolution(RESOLUTION_INFO *res) const;
+
+  virtual bool  ShowWindow(bool show);
+private:
+
+  class Private;
+
+  boost::scoped_ptr <Private> priv;
+};
index 651ef34..4778f97 100644 (file)
  *
  */
 
-#define EGL_QUIRK_NONE 0
+#define EGL_QUIRK_NONE (0)
 
 /*! \brief Enable this if the implementation does not know its native
      resolution until a surface has been created. Used, for example, on Android
      where we have no control over the resolution, so we query it once the
      surface exists.
 */
-#define EGL_QUIRK_NEED_WINDOW_FOR_RES 1
+#define EGL_QUIRK_NEED_WINDOW_FOR_RES (1 << 0)
 
 /*! \brief Enable this if the implementation should have its native window
      destroyed when the surface is destroyed. In practice this means that a new
      native window will be created each time the main XBMC window is recreated.
 */
-#define EGL_QUIRK_DESTROY_NATIVE_WINDOW_WITH_SURFACE 2
+#define EGL_QUIRK_DESTROY_NATIVE_WINDOW_WITH_SURFACE (1 << 1)
+
+/*! \brief The intel driver on wayland is broken and always returns a surface
+           size of -1, -1. Work around it for now
+*/
+#define EGL_QUIRK_DONT_TRUST_SURFACE_SIZE (1 << 2)
index 5284b4f..045cdfc 100644 (file)
@@ -26,6 +26,7 @@
 #include "EGLNativeTypeAndroid.h"
 #include "EGLNativeTypeAmlogic.h"
 #include "EGLNativeTypeRaspberryPI.h"
+#include "EGLNativeTypeWayland.h"
 #include "EGLWrapper.h"
 
 #define CheckError() m_result = eglGetError(); if(m_result != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",__FUNCTION__, m_result);
@@ -79,7 +80,8 @@ bool CEGLWrapper::Initialize(const std::string &implementation)
 
   // Try to create each backend in sequence and go with the first one
   // that we know will work
-  if ((nativeGuess = CreateEGLNativeType<CEGLNativeTypeAndroid>(implementation)) ||
+  if ((nativeGuess = CreateEGLNativeType<CEGLNativeTypeWayland>(implementation)) ||
+      (nativeGuess = CreateEGLNativeType<CEGLNativeTypeAndroid>(implementation)) ||
       (nativeGuess = CreateEGLNativeType<CEGLNativeTypeAmlogic>(implementation)) ||
       (nativeGuess = CreateEGLNativeType<CEGLNativeTypeRaspberryPI>(implementation)))
   {
@@ -273,15 +275,24 @@ bool CEGLWrapper::CreateSurface(EGLDisplay display, EGLConfig config, EGLSurface
   return *surface != EGL_NO_SURFACE;
 }
 
+bool CEGLWrapper::TrustSurfaceSize()
+{
+  return !(m_nativeTypes->GetQuirks() & EGL_QUIRK_DONT_TRUST_SURFACE_SIZE);
+}
+
 bool CEGLWrapper::GetSurfaceSize(EGLDisplay display, EGLSurface surface, EGLint *width, EGLint *height)
 {
   if (!width || !height)
     return false;
 
-  if (!eglQuerySurface(display, surface, EGL_WIDTH, width)     ||
-        !eglQuerySurface(display, surface, EGL_HEIGHT, height) ||
-        *width <= 0 || *height <= 0)
-  return false;
+  const bool failedToQuerySurfaceSize =
+    !eglQuerySurface(display, surface, EGL_WIDTH, width) ||
+    !eglQuerySurface(display, surface, EGL_HEIGHT, height);
+  const bool invalidSurfaceSize =
+    *width <= 0 || *height <= 0;
+
+  if (failedToQuerySurfaceSize || invalidSurfaceSize)
+    return false;
 
   return true;
 }
index 827352f..cd4bbb5 100644 (file)
@@ -64,9 +64,12 @@ public:
   bool GetConfigAttrib(EGLDisplay display, EGLConfig config, EGLint attribute, EGLint *value);
   bool SurfaceAttrib(EGLDisplay display, EGLSurface surface, EGLint  attribute, EGLint  value);
 
+  bool TrustSurfaceSize();
+
   static void* GetProcAddress(const char* function);
 
 private:
-    CEGLNativeType          *m_nativeTypes;
-    EGLint                  m_result;
+
+  CEGLNativeType *m_nativeTypes;
+  EGLint         m_result;
 };
diff --git a/xbmc/windowing/egl/Makefile b/xbmc/windowing/egl/Makefile
deleted file mode 100644 (file)
index 241220a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-INCLUDES=-I.
-
-SRCS = WinSystemEGL.cpp
-SRCS+= EGLNativeTypeAmlogic.cpp
-SRCS+= EGLNativeTypeAndroid.cpp
-SRCS+= EGLNativeTypeRaspberryPI.cpp
-SRCS+= EGLWrapper.cpp
-
-LIB = windowing_egl.a
-
-include ../../../Makefile.include
--include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/windowing/egl/Makefile.in b/xbmc/windowing/egl/Makefile.in
new file mode 100644 (file)
index 0000000..f800b7f
--- /dev/null
@@ -0,0 +1,30 @@
+INCLUDES=-I.
+
+SRCS = WinSystemEGL.cpp
+SRCS+= EGLNativeTypeAmlogic.cpp
+SRCS+= EGLNativeTypeAndroid.cpp
+SRCS+= EGLNativeTypeRaspberryPI.cpp
+SRCS+= EGLNativeTypeWayland.cpp
+SRCS+= EGLWrapper.cpp
+
+# Wayland specific detail
+ifeq (@USE_WAYLAND@,1)
+SRCS+= wayland/Callback.cpp \
+       wayland/Compositor.cpp \
+       wayland/Display.cpp \
+       wayland/OpenGLSurface.cpp \
+       wayland/Output.cpp \
+       wayland/Region.cpp \
+       wayland/Registry.cpp \
+       wayland/Shell.cpp \
+       wayland/ShellSurface.cpp \
+       wayland/Surface.cpp \
+       wayland/WaylandLibraries.cpp \
+       wayland/XBMCConnection.cpp \
+       wayland/XBMCSurface.cpp
+endif
+
+LIB = windowing_egl.a
+
+include ../../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
index 8454822..2f063e6 100644 (file)
@@ -165,13 +165,20 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
     }
   }
 
-  int width = 0, height = 0;
-  if (!m_egl->GetSurfaceSize(m_display, m_surface, &width, &height))
+  /* The intel driver on wayland is broken and always returns a surface
+   * size of -1, -1. Work around it for now */
+  if (m_egl->TrustSurfaceSize())
   {
-    CLog::Log(LOGERROR, "%s: Surface is invalid",__FUNCTION__);
-    return false;
+    int width = 0, height = 0;
+    if (!m_egl->GetSurfaceSize(m_display, m_surface, &width, &height))
+    {
+      CLog::Log(LOGERROR, "%s: Surface is invalid",__FUNCTION__);
+      return false;
+    }
+    CLog::Log(LOGDEBUG, "%s: Created surface of size %ix%i",__FUNCTION__, width, height);
   }
-  CLog::Log(LOGDEBUG, "%s: Created surface of size %ix%i",__FUNCTION__, width, height);
+  else
+    CLog::Log(LOGDEBUG, "%s: Cannot reliably get surface size with this backend",__FUNCTION__);
 
   EGLint contextAttrs[] =
   {
diff --git a/xbmc/windowing/egl/wayland/Callback.cpp b/xbmc/windowing/egl/wayland/Callback.cpp
new file mode 100644 (file)
index 0000000..86a288a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <wayland-client.h>
+
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "Callback.h"
+
+namespace xw = xbmc::wayland;
+
+const wl_callback_listener xw::Callback::m_listener =
+{
+  Callback::OnCallback
+};
+
+xw::Callback::Callback(IDllWaylandClient &clientLibrary,
+                       struct wl_callback *callback,
+                       const Func &func) :
+  m_clientLibrary(clientLibrary),
+  m_callback(callback),
+  m_func(func)
+{
+  protocol::AddListenerOnWaylandObject(m_clientLibrary,
+                                       m_callback,
+                                       &m_listener,
+                                       reinterpret_cast<void *>(this));
+}
+
+xw::Callback::~Callback()
+{
+  protocol::DestroyWaylandObject(m_clientLibrary,
+                                 m_callback);
+}
+
+struct wl_callback *
+xw::Callback::GetWlCallback()
+{
+  return m_callback;
+}
+
+void
+xw::Callback::OnCallback(void *data,
+                         struct wl_callback *callback,
+                         uint32_t time)
+{
+  static_cast<Callback *>(data)->m_func(time);
+}
diff --git a/xbmc/windowing/egl/wayland/Callback.h b/xbmc/windowing/egl/wayland/Callback.h
new file mode 100644 (file)
index 0000000..9b184a2
--- /dev/null
@@ -0,0 +1,65 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+#include <boost/function.hpp>
+
+#include <wayland-client.h>
+
+class IDllWaylandClient;
+
+namespace xbmc
+{
+namespace wayland
+{
+/* Callback encapsulates a callback object that might be called
+ * by the compositor through the client library at an arbitrary point
+ * in time. A custom closure can be provided as func to be called
+ * whenever this callback is fired
+ */
+class Callback :
+  boost::noncopyable
+{
+public:
+
+  typedef boost::function<void(uint32_t)> Func;
+
+  Callback(IDllWaylandClient &clientLibrary,
+           struct wl_callback *callback,
+           const Func &func);
+  ~Callback();
+
+  struct wl_callback * GetWlCallback();
+
+  static const struct wl_callback_listener m_listener;
+
+  static void OnCallback(void *,
+                         struct wl_callback *,
+                         uint32_t);
+
+private:
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_callback *m_callback;
+  Func m_func;
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/Compositor.cpp b/xbmc/windowing/egl/wayland/Compositor.cpp
new file mode 100644 (file)
index 0000000..c1a4258
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "Compositor.h"
+
+namespace xw = xbmc::wayland;
+
+xw::Compositor::Compositor(IDllWaylandClient &clientLibrary,
+                           struct wl_compositor *compositor) :
+  m_clientLibrary(clientLibrary),
+  m_compositor(compositor)
+{
+}
+
+xw::Compositor::~Compositor()
+{
+  protocol::DestroyWaylandObject(m_clientLibrary,
+                                 m_compositor);
+}
+
+struct wl_compositor *
+xw::Compositor::GetWlCompositor()
+{
+  return m_compositor;
+}
+
+struct wl_surface *
+xw::Compositor::CreateSurface() const
+{
+  struct wl_surface *surface =
+    protocol::CreateWaylandObject<struct wl_surface *,
+                                  struct wl_compositor *>(m_clientLibrary,
+                                                          m_compositor,
+                                                          m_clientLibrary.Get_wl_surface_interface());
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_compositor,
+                                      WL_COMPOSITOR_CREATE_SURFACE,
+                                      surface);
+  return surface;
+}
+
+struct wl_region *
+xw::Compositor::CreateRegion() const
+{
+  struct wl_region *region =
+    protocol::CreateWaylandObject<struct wl_region *,
+                                  struct wl_compositor *>(m_clientLibrary,
+                                                          m_compositor,
+                                                          m_clientLibrary.Get_wl_region_interface ());
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_compositor,
+                                      WL_COMPOSITOR_CREATE_REGION,
+                                      region);
+  return region;
+}
diff --git a/xbmc/windowing/egl/wayland/Compositor.h b/xbmc/windowing/egl/wayland/Compositor.h
new file mode 100644 (file)
index 0000000..e2955d6
--- /dev/null
@@ -0,0 +1,61 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+
+struct wl_compositor;
+struct wl_surface;
+struct wl_region;
+
+class IDllWaylandClient;
+
+namespace xbmc
+{
+namespace wayland
+{
+class Compositor :
+  boost::noncopyable
+{
+public:
+
+  Compositor(IDllWaylandClient &clientLibrary,
+             struct wl_compositor *compositor);
+  ~Compositor();
+
+  struct wl_compositor * GetWlCompositor();
+  
+  /* Creates a "surface" on the compositor. This is not a renderable
+   * surface immediately, a renderable "buffer" must be bound to it
+   * (usually an EGL Window) */
+  struct wl_surface * CreateSurface() const;
+  
+  /* Creates a "region" on the compositor side. Server side regions
+   * are manipulated on the client side and then can be used to
+   * affect rendering and input on the server side */
+  struct wl_region * CreateRegion() const;
+
+private:
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_compositor *m_compositor;
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/Display.cpp b/xbmc/windowing/egl/wayland/Display.cpp
new file mode 100644 (file)
index 0000000..5afb6d0
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/function.hpp>
+
+#include <cstdlib>
+
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "Display.h"
+
+namespace xw = xbmc::wayland;
+
+void
+xw::WaylandDisplayListener::SetHandler(const Handler &handler)
+{
+  m_handler = handler;
+}
+
+void
+xw::WaylandDisplayListener::DisplayAvailable(Display &display)
+{
+  if (!m_handler.empty())
+    m_handler(display);
+}
+
+xw::WaylandDisplayListener &
+xw::WaylandDisplayListener::GetInstance()
+{
+  if (!m_instance)
+    m_instance.reset(new WaylandDisplayListener());
+
+  return *m_instance;
+}
+
+boost::scoped_ptr<xw::WaylandDisplayListener> xw::WaylandDisplayListener::m_instance;
+
+xw::Display::Display(IDllWaylandClient &clientLibrary) :
+  m_clientLibrary(clientLibrary),
+  m_display(m_clientLibrary.wl_display_connect(NULL))
+{
+  /* wl_display_connect won't throw when it fails, but it does
+   * return NULL on failure. If this object would be incomplete
+   * then that is a fatal error for the backend and we should
+   * throw a runtime_error for the main connection manager to handle
+   */
+  if (!m_display)
+  {
+    std::stringstream ss;
+    ss << "Failed to connect to "
+       << getenv("WAYLAND_DISPLAY");
+    throw std::runtime_error(ss.str());
+  }
+  
+  WaylandDisplayListener::GetInstance().DisplayAvailable(*this);
+}
+
+xw::Display::~Display()
+{
+  m_clientLibrary.wl_display_flush(m_display);
+  m_clientLibrary.wl_display_disconnect(m_display);
+}
+
+struct wl_display *
+xw::Display::GetWlDisplay()
+{
+  return m_display;
+}
+
+EGLNativeDisplayType *
+xw::Display::GetEGLNativeDisplay()
+{
+  return &m_display;
+}
+
+/* Create a sync callback object. This can be wrapped in an
+ * xbmc::wayland::Callback object to call an arbitrary function
+ * as soon as the display has finished processing all commands.
+ * 
+ * This does not block until a synchronization is complete -
+ * consider using a function like WaitForSynchronize to do that */
+struct wl_callback *
+xw::Display::Sync()
+{
+  struct wl_callback *callback =
+      protocol::CreateWaylandObject<struct wl_callback *,
+                                    struct wl_display *> (m_clientLibrary,
+                                                          m_display,
+                                                          m_clientLibrary.Get_wl_callback_interface());
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_display,
+                                      WL_DISPLAY_SYNC,
+                                      callback);
+  return callback;
+}
diff --git a/xbmc/windowing/egl/wayland/Display.h b/xbmc/windowing/egl/wayland/Display.h
new file mode 100644 (file)
index 0000000..49b68f9
--- /dev/null
@@ -0,0 +1,75 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+#include <boost/function.hpp>
+#include <boost/scoped_ptr.hpp>
+
+class IDllWaylandClient;
+
+struct wl_display;
+struct wl_callback;
+
+typedef struct wl_display * EGLNativeDisplayType;
+
+namespace xbmc
+{
+namespace wayland
+{
+class Display :
+  boost::noncopyable
+{
+  public:
+
+    Display(IDllWaylandClient &clientLibrary);
+    ~Display();
+
+    struct wl_display * GetWlDisplay();
+    EGLNativeDisplayType* GetEGLNativeDisplay();
+    struct wl_callback * Sync();
+
+  private:
+
+    IDllWaylandClient &m_clientLibrary;
+    struct wl_display *m_display;
+};
+
+/* This is effectively just a seam for testing purposes so that
+ * we can listen for extra objects that the core implementation might
+ * not necessarily be interested in */
+class WaylandDisplayListener
+{
+public:
+
+  typedef boost::function<void(Display &)> Handler;
+  
+  void SetHandler(const Handler &);
+  void DisplayAvailable(Display &);
+
+  static WaylandDisplayListener & GetInstance();
+private:
+
+  Handler m_handler;
+  
+  static boost::scoped_ptr<WaylandDisplayListener> m_instance;
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/OpenGLSurface.cpp b/xbmc/windowing/egl/wayland/OpenGLSurface.cpp
new file mode 100644 (file)
index 0000000..1b8b3b1
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <wayland-client.h>
+#include <wayland-egl.h>
+
+#include "windowing/DllWaylandEgl.h"
+#include "OpenGLSurface.h"
+
+namespace xw = xbmc::wayland;
+
+xw::OpenGLSurface::OpenGLSurface(IDllWaylandEGL &eglLibrary,
+                                 struct wl_surface *surface,
+                                 int width,
+                                 int height) :
+  m_eglLibrary(eglLibrary),
+  m_eglWindow(m_eglLibrary.wl_egl_window_create(surface,
+                                                width,
+                                                height))
+{
+}
+
+xw::OpenGLSurface::~OpenGLSurface()
+{
+  m_eglLibrary.wl_egl_window_destroy(m_eglWindow);
+}
+
+struct wl_egl_window *
+xw::OpenGLSurface::GetWlEglWindow()
+{
+  return m_eglWindow;
+}
+
+EGLNativeWindowType *
+xw::OpenGLSurface::GetEGLNativeWindow()
+{
+  return &m_eglWindow;
+}
+
+void
+xw::OpenGLSurface::Resize(int width, int height)
+{
+  m_eglLibrary.wl_egl_window_resize(m_eglWindow,
+                                    width,
+                                    height,
+                                    0,
+                                    0);
+}
diff --git a/xbmc/windowing/egl/wayland/OpenGLSurface.h b/xbmc/windowing/egl/wayland/OpenGLSurface.h
new file mode 100644 (file)
index 0000000..915934d
--- /dev/null
@@ -0,0 +1,56 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+
+class IDllWaylandEGL;
+
+struct wl_surface;
+struct wl_egl_window;
+
+typedef struct wl_egl_window * EGLNativeWindowType;
+
+namespace xbmc
+{
+namespace wayland
+{
+class OpenGLSurface :
+  boost::noncopyable
+{
+public:
+
+  OpenGLSurface(IDllWaylandEGL &eglLibrary,
+                struct wl_surface *surface,
+                int32_t width,
+                int32_t height);
+  ~OpenGLSurface();
+
+  struct wl_egl_window * GetWlEglWindow();
+  EGLNativeWindowType * GetEGLNativeWindow();
+  void Resize(int width, int height);
+
+private:
+
+  IDllWaylandEGL &m_eglLibrary;
+  struct wl_egl_window *m_eglWindow;
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/Output.cpp b/xbmc/windowing/egl/wayland/Output.cpp
new file mode 100644 (file)
index 0000000..df3ac71
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "Output.h"
+
+namespace xw = xbmc::wayland;
+
+/* We only support version 1 of this interface, the other
+ * struct members are impliedly set to NULL */
+const wl_output_listener xw::Output::m_listener = 
+{
+  Output::GeometryCallback,
+  Output::ModeCallback
+};
+
+xw::Output::Output(IDllWaylandClient &clientLibrary,
+                   struct wl_output *output) :
+  m_clientLibrary(clientLibrary),
+  m_output(output),
+  m_scaleFactor(1.0),
+  m_current(NULL),
+  m_preferred(NULL)
+{
+  protocol::AddListenerOnWaylandObject(m_clientLibrary,
+                                       m_output,
+                                       &m_listener,
+                                       reinterpret_cast<void *>(this));
+}
+
+xw::Output::~Output()
+{
+  protocol::DestroyWaylandObject(m_clientLibrary,
+                                 m_output);
+}
+
+struct wl_output *
+xw::Output::GetWlOutput()
+{
+  return m_output;
+}
+
+/* It is a precondition violation to use CurrentMode() and
+ * PreferredMode() before output modes have arrived yet, use
+ * a synchronization function to ensure that this is the case */
+const xw::Output::ModeGeometry &
+xw::Output::CurrentMode()
+{
+  if (!m_current)
+    throw std::logic_error("No current mode has been set by the server"
+                           " yet");
+  
+  return *m_current;
+}
+
+const xw::Output::ModeGeometry &
+xw::Output::PreferredMode()
+{
+  if (!m_preferred)
+    throw std::logic_error("No preferred mode has been set by the "
+                           " server yet");
+
+  return *m_preferred;
+}
+
+const std::vector <xw::Output::ModeGeometry> &
+xw::Output::AllModes()
+{
+  return m_modes;
+}
+
+const xw::Output::PhysicalGeometry &
+xw::Output::Geometry()
+{
+  return m_geometry;
+}
+
+uint32_t
+xw::Output::ScaleFactor()
+{
+  return m_scaleFactor;
+}
+
+void
+xw::Output::GeometryCallback(void *data,
+                             struct wl_output *output,
+                             int32_t x,
+                             int32_t y,
+                             int32_t physicalWidth,
+                             int32_t physicalHeight,
+                             int32_t subpixelArrangement,
+                             const char *make,
+                             const char *model,
+                             int32_t transform)
+{
+  return static_cast<xw::Output *>(data)->Geometry(x,
+                                                   y,
+                                                   physicalWidth,
+                                                   physicalHeight,
+                                                   subpixelArrangement,
+                                                   make,
+                                                   model,
+                                                   transform);
+}
+
+void
+xw::Output::ModeCallback(void *data,
+                         struct wl_output *output,
+                         uint32_t flags,
+                         int32_t width,
+                         int32_t height,
+                         int32_t refresh)
+{
+  return static_cast<xw::Output *>(data)->Mode(flags,
+                                               width,
+                                               height,
+                                               refresh);
+}
+
+void
+xw::Output::DoneCallback(void *data,
+                         struct wl_output *output)
+{
+  return static_cast<xw::Output *>(data)->Done();
+}
+
+void
+xw::Output::ScaleCallback(void *data,
+                          struct wl_output *output,
+                          int32_t factor)
+{
+  return static_cast<xw::Output *>(data)->Scale(factor);
+}
+
+/* This function is called when the output geometry is determined.
+ * 
+ * The output geometry represents the actual geometry of the monitor.
+ * As it is per-output, there is only one geometry.
+ */
+void
+xw::Output::Geometry(int32_t x,
+                     int32_t y,
+                     int32_t physicalWidth,
+                     int32_t physicalHeight,
+                     int32_t subpixelArrangement,
+                     const char *make,
+                     const char *model,
+                     int32_t transform)
+{
+  m_geometry.x = x;
+  m_geometry.y = y;
+  m_geometry.physicalWidth = physicalWidth;
+  m_geometry.physicalHeight = physicalHeight;
+  m_geometry.subpixelArrangement =
+    static_cast<enum wl_output_subpixel>(subpixelArrangement);
+  m_geometry.outputTransformation =
+    static_cast<enum wl_output_transform>(transform);
+}
+
+/* This function is called when a new mode is available on this output
+ * or a mode's state changes.
+ * 
+ * It is possible that the same mode can change its state, so we will
+ * not add it twice. Instead, we will determine if the mode is the
+ * same one, but its flags have been updated and if so, update
+ * the pointers to modes having those flags.
+ */
+void
+xw::Output::Mode(uint32_t flags,
+                 int32_t width,
+                 int32_t height,
+                 int32_t refresh)
+{
+  xw::Output::ModeGeometry *update = NULL;
+  
+  for (std::vector<ModeGeometry>::iterator it = m_modes.begin();
+       it != m_modes.end();
+       ++it)
+  { 
+    if (it->width == width &&
+        it->height == height &&
+        it->refresh == refresh)
+    {
+      update = &(*it);
+      break;
+    }
+  }
+  
+  enum wl_output_mode outputFlags =
+    static_cast<enum wl_output_mode>(flags);
+  
+  if (!update)
+  {
+    /* New output created */
+    m_modes.push_back(ModeGeometry());
+    ModeGeometry &next(m_modes.back());
+    
+    next.width = width;
+    next.height = height;
+    next.refresh = refresh;
+    
+    update = &next;
+  }
+  
+  /* We may get a mode notification for a new or
+   * or existing mode. In both cases we need to
+   * update the current and preferred modes */
+  if (outputFlags & WL_OUTPUT_MODE_CURRENT)
+    m_current = update;
+  if (outputFlags & WL_OUTPUT_MODE_PREFERRED)
+    m_preferred = update;
+}
+
+void
+xw::Output::Done()
+{
+}
+
+/* This function is called whenever the scaling factor for this
+ * output changes. It there for clients to support HiDPI displays,
+ * although unused as of present */
+void
+xw::Output::Scale(int32_t factor)
+{
+  m_scaleFactor = factor;
+}
diff --git a/xbmc/windowing/egl/wayland/Output.h b/xbmc/windowing/egl/wayland/Output.h
new file mode 100644 (file)
index 0000000..6ae5824
--- /dev/null
@@ -0,0 +1,150 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <vector>
+
+#include <boost/noncopyable.hpp>
+
+#include <wayland-client.h>
+
+class IDllWaylandClient;
+
+namespace xbmc
+{
+namespace wayland
+{
+struct Output :
+  boost::noncopyable
+{
+public:
+
+  Output(IDllWaylandClient &,
+         struct wl_output *);
+  ~Output();
+
+  struct ModeGeometry
+  {
+    int32_t width;
+    int32_t height;
+    int32_t refresh;
+  };
+
+  struct PhysicalGeometry
+  {
+    int32_t x;
+    int32_t y;
+    int32_t physicalWidth;
+    int32_t physicalHeight;
+    enum wl_output_subpixel subpixelArrangement;
+    enum wl_output_transform outputTransformation;
+  };
+
+  struct wl_output * GetWlOutput();
+
+  /* It is a precondition violation to use the following four
+   * functions when the first modes have not yet been received.
+   * 
+   * Use a synchronization point after creating this object
+   * (eg, WaitForSynchronize() to ensure that the initial modes
+   * are available */
+  
+  /* The "current" mode is the mode that the display is currently
+   * using */
+  const ModeGeometry & CurrentMode();
+  
+  /* The "preferred" mode is the mode most optimal to this output.
+   * 
+   * This is usually the maximum possible mode that this output
+   * supports. All fullscreen windows should generally have a buffer
+   * of this size in order to avoid scaling. */
+  const ModeGeometry & PreferredMode();
+
+  const std::vector <ModeGeometry> & AllModes();
+
+  /* The geometry represents the physical geometry of this monitor */
+  const PhysicalGeometry & Geometry();
+  
+  /* The scale factor of this output is an integer value representing
+   * the number of output pixels per hardware pixel. For instance,
+   * if UI elements were scaled up to 1680x1050 and the monitor was
+   * displaying at a native resolution of 3360x2100 when this would be
+   * "2". This is useful for supporting HiDPI display modes where,
+   * for instance we allocate a 3360x2100 buffer but display our UI
+   * elements at 1680x1050 */
+  uint32_t ScaleFactor();
+
+  static void GeometryCallback(void *,
+                               struct wl_output *,
+                               int32_t,
+                               int32_t,
+                               int32_t,
+                               int32_t,
+                               int32_t,
+                               const char *,
+                               const char *,
+                               int32_t);
+  static void ModeCallback(void *,
+                           struct wl_output *,
+                           uint32_t,
+                           int32_t,
+                           int32_t,
+                           int32_t);
+  static void ScaleCallback(void *,
+                            struct wl_output *,
+                            int32_t);
+  static void DoneCallback(void *,
+                           struct wl_output *);
+
+private:
+
+  static const wl_output_listener m_listener;
+
+  void Geometry(int32_t x,
+                int32_t y,
+                int32_t physicalWidth,
+                int32_t physicalHeight,
+                int32_t subpixel,
+                const char *make,
+                const char *model,
+                int32_t transform);
+  void Mode(uint32_t flags,
+            int32_t width,
+            int32_t height,
+            int32_t refresh);
+  void Scale(int32_t);
+  void Done();
+
+  IDllWaylandClient &m_clientLibrary;
+
+  struct wl_output *m_output;
+
+  PhysicalGeometry m_geometry;
+  std::vector<ModeGeometry> m_modes;
+
+  uint32_t m_scaleFactor;
+
+  /* Only one mode at a time can have the current or preferred
+   * flags set, so only one pointer is set here */
+  ModeGeometry *m_current;
+  ModeGeometry *m_preferred;
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/Region.cpp b/xbmc/windowing/egl/wayland/Region.cpp
new file mode 100644 (file)
index 0000000..d1d2907
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "Region.h"
+
+namespace xw = xbmc::wayland;
+
+xw::Region::Region(IDllWaylandClient &clientLibrary,
+                   struct wl_region *region) :
+  m_clientLibrary(clientLibrary),
+  m_region(region)
+{
+}
+
+xw::Region::~Region()
+{
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_region,
+                                      WL_REGION_DESTROY);
+  protocol::DestroyWaylandObject(m_clientLibrary,
+                                 m_region);
+}
+
+struct wl_region *
+xw::Region::GetWlRegion()
+{
+  return m_region;
+}
+
+void
+xw::Region::AddRectangle(int32_t x,
+                         int32_t y,
+                         int32_t width,
+                         int32_t height)
+{
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_region,
+                                      WL_REGION_ADD,
+                                      x,
+                                      y,
+                                      width,
+                                      height);
+}
diff --git a/xbmc/windowing/egl/wayland/Region.h b/xbmc/windowing/egl/wayland/Region.h
new file mode 100644 (file)
index 0000000..205bd03
--- /dev/null
@@ -0,0 +1,54 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+
+class IDllWaylandClient;
+
+struct wl_region;
+
+namespace xbmc
+{
+namespace wayland
+{
+class Region :
+  boost::noncopyable
+{
+public:
+
+  Region(IDllWaylandClient &clientLibrary,
+         struct wl_region *);
+  ~Region();
+  
+  struct wl_region * GetWlRegion();
+
+  void AddRectangle(int32_t x,
+                    int32_t y,
+                    int32_t width,
+                    int32_t height);
+
+private:
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_region *m_region;
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/Registry.cpp b/xbmc/windowing/egl/wayland/Registry.cpp
new file mode 100644 (file)
index 0000000..a79a5a2
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "Registry.h"
+
+namespace xw = xbmc::wayland;
+
+const struct wl_registry_listener xw::Registry::m_listener =
+{
+  Registry::HandleGlobalCallback,
+  Registry::HandleRemoveGlobalCallback
+};
+
+/* Only one observer may be registered at a time */
+void
+xw::ExtraWaylandGlobals::SetHandler(const GlobalHandler &handler)
+{
+  m_handler = handler;
+}
+
+void
+xw::ExtraWaylandGlobals::NewGlobal(struct wl_registry *registry,
+                                   uint32_t name,
+                                   const char *interface,
+                                   uint32_t version)
+{
+  if (!m_handler.empty())
+    m_handler(registry, name, interface, version);
+}
+
+xw::ExtraWaylandGlobals &
+xw::ExtraWaylandGlobals::GetInstance()
+{
+  if (!m_instance)
+    m_instance.reset(new ExtraWaylandGlobals());
+
+  return *m_instance;
+}
+
+boost::scoped_ptr<xw::ExtraWaylandGlobals> xw::ExtraWaylandGlobals::m_instance;
+
+/* We inject an IWaylandRegistration here which is a virtual
+ * class which a callback for the global objects
+ * used by xbmc. Once one of those objects becomes
+ * available, we call the callback function on that
+ * interface. If it returns false, then it means that the main
+ * xbmc implementation isn't interested in that object, so we 
+ * call out to a listener that can be bound to by any client code
+ * (as it is a singleton) to see if that code is interested
+ * in the interface and wants to bind to it. This is particularly
+ * useful for testing purposes where custom objects on the compositor
+ * side are used. */
+xw::Registry::Registry(IDllWaylandClient &clientLibrary,
+                       struct wl_display *display,
+                       IWaylandRegistration &registration) :
+  m_clientLibrary(clientLibrary),
+  m_registry(protocol::CreateWaylandObject<struct wl_registry *,
+                                           struct wl_display *> (m_clientLibrary,
+                                                                 display,
+                                                                 m_clientLibrary.Get_wl_registry_interface())),
+  m_registration(registration)
+{
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      display,
+                                      WL_DISPLAY_GET_REGISTRY,
+                                      m_registry);
+  protocol::AddListenerOnWaylandObject(m_clientLibrary,
+                                       m_registry,
+                                       &m_listener,
+                                       reinterpret_cast<void *>(this));
+}
+
+xw::Registry::~Registry()
+{
+  protocol::DestroyWaylandObject(m_clientLibrary, m_registry);
+}
+
+/* Once a global becomes available, we immediately bind to it here
+ * and then notify the injected listener interface that the global
+ * is available on a named object. This allows that interface to
+ * respond to the arrival of the new global how it wishes */
+void
+xw::Registry::BindInternal(uint32_t name,
+                           const char *interface,
+                           uint32_t version,
+                           void *proxy)
+{
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_registry,
+                                      WL_REGISTRY_BIND,
+                                      name,
+                                      interface,
+                                      version,
+                                      proxy);
+}
+
+void
+xw::Registry::HandleGlobal(uint32_t name,
+                           const char *interface,
+                           uint32_t version)
+{
+  /* Check if our injected listener wants to know about this -
+   * otherwise let any external listeners know */
+  if (!m_registration.OnGlobalInterfaceAvailable(name,
+                                                 interface,
+                                                 version))
+  {
+    ExtraWaylandGlobals::GetInstance().NewGlobal(m_registry,
+                                                 name,
+                                                 interface,
+                                                 version);
+  }
+}
+
+void
+xw::Registry::HandleRemoveGlobal(uint32_t name)
+{
+}
+
+void
+xw::Registry::HandleGlobalCallback(void *data,
+                                   struct wl_registry *registry,
+                                   uint32_t name,
+                                   const char *interface,
+                                   uint32_t version)
+{
+  static_cast<Registry *>(data)->HandleGlobal(name, interface, version);
+}
+
+void
+xw::Registry::HandleRemoveGlobalCallback(void *data,
+                                         struct wl_registry *registry,
+                                         uint32_t name)
+{
+  static_cast<Registry *>(data)->HandleRemoveGlobal(name);
+}
diff --git a/xbmc/windowing/egl/wayland/Registry.h b/xbmc/windowing/egl/wayland/Registry.h
new file mode 100644 (file)
index 0000000..f40d2f6
--- /dev/null
@@ -0,0 +1,130 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <string>
+
+#include <boost/noncopyable.hpp>
+#include <boost/function.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <wayland-client.h>
+
+#include "windowing/WaylandProtocol.h"
+
+class IDllWaylandClient;
+
+namespace xbmc
+{
+namespace wayland
+{
+/* This is effectively just a seam for testing purposes so that
+ * we can listen for extra objects that the core implementation might
+ * not necessarily be interested in */
+class ExtraWaylandGlobals
+{
+public:
+
+  typedef boost::function<void(struct wl_registry *,
+                               uint32_t,
+                               const char *,
+                               uint32_t)> GlobalHandler;
+  
+  void SetHandler(const GlobalHandler &);
+  void NewGlobal(struct wl_registry *,
+                 uint32_t,
+                 const char *,
+                 uint32_t);
+
+  static ExtraWaylandGlobals & GetInstance();
+private:
+
+  GlobalHandler m_handler;
+  
+  static boost::scoped_ptr<ExtraWaylandGlobals> m_instance;
+};
+
+class IWaylandRegistration
+{
+public:
+
+  virtual ~IWaylandRegistration() {};
+
+  virtual bool OnGlobalInterfaceAvailable(uint32_t,
+                                          const char *,
+                                          uint32_t) = 0;
+};
+
+class Registry :
+  boost::noncopyable
+{
+public:
+
+  Registry(IDllWaylandClient &clientLibrary,
+           struct wl_display   *display,
+           IWaylandRegistration &registration);
+  ~Registry();
+
+  struct wl_registry * GetWlRegistry();
+  
+  template<typename Create>
+  Create Bind(uint32_t name,
+              struct wl_interface **interface,
+              uint32_t version)
+  {
+    Create object =
+      protocol::CreateWaylandObject<Create,
+                                    struct wl_registry *>(m_clientLibrary,
+                                                          m_registry,
+                                                          interface);
+
+    /* This looks a bit funky - but it is correct. The dll returns
+     * a ** to wl_interface when it is in fact just a pointer to
+     * the static variable, so we need to remove one indirection */
+    BindInternal(name,
+                 reinterpret_cast<struct wl_interface *>(interface)->name,
+                 version,
+                 object);
+    return object;
+  }
+
+private:
+
+  static const struct wl_registry_listener m_listener;
+
+  static void HandleGlobalCallback(void *, struct wl_registry *,
+                                   uint32_t, const char *, uint32_t);
+  static void HandleRemoveGlobalCallback(void *, struct wl_registry *,
+                                         uint32_t name);
+
+  void BindInternal(uint32_t name,
+                    const char *interface,
+                    uint32_t version,
+                    void *proxy);
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_registry *m_registry;
+  IWaylandRegistration &m_registration;
+
+  void HandleGlobal(uint32_t, const char *, uint32_t);
+  void HandleRemoveGlobal(uint32_t);
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/Shell.cpp b/xbmc/windowing/egl/wayland/Shell.cpp
new file mode 100644 (file)
index 0000000..281ecb0
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "Shell.h"
+
+namespace xw = xbmc::wayland;
+
+xw::Shell::Shell(IDllWaylandClient &clientLibrary,
+                 struct wl_shell *shell) :
+  m_clientLibrary(clientLibrary),
+  m_shell(shell)
+{
+}
+
+xw::Shell::~Shell()
+{
+  protocol::DestroyWaylandObject(m_clientLibrary,
+                                 m_shell);
+}
+
+struct wl_shell *
+xw::Shell::GetWlShell()
+{
+  return m_shell;
+}
+
+struct wl_shell_surface *
+xw::Shell::CreateShellSurface(struct wl_surface *surface)
+{
+  struct wl_shell_surface *shellSurface =
+    protocol::CreateWaylandObject<struct wl_shell_surface *,
+                                  struct wl_shell *>(m_clientLibrary,
+                                                     m_shell,
+                                                     m_clientLibrary.Get_wl_shell_surface_interface ());
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_shell,
+                                      WL_SHELL_GET_SHELL_SURFACE,
+                                      shellSurface,
+                                      surface);
+  return shellSurface;
+}
diff --git a/xbmc/windowing/egl/wayland/Shell.h b/xbmc/windowing/egl/wayland/Shell.h
new file mode 100644 (file)
index 0000000..00f12e0
--- /dev/null
@@ -0,0 +1,52 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+
+class IDllWaylandClient;
+
+struct wl_shell;
+struct wl_shell_surface;
+struct wl_surface;
+
+namespace xbmc
+{
+namespace wayland
+{
+class Shell :
+  boost::noncopyable
+{
+public:
+
+  Shell(IDllWaylandClient &clientLibrary,
+        struct wl_shell *shell);
+  ~Shell();
+
+  struct wl_shell * GetWlShell();
+  struct wl_shell_surface * CreateShellSurface(struct wl_surface *);
+
+private:
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_shell *m_shell;
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/ShellSurface.cpp b/xbmc/windowing/egl/wayland/ShellSurface.cpp
new file mode 100644 (file)
index 0000000..59a077f
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "ShellSurface.h"
+
+namespace xw = xbmc::wayland;
+
+const wl_shell_surface_listener xw::ShellSurface::m_listener =
+{
+  ShellSurface::HandlePingCallback,
+  ShellSurface::HandleConfigureCallback,
+  ShellSurface::HandlePopupDoneCallback
+};
+
+xw::ShellSurface::ShellSurface(IDllWaylandClient &clientLibrary,
+                               struct wl_shell_surface *shell_surface) :
+  m_clientLibrary(clientLibrary),
+  m_shellSurface(shell_surface)
+{
+  protocol::AddListenerOnWaylandObject(m_clientLibrary,
+                                       m_shellSurface,
+                                       &m_listener,
+                                       reinterpret_cast<void *>(this));
+}
+
+xw::ShellSurface::~ShellSurface()
+{
+  protocol::DestroyWaylandObject(m_clientLibrary, m_shellSurface);
+}
+
+struct wl_shell_surface *
+xw::ShellSurface::GetWlShellSurface()
+{
+  return m_shellSurface;
+}
+
+void
+xw::ShellSurface::SetFullscreen(enum wl_shell_surface_fullscreen_method method,
+                                uint32_t framerate,
+                                struct wl_output *output)
+{
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_shellSurface,
+                                      WL_SHELL_SURFACE_SET_FULLSCREEN,
+                                      method,
+                                      framerate,
+                                      output);
+}
+
+void
+xw::ShellSurface::HandlePingCallback(void *data,
+                                     struct wl_shell_surface *shell_surface,
+                                     uint32_t serial)
+{
+  return static_cast<ShellSurface *>(data)->HandlePing(serial);
+}
+
+void
+xw::ShellSurface::HandleConfigureCallback(void *data,
+                                          struct wl_shell_surface *shell_surface,
+                                          uint32_t edges,
+                                          int32_t width,
+                                          int32_t height)
+{
+  return static_cast<ShellSurface *>(data)->HandleConfigure(edges,
+                                                            width,
+                                                            height);
+}
+
+void
+xw::ShellSurface::HandlePopupDoneCallback(void *data,
+                                          struct wl_shell_surface *shell_surface)
+{
+  return static_cast<ShellSurface *>(data)->HandlePopupDone();
+}
+
+void
+xw::ShellSurface::HandlePing(uint32_t serial)
+{
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_shellSurface,
+                                      WL_SHELL_SURFACE_PONG,
+                                      serial);
+}
+
+void
+xw::ShellSurface::HandleConfigure(uint32_t edges,
+                                  int32_t width,
+                                  int32_t height)
+{
+}
+
+void
+xw::ShellSurface::HandlePopupDone()
+{
+}
diff --git a/xbmc/windowing/egl/wayland/ShellSurface.h b/xbmc/windowing/egl/wayland/ShellSurface.h
new file mode 100644 (file)
index 0000000..d052891
--- /dev/null
@@ -0,0 +1,71 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <wayland-client.h>
+
+#include <boost/noncopyable.hpp>
+
+class IDllWaylandClient;
+
+namespace xbmc
+{
+namespace wayland
+{
+class ShellSurface :
+  boost::noncopyable
+{
+public:
+
+  ShellSurface(IDllWaylandClient &clientLibrary,
+               struct wl_shell_surface *shellSurface);
+  ~ShellSurface();
+
+  struct wl_shell_surface * GetWlShellSurface();
+  void SetFullscreen(enum wl_shell_surface_fullscreen_method method,
+                     uint32_t framerate,
+                     struct wl_output *output);
+
+  static const wl_shell_surface_listener m_listener;
+
+  static void HandlePingCallback(void *,
+                                 struct wl_shell_surface *,
+                                 uint32_t);
+  static void HandleConfigureCallback(void *,
+                                      struct wl_shell_surface *,
+                                      uint32_t,
+                                      int32_t,
+                                      int32_t);
+  static void HandlePopupDoneCallback(void *,
+                                      struct wl_shell_surface *);
+
+private:
+
+  void HandlePing(uint32_t serial);
+  void HandleConfigure(uint32_t edges,
+                       int32_t width,
+                       int32_t height);
+  void HandlePopupDone();
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_shell_surface *m_shellSurface;
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/Surface.cpp b/xbmc/windowing/egl/wayland/Surface.cpp
new file mode 100644 (file)
index 0000000..935d058
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "Surface.h"
+
+namespace xw = xbmc::wayland;
+
+boost::scoped_ptr<xw::WaylandSurfaceListener> xw::WaylandSurfaceListener::m_instance;
+
+xw::WaylandSurfaceListener &
+xw::WaylandSurfaceListener::GetInstance()
+{
+  if (!m_instance)
+    m_instance.reset(new WaylandSurfaceListener());
+
+  return *m_instance;
+}
+
+void
+xw::WaylandSurfaceListener::SetHandler(const Handler &handler)
+{
+  m_handler = handler;
+}
+
+void
+xw::WaylandSurfaceListener::SurfaceCreated(xw::Surface &surface)
+{
+  if (!m_handler.empty())
+    m_handler(surface);
+}
+
+xw::Surface::Surface(IDllWaylandClient &clientLibrary,
+                     struct wl_surface *surface) :
+  m_clientLibrary(clientLibrary),
+  m_surface(surface)
+{
+  WaylandSurfaceListener::GetInstance().SurfaceCreated(*this);
+}
+
+xw::Surface::~Surface()
+{
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_surface,
+                                      WL_SURFACE_DESTROY);
+  protocol::DestroyWaylandObject(m_clientLibrary,
+                                 m_surface);
+}
+
+struct wl_surface *
+xw::Surface::GetWlSurface()
+{
+  return m_surface;
+}
+
+struct wl_callback *
+xw::Surface::CreateFrameCallback()
+{
+  struct wl_callback *callback =
+    protocol::CreateWaylandObject<struct wl_callback *,
+                                  struct wl_surface *>(m_clientLibrary,
+                                                       m_surface,
+                                                       m_clientLibrary.Get_wl_callback_interface());
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_surface,
+                                      WL_SURFACE_FRAME, callback);
+  return callback;
+}
+
+void
+xw::Surface::SetOpaqueRegion(struct wl_region *region)
+{
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_surface,
+                                      WL_SURFACE_SET_OPAQUE_REGION,
+                                      region);
+}
+
+void
+xw::Surface::Commit()
+{
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_surface,
+                                      WL_SURFACE_COMMIT);
+}
diff --git a/xbmc/windowing/egl/wayland/Surface.h b/xbmc/windowing/egl/wayland/Surface.h
new file mode 100644 (file)
index 0000000..1445ccf
--- /dev/null
@@ -0,0 +1,78 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+
+struct wl_surface;
+struct wl_callback;
+struct wl_region;
+
+class IDllWaylandClient;
+
+namespace xbmc
+{
+namespace wayland
+{
+class Surface :
+  boost::noncopyable
+{
+public:
+
+  Surface(IDllWaylandClient &clientLibrary,
+          struct wl_surface *surface);
+  ~Surface();
+
+  struct wl_surface * GetWlSurface();
+  struct wl_callback * CreateFrameCallback();
+  void SetOpaqueRegion(struct wl_region *region);
+  void Commit();
+
+private:
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_surface *m_surface;
+};
+
+/* This is effectively just a seam for testing purposes so that
+ * we can listen for extra objects that the core implementation might
+ * not necessarily be interested in. It isn't possible to get any
+ * notification from within weston that a surface was created so
+ * we need to rely on the client side in order to do that */
+class WaylandSurfaceListener
+{
+public:
+
+  typedef boost::function<void(Surface &)> Handler;
+  
+  void SetHandler(const Handler &);
+  void SurfaceCreated(Surface &);
+
+  static WaylandSurfaceListener & GetInstance();
+private:
+
+  Handler m_handler;
+  
+  static boost::scoped_ptr<WaylandSurfaceListener> m_instance;
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/WaylandLibraries.cpp b/xbmc/windowing/egl/wayland/WaylandLibraries.cpp
new file mode 100644 (file)
index 0000000..0e77f86
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <sstream>
+#include <stdexcept>
+
+#include <wayland-client.h>
+#include "WaylandLibraries.h"
+
+namespace xw = xbmc::wayland;
+
+void
+xw::LoadLibrary(DllDynamic &dll)
+{
+  if (!dll.Load())
+  {
+    std::stringstream ss;
+    ss << "Failed to load library "
+       << dll.GetFile().c_str();
+
+    throw std::runtime_error(ss.str());
+  }
+}
+
+IDllWaylandClient &
+xw::Libraries::ClientLibrary()
+{
+  return m_clientLibrary.Get();
+}
+
+IDllWaylandEGL &
+xw::Libraries::EGLLibrary()
+{
+  return m_eglLibrary.Get();
+}
+
+IDllXKBCommon &
+xw::Libraries::XKBCommonLibrary()
+{
+  return m_xkbCommonLibrary.Get();
+}
diff --git a/xbmc/windowing/egl/wayland/WaylandLibraries.h b/xbmc/windowing/egl/wayland/WaylandLibraries.h
new file mode 100644 (file)
index 0000000..32f12aa
--- /dev/null
@@ -0,0 +1,84 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/DllWaylandEgl.h"
+#include "windowing/DllXKBCommon.h"
+
+namespace xbmc
+{
+namespace wayland
+{
+template <class DllInterface, class Dll>
+class AutoloadDll :
+  boost::noncopyable
+{
+  public:
+
+    AutoloadDll();
+    ~AutoloadDll();
+    DllInterface & Get();
+
+  private:
+
+    Dll m_dll;
+};
+
+class Libraries :
+  boost::noncopyable
+{
+public:
+
+  IDllWaylandClient & ClientLibrary();
+  IDllWaylandEGL & EGLLibrary();
+  IDllXKBCommon & XKBCommonLibrary();
+
+private:
+
+  AutoloadDll<IDllWaylandClient, DllWaylandClient> m_clientLibrary;
+  AutoloadDll<IDllWaylandEGL, DllWaylandEGL> m_eglLibrary;
+  AutoloadDll<IDllXKBCommon, DllXKBCommon> m_xkbCommonLibrary;
+};
+
+void LoadLibrary(DllDynamic &dll);
+
+template <class DllInterface, class Dll>
+AutoloadDll<DllInterface, Dll>::AutoloadDll()
+{
+  LoadLibrary(m_dll);
+}
+
+template <class DllInterface, class Dll>
+DllInterface &
+AutoloadDll<DllInterface, Dll>::Get()
+{
+  return m_dll;
+}
+
+template <class DllInterface, class Dll>
+AutoloadDll<DllInterface, Dll>::~AutoloadDll()
+{
+  m_dll.Unload();
+}
+}
+}
diff --git a/xbmc/windowing/egl/wayland/XBMCConnection.cpp b/xbmc/windowing/egl/wayland/XBMCConnection.cpp
new file mode 100644 (file)
index 0000000..6734ed5
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <algorithm>
+#include <sstream>
+#include <stdexcept>
+#include <queue>
+
+#include <boost/array.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <wayland-client.h>
+
+#include "guilib/Resolution.h"
+#include "guilib/gui3d.h"
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/DllXKBCommon.h"
+
+#include "Callback.h"
+#include "Compositor.h"
+#include "Display.h"
+#include "Output.h"
+#include "Registry.h"
+#include "Region.h"
+#include "Shell.h"
+
+#include "windowing/WaylandProtocol.h"
+#include "XBMCConnection.h"
+
+#include "windowing/wayland/Wayland11EventQueueStrategy.h"
+#include "windowing/wayland/Wayland12EventQueueStrategy.h"
+
+namespace xbmc
+{
+namespace wayland
+{
+/* A RemoteGlobalInterface just describes a pure virtual class
+ * which is an observer for Private::OnGlobalInterfaceAvailable
+ * when a new global interface appears on the compositor for the
+ * client to bind to */
+class RemoteGlobalInterface
+{
+public:
+
+  virtual ~RemoteGlobalInterface() {}
+  
+  struct Constructor
+  {
+    const char *interfaceName;
+    RemoteGlobalInterface *interface;
+  };
+  
+  virtual void OnObjectAvailable(uint32_t name, uint32_t version) = 0;
+};
+
+/* A GlobalInterface is a simple implementation of a
+ * RemoteGlobalInterface with OnObjectAvailable already implemented.
+ * 
+ * Users of this class are able to inject a custom function to be
+ * observe whenever an object becomes avilable to this class and can
+ * get a queue of all names available for the particular interface
+ * this class is asked to observe. The object name is effectively
+ * just a number referring to the global object ID on the compositor
+ * side that can be bound to by a client. */ 
+class GlobalInterface :
+  public RemoteGlobalInterface
+{
+public:
+
+  typedef boost::function<void(uint32_t version)> AvailabilityHook;
+
+protected:
+
+  GlobalInterface(const AvailabilityHook &hook) :
+    m_hook(hook)
+  {
+  }
+  
+  GlobalInterface()
+  {
+  }
+
+  std::queue<uint32_t> & ObjectsAvailable(uint32_t minimum);
+
+private:
+
+  virtual void OnObjectAvailable(uint32_t name, uint32_t version);
+
+  std::queue<uint32_t> m_availableNames;
+  uint32_t m_version;
+  AvailabilityHook m_hook;
+};
+
+/* A WaylandGlobalObject is a more complete implementation of
+ * GlobalInterface. It observes for when objects become available
+ * and provides a method to fetch-and-bind names on-demand.
+ * 
+ * Once FetchPending is called, the name is removed from the pending
+ * queue of GlobalInterface, bound to the interface provided and
+ * returned as an Implementation */
+template <typename Implementation>
+class WaylandGlobalObject :
+  public GlobalInterface
+{
+public:
+
+  WaylandGlobalObject(uint32_t minimum,
+                      struct wl_interface **interface) :
+    GlobalInterface(),
+    m_minimum(minimum),
+    m_interface(interface)
+  {
+  }
+  
+  WaylandGlobalObject(uint32_t minimum,
+                      struct wl_interface **interface,
+                      const AvailabilityHook &hook) :
+    GlobalInterface(hook),
+    m_minimum(minimum),
+    m_interface(interface)
+  {
+  }
+  
+  Implementation * FetchPending(Registry &registry);
+
+private:
+
+  uint32_t m_minimum;
+  struct wl_interface **m_interface;
+};
+
+/* A StoredGlobalInterface is an implementation of RemoteGlobalInterface
+ * which composes a WaylandGlobalObject internally.
+ * 
+ * This class takes a factory function to produce an Implementation *
+ * (usually a wrapper class of some sort) from a WaylandImplementation *
+ * (usually the defined wayland proxy object in the autogenerated
+ *  protocol).  It also has an alternate constructor that allows
+ * outside users to observe when an object has initially become available
+ * which is useful if it needs to be registered right away.
+ */
+template <typename Implementation, typename WaylandImplementation>
+class StoredGlobalInterface :
+  public RemoteGlobalInterface
+{
+public:
+
+  typedef boost::function<Implementation * (WaylandImplementation *)> Factory;
+  typedef std::vector<boost::shared_ptr<Implementation> > Implementations;
+  
+  /* Factory must be capable of returning a new Implementation *
+   * corresponding to a WaylandImplementation *. This is usually
+   * a wrapper class around that wayland object */
+  StoredGlobalInterface(const Factory &factory,
+                        uint32_t minimum,
+                        struct wl_interface **interface) :
+    m_waylandObject(minimum, interface),
+    m_factory(factory)
+  {
+  }
+
+  StoredGlobalInterface(const Factory &factory,
+                        uint32_t minimum,
+                        struct wl_interface **interface,
+                        const GlobalInterface::AvailabilityHook &hook) :
+    m_waylandObject(minimum, interface, hook),
+    m_factory(factory)
+  {
+  }
+  
+  ~StoredGlobalInterface()
+  {
+  }
+
+  /* These two functions always return constant values, although
+   * they might be required to create new Implementation objects
+   * by binding a global wayland object and wrapping it when they
+   * are initially called.
+   * 
+   * The first function always returns the first-available interface,
+   * the second function always returns the list of available global
+   * objects which have that interface */ 
+  Implementation & GetFirst(Registry &registry);
+  Implementations & Get(Registry &registry);
+
+private:
+
+  void OnObjectAvailable(uint32_t name,
+                         uint32_t version);
+
+  WaylandGlobalObject<WaylandImplementation> m_waylandObject;
+  Factory m_factory;
+  Implementations m_implementations;
+};
+
+class XBMCConnection::Private :
+  public IWaylandRegistration
+{
+public:
+
+  Private(IDllWaylandClient &clientLibrary,
+          IDllXKBCommon &xkbCommonLibrary,
+          EventInjector &eventInjector);
+  ~Private();
+
+  /* Synchronization entry point - call this function to issue a
+   * wl_display.sync request to the server. All this does is cause
+   * the server to send back an event that acknowledges the receipt
+   * of the request. However, it is useful in a number of circumstances
+   * - all request processing in wayland is sequential and guarunteed
+   * to be in the same order as requests were made. That means that
+   * once the event is received from the server, it is guarunteed
+   * that all requests made prior to the sync request have finished
+   * processing on the server and events have been issued to us.
+   * 
+   * Do not call this from a non-main thread. The main thread may be
+   * waiting for a wl_display.sync event to be coming through and this
+   * function will merely spin until synchronized == true, for which
+   * a non-main thread may be responsible for setting as true */
+  void WaitForSynchronize();
+  
+  wayland::Display & Display();
+  wayland::Compositor & Compositor();
+  wayland::Shell & Shell();
+  wayland::Output & Output();
+  
+private:
+
+  IDllWaylandClient &m_clientLibrary;
+  IDllXKBCommon &m_xkbCommonLibrary;
+  
+  EventInjector m_eventInjector;
+
+  /* Do not call this from a non-main thread. The main thread may be
+   * waiting for a wl_display.sync event to be coming through and this
+   * function will merely spin until synchronized == true, for which
+   * a non-main thread may be responsible for setting as true */
+  void Synchronize();
+
+  /* Synchronization logic - these variables should not be touched
+   * outside the scope of WaitForSynchronize() */
+  bool synchronized;
+  boost::scoped_ptr<Callback> synchronizeCallback;
+  
+  bool OnGlobalInterfaceAvailable(uint32_t name,
+                                  const char *interface,
+                                  uint32_t version);
+
+  void InjectSeat();
+
+  boost::scoped_ptr<wayland::Display> m_display;
+  boost::scoped_ptr<wayland::Registry> m_registry;
+  
+  StoredGlobalInterface<wayland::Compositor, struct wl_compositor> m_compositor;
+  StoredGlobalInterface<wayland::Shell, struct wl_shell> m_shell;
+  WaylandGlobalObject<struct wl_seat> m_seat;
+  StoredGlobalInterface<wayland::Output, struct wl_output> m_outputs;
+  
+  boost::scoped_ptr<events::IEventQueueStrategy> m_eventQueue;
+};
+}
+}
+
+namespace xw = xbmc::wayland;
+namespace xwe = xbmc::wayland::events;
+namespace xwe = xbmc::wayland::events;
+
+void
+xw::GlobalInterface::OnObjectAvailable(uint32_t name,
+                                       uint32_t version)
+{
+  m_availableNames.push(name);
+  m_version = version;
+  
+  if (!m_hook.empty())
+    m_hook(m_version);
+}
+
+std::queue<uint32_t> &
+xw::GlobalInterface::ObjectsAvailable(uint32_t minimum)
+{
+  if (m_version < minimum)
+  {
+    std::stringstream ss;
+    ss << "Interface version at least "
+       << minimum
+       << " is not available"
+       << " (less than version: "
+       << m_version
+       << ")";
+    throw std::runtime_error(ss.str());
+  }
+  
+  return m_availableNames;
+}
+
+template<typename Implementation>
+Implementation *
+xw::WaylandGlobalObject<Implementation>::FetchPending(Registry &registry)
+{
+  /* Pop any new names and bind them */
+  std::queue<uint32_t> &availableObjects(ObjectsAvailable(m_minimum));
+  if (!availableObjects.empty())
+  {
+    uint32_t name = availableObjects.front();
+    Implementation *proxy =
+      registry.Bind<Implementation *>(name,
+                                      m_interface,
+                                      m_minimum);
+    availableObjects.pop();
+    return proxy;
+  }
+  
+  return NULL;
+}
+
+template<typename Implementation, typename WaylandImplementation>
+void
+xw::StoredGlobalInterface<Implementation, WaylandImplementation>::OnObjectAvailable(uint32_t name, uint32_t version)
+{
+  RemoteGlobalInterface &rgi =
+    static_cast<RemoteGlobalInterface &>(m_waylandObject);
+  rgi.OnObjectAvailable(name, version);
+}
+
+template <typename Implementation, typename WaylandImplementation>
+typename xw::StoredGlobalInterface<Implementation, WaylandImplementation>::Implementations &
+xw::StoredGlobalInterface<Implementation, WaylandImplementation>::Get(Registry &registry)
+{
+  /* Instantiate any pending objects with this interface and then
+   * return the available implementations */
+  WaylandImplementation *proxy =
+    m_waylandObject.FetchPending(registry);
+  
+  while (proxy)
+  {
+    boost::shared_ptr<Implementation> instance(m_factory(proxy));
+    m_implementations.push_back(instance);
+    proxy = m_waylandObject.FetchPending(registry);
+  }
+
+  /* Calling Get() before we've received any notification that
+   * objects are available is a runtime_error and will be thrown as
+   * such.
+   * 
+   * Calling code that wishes to avoid this error should either
+   * insert a synchronization point right after creating the object
+   * registry or register a callback using the second constructor
+   * to observe when the object has become available before calling
+   * Get(). */
+  if (m_implementations.empty())
+    throw std::runtime_error("Remote interface not available");
+  
+  return m_implementations;
+}
+
+template <typename Implementation, typename WaylandImplementation>
+Implementation &
+xw::StoredGlobalInterface<Implementation, WaylandImplementation>::GetFirst(xw::Registry &registry)
+{
+  return *(Get(registry)[0]);
+}
+
+namespace
+{
+const std::string CompositorName("wl_compositor");
+const std::string ShellName("wl_shell");
+const std::string SeatName("wl_seat");
+const std::string OutputName("wl_output");
+
+/* These are functions that satisfy the definition of a "Factory"
+ * for the purposes of StoredGlobalInterface */
+xw::Compositor * CreateCompositor(struct wl_compositor *compositor,
+                                  IDllWaylandClient *clientLibrary)
+{
+  return new xw::Compositor(*clientLibrary, compositor);
+}
+
+xw::Output * CreateOutput(struct wl_output *output,
+                          IDllWaylandClient *clientLibrary)
+{
+  return new xw::Output(*clientLibrary, output);
+}
+
+xw::Shell * CreateShell(struct wl_shell *shell,
+                        IDllWaylandClient *clientLibrary)
+{
+  return new xw::Shell(*clientLibrary, shell);
+}
+
+bool ConstructorMatchesInterface(const xw::RemoteGlobalInterface::Constructor &constructor,
+                                 const char *interface)
+{
+  return std::strcmp(constructor.interfaceName,
+                     interface) < 0;
+}
+
+const unsigned int RequestedCompositorVersion = 1;
+const unsigned int RequestedShellVersion = 1;
+const unsigned int RequestedOutputVersion = 1;
+const unsigned int RequestedSeatVersion = 1;
+
+/* A deficiency in the client library in wayland versions prior to
+ * 1.2 means that there is divergent behaviour between versions here
+ * and this is explicitly expressed and encapsulated in these two
+ * strategies.
+ * 
+ * Because xbmc uses a game-loop, it is expected that no operation
+ * should block the main thread. This includes any operations to
+ * read the window system event queue. The main thread might be blocked
+ * for a prolonged period in the situation where the main xbmc surface
+ * is not visible, because the screen lock is active or another
+ * surface is obstructing it. When the main thread becomes blocked,
+ * it means that xbmc isn't able to start or stop any background jobs,
+ * which could interrupt library updates which occurr on idle or
+ * other such operations.
+ * 
+ * However, wayland versions prior to 1.2 had the expectation that
+ * clients expected to block if there were no incoming compositor
+ * events because it is part of wayland's design that the compositor
+ * is responsible for sending the events to drive a client's render
+ * and input loop. As such, on wayland <= 1.1, the expectation is that
+ * compositor event read and dispatch occurrs in the same thread and
+ * on wayland >= 1.2 the expectation is that these operations can
+ * occurr in multiple threads.
+ * 
+ * The following table illustrates these differences:
+ * 
+ * ---------------------------------------------------------------------
+ * | Wayland | Thread that  | Thread that | Thread that   | Strategy   |
+ * | Version | Reads happen | wrappers    | flush happens | Object     |
+ * |         | in           | operate in  |               |            |
+ * |         |              | in          |               |            |
+ * ---------------------------------------------------------------------
+ * | <= 1.1  | Poll Thread  | Poll Thread | Main Thread   | xw::versio-|
+ * |         |              |             |               | n11::Event-|
+ * |         |              |             |               | QueueStrat-|
+ * |         |              |             |               | egy        |
+ * ---------------------------------------------------------------------
+ * | >= 1.2  | Poll Thread  | Main Thread | Main Thread   | xw::versio-|
+ * |         |              |             |               | n12::Event-|
+ * |         |              |             |               | QueueStrat-|
+ * |         |              |             |               | egy        |
+ * ---------------------------------------------------------------------
+ * 
+ * The reason why it is different between the two versions it that it
+ * is generally desirable that the operation of all the wrapper objects
+ * occurr in the main thread, because there's less overhead in having
+ * to allocate temporary storage for their results in a queue so that
+ * they can be re-dispatched later. The plan is to eventually deprecate
+ * and remove support for wayland versions <= 1.1.
+ */
+xwe::IEventQueueStrategy *
+EventQueueForClientVersion(IDllWaylandClient &clientLibrary,
+                           struct wl_display *display)
+{
+  /* TODO: Test for wl_display_read_events / wl_display_prepare_read */
+  const bool version12 =
+    clientLibrary.wl_display_read_events_proc() &&
+    clientLibrary.wl_display_prepare_read_proc();
+  if (version12)
+    return new xw::version_12::EventQueueStrategy(clientLibrary,
+                                                  display);
+  else
+    return new xw::version_11::EventQueueStrategy(clientLibrary,
+                                                  display);
+}
+}
+
+/* Creating a new xbmc::wayland::XBMCConnection effectively creates
+ * a new xbmc::wayland::Display object, which in turn will connect
+ * to the running wayland compositor and encapsulate the return value
+ * from the client library. Then it creates a new
+ * xbmc::wayland::Registry object which is responsible for managing
+ * all of the global objects on the wayland connection that we might
+ * want to use. On creation of this object, a request is sent to
+ * the compositor to send back an event for every available global
+ * object. Once we know which objects exist, we can easily
+ * bind to them.
+ * 
+ * The WaitForSynchronize call at the end of the constructor is
+ * important. Once we make a request to the server for all of the
+ * available global objects, we need to know what they all are
+ * by the time this constructor finishes running so that the
+ * object will be complete. The only way to do that is to know
+ * when our wl_registry.add_listener request has finished processing
+ * on both the server and client side
+ */
+xw::XBMCConnection::Private::Private(IDllWaylandClient &clientLibrary,
+                                     IDllXKBCommon &xkbCommonLibrary,
+                                     EventInjector &eventInjector) :
+  m_clientLibrary(clientLibrary),
+  m_xkbCommonLibrary(xkbCommonLibrary),
+  m_eventInjector(eventInjector),
+  m_display(new xw::Display(clientLibrary)),
+  m_registry(new xw::Registry(clientLibrary,
+                              m_display->GetWlDisplay(),
+                              *this)),
+  m_compositor(boost::bind(CreateCompositor, _1, &m_clientLibrary),
+               RequestedCompositorVersion,
+               clientLibrary.Get_wl_compositor_interface()),
+  m_shell(boost::bind(CreateShell, _1, &m_clientLibrary),
+          RequestedShellVersion,
+          clientLibrary.Get_wl_shell_interface()),
+  m_seat(RequestedSeatVersion,
+         clientLibrary.Get_wl_seat_interface(),
+         boost::bind(&Private::InjectSeat, this)),
+  m_outputs(boost::bind(CreateOutput, _1, &m_clientLibrary),
+            RequestedOutputVersion,
+            clientLibrary.Get_wl_output_interface()),
+  m_eventQueue(EventQueueForClientVersion(m_clientLibrary,
+                                          m_display->GetWlDisplay()))
+{
+  /* Tell CWinEvents what our event queue is. That way
+   * CWinEvents::MessagePump is now able to dispatch events from
+   * the display whenever it is called */ 
+  (*m_eventInjector.setEventQueue)(*(m_eventQueue.get()));
+       
+  /* Wait only for the globals to appear, we will wait for
+   * initialization upon binding them */
+  WaitForSynchronize();
+}
+
+void
+xw::XBMCConnection::Private::InjectSeat()
+{
+  /* When the seat becomes available and bound, let CWinEventsWayland
+   * know about it so that it can wrap it and query it for more
+   * information about input devices */
+  struct wl_seat *seat = m_seat.FetchPending(*m_registry);
+  (*m_eventInjector.setWaylandSeat)(m_clientLibrary,
+                                    m_xkbCommonLibrary,
+                                    seat);
+}
+
+xw::XBMCConnection::Private::~Private()
+{
+  (*m_eventInjector.destroyWaylandSeat)();
+  (*m_eventInjector.destroyEventQueue)();
+}
+
+xw::XBMCConnection::XBMCConnection(IDllWaylandClient &clientLibrary,
+                                   IDllXKBCommon &xkbCommonLibrary,
+                                   EventInjector &eventInjector) :
+  priv(new Private (clientLibrary, xkbCommonLibrary, eventInjector))
+{
+}
+
+/* A defined destructor is required such that
+ * boost::scoped_ptr<Private>::~scoped_ptr is generated here */
+xw::XBMCConnection::~XBMCConnection()
+{
+}
+
+xw::Display &
+xw::XBMCConnection::Private::Display()
+{
+  return *m_display;
+}
+
+xw::Compositor &
+xw::XBMCConnection::Private::Compositor()
+{
+  return m_compositor.GetFirst(*m_registry);
+}
+
+xw::Shell &
+xw::XBMCConnection::Private::Shell()
+{
+  return m_shell.GetFirst(*m_registry);
+}
+
+xw::Output &
+xw::XBMCConnection::Private::Output()
+{
+  xw::Output &output(m_outputs.GetFirst(*m_registry));
+  
+  /* Wait for synchronize upon lazy-binding the first output
+   * and then check if we got any modes */
+  WaitForSynchronize();
+  if (output.AllModes().empty())
+  {
+    std::stringstream ss;
+    ss << "No modes detected on first output";
+    throw std::runtime_error(ss.str());
+  }
+  return output;
+}
+
+/* Once an object becomes available, we need to take note of that
+ * fact and store its interface information somewhere. We then
+ * call a function to indicate to any interested observer that the
+ * object is available and can be bound to. Callers might not do this
+ * right away. */
+bool
+xw::XBMCConnection::Private::OnGlobalInterfaceAvailable(uint32_t name,
+                                                        const char *interface,
+                                                        uint32_t version)
+{
+  /* A boost::array is effectively immutable so we can leave out
+   * const here */
+  typedef boost::array<RemoteGlobalInterface::Constructor, 4> ConstructorArray;
+
+  
+  /* Not static, as the pointers here may change in cases where
+   * Private is re-constructed.
+   * 
+   * These are sorted into alphabetical order so that we can do
+   * a simple binary search for them. */
+  ConstructorArray constructors =
+  {
+    {
+      { CompositorName.c_str(), &m_compositor },
+      { OutputName.c_str(), &m_outputs },
+      { SeatName.c_str(), &m_seat },
+      { ShellName.c_str(), &m_shell }
+    }
+  };
+
+  /* Simple binary search for a known object constructor that matches
+   * this interface */
+  ConstructorArray::iterator it(std::lower_bound(constructors.begin(),
+                                                 constructors.end(),
+                                                 interface,
+                                                 ConstructorMatchesInterface));
+  if (it != constructors.end() &&
+      strcmp(it->interfaceName, interface) == 0)
+  {
+    it->interface->OnObjectAvailable(name, version);
+    return true;
+  }
+  
+  return false;
+}
+
+void xw::XBMCConnection::Private::WaitForSynchronize()
+{
+  boost::function<void(uint32_t)> func(boost::bind(&Private::Synchronize,
+                                                   this));
+  
+  synchronized = false;
+  synchronizeCallback.reset(new xw::Callback(m_clientLibrary,
+                                             m_display->Sync(),
+                                             func));
+
+  /* For version 1.1 event queues the effect of this is going to be
+   * a spin-wait. That's not exactly ideal, but we do need to
+   * continuously flush the event queue */
+  while (!synchronized)
+    (*m_eventInjector.messagePump)();
+}
+
+void xw::XBMCConnection::Private::Synchronize()
+{
+  synchronized = true;
+  synchronizeCallback.reset();
+}
+
+namespace
+{
+void ResolutionInfoForMode(const xw::Output::ModeGeometry &mode,
+                           RESOLUTION_INFO &res)
+{
+  res.iWidth = mode.width;
+  res.iHeight = mode.height;
+  
+  /* The refresh rate is given as an integer in the second exponent
+   * so we need to divide by 100.0f to get a floating point value */
+  res.fRefreshRate = mode.refresh / 100.0f;
+  res.dwFlags = D3DPRESENTFLAG_PROGRESSIVE;
+  res.iScreen = 0;
+  res.bFullScreen = true;
+  res.iSubtitles = static_cast<int>(0.965 * res.iHeight);
+  res.fPixelRatio = 1.0f;
+  res.iScreenWidth = res.iWidth;
+  res.iScreenHeight = res.iHeight;
+  res.strMode.Format("%dx%d @ %.2fp",
+                     res.iScreenWidth,
+                     res.iScreenHeight,
+                     res.fRefreshRate);
+}
+}
+
+void
+xw::XBMCConnection::CurrentResolution(RESOLUTION_INFO &res) const
+{
+  /* Supporting only the first output device at the moment */
+  const xw::Output::ModeGeometry &current(priv->Output().CurrentMode());
+  
+  ResolutionInfoForMode(current, res);
+}
+
+void
+xw::XBMCConnection::PreferredResolution(RESOLUTION_INFO &res) const
+{
+  /* Supporting only the first output device at the moment */
+  const xw::Output::ModeGeometry &preferred(priv->Output().PreferredMode());
+  ResolutionInfoForMode(preferred, res);
+}
+
+void
+xw::XBMCConnection::AvailableResolutions(std::vector<RESOLUTION_INFO> &resolutions) const
+{
+  /* Supporting only the first output device at the moment */
+  xw::Output &output(priv->Output());
+  const std::vector<xw::Output::ModeGeometry> &m_modes(output.AllModes());
+
+  for (std::vector<xw::Output::ModeGeometry>::const_iterator it = m_modes.begin();
+       it != m_modes.end();
+       ++it)
+  {
+    resolutions.push_back(RESOLUTION_INFO());
+    RESOLUTION_INFO &back(resolutions.back());
+    
+    ResolutionInfoForMode(*it, back);
+  }
+}
+
+EGLNativeDisplayType *
+xw::XBMCConnection::NativeDisplay() const
+{
+  return priv->Display().GetEGLNativeDisplay();
+}
+
+xw::Compositor &
+xw::XBMCConnection::GetCompositor()
+{
+  return priv->Compositor();
+}
+
+xw::Shell &
+xw::XBMCConnection::GetShell()
+{
+  return priv->Shell();
+}
+
+xw::Output &
+xw::XBMCConnection::GetFirstOutput()
+{
+  return priv->Output();
+}
diff --git a/xbmc/windowing/egl/wayland/XBMCConnection.h b/xbmc/windowing/egl/wayland/XBMCConnection.h
new file mode 100644 (file)
index 0000000..45c0c29
--- /dev/null
@@ -0,0 +1,93 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+
+class IDllWaylandClient;
+class IDllXKBCommon;
+
+struct wl_compositor;
+struct wl_display;
+struct wl_output;
+struct wl_shell;
+struct wl_seat;
+
+typedef struct wl_egl_window * EGLNativeWindowType;
+
+struct RESOLUTION_INFO;
+
+namespace xbmc
+{
+namespace wayland
+{
+class Compositor;
+class Output;
+class Shell;
+
+namespace events
+{
+class IEventQueueStrategy;
+}
+
+class XBMCConnection
+{
+public:
+
+  struct EventInjector
+  {
+    typedef void (*SetEventQueue)(events::IEventQueueStrategy &strategy);
+    typedef void (*DestroyEventQueue)();
+    typedef void (*SetWaylandSeat)(IDllWaylandClient &clientLibrary,
+                                   IDllXKBCommon &xkbCommonLibrary,
+                                   struct wl_seat *seat);
+    typedef void (*DestroyWaylandSeat)();
+    typedef bool (*MessagePump)();
+    
+    SetEventQueue setEventQueue;
+    DestroyEventQueue destroyEventQueue;
+    SetWaylandSeat setWaylandSeat;
+    DestroyWaylandSeat destroyWaylandSeat;
+    MessagePump messagePump;
+  };
+
+  XBMCConnection(IDllWaylandClient &clientLibrary,
+                 IDllXKBCommon &xkbCommonLibrary,
+                 EventInjector &injector);
+  ~XBMCConnection();
+  
+  void PreferredResolution(RESOLUTION_INFO &res) const;
+  void CurrentResolution(RESOLUTION_INFO &res) const;
+  void AvailableResolutions(std::vector<RESOLUTION_INFO> &res) const;
+  
+  EGLNativeDisplayType * NativeDisplay() const;
+  
+  Compositor & GetCompositor();
+  Shell & GetShell();
+  Output & GetFirstOutput();
+  
+private:
+
+  class Private;
+  boost::scoped_ptr<Private> priv;
+};
+}
+}
diff --git a/xbmc/windowing/egl/wayland/XBMCSurface.cpp b/xbmc/windowing/egl/wayland/XBMCSurface.cpp
new file mode 100644 (file)
index 0000000..47d8830
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <sstream>
+#include <stdexcept>
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/DllWaylandEgl.h"
+
+#include "Callback.h"
+#include "Compositor.h"
+#include "OpenGLSurface.h"
+#include "Output.h"
+#include "Region.h"
+#include "Shell.h"
+#include "ShellSurface.h"
+#include "Surface.h"
+
+#include "windowing/WaylandProtocol.h"
+#include "XBMCSurface.h"
+
+namespace xbmc
+{
+namespace wayland
+{
+class XBMCSurface::Private
+{
+public:
+
+  Private(IDllWaylandClient &clientLibrary,
+          IDllWaylandEGL &eglLibrary,
+          const EventInjector &eventInjector,
+          Compositor &compositor,
+          Shell &shell,
+          uint32_t width,
+          uint32_t height);
+
+  typedef boost::function<struct wl_region * ()> RegionFactory;
+
+  IDllWaylandClient &m_clientLibrary;
+  IDllWaylandEGL &m_eglLibrary;
+  
+  EventInjector m_eventInjector;
+
+  /* We only care about xbmc::Compositor's CreateRegion function
+   * and don't want to store a pointer to the compositor to create
+   * a region later */ 
+  RegionFactory m_regionFactory;
+
+  boost::scoped_ptr<Surface> m_surface;
+  boost::scoped_ptr<ShellSurface> m_shellSurface;
+  boost::scoped_ptr<OpenGLSurface> m_glSurface;
+  boost::scoped_ptr<Callback> m_frameCallback;
+  
+  void OnFrameCallback(uint32_t);
+  void AddFrameCallback();
+};
+}
+}
+
+namespace xw = xbmc::wayland;
+
+/* Creating a new xbmc::wayland::XBMCSurface effectively creates
+ * an OpenGL ES bindable EGL Window and a corresponding 
+ * surface object for the compositor to display it on-screen. It also
+ * creates a "shell surface", which is a special extension to a normal
+ * surface which adds window-management functionality to a surface.
+ * 
+ * If there are any errors in creating the surface they will be thrown
+ * as std::runtime_errors and the object that creates this one
+ * needs to handle catching them.
+ */
+xw::XBMCSurface::Private::Private(IDllWaylandClient &clientLibrary,
+                                  IDllWaylandEGL &eglLibrary,
+                                  const EventInjector &eventInjector,
+                                  Compositor &compositor,
+                                  Shell &shell,
+                                  uint32_t width,
+                                  uint32_t height) :
+  m_clientLibrary(clientLibrary),
+  m_eglLibrary(eglLibrary),
+  m_eventInjector(eventInjector),
+  m_regionFactory(boost::bind(&Compositor::CreateRegion,
+                              &compositor)),
+  m_surface(new xw::Surface(m_clientLibrary,
+                            compositor.CreateSurface())),
+  m_shellSurface(new xw::ShellSurface(m_clientLibrary,
+                                      shell.CreateShellSurface(
+                                        m_surface->GetWlSurface()))),
+  /* Creating a new xbmc::wayland::OpenGLSurface will manage the
+   * attach-and-commit process on eglSwapBuffers */
+  m_glSurface(new xw::OpenGLSurface(m_eglLibrary,
+                                    m_surface->GetWlSurface(),
+                                    width,
+                                    height))
+{
+  /* SetOpaqueRegion here is an important optimization for the
+   * compositor. It effectively tells it that this window is completely
+   * opaque. This means that the window can be rendered without
+   * the use of GL_BLEND which represents a substantial rendering
+   * speedup, especially for larger surfaces. It also means that
+   * this window can be placed in an overlay plane, so it can
+   * skip compositing alltogether */
+  xw::Region region(m_clientLibrary, m_regionFactory());
+  
+  region.AddRectangle(0, 0, 640, 480);
+  
+  m_surface->SetOpaqueRegion(region.GetWlRegion());
+  m_surface->Commit();
+  
+  /* The compositor is responsible for letting us know when to
+   * draw things. This is effectively to conserve battery life
+   * where drawing our surface would be a futile operation. Its not
+   * entirely applicable to the xbmc case because we use a game loop,
+   * but some compositor expect it, so we must add a frame callback
+   * as soon as the surface is ready to be rendered to */ 
+  AddFrameCallback();
+  
+  (*m_eventInjector.setXBMCSurface)(m_surface->GetWlSurface());
+}
+
+xw::XBMCSurface::XBMCSurface(IDllWaylandClient &clientLibrary,
+                             IDllWaylandEGL &eglLibrary,
+                             const EventInjector &eventInjector,
+                             Compositor &compositor,
+                             Shell &shell,
+                             uint32_t width,
+                             uint32_t height) :
+  priv(new Private(clientLibrary,
+                   eglLibrary,
+                   eventInjector,
+                   compositor,
+                   shell,
+                   width,
+                   height))
+{
+}
+
+/* A defined destructor is required such that
+ * boost::scoped_ptr<Private>::~scoped_ptr is generated here */
+xw::XBMCSurface::~XBMCSurface()
+{
+}
+
+void
+xw::XBMCSurface::Show(xw::Output &output)
+{ 
+  /* Calling SetFullscreen will implicitly show the surface, center
+   * it as full-screen on the selected output and change the resolution
+   * of the output so as to fit as much of the surface as possible
+   * without adding black bars.
+   * 
+   * While the surface is fullscreen, any attempt to resize it will
+   * result in the resolution changing to the nearest match */
+  priv->m_shellSurface->SetFullscreen(WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER,
+                                      0,
+                                      output.GetWlOutput());
+}
+
+void
+xw::XBMCSurface::Resize(uint32_t width, uint32_t height)
+{
+  /* Since the xbmc::wayland::OpenGLSurface owns the buffer, it is
+   * responsible for changing its size. When the size changes, the
+   * opaque region must also change */
+  priv->m_glSurface->Resize(width, height);
+  
+  xw::Region region(priv->m_clientLibrary,
+                    priv->m_regionFactory());
+  
+  region.AddRectangle(0, 0, width, height);
+  
+  priv->m_surface->SetOpaqueRegion(region.GetWlRegion());
+  priv->m_surface->Commit();
+}
+
+EGLNativeWindowType *
+xw::XBMCSurface::EGLNativeWindow() const
+{
+  return priv->m_glSurface->GetEGLNativeWindow();
+}
+
+void xw::XBMCSurface::Private::OnFrameCallback(uint32_t time)
+{
+  AddFrameCallback();
+}
+
+void xw::XBMCSurface::Private::AddFrameCallback()
+{
+  m_frameCallback.reset(new xw::Callback(m_clientLibrary,
+                                         m_surface->CreateFrameCallback(),
+                                         boost::bind(&Private::OnFrameCallback,
+                                                     this,
+                                                     _1)));
+}
diff --git a/xbmc/windowing/egl/wayland/XBMCSurface.h b/xbmc/windowing/egl/wayland/XBMCSurface.h
new file mode 100644 (file)
index 0000000..64af908
--- /dev/null
@@ -0,0 +1,74 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+
+class IDllWaylandClient;
+class IDllWaylandEGL;
+
+struct wl_region;
+
+typedef struct wl_egl_window * EGLNativeWindowType;
+
+namespace xbmc
+{
+namespace wayland
+{
+class Callback;
+class Compositor;
+class OpenGLSurface;
+class Output;
+class Shell;
+class ShellSurface;
+class Surface;
+
+class XBMCSurface
+{
+public:
+
+  struct EventInjector
+  {
+    typedef void (*SetXBMCSurface)(struct wl_surface *);
+    
+    SetXBMCSurface setXBMCSurface;
+  };
+
+  XBMCSurface(IDllWaylandClient &clientLibrary,
+              IDllWaylandEGL &eglLibrary,
+              const EventInjector &eventInjector,
+              Compositor &compositor,
+              Shell &shell,
+              uint32_t width,
+              uint32_t height);
+  ~XBMCSurface();
+
+  void Show(Output &output);
+  void Resize(uint32_t width, uint32_t height);
+  EGLNativeWindowType * EGLNativeWindow() const;
+
+private:
+
+  class Private;
+  boost::scoped_ptr<Private> priv;
+};
+}
+}
diff --git a/xbmc/windowing/tests/wayland/Makefile.in b/xbmc/windowing/tests/wayland/Makefile.in
new file mode 100644 (file)
index 0000000..5c1690b
--- /dev/null
@@ -0,0 +1,51 @@
+ifeq (@USE_WAYLAND@,1)
+SRCS = StubCursorManager.cpp \
+       StubEventListener.cpp \
+       TestEGLNativeTypeWayland.cpp \
+       TestWaylandInputUnit.cpp \
+       TestXBMCWaylandInputAcceptance.cpp \
+       TmpEnv.cpp \
+       WestonProcess.cpp \
+       WestonTest.cpp \
+       XBMCWayland.cpp
+
+WAYLAND_TEST_MODULE_PROTOCOL = protocol.xml
+WAYLAND_TEST_MODULE_PROTOCOL_SRCS = xbmc_wayland_test_protocol.c
+WAYLAND_TEST_MODULE_PROTOCOL_GENERATED_SRCS = $(WAYLAND_TEST_MODULE_PROTOCOL_SRCS)
+WAYLAND_TEST_MODULE_PROTOCOL_GENERATED_SRCS += xbmc_wayland_test_server_protocol.h
+WAYLAND_TEST_MODULE_PROTOCOL_GENERATED_SRCS += xbmc_wayland_test_client_protocol.h
+WAYLAND_TEST_MODULE_SRCS = XBMCWaylandTestExtension.cpp
+
+INCLUDES += -I@abs_top_srcdir@/lib/gtest/include -I@WAYLAND_TEST_INCLUDES@
+LIB = test_wayland.a
+
+ifneq (,@WAYLAND_SCANNER@)
+SRCS += $(WAYLAND_TEST_MODULE_PROTOCOL_SRCS)
+endif
+
+CLEAN_FILES += $(WAYLAND_TEST_MODULE_PROTOCOL_GENERATED_SRCS) xbmc-wayland-test-extension.so
+
+include @abs_top_srcdir@/Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(patsubst %.h,%.P,$(SRCS))))
+
+ifneq (,@WAYLAND_SCANNER@)
+TestEGLNativeTypeWayland.cpp : xbmc_wayland_test_client_protocol.h
+
+$(WAYLAND_TEST_MODULE_SRCS) : $(WAYLAND_TEST_MODULE_PROTOCOL_GENERATED_SRCS)
+
+xbmc_wayland_test_protocol.c: $(WAYLAND_TEST_MODULE_PROTOCOL)
+       @WAYLAND_SCANNER@ code < $< > $@
+
+xbmc_wayland_test_server_protocol.h: $(WAYLAND_TEST_MODULE_PROTOCOL)
+       @WAYLAND_SCANNER@ server-header < $< > $@
+
+xbmc_wayland_test_client_protocol.h: $(WAYLAND_TEST_MODULE_PROTOCOL)
+       @WAYLAND_SCANNER@ client-header < $< > $@
+
+ifeq (@USE_WAYLAND_TEST_EXTENSION@,1)
+xbmc-wayland-test-extension.so: $(WAYLAND_TEST_MODULE_PROTOCOL_SRCS:.c=.o) $(WAYLAND_TEST_MODULE_SRCS:.cpp=.o)
+       $(SILENT_LD) $(CXX) $(CXXFLAGS) $(LDFLAGS) $(WAYLAND_TEST_LIBS) -shared -o $@ $+ -rdynamic
+endif
+
+endif
+endif
diff --git a/xbmc/windowing/tests/wayland/StubCursorManager.cpp b/xbmc/windowing/tests/wayland/StubCursorManager.cpp
new file mode 100644 (file)
index 0000000..1afe103
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include "StubCursorManager.h"
+
+void
+StubCursorManager::SetCursor(uint32_t serial,
+                             struct wl_surface *surface,
+                             double surfaceX,
+                             double surfaceY)
+{
+}
diff --git a/xbmc/windowing/tests/wayland/StubCursorManager.h b/xbmc/windowing/tests/wayland/StubCursorManager.h
new file mode 100644 (file)
index 0000000..819ea4c
--- /dev/null
@@ -0,0 +1,35 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <windowing/wayland/CursorManager.h>
+
+struct wl_surface;
+
+class StubCursorManager :
+  public xbmc::ICursorManager
+{
+public:
+
+  void SetCursor(uint32_t serial,
+                 struct wl_surface *surface,
+                 double surfaceX,
+                 double surfaceY);
+};
diff --git a/xbmc/windowing/tests/wayland/StubEventListener.cpp b/xbmc/windowing/tests/wayland/StubEventListener.cpp
new file mode 100644 (file)
index 0000000..6e5f034
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <stdexcept>
+
+#include "StubEventListener.h"
+
+StubEventListener::StubEventListener() :
+  m_focused(false)
+{
+}
+
+XBMC_Event
+StubEventListener::FetchLastEvent()
+{
+  if (m_events.empty())
+    throw std::logic_error("No events left to get!");
+  
+  XBMC_Event ev = m_events.front();
+  m_events.pop();
+  return ev;
+}
+
+bool
+StubEventListener::Focused()
+{
+  return m_focused;
+}
+
+void
+StubEventListener::OnFocused()
+{
+  m_focused = true;
+}
+
+void
+StubEventListener::OnUnfocused()
+{
+  m_focused = false;
+}
+
+void
+StubEventListener::OnEvent(XBMC_Event &ev)
+{
+  m_events.push(ev);
+}
diff --git a/xbmc/windowing/tests/wayland/StubEventListener.h b/xbmc/windowing/tests/wayland/StubEventListener.h
new file mode 100644 (file)
index 0000000..21f0a21
--- /dev/null
@@ -0,0 +1,45 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <queue>
+
+#include "windowing/wayland/EventListener.h"
+
+class StubEventListener :
+  public xbmc::IEventListener
+{
+public:
+
+  StubEventListener();
+
+  /* Returns front of event queue, otherwise throws */
+  XBMC_Event FetchLastEvent();
+  bool Focused();
+
+private:
+
+  void OnFocused();
+  void OnUnfocused();
+  void OnEvent(XBMC_Event &);
+
+  bool m_focused;
+  std::queue<XBMC_Event> m_events;
+};
diff --git a/xbmc/windowing/tests/wayland/TestEGLNativeTypeWayland.cpp b/xbmc/windowing/tests/wayland/TestEGLNativeTypeWayland.cpp
new file mode 100644 (file)
index 0000000..945717e
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include "system.h"
+
+#define WL_EGL_PLATFORM
+
+#include <string>
+#include <vector>
+
+#include <boost/bind.hpp>
+
+#include <gtest/gtest.h>
+
+#include <wayland-client.h>
+#include <wayland-client-protocol.h>
+
+#if defined(HAVE_WAYLAND_XBMC_PROTO)
+#include "xbmc_wayland_test_client_protocol.h"
+#endif
+
+#include "windowing/egl/wayland/Display.h"
+#include "windowing/egl/wayland/Registry.h"
+#include "windowing/egl/wayland/Surface.h"
+#include "windowing/egl/EGLNativeTypeWayland.h"
+
+#include "TmpEnv.h"
+#include "WestonTest.h"
+#include "XBMCWayland.h"
+
+using ::testing::Values;
+using ::testing::WithParamInterface;
+
+namespace xt = xbmc::test;
+namespace xw = xbmc::wayland;
+namespace xtw = xbmc::test::wayland;
+
+class EGLNativeTypeWaylandWestonTest :
+  public WestonTest
+{
+protected:
+
+  CEGLNativeTypeWayland m_nativeType;
+};
+
+TEST_F(EGLNativeTypeWaylandWestonTest, TestCheckCompatibilityWithEnvSet)
+{
+  TmpEnv env("WAYLAND_DISPLAY", TempSocketName().c_str());
+  EXPECT_TRUE(m_nativeType.CheckCompatibility());
+}
+
+TEST_F(EGLNativeTypeWaylandWestonTest, TestCheckCompatibilityWithEnvNotSet)
+{
+  EXPECT_FALSE(m_nativeType.CheckCompatibility());
+}
+
+class CompatibleEGLNativeTypeWaylandWestonTest :
+  public EGLNativeTypeWaylandWestonTest
+{
+public:
+
+  CompatibleEGLNativeTypeWaylandWestonTest();
+  virtual void SetUp();
+  
+private:
+
+  TmpEnv m_waylandDisplayEnv;
+};
+
+CompatibleEGLNativeTypeWaylandWestonTest::CompatibleEGLNativeTypeWaylandWestonTest() :
+  m_waylandDisplayEnv("WAYLAND_DISPLAY",
+                      TempSocketName().c_str())
+{
+}
+
+void
+CompatibleEGLNativeTypeWaylandWestonTest::SetUp()
+{
+  WestonTest::SetUp();
+  ASSERT_TRUE(m_nativeType.CheckCompatibility());
+}
+
+TEST_F(CompatibleEGLNativeTypeWaylandWestonTest, TestConnection)
+{
+  EXPECT_TRUE(m_nativeType.CreateNativeDisplay());
+}
+
+class ConnectedEGLNativeTypeWaylandWestonTest :
+  public CompatibleEGLNativeTypeWaylandWestonTest
+{
+public:
+
+  ConnectedEGLNativeTypeWaylandWestonTest();
+  ~ConnectedEGLNativeTypeWaylandWestonTest();
+  virtual void SetUp();
+
+protected:
+
+  xw::Display *m_display;
+  struct wl_surface *m_mostRecentSurface;
+
+private:
+
+  void Global(struct wl_registry *, uint32_t, const char *, uint32_t);
+  void DisplayAvailable(xw::Display &display);
+  void SurfaceCreated(xw::Surface &surface);
+};
+
+ConnectedEGLNativeTypeWaylandWestonTest::ConnectedEGLNativeTypeWaylandWestonTest()
+{
+  xw::WaylandDisplayListener &displayListener(xw::WaylandDisplayListener::GetInstance());
+  displayListener.SetHandler(boost::bind(&ConnectedEGLNativeTypeWaylandWestonTest::DisplayAvailable,
+                                         this, _1));
+
+  xw::WaylandSurfaceListener &surfaceListener(xw::WaylandSurfaceListener::GetInstance());
+  surfaceListener.SetHandler(boost::bind(&ConnectedEGLNativeTypeWaylandWestonTest::SurfaceCreated,
+                                         this, _1));
+}
+
+ConnectedEGLNativeTypeWaylandWestonTest::~ConnectedEGLNativeTypeWaylandWestonTest()
+{
+  xw::WaylandDisplayListener &displayListener(xw::WaylandDisplayListener::GetInstance());
+  displayListener.SetHandler(xw::WaylandDisplayListener::Handler());
+  
+  xw::WaylandSurfaceListener &surfaceListener(xw::WaylandSurfaceListener::GetInstance());
+  surfaceListener.SetHandler(xw::WaylandSurfaceListener::Handler());
+}
+
+void
+ConnectedEGLNativeTypeWaylandWestonTest::SetUp()
+{
+  CompatibleEGLNativeTypeWaylandWestonTest::SetUp();
+  ASSERT_TRUE(m_nativeType.CreateNativeDisplay());
+}
+
+void
+ConnectedEGLNativeTypeWaylandWestonTest::DisplayAvailable(xw::Display &display)
+{
+  m_display = &display;
+}
+
+void
+ConnectedEGLNativeTypeWaylandWestonTest::SurfaceCreated(xw::Surface &surface)
+{
+  m_mostRecentSurface = surface.GetWlSurface();
+}
+
+TEST_F(ConnectedEGLNativeTypeWaylandWestonTest, CreateNativeWindowSuccess)
+{
+  EXPECT_TRUE(m_nativeType.CreateNativeWindow());
+}
+
+TEST_F(ConnectedEGLNativeTypeWaylandWestonTest, ProbeResolutionsSuccess)
+{
+  std::vector<RESOLUTION_INFO> info;
+  EXPECT_TRUE(m_nativeType.ProbeResolutions(info));
+}
+
+TEST_F(ConnectedEGLNativeTypeWaylandWestonTest, PreferredResolutionSuccess)
+{
+  RESOLUTION_INFO info;
+  EXPECT_TRUE(m_nativeType.GetPreferredResolution(&info));
+}
+
+TEST_F(ConnectedEGLNativeTypeWaylandWestonTest, CurrentNativeSuccess)
+{
+  RESOLUTION_INFO info;
+  EXPECT_TRUE(m_nativeType.GetNativeResolution(&info));
+}
+
+TEST_F(ConnectedEGLNativeTypeWaylandWestonTest, GetMostRecentSurface)
+{
+  m_nativeType.CreateNativeWindow();
+  EXPECT_TRUE(m_mostRecentSurface != NULL);
+}
+
+#if defined(HAVE_WAYLAND_XBMC_PROTO)
+
+class AssistedEGLNativeTypeWaylandTest :
+  public ConnectedEGLNativeTypeWaylandWestonTest
+{
+protected:
+
+  AssistedEGLNativeTypeWaylandTest();
+  ~AssistedEGLNativeTypeWaylandTest();
+
+  virtual void SetUp();
+  
+  void Global(struct wl_registry *registry,
+              uint32_t name,
+              const char *interface,
+              uint32_t version);
+  
+  boost::scoped_ptr<xtw::XBMCWayland> m_xbmcWayland;
+};
+
+AssistedEGLNativeTypeWaylandTest::AssistedEGLNativeTypeWaylandTest()
+{
+  xw::ExtraWaylandGlobals &extra(xw::ExtraWaylandGlobals::GetInstance());
+  extra.SetHandler(boost::bind(&AssistedEGLNativeTypeWaylandTest::Global,
+                               this, _1, _2, _3, _4));
+}
+
+AssistedEGLNativeTypeWaylandTest::~AssistedEGLNativeTypeWaylandTest()
+{
+  xw::ExtraWaylandGlobals &extra(xw::ExtraWaylandGlobals::GetInstance());
+  extra.SetHandler(xw::ExtraWaylandGlobals::GlobalHandler());
+}
+
+void
+AssistedEGLNativeTypeWaylandTest::SetUp()
+{
+  ConnectedEGLNativeTypeWaylandWestonTest::SetUp();
+  ASSERT_TRUE(m_xbmcWayland.get());
+}
+
+void
+AssistedEGLNativeTypeWaylandTest::Global(struct wl_registry *registry,
+                                         uint32_t name,
+                                         const char *interface,
+                                         uint32_t version)
+{
+  if (std::string(interface) == "xbmc_wayland")
+    m_xbmcWayland.reset(new xtw::XBMCWayland(static_cast<xbmc_wayland *>(wl_registry_bind(registry,
+                                                                                          name,
+                                                                                          &xbmc_wayland_interface,
+                                                                                          version))));
+}
+
+TEST_F(AssistedEGLNativeTypeWaylandTest, TestGotXBMCWayland)
+{
+  EXPECT_TRUE(m_xbmcWayland.get() != NULL);
+}
+
+TEST_F(AssistedEGLNativeTypeWaylandTest, AdditionalResolutions)
+{
+  m_xbmcWayland->AddMode(2, 2, 2, static_cast<enum wl_output_mode>(0));
+  std::vector<RESOLUTION_INFO> resolutions;
+  m_nativeType.ProbeResolutions(resolutions);
+  EXPECT_TRUE(resolutions.size() == 2);
+}
+
+TEST_F(AssistedEGLNativeTypeWaylandTest, PreferredResolutionChange)
+{
+  m_xbmcWayland->AddMode(2, 2, 2, static_cast<enum wl_output_mode>(WL_OUTPUT_MODE_PREFERRED));
+  RESOLUTION_INFO res;
+  m_nativeType.GetPreferredResolution(&res);
+  EXPECT_EQ(res.iWidth, 2);
+  EXPECT_EQ(res.iHeight, 2);
+}
+
+TEST_F(AssistedEGLNativeTypeWaylandTest, CurrentResolutionChange)
+{
+  m_xbmcWayland->AddMode(2, 2, 2, static_cast<enum wl_output_mode>(WL_OUTPUT_MODE_CURRENT));
+  RESOLUTION_INFO res;
+  m_nativeType.GetNativeResolution(&res);
+  EXPECT_EQ(res.iWidth, 2);
+  EXPECT_EQ(res.iHeight, 2);
+}
+
+#endif
diff --git a/xbmc/windowing/tests/wayland/TestWaylandInputUnit.cpp b/xbmc/windowing/tests/wayland/TestWaylandInputUnit.cpp
new file mode 100644 (file)
index 0000000..8c3b4d4
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <tr1/tuple>
+
+#include <gtest/gtest.h>
+
+#include <wayland-client-protocol.h>
+
+#include "windowing/wayland/Pointer.h"
+#include "windowing/wayland/PointerProcessor.h"
+
+#include "StubCursorManager.h"
+#include "StubEventListener.h"
+
+using ::testing::Values;
+using ::testing::WithParamInterface;
+
+namespace xw = xbmc::wayland;
+
+class WaylandPointerProcessor :
+  public ::testing::Test
+{
+public:
+
+  WaylandPointerProcessor();
+
+protected:
+
+  StubCursorManager cursorManager;
+  StubEventListener listener;
+  xbmc::PointerProcessor processor;
+};
+
+WaylandPointerProcessor::WaylandPointerProcessor() :
+  processor(listener, cursorManager)
+{
+}
+
+class WaylandPointerProcessorButtons :
+  public WaylandPointerProcessor,
+  public WithParamInterface<std::tr1::tuple<uint32_t, uint32_t> >
+{
+protected:
+
+  uint32_t WaylandButton();
+  uint32_t XBMCButton();
+};
+
+uint32_t WaylandPointerProcessorButtons::WaylandButton()
+{
+  return std::tr1::get<0>(GetParam());
+}
+
+uint32_t WaylandPointerProcessorButtons::XBMCButton()
+{
+  return std::tr1::get<1>(GetParam());
+}
+
+TEST_P(WaylandPointerProcessorButtons, ButtonPress)
+{
+  xw::IPointerReceiver &receiver =
+    static_cast<xw::IPointerReceiver &>(processor);
+  receiver.Button(0, 0, WaylandButton(), WL_POINTER_BUTTON_STATE_PRESSED);
+  
+  XBMC_Event event(listener.FetchLastEvent());
+  EXPECT_EQ(XBMC_MOUSEBUTTONDOWN, event.type);
+  EXPECT_EQ(XBMCButton(), event.button.button);
+}
+
+TEST_P(WaylandPointerProcessorButtons, ButtonRelease)
+{
+  xw::IPointerReceiver &receiver =
+    static_cast<xw::IPointerReceiver &>(processor);
+  receiver.Button(0, 0, WaylandButton(), WL_POINTER_BUTTON_STATE_RELEASED);
+  
+  XBMC_Event event(listener.FetchLastEvent());
+  EXPECT_EQ(XBMC_MOUSEBUTTONUP, event.type);
+  EXPECT_EQ(XBMCButton(), event.button.button);
+}
+
+INSTANTIATE_TEST_CASE_P(ThreeButtonMouse,
+                        WaylandPointerProcessorButtons,
+                        Values(std::tr1::tuple<uint32_t, uint32_t>(272, 1),
+                               std::tr1::tuple<uint32_t, uint32_t>(274, 2),
+                               std::tr1::tuple<uint32_t, uint32_t>(273, 3)));
+
+class WaylandPointerProcessorAxisButtons :
+  public WaylandPointerProcessor,
+  public WithParamInterface<std::tr1::tuple<float, uint32_t> >
+{
+protected:
+
+  float Magnitude();
+  uint32_t XBMCButton();
+};
+
+float WaylandPointerProcessorAxisButtons::Magnitude()
+{
+  return std::tr1::get<0>(GetParam());
+}
+
+uint32_t WaylandPointerProcessorAxisButtons::XBMCButton()
+{
+  return std::tr1::get<1>(GetParam());
+}
+
+TEST_P(WaylandPointerProcessorAxisButtons, Axis)
+{
+  xw::IPointerReceiver &receiver =
+    static_cast<xw::IPointerReceiver &>(processor);
+  receiver.Axis(0, WL_POINTER_AXIS_VERTICAL_SCROLL, Magnitude());
+  
+  XBMC_Event event(listener.FetchLastEvent());
+  EXPECT_EQ(XBMC_MOUSEBUTTONDOWN, event.type);
+  EXPECT_EQ(XBMCButton(), event.button.button);
+  
+  event = listener.FetchLastEvent();
+  EXPECT_EQ(XBMC_MOUSEBUTTONUP, event.type);
+  EXPECT_EQ(XBMCButton(), event.button.button);
+}
+
+INSTANTIATE_TEST_CASE_P(VerticalScrollWheel,
+                        WaylandPointerProcessorAxisButtons,
+                        Values(std::tr1::tuple<float, uint32_t>(-1.0, 4),
+                               std::tr1::tuple<float, uint32_t>(1.0, 5)));
+
+TEST_F(WaylandPointerProcessor, Motion)
+{
+  const float x = 5.0;
+  const float y = 5.0;
+  xw::IPointerReceiver &receiver =
+    static_cast<xw::IPointerReceiver &>(processor);
+  receiver.Motion(0, x, y);
+  
+  XBMC_Event event(listener.FetchLastEvent());
+  EXPECT_EQ(XBMC_MOUSEMOTION, event.type);
+  EXPECT_EQ(::round(x), event.motion.xrel);
+  EXPECT_EQ(::round(y), event.motion.yrel);  
+}
+
+TEST_F(WaylandPointerProcessor, MotionThenButton)
+{
+  const float x = 5.0;
+  const float y = 5.0;
+  xw::IPointerReceiver &receiver =
+    static_cast<xw::IPointerReceiver &>(processor);
+  receiver.Motion(0, x, y);
+  receiver.Button(0, 0, 272, WL_POINTER_BUTTON_STATE_PRESSED);
+  
+  listener.FetchLastEvent();
+  XBMC_Event event(listener.FetchLastEvent());
+  EXPECT_EQ(XBMC_MOUSEBUTTONDOWN, event.type);
+  EXPECT_EQ(::round(x), event.button.y);
+  EXPECT_EQ(::round(y), event.button.x);  
+}
diff --git a/xbmc/windowing/tests/wayland/TestXBMCWaylandInputAcceptance.cpp b/xbmc/windowing/tests/wayland/TestXBMCWaylandInputAcceptance.cpp
new file mode 100644 (file)
index 0000000..2e7f290
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#define WL_EGL_PLATFORM
+
+#include <stdexcept>
+
+#include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <gtest/gtest.h>
+
+#include <wayland-client.h>
+#include <wayland-client-protocol.h>
+#include <wayland-version.h>
+#include "xbmc_wayland_test_client_protocol.h"
+#include "windowing/DllWaylandClient.h"
+#include "windowing/DllWaylandEgl.h"
+#include "windowing/DllXKBCommon.h"
+
+#include "windowing/egl/wayland/Callback.h"
+#include "windowing/egl/wayland/Compositor.h"
+#include "windowing/egl/wayland/Display.h"
+#include "windowing/egl/wayland/OpenGLSurface.h"
+#include "windowing/egl/wayland/Registry.h"
+#include "windowing/egl/wayland/Surface.h"
+#include "windowing/egl/wayland/Shell.h"
+#include "windowing/egl/wayland/ShellSurface.h"
+#include "windowing/egl/EGLNativeTypeWayland.h"
+#include "windowing/wayland/EventLoop.h"
+#include "windowing/wayland/EventQueueStrategy.h"
+#include "windowing/wayland/TimeoutManager.h"
+#include "windowing/wayland/CursorManager.h"
+#include "windowing/wayland/InputFactory.h"
+#include "windowing/wayland/Wayland11EventQueueStrategy.h"
+#include "windowing/wayland/Wayland12EventQueueStrategy.h"
+
+#include "input/linux/XKBCommonKeymap.h"
+#include "input/XBMC_keysym.h"
+
+#include "StubCursorManager.h"
+#include "StubEventListener.h"
+#include "TmpEnv.h"
+#include "WestonTest.h"
+#include "XBMCWayland.h"
+
+#define WAYLAND_VERSION_NUMBER ((WAYLAND_VERSION_MAJOR << 16) | (WAYLAND_VERSION_MINOR << 8) | (WAYLAND_VERSION_MICRO))
+#define WAYLAND_VERSION_CHECK(major, minor, micro) ((major << 16) | (minor << 8) | (micro))
+
+namespace xw = xbmc::wayland;
+namespace xtw = xbmc::test::wayland;
+namespace xwe = xbmc::wayland::events;
+
+namespace
+{
+class SingleThreadedEventQueue :
+  public xwe::IEventQueueStrategy
+{
+public:
+
+  SingleThreadedEventQueue(IDllWaylandClient &clientLibrary,
+                           struct wl_display *display);
+
+private:
+
+  void PushAction(const Action &action);
+  void DispatchEventsFromMain();
+  
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_display *m_display;
+};
+
+SingleThreadedEventQueue::SingleThreadedEventQueue(IDllWaylandClient &clientLibrary,
+                                                   struct wl_display *display) :
+  m_clientLibrary(clientLibrary),
+  m_display(display)
+{
+}
+
+void SingleThreadedEventQueue::PushAction(const Action &action)
+{
+  action();
+}
+
+void SingleThreadedEventQueue::DispatchEventsFromMain()
+{
+  m_clientLibrary.wl_display_dispatch_pending(m_display);
+  m_clientLibrary.wl_display_flush(m_display);
+  m_clientLibrary.wl_display_dispatch(m_display);
+}
+}
+
+class InputEventsWestonTest :
+  public WestonTest,
+  public xw::IWaylandRegistration
+{
+public:
+
+  InputEventsWestonTest();
+  virtual void SetUp();
+
+protected:
+
+  DllWaylandClient clientLibrary;
+  DllWaylandEGL eglLibrary;
+  DllXKBCommon xkbCommonLibrary;
+  
+  StubCursorManager cursors;
+  StubEventListener listener;
+
+  boost::shared_ptr<struct xkb_context> xkbContext;
+  boost::scoped_ptr<CXKBKeymap> keymap;
+
+  boost::scoped_ptr<xw::Display> display;
+  boost::scoped_ptr<xwe::IEventQueueStrategy> queue;
+  boost::scoped_ptr<xw::Registry> registry;
+
+  boost::scoped_ptr<xwe::Loop> loop;
+  boost::scoped_ptr<xbmc::InputFactory> input;
+
+  boost::scoped_ptr<xw::Compositor> compositor;
+  boost::scoped_ptr<xw::Shell> shell;
+  boost::scoped_ptr<xtw::XBMCWayland> xbmcWayland;
+
+  boost::scoped_ptr<xw::Surface> surface;
+  boost::scoped_ptr<xw::ShellSurface> shellSurface;
+  boost::scoped_ptr<xw::OpenGLSurface> openGLSurface;
+
+  virtual xwe::IEventQueueStrategy * CreateEventQueue() = 0;
+
+  void WaitForSynchronize();
+  
+  static const unsigned int SurfaceWidth = 512;
+  static const unsigned int SurfaceHeight = 512;
+
+private:
+
+  virtual bool OnGlobalInterfaceAvailable(uint32_t name,
+                                          const char *interface,
+                                          uint32_t version);
+
+  bool synchronized;
+  void Synchronize();
+  boost::scoped_ptr<xw::Callback> syncCallback;
+  
+  TmpEnv m_waylandDisplayEnv;
+};
+
+InputEventsWestonTest::InputEventsWestonTest() :
+  m_waylandDisplayEnv("WAYLAND_DISPLAY",
+                      TempSocketName().c_str())
+{
+}
+
+void InputEventsWestonTest::SetUp()
+{
+  WestonTest::SetUp();
+  
+  clientLibrary.Load();
+  eglLibrary.Load();
+  xkbCommonLibrary.Load();
+  
+  xkbContext.reset(CXKBKeymap::CreateXKBContext(xkbCommonLibrary),
+                   boost::bind(&IDllXKBCommon::xkb_context_unref,
+                               &xkbCommonLibrary, _1));
+  keymap.reset(new CXKBKeymap(
+                 xkbCommonLibrary, 
+                 CXKBKeymap::CreateXKBKeymapFromNames(xkbCommonLibrary,
+                                                      xkbContext.get(),
+                                                      "evdev",
+                                                      "pc105",
+                                                      "us",
+                                                      "",
+                                                      "")));
+  
+  display.reset(new xw::Display(clientLibrary));
+  queue.reset(CreateEventQueue());
+  registry.reset(new xw::Registry(clientLibrary,
+                                  display->GetWlDisplay(),
+                                  *this));
+  loop.reset(new xwe::Loop(listener, *queue));
+
+  /* Wait for the seat, shell, compositor to appear */
+  WaitForSynchronize();
+  
+  ASSERT_TRUE(input.get() != NULL);
+  ASSERT_TRUE(compositor.get() != NULL);
+  ASSERT_TRUE(shell.get() != NULL);
+  ASSERT_TRUE(xbmcWayland.get() != NULL);
+  
+  /* Wait for input devices to appear etc */
+  WaitForSynchronize();
+  
+  surface.reset(new xw::Surface(clientLibrary,
+                                compositor->CreateSurface()));
+  shellSurface.reset(new xw::ShellSurface(clientLibrary,
+                                          shell->CreateShellSurface(
+                                            surface->GetWlSurface())));
+  openGLSurface.reset(new xw::OpenGLSurface(eglLibrary,
+                                            surface->GetWlSurface(),
+                                            SurfaceWidth,
+                                            SurfaceHeight));
+
+  wl_shell_surface_set_toplevel(shellSurface->GetWlShellSurface());
+  surface->Commit();
+}
+
+bool InputEventsWestonTest::OnGlobalInterfaceAvailable(uint32_t name,
+                                                       const char *interface,
+                                                       uint32_t version)
+{
+  if (strcmp(interface, "wl_seat") == 0)
+  {
+    /* We must use the one provided by dlopen, as the address
+     * may be different */
+    struct wl_interface **seatInterface =
+      clientLibrary.Get_wl_seat_interface();
+    struct wl_seat *seat =
+      registry->Bind<struct wl_seat *>(name,
+                                       seatInterface,
+                                       1);
+    input.reset(new xbmc::InputFactory(clientLibrary,
+                                       xkbCommonLibrary,
+                                       seat,
+                                       listener,
+                                       *loop));
+    return true;
+  }
+  else if (strcmp(interface, "wl_compositor") == 0)
+  {
+    struct wl_interface **compositorInterface =
+      clientLibrary.Get_wl_compositor_interface();
+    struct wl_compositor *wlcompositor =
+      registry->Bind<struct wl_compositor *>(name,
+                                             compositorInterface,
+                                             1);
+    compositor.reset(new xw::Compositor(clientLibrary, wlcompositor));
+    return true;
+  }
+  else if (strcmp(interface, "wl_shell") == 0)
+  {
+    struct wl_interface **shellInterface =
+      clientLibrary.Get_wl_shell_interface();
+    struct wl_shell *wlshell =
+      registry->Bind<struct wl_shell *>(name,
+                                        shellInterface,
+                                        1);
+    shell.reset(new xw::Shell(clientLibrary, wlshell));
+    return true;
+  }
+  else if (strcmp(interface, "xbmc_wayland") == 0)
+  {
+    struct wl_interface **xbmcWaylandInterface =
+      (struct wl_interface **) &xbmc_wayland_interface;
+    struct xbmc_wayland *wlxbmc_wayland =
+      registry->Bind<struct xbmc_wayland *>(name,
+                                            xbmcWaylandInterface,
+                                            version);
+    xbmcWayland.reset(new xtw::XBMCWayland(wlxbmc_wayland));
+    return true;
+  }
+  
+  return false;
+}
+
+void InputEventsWestonTest::WaitForSynchronize()
+{
+  synchronized = false;
+  syncCallback.reset(new xw::Callback(clientLibrary,
+                                      display->Sync(),
+                                      boost::bind(&InputEventsWestonTest::Synchronize,
+                                                  this)));
+  
+  while (!synchronized)
+    loop->Dispatch();
+}
+
+void InputEventsWestonTest::Synchronize()
+{
+  synchronized = true;
+}
+
+template <typename EventQueue>
+class InputEventQueueWestonTest :
+  public InputEventsWestonTest
+{
+private:
+
+  virtual xwe::IEventQueueStrategy * CreateEventQueue()
+  {
+    return new EventQueue(clientLibrary, display->GetWlDisplay());
+  }
+};
+TYPED_TEST_CASE_P(InputEventQueueWestonTest);
+
+TYPED_TEST_P(InputEventQueueWestonTest, Construction)
+{
+}
+
+TYPED_TEST_P(InputEventQueueWestonTest, MotionEvent)
+{
+  typedef InputEventsWestonTest Base;
+  int x = Base::SurfaceWidth / 2;
+  int y = Base::SurfaceHeight / 2;
+  Base::xbmcWayland->MovePointerTo(Base::surface->GetWlSurface(),
+                                   wl_fixed_from_int(x),
+                                   wl_fixed_from_int(y));
+  Base::WaitForSynchronize();
+  XBMC_Event event(Base::listener.FetchLastEvent());
+
+  EXPECT_EQ(XBMC_MOUSEMOTION, event.type);
+  EXPECT_EQ(x, event.motion.xrel);
+  EXPECT_EQ(y, event.motion.yrel);
+}
+
+TYPED_TEST_P(InputEventQueueWestonTest, ButtonEvent)
+{
+  typedef InputEventsWestonTest Base;
+  int x = Base::SurfaceWidth / 2;
+  int y = Base::SurfaceHeight / 2;
+  const unsigned int WaylandLeftButton = 272;
+  
+  Base::xbmcWayland->MovePointerTo(Base::surface->GetWlSurface(),
+                                   wl_fixed_from_int(x),
+                                   wl_fixed_from_int(y));
+  Base::xbmcWayland->SendButtonTo(Base::surface->GetWlSurface(),
+                                  WaylandLeftButton,
+                                  WL_POINTER_BUTTON_STATE_PRESSED);
+  Base::WaitForSynchronize();
+  
+  /* Throw away motion event */
+  Base::listener.FetchLastEvent();
+
+  XBMC_Event event(Base::listener.FetchLastEvent());
+
+  EXPECT_EQ(XBMC_MOUSEBUTTONDOWN, event.type);
+  EXPECT_EQ(1, event.button.button);
+  EXPECT_EQ(x, event.button.x);
+  EXPECT_EQ(y, event.button.y);
+}
+
+TYPED_TEST_P(InputEventQueueWestonTest, AxisEvent)
+{
+  typedef InputEventsWestonTest Base;
+  int x = Base::SurfaceWidth / 2;
+  int y = Base::SurfaceHeight / 2;
+  
+  Base::xbmcWayland->MovePointerTo(Base::surface->GetWlSurface(),
+                                   wl_fixed_from_int(x),
+                                   wl_fixed_from_int(y));
+  Base::xbmcWayland->SendAxisTo(Base::surface->GetWlSurface(),
+                                WL_POINTER_AXIS_VERTICAL_SCROLL,
+                                wl_fixed_from_int(10));
+  Base::WaitForSynchronize();
+  
+  /* Throw away motion event */
+  Base::listener.FetchLastEvent();
+
+  /* Should get button up and down */
+  XBMC_Event event(Base::listener.FetchLastEvent());
+
+  EXPECT_EQ(XBMC_MOUSEBUTTONDOWN, event.type);
+  EXPECT_EQ(5, event.button.button);
+  EXPECT_EQ(x, event.button.x);
+  EXPECT_EQ(y, event.button.y);
+  
+  event = Base::listener.FetchLastEvent();
+
+  EXPECT_EQ(XBMC_MOUSEBUTTONUP, event.type);
+  EXPECT_EQ(5, event.button.button);
+  EXPECT_EQ(x, event.button.x);
+  EXPECT_EQ(y, event.button.y);
+}
+
+namespace
+{
+/* Brute-force lookup functions to compensate for the fact that
+ * Keymap interface only supports conversion from scancodes
+ * to keysyms and not vice-versa (as such is not implemented in
+ * xkbcommon)
+ */
+uint32_t LookupKeycodeForKeysym(ILinuxKeymap &keymap,
+                                XBMCKey sym)
+{
+  uint32_t code = 0;
+  
+  while (code < XKB_KEYCODE_MAX)
+  {
+    /* Supress exceptions from unsupported keycodes */
+    try
+    {
+      if (keymap.XBMCKeysymForKeycode(code) == sym)
+        return code;
+    }
+    catch (std::runtime_error &err)
+    {
+    }
+    
+    ++code;
+  }
+  
+  throw std::logic_error("Keysym has no corresponding keycode");
+}
+
+uint32_t LookupModifierIndexForModifier(ILinuxKeymap &keymap,
+                                        XBMCMod modifier)
+{
+  uint32_t maxIndex = std::numeric_limits<uint32_t>::max();
+  uint32_t index = 0;
+  
+  while (index < maxIndex)
+  {
+    keymap.UpdateMask(1 << index, 0, 0, 0);
+    XBMCMod mask = static_cast<XBMCMod>(keymap.ActiveXBMCModifiers());
+    keymap.UpdateMask(0, 0, 0, 0);
+    if (mask & modifier)
+      return index;
+    
+    ++index;
+  }
+  
+  throw std::logic_error("Modifier has no corresponding keymod index");
+}
+}
+
+TYPED_TEST_P(InputEventQueueWestonTest, KeyEvent)
+{
+  typedef InputEventsWestonTest Base;
+  
+  const unsigned int oKeycode = LookupKeycodeForKeysym(*Base::keymap,
+                                                       XBMCK_o);
+
+  Base::xbmcWayland->GiveSurfaceKeyboardFocus(Base::surface->GetWlSurface());
+  Base::xbmcWayland->SendKeyToKeyboard(Base::surface->GetWlSurface(),
+                                       oKeycode,
+                                       WL_KEYBOARD_KEY_STATE_PRESSED);
+  Base::WaitForSynchronize();
+  
+  XBMC_Event event(Base::listener.FetchLastEvent());
+  EXPECT_EQ(XBMC_KEYDOWN, event.type);
+  EXPECT_EQ(oKeycode, event.key.keysym.scancode);
+  EXPECT_EQ(XBMCK_o, event.key.keysym.sym);
+  EXPECT_EQ(XBMCK_o, event.key.keysym.unicode);
+}
+
+TYPED_TEST_P(InputEventQueueWestonTest, RepeatAfter1000Ms)
+{
+  typedef InputEventsWestonTest Base;
+  
+  const unsigned int oKeycode = LookupKeycodeForKeysym(*Base::keymap,
+                                                       XBMCK_o);
+
+  Base::xbmcWayland->GiveSurfaceKeyboardFocus(Base::surface->GetWlSurface());
+  Base::xbmcWayland->SendKeyToKeyboard(Base::surface->GetWlSurface(),
+                                       oKeycode,
+                                       WL_KEYBOARD_KEY_STATE_PRESSED);
+  Base::WaitForSynchronize();
+  ::usleep(1100000); // 1100ms
+  Base::xbmcWayland->SendKeyToKeyboard(Base::surface->GetWlSurface(),
+                                       oKeycode,
+                                       WL_KEYBOARD_KEY_STATE_RELEASED);
+  Base::WaitForSynchronize();
+  
+  /* Throw away first key down */
+  XBMC_Event event(Base::listener.FetchLastEvent());
+  
+  /* Synthetic key up should be generated */
+  event = Base::listener.FetchLastEvent();
+  EXPECT_EQ(XBMC_KEYUP, event.type);
+  EXPECT_EQ(oKeycode, event.key.keysym.scancode);
+  
+  /* Synthetic key down should be generated */
+  event = Base::listener.FetchLastEvent();
+  EXPECT_EQ(XBMC_KEYDOWN, event.type);
+  EXPECT_EQ(oKeycode, event.key.keysym.scancode);
+}
+
+TYPED_TEST_P(InputEventQueueWestonTest, NoRepeatAfterRelease)
+{
+  typedef InputEventsWestonTest Base;
+  
+  const unsigned int oKeycode = LookupKeycodeForKeysym(*Base::keymap,
+                                                       XBMCK_o);
+
+  Base::xbmcWayland->GiveSurfaceKeyboardFocus(Base::surface->GetWlSurface());
+  Base::xbmcWayland->SendKeyToKeyboard(Base::surface->GetWlSurface(),
+                                       oKeycode,
+                                       WL_KEYBOARD_KEY_STATE_PRESSED);
+  Base::WaitForSynchronize();
+  ::usleep(1100000); // 1100ms
+  Base::xbmcWayland->SendKeyToKeyboard(Base::surface->GetWlSurface(),
+                                       oKeycode,
+                                       WL_KEYBOARD_KEY_STATE_RELEASED);
+  Base::WaitForSynchronize();
+
+  /* Drain any residual events */
+  bool eventsPending = true;
+  while (eventsPending)
+  {
+    try
+    {
+      Base::listener.FetchLastEvent();
+    }
+    catch (std::logic_error &err)
+    {
+      eventsPending = false;
+    }
+  }
+  
+  /* Sleep-wait again */
+  ::usleep(1100000); // 1100ms
+  Base::WaitForSynchronize();
+  
+  /* Should not be any more events */
+  EXPECT_THROW({ Base::listener.FetchLastEvent(); }, std::logic_error);
+}
+
+TYPED_TEST_P(InputEventQueueWestonTest, Modifiers)
+{
+  typedef InputEventsWestonTest Base;
+  
+  const unsigned int oKeycode = LookupKeycodeForKeysym(*Base::keymap,
+                                                       XBMCK_o);
+  const unsigned int leftShiftIndex =
+    LookupModifierIndexForModifier(*Base::keymap, XBMCKMOD_LSHIFT);
+
+  Base::xbmcWayland->GiveSurfaceKeyboardFocus(Base::surface->GetWlSurface());
+  Base::xbmcWayland->SendModifiersToKeyboard(Base::surface->GetWlSurface(),
+                                             1 << leftShiftIndex,
+                                             0,
+                                             0,
+                                             0);
+  Base::xbmcWayland->SendKeyToKeyboard(Base::surface->GetWlSurface(),
+                                       oKeycode,
+                                       WL_KEYBOARD_KEY_STATE_PRESSED);
+  Base::WaitForSynchronize();
+  
+  XBMC_Event event(Base::listener.FetchLastEvent());
+  EXPECT_EQ(XBMC_KEYDOWN, event.type);
+  EXPECT_EQ(oKeycode, event.key.keysym.scancode);
+  EXPECT_TRUE((XBMCKMOD_LSHIFT & event.key.keysym.mod) != 0);
+}
+
+REGISTER_TYPED_TEST_CASE_P(InputEventQueueWestonTest,
+                           Construction,
+                           MotionEvent,
+                           ButtonEvent,
+                           AxisEvent,
+                           KeyEvent,
+                           RepeatAfter1000Ms,
+                           NoRepeatAfterRelease,
+                           Modifiers);
+
+typedef ::testing::Types<SingleThreadedEventQueue,
+#if (WAYLAND_VERSION_NUMBER >= WAYLAND_VERSION_CHECK(1, 1, 90))
+                         xw::version_11::EventQueueStrategy,
+                         xw::version_12::EventQueueStrategy> EventQueueTypes;
+#else
+                         xw::version_11::EventQueueStrategy> EventQueueTypes;
+#endif
+
+INSTANTIATE_TYPED_TEST_CASE_P(EventQueues,
+                              InputEventQueueWestonTest,
+                              EventQueueTypes);
diff --git a/xbmc/windowing/tests/wayland/TmpEnv.cpp b/xbmc/windowing/tests/wayland/TmpEnv.cpp
new file mode 100644 (file)
index 0000000..87bdb34
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <stdlib.h>
+
+#include "TmpEnv.h"
+
+TmpEnv::TmpEnv(const char *env,
+               const char *val) :
+  m_env(env),
+  m_previous(getenv(env))
+{
+  setenv(env, val, 1);
+}
+
+TmpEnv::~TmpEnv()
+{
+  if (m_previous)
+    setenv(m_env, m_previous, 1);
+  else
+    unsetenv(m_env);
+}
diff --git a/xbmc/windowing/tests/wayland/TmpEnv.h b/xbmc/windowing/tests/wayland/TmpEnv.h
new file mode 100644 (file)
index 0000000..0e74fc8
--- /dev/null
@@ -0,0 +1,36 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <boost/noncopyable.hpp>
+
+class TmpEnv :
+  boost::noncopyable
+{
+public:
+
+  TmpEnv(const char *env, const char *val);
+  ~TmpEnv();
+
+private:
+
+  const char *m_env;
+  const char *m_previous;
+};
diff --git a/xbmc/windowing/tests/wayland/WestonProcess.cpp b/xbmc/windowing/tests/wayland/WestonProcess.cpp
new file mode 100644 (file)
index 0000000..36712e8
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <sstream>
+#include <stdexcept>
+
+#include <boost/noncopyable.hpp>
+#include <boost/tokenizer.hpp>
+
+#include <unistd.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "Util.h"
+#include "utils/StdString.h"
+
+#include "WestonProcess.h"
+
+namespace xt = xbmc::test;
+
+namespace
+{
+std::string
+FindBinaryFromPATH(const std::string &binary)
+{
+  const char *pathEnvironmentCArray = getenv("PATH");
+  if (!pathEnvironmentCArray)
+    throw std::runtime_error("PATH is not set");
+
+  std::string pathEnvironment(pathEnvironmentCArray);
+  
+  typedef boost::char_separator<char> CharSeparator;
+  typedef boost::tokenizer<CharSeparator> CharTokenizer;
+  
+  CharTokenizer paths(pathEnvironment,
+                      CharSeparator(":"));
+
+  for (CharTokenizer::iterator it = paths.begin();
+       it != paths.end();
+       ++it)
+  {
+    std::stringstream possibleBinaryLocationStream;
+    possibleBinaryLocationStream << *it
+                                 << "/"
+                                 << binary;
+    std::string possibleBinaryLocation(possibleBinaryLocationStream.str());
+    int ok = access(possibleBinaryLocation.c_str(), X_OK);
+
+    if (ok == -1)
+    {
+      switch (errno)
+      {
+        case EACCES:
+        case ENOENT:
+          continue;
+        default:
+          throw std::runtime_error(strerror(errno));
+      }
+    }
+
+    return possibleBinaryLocation.c_str();
+  }
+  
+  std::stringstream ss;
+  ss << "Unable to find "
+     << binary
+     << " in PATH as it does not exist or is not executable";
+  
+  throw std::runtime_error(ss.str());
+}
+}
+
+xt::Process::Process(const CStdString &xbmcTestBase,
+                     const CStdString &tempFileName) :
+  m_pid(0)
+{
+  std::stringstream socketOptionStream;
+  socketOptionStream << "--socket=";
+  socketOptionStream << tempFileName.c_str();
+  
+  std::string socketOption(socketOptionStream.str());
+
+  std::stringstream modulesOptionStream;
+  modulesOptionStream << "--modules=";
+  modulesOptionStream << xbmcTestBase.c_str();
+  modulesOptionStream << "xbmc/windowing/tests/wayland/xbmc-wayland-test-extension.so";
+  
+  std::string modulesOption(modulesOptionStream.str());
+  
+  std::string program(FindBinaryFromPATH("weston"));
+  const char *options[] =
+  {
+    program.c_str(),
+    "--backend=headless-backend.so",
+    modulesOption.c_str(),
+    socketOption.c_str(),
+    NULL
+  };
+  
+  m_pid = fork();
+  
+  switch (m_pid)
+  {
+    case 0:
+      Child(program.c_str(),
+            const_cast <char * const *>(options));
+    case -1:
+      ForkError();
+    default:
+      Parent();
+  }
+}
+
+pid_t
+xt::Process::Pid()
+{
+  return m_pid;
+}
+
+void
+xt::Process::Child(const char *program,
+                   char * const *options)
+{
+  ::signal(SIGUSR2, SIG_IGN);
+  
+  /* Unblock SIGUSR2 */
+  sigset_t signalMask;
+  sigemptyset(&signalMask);
+  sigaddset(&signalMask, SIGUSR2);
+  if (sigprocmask(SIG_UNBLOCK, &signalMask, NULL))
+  {
+    std::stringstream ss;
+    ss << "sigprocmask: " << strerror(errno);
+    throw std::runtime_error(ss.str());
+  }
+  
+  if (!getenv("XBMC_WESTON_GTEST_CHILD_STDOUT"))
+  {
+    ::close(STDOUT_FILENO);
+    ::close(STDERR_FILENO);
+  }
+  
+  if (execvpe(program, options, environ) == -1)
+  {
+    std::stringstream ss;
+    ss << "execvpe: " << strerror(errno);
+    throw std::runtime_error(ss.str());
+  }
+}
+
+void
+xt::Process::Parent()
+{
+}
+
+void
+xt::Process::ForkError()
+{
+  std::stringstream ss;
+  ss << "fork: "
+     << strerror(errno);
+  throw std::runtime_error(ss.str());
+}
+
+void
+xt::Process::WaitForSignal(int signal, int timeout)
+{
+  sigset_t signalMask;
+  
+  if (timeout >= 0)
+  {
+    static const uint32_t MsecToNsec = 1000000;
+    static const uint32_t SecToMsec = 1000;
+    int seconds = timeout / SecToMsec;
+    
+    /* Remove seconds from timeout */
+    timeout -= seconds * SecToMsec;
+    struct timespec ts = { seconds, timeout * MsecToNsec };
+    
+    sigemptyset(&signalMask);
+    sigaddset(&signalMask, signal);
+    int received = 0;
+    
+    do
+    {
+      errno = 0;
+      received = sigtimedwait(&signalMask,
+                              NULL,
+                              &ts);
+      if (received == -1)
+      {
+        /* Just retry if we got signalled */
+        if (errno != EINTR)
+        {
+          std::stringstream ss;
+          ss << "sigtimedwait: "
+             << strerror(errno);
+
+          throw std::runtime_error(ss.str());
+        }
+      }
+    } while (errno != 0);
+    
+    return;
+  }
+  else
+  {
+    sigemptyset(&signalMask);
+    sigaddset(&signalMask, signal);
+    errno = 0;
+    int received = sigwaitinfo(&signalMask, NULL);
+    
+    if (received != signal)
+    {
+      std::stringstream ss;
+      ss << "sigwaitinfo: "
+         << strerror(errno);
+    }
+  }
+}
+
+namespace
+{
+void
+WestonMisbehaviourMessage(std::stringstream &ss)
+{
+  ss << std::endl;
+  ss << "It is possible that Weston is just shutting down uncleanly "
+     << " - you should check the stacktrace and run with "
+     << " ALLOW_WESTON_MISBEHAVIOUR set to suppress this";
+}
+
+bool
+NoMisbehaviour()
+{
+  return !getenv("ALLOW_WESTON_MISBEHAVIOUR");
+}
+
+class StatusWaitTimeoutError :
+  public std::exception
+{
+public:
+
+  StatusWaitTimeoutError(int expected, int timeout);
+  ~StatusWaitTimeoutError() throw() {}
+
+private:
+
+  const char * what() const throw();
+
+  int m_expected;
+  int m_timeout;
+  
+  mutable std::string m_what;
+};
+
+class TerminatedBySignalError :
+  public std::exception
+{
+public:
+
+  TerminatedBySignalError(int expected, int signal);
+  ~TerminatedBySignalError() throw() {}
+
+private:
+
+  const char * what() const throw();
+
+  int m_expected;
+  int m_signal;
+  
+  mutable std::string m_what;
+};
+
+class AbnormalExitStatusError :
+  public std::exception
+{
+public:
+
+  AbnormalExitStatusError(int expected, int status);
+  ~AbnormalExitStatusError() throw() {}
+
+private:
+
+  const char * what() const throw();
+
+  int m_expected;
+  int m_status;
+  
+  mutable std::string m_what;
+};
+
+StatusWaitTimeoutError::StatusWaitTimeoutError(int expected,
+                                               int timeout) :
+  m_expected(expected),
+  m_timeout(timeout)
+{
+}
+
+const char *
+StatusWaitTimeoutError::what() const throw()
+{
+  std::stringstream ss;
+  ss << "Expected exit status "
+     << m_expected
+     << " within "
+     << m_timeout
+     << " ms";
+  m_what = ss.str();
+  return m_what.c_str();
+}
+
+TerminatedBySignalError::TerminatedBySignalError(int expected,
+                                                 int signal) :
+  m_expected(expected),
+  m_signal(signal)
+{
+}
+
+const char *
+TerminatedBySignalError::what() const throw()
+{
+  std::stringstream ss;
+  ss << "Expected exit status "
+     << m_expected
+     << " but was instead terminated by signal "
+     << m_signal
+     << " - "
+     << strsignal(m_signal);
+  WestonMisbehaviourMessage(ss);
+  m_what = ss.str();
+  return m_what.c_str();
+}
+
+AbnormalExitStatusError::AbnormalExitStatusError(int expected,
+                                                 int status) :
+  m_expected(expected),
+  m_status(status)
+{
+}
+
+const char *
+AbnormalExitStatusError::what() const throw()
+{
+  std::stringstream ss;
+  ss << "Expected exit status "
+     << m_expected
+     << " but instead exited with "
+     << m_status
+     << " - "
+     << strsignal(m_status);
+  WestonMisbehaviourMessage(ss);
+  m_what = ss.str();
+  return m_what.c_str();
+}
+}
+
+void
+xt::Process::WaitForStatus(int code, int timeout)
+{
+  struct timespec startTime;
+  struct timespec currentTime;
+  clock_gettime(CLOCK_MONOTONIC, &startTime);
+  clock_gettime(CLOCK_MONOTONIC, &currentTime);
+  
+  const uint32_t SecToMsec = 1000;
+  const uint32_t MsecToNsec = 1000000;
+  
+  int32_t startTimestamp = startTime.tv_sec * SecToMsec +
+                           startTime.tv_nsec / MsecToNsec;
+  int32_t currentTimestamp = currentTime.tv_sec * SecToMsec +
+                             currentTime.tv_nsec / MsecToNsec;
+  
+  int options = WUNTRACED;
+  
+  std::stringstream statusMessage;
+  
+  if (timeout >= 0)
+    options |= WNOHANG;
+  
+  do
+  {
+    clock_gettime(CLOCK_MONOTONIC, &currentTime);
+    
+    currentTimestamp = currentTime.tv_sec * SecToMsec +
+                       currentTime.tv_nsec / MsecToNsec;
+    
+    int returnedStatus;
+    pid_t pid = waitpid(m_pid, &returnedStatus, options);
+    
+    if (pid == m_pid)
+    {
+      /* At least one child has exited */
+      if (WIFEXITED(returnedStatus))
+      {
+        int returnedExitCode = WEXITSTATUS(returnedStatus);
+        if (returnedExitCode == code)
+          return;
+        
+        /* Abnormal exit status */
+        throw AbnormalExitStatusError(code, returnedExitCode);
+      }
+      else if (WIFSIGNALED(returnedStatus))
+      {
+        int returnedSignal = WTERMSIG(returnedStatus);
+
+        /* Signaled and died */
+        throw TerminatedBySignalError(code, returnedSignal);
+      }
+    }
+    else if (pid == -1)
+    {
+      std::stringstream ss;
+      ss << "waitpid failed: "
+         << strerror(errno);
+      throw std::runtime_error(ss.str());
+    }
+    else if (!pid)
+    {
+      struct timespec ts;
+      ts.tv_sec = 0;
+      
+      /* Don't sleep the whole time, we might have just missed
+       * the signal */
+      ts.tv_nsec = timeout * MsecToNsec / 10;
+      
+      nanosleep(&ts, NULL);
+    }
+  }
+  while (timeout == -1 ||
+         (timeout > currentTimestamp - startTimestamp));
+
+  /* If we didn't get out early, it means we timed out */
+  throw StatusWaitTimeoutError(code, timeout);
+}
+
+void
+xt::Process::SendSignal(int signal)
+{
+  if (kill(m_pid, signal) == -1)
+  {
+    /* Already dead ... lets see if it exited normally */
+    if (errno == ESRCH)
+    {
+      try
+      {
+        WaitForStatus(0, 0);
+      }
+      catch (std::runtime_error &err)
+      {
+        std::stringstream ss;
+        ss << err.what()
+           << " - process was already dead"
+           << std::endl;
+        throw std::runtime_error(ss.str());
+      }
+    }
+    else
+    {
+      std::stringstream ss;
+      ss << "failed to send signal "
+         << signal
+         << " to process "
+         << m_pid
+         << ": " << strerror(errno);
+      throw std::runtime_error(ss.str());
+    }
+  }
+}
+
+void
+xt::Process::Interrupt()
+{
+  SendSignal(SIGINT);
+}
+
+void
+xt::Process::Terminate()
+{
+  SendSignal(SIGTERM);
+}
+
+void
+xt::Process::Kill()
+{
+  SendSignal(SIGKILL);
+}
+
+xt::Process::~Process()
+{
+  typedef void (Process::*SignalAction)(void);
+  SignalAction deathActions[] =
+  {
+    &Process::Interrupt,
+    &Process::Terminate,
+    &Process::Kill
+  };
+
+  static const size_t deathActionsSize = sizeof(deathActions) /
+                                         sizeof(deathActions[0]);
+
+  size_t i = 0;
+  
+  std::stringstream processStatusMessages;
+
+  for (; i < deathActionsSize; ++i)
+  {
+    try
+    {
+      SignalAction func(deathActions[i]);
+      ((*this).*(func))();
+      WaitForStatus(0, DefaultProcessWaitTimeout);
+      break;
+    }
+    catch (const TerminatedBySignalError &err)
+    {
+      if (NoMisbehaviour())
+        throw;
+      else
+        break;
+    }
+    catch (const AbnormalExitStatusError &err)
+    {
+      if (NoMisbehaviour())
+        throw;
+      else
+        break;
+    }
+    catch (const StatusWaitTimeoutError &err)
+    {
+      processStatusMessages << "[TIMEOUT] "
+                            << static_cast<const std::exception &>(err).what()
+                            << std::endl;
+    }
+  }
+  
+  if (i == deathActionsSize)
+  {
+    std::stringstream ss;
+    ss << "Failed to terminate "
+       << m_pid
+       << std::endl;
+    ss << processStatusMessages;
+    throw std::runtime_error(ss.str());
+  }
+}
+
+
+
diff --git a/xbmc/windowing/tests/wayland/WestonProcess.h b/xbmc/windowing/tests/wayland/WestonProcess.h
new file mode 100644 (file)
index 0000000..aba56b1
--- /dev/null
@@ -0,0 +1,70 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include "system.h"
+
+#include <boost/noncopyable.hpp>
+
+#ifdef UNICODE
+  typedef CStdStringW        CStdString;
+#else
+  typedef CStdStringA        CStdString;
+#endif
+
+typedef int32_t pid_t;
+
+namespace xbmc
+{
+namespace test
+{
+class Process :
+  boost::noncopyable
+{
+public:
+
+  Process(const CStdString &base,
+          const CStdString &socket);
+  ~Process();
+
+  void WaitForSignal(int signal, int timeout);
+  void WaitForStatus(int status, int timeout);
+
+  void Interrupt();
+  void Terminate();
+  void Kill();
+  
+  pid_t Pid();
+  
+  static const int DefaultProcessWaitTimeout = 3000; // 3000ms
+
+private:
+  
+  void SendSignal(int signal);
+  
+  void Child(const char *program,
+             char * const *options);
+  void ForkError();
+  void Parent();
+  
+  pid_t m_pid;
+};
+}
+}
diff --git a/xbmc/windowing/tests/wayland/WestonTest.cpp b/xbmc/windowing/tests/wayland/WestonTest.cpp
new file mode 100644 (file)
index 0000000..8677fb5
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <sstream>
+#include <stdexcept>
+
+#include <boost/array.hpp>
+
+#include <signal.h>
+
+#include "test/TestUtils.h"
+#include "utils/log.h"
+
+#include "TmpEnv.h"
+#include "WestonProcess.h"
+#include "WestonTest.h"
+
+namespace xt = xbmc::test;
+
+namespace
+{
+class TempFileWrapper :
+  boost::noncopyable
+{
+public:
+
+  TempFileWrapper(const CStdString &suffix);
+  ~TempFileWrapper();
+  
+  void FetchDirectory(CStdString &directory);
+  void FetchFilename(CStdString &name);
+private:
+
+  XFILE::CFile *m_file;
+};
+
+TempFileWrapper::TempFileWrapper(const CStdString &suffix) :
+  m_file(CXBMCTestUtils::Instance().CreateTempFile(suffix))
+{
+}
+
+TempFileWrapper::~TempFileWrapper()
+{
+  CXBMCTestUtils::Instance().DeleteTempFile(m_file);
+}
+
+void TempFileWrapper::FetchDirectory(CStdString &directory)
+{
+  directory = CXBMCTestUtils::Instance().TempFileDirectory(m_file);
+  /* Strip trailing "/" */
+  directory.resize(directory.size() - 1);
+}
+
+void TempFileWrapper::FetchFilename(CStdString &name)
+{
+  CStdString path(CXBMCTestUtils::Instance().TempFilePath(m_file));
+  CStdString directory(CXBMCTestUtils::Instance().TempFileDirectory(m_file));
+  
+  name = path.substr(directory.size());
+}
+
+class SavedTempSocket :
+  boost::noncopyable
+{
+public:
+
+  SavedTempSocket();
+
+  const CStdString & FetchFilename();
+  const CStdString & FetchDirectory();
+
+private:
+
+  CStdString m_filename;
+  CStdString m_directory;
+};
+
+SavedTempSocket::SavedTempSocket()
+{
+  TempFileWrapper wrapper("");
+  wrapper.FetchDirectory(m_directory);
+  wrapper.FetchFilename(m_filename);
+}
+
+const CStdString &
+SavedTempSocket::FetchFilename()
+{
+  return m_filename;
+}
+
+const CStdString &
+SavedTempSocket::FetchDirectory()
+{
+  return m_directory;
+}
+
+template <typename Iterator>
+class SignalGuard :
+  boost::noncopyable
+{
+public:
+
+  SignalGuard(const Iterator &begin,
+              const Iterator &end);
+  ~SignalGuard();
+private:
+
+  sigset_t mask;
+};
+
+template <typename Iterator>
+SignalGuard<Iterator>::SignalGuard(const Iterator &begin,
+                                   const Iterator &end)
+{
+  sigemptyset(&mask);
+  for (Iterator it = begin;
+       it != end;
+       ++it)
+    sigaddset(&mask, *it);
+
+  if (sigprocmask(SIG_BLOCK, &mask, NULL))
+  {
+    std::stringstream ss;
+    ss << "sigprogmask: "
+       << strerror(errno);
+    throw std::runtime_error(ss.str());
+  }
+}
+
+template <typename Iterator>
+SignalGuard<Iterator>::~SignalGuard()
+{
+  if (sigprocmask(SIG_UNBLOCK, &mask, NULL))
+    CLog::Log(LOGERROR, "Failed to unblock signals");
+}
+
+typedef boost::array<int, 4> SigArray;
+SigArray BlockedSignals =
+{
+  {
+    SIGUSR2,
+    SIGCHLD
+  }
+};
+}
+
+class WestonTest::Private
+{
+public:
+  
+  Private();
+  ~Private();
+  
+  CStdString m_xbmcTestBase;
+  SavedTempSocket m_tempSocketName;
+  TmpEnv m_xdgRuntimeDir;
+
+  SignalGuard<SigArray::iterator> m_signalGuard;
+
+  xt::Process m_process;
+};
+
+WestonTest::WestonTest() :
+  priv(new Private())
+{
+}
+
+/* We need a defined destructor, otherwise we will
+ * generate the destructors for all of the owned objects
+ * multiple times where the definitions for those
+ * destructors is unavailable */
+WestonTest::~WestonTest()
+{
+}
+
+WestonTest::Private::Private() :
+  m_xbmcTestBase(CXBMCTestUtils::Instance().ReferenceFilePath("")),
+  /* We want wayland (client and server) to look in our
+   * temp file directory for the socket */
+  m_xdgRuntimeDir("XDG_RUNTIME_DIR", m_tempSocketName.FetchDirectory().c_str()),
+  /* Block emission of SIGUSR2 so that we can wait on it */
+  m_signalGuard(BlockedSignals.begin(), BlockedSignals.end()),
+  m_process(m_xbmcTestBase,
+            m_tempSocketName.FetchFilename())
+{
+}
+
+WestonTest::Private::~Private()
+{
+}
+
+pid_t
+WestonTest::Pid()
+{
+  return priv->m_process.Pid();
+}
+
+const CStdString &
+WestonTest::TempSocketName()
+{
+  return priv->m_tempSocketName.FetchFilename();
+}
+
+void
+WestonTest::SetUp()
+{
+  priv->m_process.WaitForSignal(SIGUSR2, xt::Process::DefaultProcessWaitTimeout);
+}
diff --git a/xbmc/windowing/tests/wayland/WestonTest.h b/xbmc/windowing/tests/wayland/WestonTest.h
new file mode 100644 (file)
index 0000000..2eb671b
--- /dev/null
@@ -0,0 +1,50 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <boost/scoped_ptr.hpp>
+
+#include <gtest/gtest.h>
+
+#ifdef UNICODE
+  typedef CStdStringW        CStdString;
+#else
+  typedef CStdStringA        CStdString;
+#endif
+
+typedef int32_t pid_t;
+
+class WestonTest :
+  public ::testing::Test
+{
+public:
+
+  WestonTest();
+  ~WestonTest();
+  pid_t Pid();
+  const CStdString & TempSocketName();
+  
+  virtual void SetUp();
+
+private:
+
+  class Private;
+  boost::scoped_ptr<Private> priv;
+};
diff --git a/xbmc/windowing/tests/wayland/XBMCWayland.cpp b/xbmc/windowing/tests/wayland/XBMCWayland.cpp
new file mode 100644 (file)
index 0000000..a7710de
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include "system.h"
+
+#if defined(HAVE_WAYLAND_XBMC_PROTO)
+
+#include <wayland-client.h>
+#include <wayland-client-protocol.h>
+#include "xbmc_wayland_test_client_protocol.h"
+
+#include "XBMCWayland.h"
+
+namespace xtw = xbmc::test::wayland;
+
+xtw::XBMCWayland::XBMCWayland(struct xbmc_wayland *xbmcWayland) :
+  m_xbmcWayland(xbmcWayland)
+{
+}
+
+xtw::XBMCWayland::~XBMCWayland()
+{
+  xbmc_wayland_destroy(m_xbmcWayland);
+}
+
+void
+xtw::XBMCWayland::AddMode(int width,
+                          int height,
+                          uint32_t refresh,
+                          enum wl_output_mode flags)
+{
+  xbmc_wayland_add_mode(m_xbmcWayland,
+                        width,
+                        height,
+                        refresh,
+                        static_cast<uint32_t>(flags));
+}
+
+void
+xtw::XBMCWayland::MovePointerTo(struct wl_surface *surface,
+                                wl_fixed_t x,
+                                wl_fixed_t y)
+{
+  xbmc_wayland_move_pointer_to_on_surface(m_xbmcWayland,
+                                          surface,
+                                          x,
+                                          y);
+}
+
+void
+xtw::XBMCWayland::SendButtonTo(struct wl_surface *surface,
+                               uint32_t button,
+                               uint32_t state)
+{
+  xbmc_wayland_send_button_to_surface(m_xbmcWayland,
+                                      surface,
+                                      button,
+                                      state);
+}
+
+void
+xtw::XBMCWayland::SendAxisTo(struct wl_surface *surface,
+                             uint32_t axis,
+                             wl_fixed_t value)
+{
+  xbmc_wayland_send_axis_to_surface(m_xbmcWayland,
+                                    surface,
+                                    axis,
+                                    value);
+}
+
+void
+xtw::XBMCWayland::SendKeyToKeyboard(struct wl_surface *surface,
+                                    uint32_t key,
+                                    enum wl_keyboard_key_state state)
+{
+  xbmc_wayland_send_key_to_keyboard(m_xbmcWayland,
+                                    surface,
+                                    key,
+                                    state);
+}
+
+void
+xtw::XBMCWayland::SendModifiersToKeyboard(struct wl_surface *surface,
+                                          uint32_t depressed,
+                                          uint32_t latched,
+                                          uint32_t locked,
+                                          uint32_t group)
+{
+  xbmc_wayland_send_modifiers_to_keyboard(m_xbmcWayland,
+                                          surface,
+                                          depressed,
+                                          latched,
+                                          locked,
+                                          group);
+}
+
+void
+xtw::XBMCWayland::GiveSurfaceKeyboardFocus(struct wl_surface *surface)
+{
+  xbmc_wayland_give_surface_keyboard_focus(m_xbmcWayland,
+                                           surface);
+}
+
+void
+xtw::XBMCWayland::PingSurface(struct wl_surface *surface,
+                              uint32_t serial)
+{
+  xbmc_wayland_ping_surface(m_xbmcWayland, surface, serial);
+}
+
+#endif
diff --git a/xbmc/windowing/tests/wayland/XBMCWayland.h b/xbmc/windowing/tests/wayland/XBMCWayland.h
new file mode 100644 (file)
index 0000000..3961d0a
--- /dev/null
@@ -0,0 +1,78 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#if defined(HAVE_WAYLAND_XBMC_PROTO)
+
+#include <boost/noncopyable.hpp>
+
+struct wl_surface;
+struct xbmc_wayland;
+
+namespace xbmc
+{
+namespace test
+{
+namespace wayland
+{
+class XBMCWayland :
+  boost::noncopyable
+{
+public:
+
+  XBMCWayland(struct xbmc_wayland *xbmcWayland);
+  ~XBMCWayland();
+
+  struct wl_surface * MostRecentSurface();
+
+  void AddMode(int width,
+               int height,
+               uint32_t refresh,
+               enum wl_output_mode mode);
+  void MovePointerTo(struct wl_surface *surface,
+                     wl_fixed_t x,
+                     wl_fixed_t y);
+  void SendButtonTo(struct wl_surface *surface,
+                    uint32_t button,
+                    uint32_t state);
+  void SendAxisTo(struct wl_surface *,
+                  uint32_t axis,
+                  wl_fixed_t value);
+  void SendKeyToKeyboard(struct wl_surface *surface,
+                         uint32_t key,
+                         enum wl_keyboard_key_state state);
+  void SendModifiersToKeyboard(struct wl_surface *surface,
+                               uint32_t depressed,
+                               uint32_t latched,
+                               uint32_t locked,
+                               uint32_t group);
+  void GiveSurfaceKeyboardFocus(struct wl_surface *surface);
+  void PingSurface (struct wl_surface *surface,
+                    uint32_t serial);
+
+private:
+
+  struct xbmc_wayland *m_xbmcWayland;
+};
+}
+}
+}
+
+#endif
diff --git a/xbmc/windowing/tests/wayland/XBMCWaylandTestExtension.cpp b/xbmc/windowing/tests/wayland/XBMCWaylandTestExtension.cpp
new file mode 100644 (file)
index 0000000..1520765
--- /dev/null
@@ -0,0 +1,792 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include "system.h"
+
+#include <sstream>
+#include <vector>
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+
+extern "C"
+{
+/* Work around usage of a reserved keyword
+ * https://bugs.freedesktop.org/show_bug.cgi?id=63485 */
+#define private cprivate
+#include <weston/compositor.h>
+#undef private
+#include <wayland-server.h>
+#include "xbmc_wayland_test_server_protocol.h"
+}
+
+namespace xbmc
+{
+namespace test
+{
+namespace wayland
+{
+class Listener :
+  boost::noncopyable
+{
+public:
+
+  typedef boost::function<void()> Delegate;
+
+  Listener(const Delegate &);
+  void BindTo(struct wl_signal *);
+
+private:
+
+  static void MainCallback(struct wl_listener *listener, void *data);
+
+  void Callback();
+
+  struct wl_listener m_listener;
+  Delegate m_delegate;
+};
+}
+
+namespace weston
+{
+class Compositor :
+  boost::noncopyable
+{
+public:
+
+  Compositor(struct weston_compositor *);
+  ~Compositor();
+
+  struct wl_display * Display();
+
+  struct weston_surface * TopSurface();
+  struct weston_mode * LastMode();
+  void OnEachMode(const boost::function<void(struct weston_mode *)> &);
+  struct wl_resource * PointerResource(struct wl_client *client);
+  struct wl_resource * KeyboardResource(struct wl_client *client);
+  struct weston_surface * Surface(struct wl_resource *client);
+  struct weston_keyboard * Keyboard();
+
+private:
+
+  static void Unload(Compositor *compositor);
+  static int Ready(void *);
+
+  struct weston_compositor *m_compositor;
+  struct wl_event_source *m_readySource;
+  wayland::Listener m_destroyListener;
+  struct weston_seat * Seat();
+  struct weston_output * FirstOutput();
+};
+}
+
+namespace wayland
+{
+class XBMCWayland :
+  boost::noncopyable
+{
+public:
+
+  ~XBMCWayland();
+  
+  struct wl_resource * GetResource();
+
+  /* Effectively a factory function for XBMCWayland. Creates an
+   * instantiation for a client */
+  static void BindToClient(struct wl_client *client,
+                           void *data,
+                           uint32_t version,
+                           uint32_t id);
+
+private:
+
+  /* Constructor is private as this object may only be constructed
+   * by a client binding to its interface */
+  XBMCWayland(struct wl_client *client,
+              uint32_t id,
+              weston::Compositor &compositor);
+
+  static void UnbindFromClientCallback(struct wl_resource *);
+
+  static const struct xbmc_wayland_interface m_listener;
+  
+  static void AddModeCallback(struct wl_client *,
+                              struct wl_resource *,
+                              int32_t,
+                              int32_t,
+                              uint32_t,
+                              uint32_t);
+  static void MovePointerToOnSurfaceCallback(struct wl_client *,
+                                             struct wl_resource *,
+                                             struct wl_resource *,
+                                             wl_fixed_t x,
+                                             wl_fixed_t y);
+  static void SendButtonToSurfaceCallback(struct wl_client *,
+                                          struct wl_resource *,
+                                          struct wl_resource *,
+                                          uint32_t,
+                                          uint32_t);
+  static void SendAxisToSurfaceCallback(struct wl_client *,
+                                        struct wl_resource *,
+                                        struct wl_resource *,
+                                        uint32_t,
+                                        wl_fixed_t);
+  static void SendKeyToKeyboardCallback(struct wl_client *,
+                                        struct wl_resource *,
+                                        struct wl_resource *,
+                                        uint32_t,
+                                        uint32_t);
+  static void SendModifiersToKeyboardCallback(struct wl_client *,
+                                              struct wl_resource *,
+                                              struct wl_resource *,
+                                              uint32_t,
+                                              uint32_t,
+                                              uint32_t,
+                                              uint32_t);
+  static void GiveSurfaceKeyboardFocusCallback(struct wl_client *,
+                                               struct wl_resource *,
+                                               struct wl_resource *);
+  static void PingSurfaceCallback(struct wl_client *,
+                                  struct wl_resource *,
+                                  struct wl_resource *,
+                                  uint32_t timestamp);
+
+  void AddMode(struct wl_client *client,
+               struct wl_resource *resource,
+               int32_t width,
+               int32_t height,
+               uint32_t refresh,
+               uint32_t flags);
+  void MovePointerToOnSurface(struct wl_client *client,
+                              struct wl_resource *resource,
+                              struct wl_resource *surface,
+                              wl_fixed_t x,
+                              wl_fixed_t y);
+  void SendButtonToSurface(struct wl_client *client,
+                           struct wl_resource *resource,
+                           struct wl_resource *surface,
+                           uint32_t button,
+                           uint32_t state);
+  void SendAxisToSurface(struct wl_client *client,
+                         struct wl_resource *resource,
+                         struct wl_resource *surface,
+                         uint32_t axis,
+                         wl_fixed_t value);
+  void SendKeyToKeyboard(struct wl_client *client,
+                         struct wl_resource *resource,
+                         struct wl_resource *surfaceResource,
+                         uint32_t key,
+                         uint32_t state);
+  void SendModifiersToKeyboard(struct wl_client *client,
+                               struct wl_resource *resource,
+                               struct wl_resource *surfaceResource,
+                               uint32_t depressed,
+                               uint32_t latched,
+                               uint32_t locked,
+                               uint32_t group);
+  void GiveSurfaceKeyboardFocus(struct wl_client *clent,
+                                struct wl_resource *resource,
+                                struct wl_resource *surfaceResource);
+  void PingSurface(struct wl_client *client,
+                   struct wl_resource *resource,
+                   struct wl_resource *surfaceResource,
+                   uint32_t timestamp);
+
+  weston::Compositor &m_compositor;
+  struct wl_resource *m_clientXBMCWaylandResource;
+  
+  std::vector<struct weston_mode> m_additionalModes;
+};
+
+const struct xbmc_wayland_interface XBMCWayland::m_listener =
+{
+  XBMCWayland::AddModeCallback,
+  XBMCWayland::MovePointerToOnSurfaceCallback,
+  XBMCWayland::SendButtonToSurfaceCallback,
+  XBMCWayland::SendAxisToSurfaceCallback,
+  XBMCWayland::SendKeyToKeyboardCallback,
+  XBMCWayland::SendModifiersToKeyboardCallback,
+  XBMCWayland::GiveSurfaceKeyboardFocusCallback,
+  XBMCWayland::PingSurfaceCallback
+};
+}
+}
+}
+
+namespace xtw = xbmc::test::wayland;
+namespace xtwc = xbmc::test::weston;
+
+xtw::XBMCWayland::XBMCWayland(struct wl_client *client,
+                              uint32_t id,
+                              xtwc::Compositor &compositor) :
+  m_compositor(compositor)
+{
+  m_clientXBMCWaylandResource =
+    static_cast<struct wl_resource *>(wl_resource_create(client,
+                                                         &xbmc_wayland_interface,
+                                                         1,
+                                                         id));
+  wl_resource_set_implementation (m_clientXBMCWaylandResource,
+                                  &m_listener,
+                                  this,
+                                  XBMCWayland::UnbindFromClientCallback);
+}
+
+xtw::XBMCWayland::~XBMCWayland()
+{
+  /* Remove all but the first output if we added any */
+  for (std::vector<struct weston_mode>::iterator it = m_additionalModes.begin();
+       it != m_additionalModes.end();
+       ++it)
+  {
+    wl_list_remove(&it->link);
+  }
+}
+
+void
+xtw::XBMCWayland::UnbindFromClientCallback(struct wl_resource *r)
+{
+  delete static_cast<XBMCWayland *>(wl_resource_get_user_data(r));
+}
+
+void
+xtw::XBMCWayland::BindToClient(struct wl_client *client,
+                               void *data,
+                               uint32_t version,
+                               uint32_t id)
+{
+  xtwc::Compositor *compositor = static_cast<xtwc::Compositor *>(data);
+  
+  /* This looks funky - however the constructor will handle registering
+   * the destructor function with wl_registry so that it gets destroyed
+   * at the right time */
+  new XBMCWayland(client, id, *compositor);
+}
+
+void
+xtw::XBMCWayland::AddModeCallback(struct wl_client *c,
+                                  struct wl_resource *r,
+                                  int32_t w,
+                                  int32_t h,
+                                  uint32_t re,
+                                  uint32_t f)
+{
+  static_cast<XBMCWayland *>(wl_resource_get_user_data(r))->AddMode(c, r, w, h, re, f);
+}
+
+void
+xtw::XBMCWayland::MovePointerToOnSurfaceCallback(struct wl_client *c,
+                                                 struct wl_resource *r,
+                                                 struct wl_resource *s,
+                                                 wl_fixed_t x,
+                                                 wl_fixed_t y)
+{
+  static_cast<XBMCWayland *>(wl_resource_get_user_data(r))->MovePointerToOnSurface(c, r, s, x, y);
+}
+
+void
+xtw::XBMCWayland::SendButtonToSurfaceCallback(struct wl_client *c,
+                                              struct wl_resource *r,
+                                              struct wl_resource *s,
+                                              uint32_t b,
+                                              uint32_t st)
+{
+  static_cast<XBMCWayland *>(wl_resource_get_user_data(r))->SendButtonToSurface(c, r, s, b, st);
+}
+
+void
+xtw::XBMCWayland::SendAxisToSurfaceCallback(struct wl_client *c,
+                                            struct wl_resource *r,
+                                            struct wl_resource *s,
+                                            uint32_t b,
+                                            wl_fixed_t v)
+{
+  static_cast<XBMCWayland *>(wl_resource_get_user_data(r))->SendAxisToSurface(c, r, s, b, v);
+}
+
+void
+xtw::XBMCWayland::SendModifiersToKeyboardCallback(struct wl_client *c,
+                                                  struct wl_resource *r,
+                                                  struct wl_resource *s,
+                                                  uint32_t d,
+                                                  uint32_t la,
+                                                  uint32_t lo,
+                                                  uint32_t g)
+{
+  static_cast<XBMCWayland *>(wl_resource_get_user_data(r))->SendModifiersToKeyboard(c, r, s, d, la, lo, g);
+}
+
+void
+xtw::XBMCWayland::SendKeyToKeyboardCallback(struct wl_client *c,
+                                            struct wl_resource *r,
+                                            struct wl_resource *s,
+                                            uint32_t k,
+                                            uint32_t st)
+{
+  static_cast<XBMCWayland *>(wl_resource_get_user_data(r))->SendKeyToKeyboard(c, r, s, k, st);
+}
+
+void
+xtw::XBMCWayland::GiveSurfaceKeyboardFocusCallback(struct wl_client *c,
+                                                   struct wl_resource *r,
+                                                   struct wl_resource *s)
+{
+  static_cast<XBMCWayland *>(wl_resource_get_user_data(r))->GiveSurfaceKeyboardFocus(c, r, s);
+}
+
+void
+xtw::XBMCWayland::PingSurfaceCallback(struct wl_client *c,
+                                      struct wl_resource *r,
+                                      struct wl_resource *s,
+                                      uint32_t t)
+{
+  static_cast<XBMCWayland *>(wl_resource_get_user_data(r))->PingSurface(c, r, s, t);
+}
+
+namespace
+{
+void ClearFlagsOnOtherModes(struct weston_mode *mode,
+                            uint32_t flags,
+                            struct weston_mode *skip)
+{
+  if (mode == skip)
+    return;
+  
+  mode->flags &= ~flags;
+}
+}
+
+void
+xtw::XBMCWayland::AddMode(struct wl_client *client,
+                          struct wl_resource *resource,
+                          int32_t width,
+                          int32_t height,
+                          uint32_t refresh,
+                          uint32_t flags)
+{
+  const struct weston_mode mode =
+  {
+    flags,
+    width,
+    height,
+    refresh
+  };
+  
+  m_additionalModes.push_back(mode);
+  struct weston_mode *lastMode = m_compositor.LastMode();
+  wl_list_insert(&lastMode->link, &m_additionalModes.back().link);
+  
+  /* Clear flags from all other outputs that may have the same flags
+   * as this one */
+  m_compositor.OnEachMode(boost::bind(ClearFlagsOnOtherModes,
+                                      _1,
+                                      flags,
+                                      &m_additionalModes.back()));
+}
+
+namespace
+{
+void GetSerialAndTime(struct wl_display *display,
+                      uint32_t &serial,
+                      uint32_t &time)
+{
+  serial = wl_display_next_serial(display);
+  
+  struct timespec ts;
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+  
+  time = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+}
+}
+
+void
+xtw::XBMCWayland::MovePointerToOnSurface(struct wl_client *client,
+                                         struct wl_resource *resource,
+                                         struct wl_resource *surface,
+                                         wl_fixed_t x,
+                                         wl_fixed_t y)
+{
+  struct wl_client *surfaceClient = wl_resource_get_client(surface);
+  struct wl_resource *pointer = m_compositor.PointerResource(surfaceClient);
+  struct wl_display *display = wl_client_get_display(surfaceClient);
+  uint32_t serial, time;
+
+  GetSerialAndTime(display, serial, time);
+  
+  wl_pointer_send_motion(pointer, time, x, y);
+}
+
+void
+xtw::XBMCWayland::SendButtonToSurface(struct wl_client *client,
+                                      struct wl_resource *resource,
+                                      struct wl_resource *surface,
+                                      uint32_t button,
+                                      uint32_t state)
+{
+  struct wl_client *surfaceClient = wl_resource_get_client(surface);
+  struct wl_resource *pointer = m_compositor.PointerResource(surfaceClient);
+  struct wl_display *display = wl_client_get_display(surfaceClient);
+  uint32_t serial, time;
+  
+  GetSerialAndTime(display, serial, time);
+  
+  wl_pointer_send_button(pointer, serial, time, button, state);
+}
+
+void
+xtw::XBMCWayland::SendAxisToSurface(struct wl_client *client,
+                                    struct wl_resource *resource,
+                                    struct wl_resource *surface,
+                                    uint32_t axis,
+                                    wl_fixed_t value)
+{
+  struct wl_client *surfaceClient = wl_resource_get_client(surface);
+  struct wl_resource *pointer = m_compositor.PointerResource(surfaceClient);
+  struct wl_display *display = wl_client_get_display(surfaceClient);
+  uint32_t serial, time;
+  
+  GetSerialAndTime(display, serial, time);
+  
+  wl_pointer_send_axis(pointer, time, axis, value);
+}
+
+void
+xtw::XBMCWayland::SendKeyToKeyboard(struct wl_client *client,
+                                    struct wl_resource *resource,
+                                    struct wl_resource *surface,
+                                    uint32_t key,
+                                    uint32_t state)
+{
+  struct wl_client *surfaceClient = wl_resource_get_client(surface);
+  struct wl_resource *keyboard = m_compositor.KeyboardResource(surfaceClient);
+  struct wl_display *display = wl_client_get_display(surfaceClient);
+  uint32_t serial, time;
+
+  GetSerialAndTime(display, serial, time);
+  
+  wl_keyboard_send_key(keyboard, serial, time, key, state);
+}
+
+void
+xtw::XBMCWayland::SendModifiersToKeyboard(struct wl_client *client,
+                                          struct wl_resource *resource,
+                                          struct wl_resource *surface,
+                                          uint32_t depressed,
+                                          uint32_t latched,
+                                          uint32_t locked,
+                                          uint32_t group)
+{
+  struct wl_client *surfaceClient = wl_resource_get_client(surface);
+  struct wl_resource *keyboard = m_compositor.KeyboardResource(surfaceClient);
+  struct wl_display *display = wl_client_get_display(surfaceClient);
+  uint32_t serial = wl_display_next_serial(display);
+  
+  wl_keyboard_send_modifiers(keyboard,
+                             serial,
+                             depressed,
+                             latched,
+                             locked,
+                             group);
+}
+
+void
+xtw::XBMCWayland::GiveSurfaceKeyboardFocus(struct wl_client *client,
+                                           struct wl_resource *resource,
+                                           struct wl_resource *surface)
+{
+  struct weston_surface *westonSurface = m_compositor.Surface(surface);
+  struct weston_keyboard *keyboard = m_compositor.Keyboard();
+  weston_keyboard_set_focus(keyboard, westonSurface);
+}
+
+void
+xtw::XBMCWayland::PingSurface(struct wl_client *client,
+                              struct wl_resource *resource,
+                              struct wl_resource *surface,
+                              uint32_t timestamp)
+{
+}
+
+xtw::Listener::Listener(const Delegate &delegate) :
+  m_delegate(delegate)
+{
+  m_listener.notify = Listener::MainCallback;
+}
+
+void
+xtw::Listener::MainCallback(struct wl_listener *listener, void *data)
+{
+  static_cast<Listener *>(data)->Callback();
+}
+
+void
+xtw::Listener::Callback()
+{
+  m_delegate();
+}
+
+void
+xtw::Listener::BindTo(struct wl_signal *s)
+{
+  wl_signal_add(s, &m_listener);
+}
+
+xtwc::Compositor::Compositor(struct weston_compositor *c) :
+  m_compositor(c),
+  /* This is a workaround for a race condition where the registry
+   * might not be ready if we send SIGUSR2 right away - so we
+   * put it on the event loop to happen after the first poll() */
+  m_readySource(wl_event_loop_add_timer(wl_display_get_event_loop(Display()),
+                                        Compositor::Ready,
+                                        this)),
+  m_destroyListener(boost::bind(Compositor::Unload, this))
+{
+  /* Dispatch ASAP */
+  wl_event_source_timer_update(m_readySource, 1);
+  m_destroyListener.BindTo(&c->destroy_signal);
+  
+  /* The parent process should have set the SIGUSR2 handler to
+   * SIG_IGN, throw if it hasn't */
+  if (signal(SIGUSR2, SIG_IGN) != SIG_IGN)
+  {
+    std::stringstream ss;
+    throw std::runtime_error("Parent process is not handling SIGUSR2");
+  }
+}
+
+int
+xtwc::Compositor::Ready(void *data)
+{
+  xtwc::Compositor *compositor = static_cast<xtwc::Compositor *>(data);
+
+  if (kill(getppid(), SIGUSR2) == -1)
+  {
+    std::stringstream ss;
+    ss << "kill: "
+       << strerror(errno);
+    throw std::runtime_error(ss.str());
+  }
+  
+  wl_event_source_remove(compositor->m_readySource);
+  compositor->m_readySource = NULL;
+  
+  /* Initialize the fake keyboard and pointer on our seat. This is
+   * effectively manipulating the backend into doing something it
+   * shouldn't, but we're in control here */
+  struct weston_seat *seat = compositor->Seat();
+  weston_seat_init_pointer(seat);
+  
+  struct xkb_keymap *keymap =
+    xkb_keymap_new_from_names(compositor->m_compositor->xkb_context,
+                              &compositor->m_compositor->xkb_names,
+                              static_cast<enum xkb_keymap_compile_flags>(0));
+  if (!keymap)
+    throw std::runtime_error("Failed to compile keymap\n");
+
+  weston_seat_init_keyboard(seat, keymap);
+  xkb_keymap_unref(keymap);
+  return 1;
+}
+
+struct weston_output *
+xtwc::Compositor::FirstOutput()
+{
+  struct weston_output *output;
+  
+  output = wl_container_of(m_compositor->output_list.prev,
+                           output,
+                           link);
+
+  return output;
+}
+
+struct wl_display *
+xtwc::Compositor::Display()
+{
+  return m_compositor->wl_display;
+}
+
+struct weston_seat *
+xtwc::Compositor::Seat()
+{
+  /* Since it is impossible to get a weston_seat from a weston_compositor
+   * and we will need that in order to get access to the weston_pointer
+   * and weston_keyboard, we need to use this hack to get access
+   * to the seat by casting the weston_compositor to this, which is
+   * copied from compositor-headless.c . Since weston_compositor is
+   * the the first member of headless_compositor, it is safe to cast
+   * from the second to the first */
+  struct headless_compositor {
+    struct weston_compositor compositor;
+    struct weston_seat seat;
+  };
+  
+  /* Before we cast, we should check if we are actually running
+   * on the headless compositor. If not, throw an exception so
+   * that the user might know what's going on */
+  struct weston_output *output = FirstOutput();
+  
+  if (!output)
+    throw std::runtime_error("Compositor does not have an output");
+
+  if (std::string(output->model) != "headless")
+  {
+    std::stringstream ss;
+    ss << "Only the compositor-headless.so backend "
+       << "is supported by this extension. "
+       << std::endl
+       << "The current output model detected was "
+       << output->model;
+    throw std::logic_error(ss.str());
+  }
+  
+  struct headless_compositor *hc =
+    reinterpret_cast<struct headless_compositor *>(m_compositor);
+
+  return &hc->seat;
+}
+
+struct weston_surface *
+xtwc::Compositor::TopSurface()
+{
+  struct weston_surface *surface;
+
+  /* The strange semantics of wl_container_of means that we can't
+   * return its result directly because it needs to have an
+   * instantiation of the type */
+  surface = wl_container_of(m_compositor->surface_list.prev,
+                            surface,
+                            link);
+  return surface;
+}
+
+void
+xtwc::Compositor::OnEachMode(const boost::function<void(struct weston_mode *)> &action)
+{
+  struct weston_output *output = FirstOutput();
+  struct weston_mode *mode;
+  
+  wl_list_for_each(mode, &output->mode_list, link)
+  {
+    action(mode);
+  }
+}
+
+struct weston_mode *
+xtwc::Compositor::LastMode()
+{
+  struct weston_mode *mode;
+  struct weston_output *output = FirstOutput();
+  mode = wl_container_of(output->mode_list.prev,
+                         mode,
+                         link);
+
+  return mode;
+}
+
+struct wl_resource *
+xtwc::Compositor::PointerResource(struct wl_client *client)
+{
+  struct weston_seat *seat = Seat();
+  struct wl_resource *r =
+    wl_resource_find_for_client(&seat->pointer->focus_resource_list,
+                                client);
+  if (!r)
+    r =  wl_resource_find_for_client(&seat->pointer->resource_list,
+                                     client);
+
+  if (!r)
+    throw std::logic_error ("No pointer resource available for this "
+                            "client ");
+  return r;
+}
+
+struct wl_resource *
+xtwc::Compositor::KeyboardResource(struct wl_client *client)
+{
+  struct weston_seat *seat = Seat();
+  struct wl_resource *r =
+    wl_resource_find_for_client(&seat->keyboard->focus_resource_list,
+                                client);
+  if (!r)
+    r =  wl_resource_find_for_client(&seat->keyboard->resource_list,
+                                     client);
+
+  if (!r)
+    throw std::logic_error ("No keyboard resource available for this "
+                            "client ");
+  return r;
+}
+
+struct weston_surface *
+xtwc::Compositor::Surface(struct wl_resource *surface)
+{
+  struct weston_surface *ws =
+    reinterpret_cast<struct weston_surface *>(wl_resource_get_user_data(surface));
+  
+  return ws;
+}
+
+void
+xtwc::Compositor::Unload(xtwc::Compositor *compositor)
+{
+  delete compositor;
+}
+
+struct weston_keyboard *
+xtwc::Compositor::Keyboard()
+{
+  struct weston_seat *seat = Seat();
+  return seat->keyboard;
+}
+
+xtwc::Compositor::~Compositor()
+{
+}
+
+extern "C"
+{
+WL_EXPORT int
+module_init(struct weston_compositor *c,
+            int *argc,
+            char *argv[])
+{
+  /* Using heap allocated memory directly here is awkward, however
+   * weston knows when we need to destroy our resources
+   * so we will let it handle it */
+  xtwc::Compositor *compositor(new xtwc::Compositor(c));
+  /* Register our factory for xbmc_wayland and pass
+   * xtwc::Compositor to it when it gets created */
+  if (wl_global_create(compositor->Display(),
+                       &xbmc_wayland_interface,
+                       1,
+                       compositor,
+                       xtw::XBMCWayland::BindToClient) == NULL)
+    return -1;
+
+  return 0;
+}
+}
+
diff --git a/xbmc/windowing/tests/wayland/protocol.xml b/xbmc/windowing/tests/wayland/protocol.xml
new file mode 100644 (file)
index 0000000..69f5202
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xbmc_wayland_test">
+  <copyright>
+  Copyright (C) 2005-2013 Team XBMC
+    http://www.xbmc.org
+
+  This Program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+
+  This Program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with XBMC; see the file COPYING.  If not, see
+  &lt;http://www.gnu.org/licenses/&gt;
+
+  </copyright>
+  <interface name="xbmc_wayland" version="1"/>
+    <request name="add_mode">
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="refresh" type="uint"/>
+      <arg name="flags" type="uint"/>
+    </request>
+    <request name="move_pointer_to_on_surface">
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="x" type="fixed"/>
+      <arg name="y" type="fixed"/>
+    </request>
+    <request name="send_button_to_surface">
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="button" type="uint"/>
+      <arg name="state" type="uint"/>
+    </request>
+    <request name="send_axis_to_surface">
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="axis" type="uint"/>
+      <arg name="value" type="fixed"/>
+    </request>
+    <request name="send_key_to_keyboard">
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="key" type="uint"/>
+      <arg name="state" type="uint"/>
+    </request>
+    <request name="send_modifiers_to_keyboard">
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="depressed" type="uint"/>
+      <arg name="latched" type="uint"/>
+      <arg name="locked" type="uint"/>
+      <arg name="group" type="uint"/>
+    </request>
+    <request name="give_surface_keyboard_focus">
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+    <request name="ping_surface">
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="timestamp" type="uint"/>
+    </request>
+</protocol>
diff --git a/xbmc/windowing/wayland/CursorManager.h b/xbmc/windowing/wayland/CursorManager.h
new file mode 100644 (file)
index 0000000..b698e88
--- /dev/null
@@ -0,0 +1,38 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <stdint.h>
+
+struct wl_surface;
+
+namespace xbmc
+{
+class ICursorManager
+{
+public:
+
+  virtual ~ICursorManager() {}
+  virtual void SetCursor(uint32_t serial,
+                         struct wl_surface *surface,
+                         double surfaceX,
+                         double surfaceY) = 0;
+};
+}
diff --git a/xbmc/windowing/wayland/EventListener.h b/xbmc/windowing/wayland/EventListener.h
new file mode 100644 (file)
index 0000000..3aca635
--- /dev/null
@@ -0,0 +1,40 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include "windowing/XBMC_events.h"
+
+namespace xbmc
+{
+/* We inject an IWaylandRegistration here which is a virtual
+ * class which a series of callbacks for the global objects
+ * used by xbmc. Once one of those objects becomes
+ * available, we call the specified callback function on that
+ * interface */
+class IEventListener
+{
+public:
+
+  virtual ~IEventListener() {}
+  virtual void OnEvent(XBMC_Event &) = 0;
+  virtual void OnFocused() = 0;
+  virtual void OnUnfocused() = 0;
+};
+}
diff --git a/xbmc/windowing/wayland/EventLoop.cpp b/xbmc/windowing/wayland/EventLoop.cpp
new file mode 100644 (file)
index 0000000..9491dbb
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <algorithm>
+#include <vector>
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+
+#include "utils/Stopwatch.h"
+
+#include "EventQueueStrategy.h"
+#include "EventLoop.h"
+
+namespace xwe = xbmc::wayland::events;
+
+/* Once xwe::Loop recieves some information we need to enqueue
+ * it to be dispatched on MessagePump. This is done by using
+ * a command pattern to wrap the incoming data in function objects
+ * and then pushing it to a queue.
+ * 
+ * The reason for this is that these three functions may or may not
+ * be running in a separate thread depending on the dispatch
+ * strategy in place.  */
+void xwe::Loop::OnEvent(XBMC_Event &e)
+{
+  m_eventQueue.PushAction(boost::bind(&IEventListener::OnEvent,
+                                      &m_queueListener, e));
+}
+
+void xwe::Loop::OnFocused()
+{
+  m_eventQueue.PushAction(boost::bind(&IEventListener::OnFocused,
+                                      &m_queueListener));
+}
+
+void xwe::Loop::OnUnfocused()
+{
+  m_eventQueue.PushAction(boost::bind(&IEventListener::OnUnfocused,
+                                      &m_queueListener));
+}
+
+xwe::Loop::Loop(IEventListener &queueListener,
+                IEventQueueStrategy &strategy) :
+  m_eventQueue(strategy),
+  m_queueListener(queueListener)
+{
+  m_stopWatch.StartZero();
+}
+
+namespace
+{
+bool TimeoutInactive(const xwe::Loop::CallbackTracker &tracker)
+{
+  return tracker.callback.expired();
+}
+
+void SubtractTimeoutAndTrigger(xwe::Loop::CallbackTracker &tracker,
+                               int time)
+{
+  int value = std::max(0, static_cast <int> (tracker.remaining - time));
+  if (value == 0)
+  {
+    tracker.remaining = time;
+    xbmc::ITimeoutManager::CallbackPtr callback (tracker.callback.lock());
+    
+    (*callback) ();
+  }
+  else
+    tracker.remaining = value;
+}
+
+bool ByRemaining(const xwe::Loop::CallbackTracker &a,
+                 const xwe::Loop::CallbackTracker &b)
+{
+  return a.remaining < b.remaining; 
+}
+}
+
+xwe::Loop::CallbackTracker::CallbackTracker(uint32_t time,
+                                            uint32_t initial,
+                                            const xbmc::ITimeoutManager::CallbackPtr &cb) :
+  time(time),
+  remaining(time > initial ? time : initial),
+  callback(cb)
+{
+}
+
+void xwe::Loop::DispatchTimers()
+{
+  float elapsedMs = m_stopWatch.GetElapsedMilliseconds();
+  m_stopWatch.Stop();
+  /* We must subtract the elapsed time from each tracked timeout and
+   * trigger any remaining ones. If a timeout is triggered, then its
+   * remaining time will return to the original timeout value */
+  std::for_each(m_callbackQueue.begin(), m_callbackQueue.end (),
+                boost::bind(SubtractTimeoutAndTrigger,
+                            _1,
+                            static_cast<int>(elapsedMs)));
+  /* Timeout times may have changed so that the timeouts are no longer
+   * in order. Sort them so that they are. If they are unsorted,
+   * the ordering of two timeouts, one which was added just before
+   * the other which both reach a zero value at the same time,
+   * will be undefined. */
+  std::sort(m_callbackQueue.begin(), m_callbackQueue.end(),
+            ByRemaining);
+  m_stopWatch.StartZero();
+}
+
+void xwe::Loop::Dispatch()
+{
+  /* Remove any timers which are no longer active */
+  m_callbackQueue.erase (std::remove_if(m_callbackQueue.begin(),
+                                        m_callbackQueue.end(),
+                                        TimeoutInactive),
+                         m_callbackQueue.end());
+
+  DispatchTimers();
+  
+  /* Calculate the poll timeout based on any current
+   * timers on the main loop. */
+  uint32_t minTimeout = 0;
+  for (std::vector<CallbackTracker>::iterator it = m_callbackQueue.begin();
+       it != m_callbackQueue.end();
+       ++it)
+  {
+    if (minTimeout < it->remaining)
+      minTimeout = it->remaining;
+  }
+  
+  m_eventQueue.DispatchEventsFromMain();
+}
+
+xbmc::ITimeoutManager::CallbackPtr
+xwe::Loop::RepeatAfterMs(const xbmc::ITimeoutManager::Callback &cb,
+                         uint32_t initial,
+                         uint32_t time)
+{
+  CallbackPtr ptr(new Callback(cb));
+  
+  bool     inserted = false;
+  
+  for (std::vector<CallbackTracker>::iterator it = m_callbackQueue.begin();
+       it != m_callbackQueue.end();
+       ++it)
+  {
+    /* The appropriate place to insert is just before an existing
+     * timer which has a greater remaining time than ours */
+    if (it->remaining > time)
+    {
+      m_callbackQueue.insert(it, CallbackTracker(time, initial, ptr));
+      inserted = true;
+      break;
+    }
+  }
+  
+  /* Insert at the back */
+  if (!inserted)
+    m_callbackQueue.push_back(CallbackTracker(time, initial, ptr));
+
+  return ptr;
+}
diff --git a/xbmc/windowing/wayland/EventLoop.h b/xbmc/windowing/wayland/EventLoop.h
new file mode 100644 (file)
index 0000000..fb21ec3
--- /dev/null
@@ -0,0 +1,92 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <vector>
+
+#include <boost/weak_ptr.hpp>
+
+#include "utils/Stopwatch.h"
+
+#include "EventListener.h"
+#include "EventQueueStrategy.h"
+#include "TimeoutManager.h"
+
+class IDllWaylandClient;
+
+struct wl_display;
+
+namespace xbmc
+{
+namespace wayland
+{
+namespace events
+{
+class IEventQueueStrategy;
+
+/* Loop encapsulates the entire process of dispatching
+ * wayland events and timers that might be in place for duplicate
+ * processing. Calling its Dispatch() method will cause any pending
+ * timers and events to be dispatched. It implements ITimeoutManager
+ * and timeouts can be added directly to it */
+class Loop :
+  public xbmc::IEventListener,
+  public xbmc::ITimeoutManager
+{
+public:
+
+  Loop(xbmc::IEventListener &listener,
+       IEventQueueStrategy &strategy);
+  
+  void Dispatch();
+  
+  struct CallbackTracker
+  {
+    typedef boost::weak_ptr <Callback> CallbackObserver;
+    
+    CallbackTracker(uint32_t time,
+                    uint32_t initial,
+                    const CallbackPtr &callback);
+    
+    uint32_t time;
+    uint32_t remaining;
+    CallbackObserver callback;
+  };
+  
+private:
+
+  CallbackPtr RepeatAfterMs(const Callback &callback,
+                            uint32_t initial,
+                            uint32_t timeout);
+  void DispatchTimers();
+  
+  void OnEvent(XBMC_Event &);
+  void OnFocused();
+  void OnUnfocused();
+  
+  std::vector<CallbackTracker> m_callbackQueue;
+  CStopWatch m_stopWatch;
+  
+  IEventQueueStrategy &m_eventQueue;
+  xbmc::IEventListener &m_queueListener;
+};
+}
+}
+}
diff --git a/xbmc/windowing/wayland/EventQueueStrategy.h b/xbmc/windowing/wayland/EventQueueStrategy.h
new file mode 100644 (file)
index 0000000..d328a95
--- /dev/null
@@ -0,0 +1,45 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+
+namespace xbmc
+{
+namespace wayland
+{
+namespace events
+{
+class IEventQueueStrategy :
+  boost::noncopyable
+{
+public:
+
+  virtual ~IEventQueueStrategy() {}
+
+  typedef boost::function<void()> Action;
+
+  virtual void PushAction(const Action &event) = 0;
+  virtual void DispatchEventsFromMain() = 0;
+};
+}
+}
+}
diff --git a/xbmc/windowing/wayland/InputFactory.cpp b/xbmc/windowing/wayland/InputFactory.cpp
new file mode 100644 (file)
index 0000000..efd7fd2
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include "EventListener.h"
+#include "Keyboard.h"
+#include "Pointer.h"
+#include "Seat.h"
+#include "TimeoutManager.h"
+#include "InputFactory.h"
+
+namespace xw = xbmc::wayland;
+
+xbmc::InputFactory::InputFactory(IDllWaylandClient &clientLibrary,
+                                 IDllXKBCommon &xkbCommonLibrary,
+                                 struct wl_seat *seat,
+                                 IEventListener &dispatch,
+                                 ITimeoutManager &timeouts) :
+  m_clientLibrary(clientLibrary),
+  m_xkbCommonLibrary(xkbCommonLibrary),
+  m_pointerProcessor(dispatch, *this),
+  m_keyboardProcessor(dispatch, timeouts),
+  m_seat(new xw::Seat(clientLibrary, seat, *this))
+{
+}
+
+void xbmc::InputFactory::SetXBMCSurface(struct wl_surface *s)
+{
+  m_keyboardProcessor.SetXBMCSurface(s);
+}
+
+void xbmc::InputFactory::SetCursor(uint32_t serial,
+                             struct wl_surface *surface,
+                             double surfaceX,
+                             double surfaceY)
+{
+  m_pointer->SetCursor(serial, surface, surfaceX, surfaceY);
+}
+
+bool xbmc::InputFactory::InsertPointer(struct wl_pointer *p)
+{
+  if (m_pointer.get())
+    return false;
+
+  m_pointer.reset(new xw::Pointer(m_clientLibrary,
+                                  p,
+                                  m_pointerProcessor));
+  return true;
+}
+
+bool xbmc::InputFactory::InsertKeyboard(struct wl_keyboard *k)
+{
+  if (m_keyboard.get())
+    return false;
+
+  m_keyboard.reset(new xw::Keyboard(m_clientLibrary,
+                                    m_xkbCommonLibrary,
+                                    k,
+                                    m_keyboardProcessor));
+  return true;
+}
+
+void xbmc::InputFactory::RemovePointer()
+{
+  m_pointer.reset();
+}
+
+void xbmc::InputFactory::RemoveKeyboard()
+{
+  m_keyboard.reset();
+}
diff --git a/xbmc/windowing/wayland/InputFactory.h b/xbmc/windowing/wayland/InputFactory.h
new file mode 100644 (file)
index 0000000..5f470a8
--- /dev/null
@@ -0,0 +1,82 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <boost/scoped_ptr.hpp>
+
+#include "CursorManager.h"
+#include "Seat.h"
+#include "Pointer.h"
+#include "PointerProcessor.h"
+#include "Keyboard.h"
+#include "KeyboardProcessor.h"
+
+class IDllWaylandClient;
+class IDllXKBCommon;
+
+struct wl_keyboard;
+struct wl_pointer;
+struct wl_seat;
+struct wl_surface;
+
+namespace xbmc
+{
+/* InputFactory is effectively just a manager class that encapsulates
+ * all input related information and ties together a wayland seat with
+ * the rest of the XBMC input handling subsystem. It is an internal
+ * class just for tying together these two ends. */
+class InputFactory :
+  public wayland::IInputReceiver,
+  public ICursorManager
+{
+public:
+
+  InputFactory(IDllWaylandClient &clientLibrary,
+               IDllXKBCommon &xkbCommonLibrary,
+               struct wl_seat *seat,
+               IEventListener &dispatch,
+               ITimeoutManager &timeouts);
+
+  void SetXBMCSurface(struct wl_surface *s);
+
+private:
+
+  void SetCursor(uint32_t serial,
+                 struct wl_surface *surface,
+                 double surfaceX,
+                 double surfaceY);
+
+  bool InsertPointer(struct wl_pointer *);
+  bool InsertKeyboard(struct wl_keyboard *);
+
+  void RemovePointer();
+  void RemoveKeyboard();
+
+  IDllWaylandClient &m_clientLibrary;
+  IDllXKBCommon &m_xkbCommonLibrary;
+
+  PointerProcessor m_pointerProcessor;
+  KeyboardProcessor m_keyboardProcessor;
+
+  boost::scoped_ptr<wayland::Seat> m_seat;
+  boost::scoped_ptr<wayland::Pointer> m_pointer;
+  boost::scoped_ptr<wayland::Keyboard> m_keyboard;
+};
+}
diff --git a/xbmc/windowing/wayland/Keyboard.cpp b/xbmc/windowing/wayland/Keyboard.cpp
new file mode 100644 (file)
index 0000000..83824c0
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/scope_exit.hpp>
+
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/DllXKBCommon.h"
+#include "windowing/WaylandProtocol.h"
+#include "input/linux/XKBCommonKeymap.h"
+#include "Keyboard.h"
+
+namespace xw = xbmc::wayland;
+
+const struct wl_keyboard_listener xw::Keyboard::m_listener =
+{
+  Keyboard::HandleKeymapCallback,
+  Keyboard::HandleEnterCallback,
+  Keyboard::HandleLeaveCallback,
+  Keyboard::HandleKeyCallback,
+  Keyboard::HandleModifiersCallback
+};
+
+namespace
+{
+void DestroyXKBCommonContext(struct xkb_context *context,
+                             IDllXKBCommon &xkbCommonLibrary)
+{
+  xkbCommonLibrary.xkb_context_unref(context);
+}
+}
+
+xw::Keyboard::Keyboard(IDllWaylandClient &clientLibrary,
+                       IDllXKBCommon &xkbCommonLibrary,
+                       struct wl_keyboard *keyboard,
+                       IKeyboardReceiver &receiver) :
+  m_clientLibrary(clientLibrary),
+  m_xkbCommonLibrary(xkbCommonLibrary),
+  m_xkbCommonContext(CXKBKeymap::CreateXKBContext(m_xkbCommonLibrary),
+                     boost::bind(DestroyXKBCommonContext,
+                                 _1,
+                                 boost::ref(m_xkbCommonLibrary))),
+  m_keyboard(keyboard),
+  m_reciever(receiver)
+{
+  protocol::AddListenerOnWaylandObject(m_clientLibrary,
+                                       m_keyboard,
+                                       &m_listener,
+                                       this);
+}
+
+xw::Keyboard::~Keyboard()
+{
+  protocol::DestroyWaylandObject(m_clientLibrary,
+                                 m_keyboard);
+}
+
+void xw::Keyboard::HandleKeymapCallback(void *data,
+                                        struct wl_keyboard *keyboard,
+                                        uint32_t format,
+                                        int fd,
+                                        uint32_t size)
+{
+  static_cast <Keyboard *>(data)->HandleKeymap(format,
+                                               fd,
+                                               size);
+}
+
+void xw::Keyboard::HandleEnterCallback(void *data,
+                                       struct wl_keyboard *keyboard,
+                                       uint32_t serial,
+                                       struct wl_surface *surface,
+                                       struct wl_array *keys)
+{
+  static_cast<Keyboard *>(data)->HandleEnter(serial,
+                                             surface,
+                                             keys);
+}
+
+void xw::Keyboard::HandleLeaveCallback(void *data,
+                                       struct wl_keyboard *keyboard,
+                                       uint32_t serial,
+                                       struct wl_surface *surface)
+{
+  static_cast<Keyboard *>(data)->HandleLeave(serial,
+                                             surface);
+}
+
+void xw::Keyboard::HandleKeyCallback(void *data,
+                                     struct wl_keyboard *keyboard,
+                                     uint32_t serial,
+                                     uint32_t time,
+                                     uint32_t key,
+                                     uint32_t state)
+{
+  static_cast<Keyboard *>(data)->HandleKey(serial,
+                                           time,
+                                           key,
+                                           state);
+}
+
+void xw::Keyboard::HandleModifiersCallback(void *data,
+                                           struct wl_keyboard *keyboard,
+                                           uint32_t serial,
+                                           uint32_t mods_depressed,
+                                           uint32_t mods_latched,
+                                           uint32_t mods_locked,
+                                           uint32_t group)
+{
+  static_cast<Keyboard *>(data)->HandleModifiers(serial,
+                                                 mods_depressed,
+                                                 mods_latched,
+                                                 mods_locked,
+                                                 group);
+}
+
+/* Creates a new internal keymap representation for a serialized
+ * keymap as represented in shared memory as referred to by fd.
+ * 
+ * Since the fd is sent to us via sendmsg(), the currently running
+ * process has ownership over it. As such, it MUST close the file
+ * descriptor after it has decided what to do with it in order to
+ * avoid a leak.
+ */
+void xw::Keyboard::HandleKeymap(uint32_t format,
+                                int fd,
+                                uint32_t size)
+{
+  /* The file descriptor must always be closed */
+  BOOST_SCOPE_EXIT((fd))
+  {
+    close(fd);
+  } BOOST_SCOPE_EXIT_END
+
+  /* We don't understand anything other than xkbv1. If we get some
+   * other keyboard, then we can't process keyboard events reliably
+   * and that's a runtime error. */
+  if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
+    throw std::runtime_error("Server gave us a keymap we don't understand");
+
+  bool successfullyCreatedKeyboard = false;
+  
+  /* Either throws or returns a valid xkb_keymap * */
+  struct xkb_keymap *keymap =
+    CXKBKeymap::ReceiveXKBKeymapFromSharedMemory(m_xkbCommonLibrary,
+                                                 m_xkbCommonContext.get(),
+                                                 fd,
+                                                 size);
+
+  BOOST_SCOPE_EXIT((&m_xkbCommonLibrary)(&successfullyCreatedKeyboard)(keymap))
+  {
+    if (!successfullyCreatedKeyboard)
+      m_xkbCommonLibrary.xkb_keymap_unref(keymap);
+  } BOOST_SCOPE_EXIT_END
+
+  m_keymap.reset(new CXKBKeymap(m_xkbCommonLibrary,
+                                keymap));
+  
+  successfullyCreatedKeyboard = true;
+
+  m_reciever.UpdateKeymap(m_keymap.get());
+}
+
+void xw::Keyboard::HandleEnter(uint32_t serial,
+                               struct wl_surface *surface,
+                               struct wl_array *keys)
+{
+  m_reciever.Enter(serial, surface, keys);
+}
+
+void xw::Keyboard::HandleLeave(uint32_t serial,
+                               struct wl_surface *surface)
+{
+  m_reciever.Leave(serial, surface);
+}
+
+void xw::Keyboard::HandleKey(uint32_t serial,
+                             uint32_t time,
+                             uint32_t key,
+                             uint32_t state)
+{
+  m_reciever.Key(serial,
+                 time,
+                 key,
+                 static_cast<enum wl_keyboard_key_state>(state));
+}
+
+void xw::Keyboard::HandleModifiers(uint32_t serial,
+                                   uint32_t mods_depressed,
+                                   uint32_t mods_latched,
+                                   uint32_t mods_locked,
+                                   uint32_t group)
+{
+  m_reciever.Modifier(serial,
+                      mods_depressed,
+                      mods_latched,
+                      mods_locked,
+                      group);
+}
diff --git a/xbmc/windowing/wayland/Keyboard.h b/xbmc/windowing/wayland/Keyboard.h
new file mode 100644 (file)
index 0000000..72385e5
--- /dev/null
@@ -0,0 +1,156 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <wayland-client.h>
+
+#include "input/linux/Keymap.h"
+
+class IDllWaylandClient;
+class IDllXKBCommon;
+
+struct xkb_context;
+
+namespace xbmc
+{
+namespace wayland
+{
+class IKeyboardReceiver
+{
+public:
+
+  virtual ~IKeyboardReceiver() {}
+
+  virtual void UpdateKeymap(ILinuxKeymap *) = 0;
+  virtual void Enter(uint32_t serial,
+                     struct wl_surface *surface,
+                     struct wl_array *keys) = 0;
+  virtual void Leave(uint32_t serial,
+                     struct wl_surface *surface) = 0;
+  virtual void Key(uint32_t serial,
+                   uint32_t time,
+                   uint32_t key,
+                   enum wl_keyboard_key_state state) = 0;
+  virtual void Modifier(uint32_t serial,
+                        uint32_t depressed,
+                        uint32_t latched,
+                        uint32_t locked,
+                        uint32_t group) = 0;
+};
+
+/* Wrapper class for a keyboard object. Generally there is one keyboard
+ * per seat.
+ * 
+ * Keyboard events are translated into a more readable form and
+ * forwarded on to the injected IKeyboardReceiver for further 
+ * processing.
+ * 
+ * Many of these events require some shared agreement between the
+ * compositor and the client as to the keymap in use. A file descriptor
+ * for a shared memory region to a serialized keymap parsable
+ * with libxkbcommon is provided in HandleKeymap and to the
+ * registered IKeyboardReceiever through UpdateKeymap. The delegate for
+ * that interface should ascertain the intended keymap before processing
+ * any other events.
+ */
+class Keyboard :
+  public boost::noncopyable
+{
+public:
+
+  Keyboard(IDllWaylandClient &,
+           IDllXKBCommon &,
+           struct wl_keyboard *,
+           IKeyboardReceiver &);
+  ~Keyboard();
+
+  struct wl_keyboard * GetWlKeyboard();
+
+  static void HandleKeymapCallback(void *,
+                                   struct wl_keyboard *,
+                                   uint32_t,
+                                   int,
+                                   uint32_t);
+  static void HandleEnterCallback(void *,
+                                  struct wl_keyboard *,
+                                  uint32_t,
+                                  struct wl_surface *,
+                                  struct wl_array *);
+  static void HandleLeaveCallback(void *,
+                                  struct wl_keyboard *,
+                                  uint32_t,
+                                  struct wl_surface *);
+  static void HandleKeyCallback(void *,
+                                struct wl_keyboard *,
+                                uint32_t,
+                                uint32_t,
+                                uint32_t,
+                                uint32_t);
+  static void HandleModifiersCallback(void *,
+                                      struct wl_keyboard *,
+                                      uint32_t,
+                                      uint32_t,
+                                      uint32_t,
+                                      uint32_t,
+                                      uint32_t);
+
+private:
+
+  void HandleKeymap(uint32_t format,
+                    int fd,
+                    uint32_t size);
+  void HandleEnter(uint32_t serial,
+                   struct wl_surface *surface,
+                   struct wl_array *keys);
+  void HandleLeave(uint32_t serial,
+                   struct wl_surface *surface);
+  void HandleKey(uint32_t serial,
+                 uint32_t time,
+                 uint32_t key,
+                 uint32_t state);
+  void HandleModifiers(uint32_t serial,
+                       uint32_t mods_depressed,
+                       uint32_t mods_latched,
+                       uint32_t mods_locked,
+                       uint32_t group);
+
+  static const struct wl_keyboard_listener m_listener;
+
+  IDllWaylandClient &m_clientLibrary;
+  IDllXKBCommon &m_xkbCommonLibrary;
+  
+  /* boost::scoped_ptr does not permit custom deleters
+   * and std::auto_ptr is deprecated, so we are using
+   * boost::shared_ptr instead */
+  boost::shared_ptr<struct xkb_context> m_xkbCommonContext;
+  struct wl_keyboard *m_keyboard;
+  IKeyboardReceiver &m_reciever;
+
+  /* Keyboard owns the keymap object, but it might inject observing
+   * references elsewhere in order to assist those objects in their
+   * processing */
+  boost::scoped_ptr<ILinuxKeymap> m_keymap;
+};
+}
+}
diff --git a/xbmc/windowing/wayland/KeyboardProcessor.cpp b/xbmc/windowing/wayland/KeyboardProcessor.cpp
new file mode 100644 (file)
index 0000000..62bbb27
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <wayland-client.h>
+#include <xkbcommon/xkbcommon.h>
+
+#include "utils/log.h"
+
+#include "EventListener.h"
+#include "Keyboard.h"
+#include "KeyboardProcessor.h"
+#include "TimeoutManager.h"
+
+#include "input/linux/Keymap.h"
+
+
+xbmc::KeyboardProcessor::KeyboardProcessor(IEventListener &listener,
+                                           ITimeoutManager &timeouts) :
+  m_listener(listener),
+  m_timeouts(timeouts),
+  m_xbmcWindow(NULL),
+  m_repeatSym(0),
+  m_context(NULL)
+{
+}
+
+xbmc::KeyboardProcessor::~KeyboardProcessor()
+{
+}
+
+void
+xbmc::KeyboardProcessor::SetXBMCSurface(struct wl_surface *s)
+{
+  m_xbmcWindow = s;
+}
+
+/* Takes an observing reference to an ILinuxKeymap */
+void
+xbmc::KeyboardProcessor::UpdateKeymap(ILinuxKeymap *keymap)
+{
+  m_keymap = keymap;
+}
+
+void
+xbmc::KeyboardProcessor::Enter(uint32_t serial,
+                               struct wl_surface *surface,
+                               struct wl_array *keys)
+{
+  if (surface == m_xbmcWindow)
+  {
+    m_listener.OnFocused();
+  }
+}
+
+void
+xbmc::KeyboardProcessor::Leave(uint32_t serial,
+                               struct wl_surface *surface)
+{
+  if (surface == m_xbmcWindow)
+  {
+    m_listener.OnUnfocused();
+  }
+}
+
+void
+xbmc::KeyboardProcessor::SendKeyToXBMC(uint32_t key,
+                                       uint32_t sym,
+                                       uint32_t eventType)
+{
+  if (!m_keymap)
+    throw std::logic_error("a keymap must be set before processing key events");
+
+  XBMC_Event event;
+  event.type = eventType;
+  event.key.keysym.scancode = key;
+  event.key.keysym.sym = static_cast<XBMCKey>(sym);
+  event.key.keysym.unicode = static_cast<XBMCKey>(sym);
+  event.key.keysym.mod =
+    static_cast<XBMCMod>(m_keymap->ActiveXBMCModifiers());
+  event.key.state = 0;
+  event.key.type = event.type;
+  event.key.which = '0';
+
+  m_listener.OnEvent(event);
+}
+
+void
+xbmc::KeyboardProcessor::RepeatCallback(uint32_t key,
+                                        uint32_t sym)
+{
+  /* Release and press the key again */
+  SendKeyToXBMC(key, sym, XBMC_KEYUP);
+  SendKeyToXBMC(key, sym, XBMC_KEYDOWN);
+}
+
+/* If this function is called before a keymap is set, then that
+ * is a precondition violation and a logic_error results */
+void
+xbmc::KeyboardProcessor::Key(uint32_t serial,
+                             uint32_t time,
+                             uint32_t key,
+                             enum wl_keyboard_key_state state)
+{
+  if (!m_keymap)
+    throw std::logic_error("a keymap must be set before processing key events");
+
+  uint32_t sym = XKB_KEY_NoSymbol;
+
+  /* If we're unable to process a single key, then catch the error
+   * and report it, but don't allow it to be fatal */
+  try
+  {
+    sym = m_keymap->XBMCKeysymForKeycode(key);
+  }
+  catch (const std::runtime_error &err)
+  {
+    CLog::Log(LOGERROR, "%s: Failed to process keycode %i: %s",
+              __FUNCTION__, key, err.what());
+    return;
+  }
+
+  uint32_t keyEventType = 0;
+
+  switch (state)
+  {
+    case WL_KEYBOARD_KEY_STATE_PRESSED:
+      keyEventType = XBMC_KEYDOWN;
+      break;
+    case WL_KEYBOARD_KEY_STATE_RELEASED:
+      keyEventType = XBMC_KEYUP;
+      break;
+    default:
+      CLog::Log(LOGERROR, "%s: Unrecognized key state", __FUNCTION__);
+      return;
+  }
+  
+  /* Key-repeat is handled on the client side so we need to add a new
+   * timeout here to repeat this symbol if it is still being held down
+   */
+  if (keyEventType == XBMC_KEYDOWN)
+  {
+    m_repeatCallback =
+      m_timeouts.RepeatAfterMs(boost::bind (
+                                 &KeyboardProcessor::RepeatCallback,
+                                 this,
+                                 key,
+                                 sym),
+                               1000,
+                               250);
+    m_repeatSym = sym;
+  }
+  else if (keyEventType == XBMC_KEYUP &&
+           sym == m_repeatSym)
+    m_repeatCallback.reset();
+  
+  SendKeyToXBMC(key, sym, keyEventType);
+}
+
+/* We MUST update the keymap mask whenever we receive a new modifier
+ * event */
+void
+xbmc::KeyboardProcessor::Modifier(uint32_t serial,
+                                  uint32_t depressed,
+                                  uint32_t latched,
+                                  uint32_t locked,
+                                  uint32_t group)
+{
+  if (!m_keymap)
+    throw std::logic_error("a keymap must be set before processing key events");
+
+  m_keymap->UpdateMask(depressed, latched, locked, group);
+}
diff --git a/xbmc/windowing/wayland/KeyboardProcessor.h b/xbmc/windowing/wayland/KeyboardProcessor.h
new file mode 100644 (file)
index 0000000..f658d0e
--- /dev/null
@@ -0,0 +1,98 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <boost/scoped_ptr.hpp>
+
+#include "input/linux/Keymap.h"
+#include "Keyboard.h"
+#include "TimeoutManager.h"
+
+class IDllXKBCommon;
+
+struct wl_array;
+struct wl_surface;
+struct xkb_context;
+enum wl_keyboard_key_state;
+
+namespace xbmc
+{
+class IEventListener;
+
+/* KeyboardProcessor implements IKeyboardReceiver and transforms
+ * keyboard events into XBMC events for further processing.
+ * 
+ * It needs to know whether or not a surface is in focus, so as soon
+ * as a surface is available, SetXBMCSurface should be called.
+ * 
+ * KeyboardProcessor also performs key-repeat and registers a callback
+ * function to repeat the currently depressed key if it has not been
+ * released within a certain period. As such it depends on
+ * ITimeoutManager */
+class KeyboardProcessor :
+  public wayland::IKeyboardReceiver
+{
+public:
+
+  KeyboardProcessor(IEventListener &listener,
+                    ITimeoutManager &timeouts);
+  ~KeyboardProcessor();
+  
+  void SetXBMCSurface(struct wl_surface *xbmcWindow);
+
+private:
+
+  void UpdateKeymap(ILinuxKeymap *);
+  void Enter(uint32_t serial,
+             struct wl_surface *surface,
+             struct wl_array *keys);
+  void Leave(uint32_t serial,
+             struct wl_surface *surface);
+  void Key(uint32_t serial,
+           uint32_t time,
+           uint32_t key,
+           enum wl_keyboard_key_state state);
+  void Modifier(uint32_t serial,
+                uint32_t depressed,
+                uint32_t latched,
+                uint32_t locked,
+                uint32_t group);
+                
+  void SendKeyToXBMC(uint32_t key,
+                     uint32_t sym,
+                     uint32_t type);
+  void RepeatCallback(uint32_t key,
+                      uint32_t sym);
+
+  IEventListener &m_listener;
+  ITimeoutManager &m_timeouts;
+  struct wl_surface *m_xbmcWindow;
+  
+  ITimeoutManager::CallbackPtr m_repeatCallback;
+  uint32_t m_repeatSym;
+  
+  struct xkb_context *m_context;
+
+  /* KeyboardProcessor has an observing reference to the  keymap and
+   * does parts of its processing by delegating to the keymap the job 
+   * of looking up generic keysyms for keycodes */
+  ILinuxKeymap *m_keymap;
+};
+}
diff --git a/xbmc/windowing/wayland/Pointer.cpp b/xbmc/windowing/wayland/Pointer.cpp
new file mode 100644 (file)
index 0000000..48c63c5
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "Pointer.h"
+
+namespace xw = xbmc::wayland;
+
+const struct wl_pointer_listener xw::Pointer::m_listener =
+{
+  Pointer::HandleEnterCallback,
+  Pointer::HandleLeaveCallback,
+  Pointer::HandleMotionCallback,
+  Pointer::HandleButtonCallback,
+  Pointer::HandleAxisCallback
+};
+
+xw::Pointer::Pointer(IDllWaylandClient &clientLibrary,
+                     struct wl_pointer *pointer,
+                     IPointerReceiver &receiver) :
+  m_clientLibrary(clientLibrary),
+  m_pointer(pointer),
+  m_receiver(receiver)
+{
+  protocol::AddListenerOnWaylandObject(m_clientLibrary,
+                                       pointer,
+                                       &m_listener,
+                                       this);
+}
+
+xw::Pointer::~Pointer()
+{
+  protocol::DestroyWaylandObject(m_clientLibrary,
+                                 m_pointer);
+}
+
+void xw::Pointer::SetCursor(uint32_t serial,
+                            struct wl_surface *surface,
+                            int32_t hotspot_x,
+                            int32_t hotspot_y)
+{
+  protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                      m_pointer,
+                                      WL_POINTER_SET_CURSOR,
+                                      serial,
+                                      surface,
+                                      hotspot_x,
+                                      hotspot_y);
+}
+
+void xw::Pointer::HandleEnterCallback(void *data,
+                                      struct wl_pointer *pointer,
+                                      uint32_t serial,
+                                      struct wl_surface *surface,
+                                      wl_fixed_t x,
+                                      wl_fixed_t y)
+{
+  static_cast<Pointer *>(data)->HandleEnter(serial,
+                                            surface,
+                                            x,
+                                            y);
+}
+
+void xw::Pointer::HandleLeaveCallback(void *data,
+                                      struct wl_pointer *pointer,
+                                      uint32_t serial,
+                                      struct wl_surface *surface)
+{
+  static_cast<Pointer *>(data)->HandleLeave(serial, surface);
+}
+
+void xw::Pointer::HandleMotionCallback(void *data,
+                                       struct wl_pointer *pointer,
+                                       uint32_t time,
+                                       wl_fixed_t x,
+                                       wl_fixed_t y)
+{
+  static_cast<Pointer *>(data)->HandleMotion(time,
+                                             x,
+                                             y);
+}
+
+void xw::Pointer::HandleButtonCallback(void *data,
+                                       struct wl_pointer * pointer,
+                                       uint32_t serial,
+                                       uint32_t time,
+                                       uint32_t button,
+                                       uint32_t state)
+{
+  static_cast<Pointer *>(data)->HandleButton(serial,
+                                             time,
+                                             button,
+                                             state);
+}
+
+void xw::Pointer::HandleAxisCallback(void *data,
+                                     struct wl_pointer *pointer,
+                                     uint32_t time,
+                                     uint32_t axis,
+                                     wl_fixed_t value)
+{
+  static_cast<Pointer *>(data)->HandleAxis(time,
+                                           axis,
+                                           value);
+}
+
+void xw::Pointer::HandleEnter(uint32_t serial,
+                              struct wl_surface *surface,
+                              wl_fixed_t surfaceXFixed,
+                              wl_fixed_t surfaceYFixed)
+{
+  m_receiver.Enter(surface,
+                   wl_fixed_to_double(surfaceXFixed),
+                   wl_fixed_to_double(surfaceYFixed));
+}
+
+void xw::Pointer::HandleLeave(uint32_t serial,
+                              struct wl_surface *surface)
+{
+}
+
+void xw::Pointer::HandleMotion(uint32_t time,
+                               wl_fixed_t surfaceXFixed,
+                               wl_fixed_t surfaceYFixed)
+{
+  m_receiver.Motion(time,
+                    wl_fixed_to_double(surfaceXFixed),
+                    wl_fixed_to_double(surfaceYFixed));
+}
+
+void xw::Pointer::HandleButton(uint32_t serial,
+                               uint32_t time,
+                               uint32_t button,
+                               uint32_t state)
+{
+  m_receiver.Button(serial,
+                    time,
+                    button,
+                    static_cast<enum wl_pointer_button_state>(state));
+}
+
+void xw::Pointer::HandleAxis(uint32_t time,
+                             uint32_t axis,
+                             wl_fixed_t value)
+{
+  m_receiver.Axis(time,
+                  axis,
+                  wl_fixed_to_double(value));
+}
diff --git a/xbmc/windowing/wayland/Pointer.h b/xbmc/windowing/wayland/Pointer.h
new file mode 100644 (file)
index 0000000..1987e06
--- /dev/null
@@ -0,0 +1,130 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+
+#include <wayland-client.h>
+
+class IDllWaylandClient;
+
+namespace xbmc
+{
+namespace wayland
+{
+class IPointerReceiver
+{
+public:
+
+  virtual ~IPointerReceiver() {}
+  virtual void Motion(uint32_t time,
+                      const float &x,
+                      const float &y) = 0;
+  virtual void Button(uint32_t serial,
+                      uint32_t time,
+                      uint32_t button,
+                      enum wl_pointer_button_state state) = 0;
+  virtual void Axis(uint32_t time,
+                    uint32_t axis,
+                    float value) = 0;
+  virtual void Enter(struct wl_surface *surface,
+                     double surfaceX,
+                     double surfaceY) = 0;
+};
+
+/* Wrapper class for a pointer object. Generally there is one pointer
+ * per seat.
+ * 
+ * Events are forwarded from the internal proxy to an IPointerReceiver
+ * for further processing. The responsibility of this class is only
+ * to receive the events and represent them in a sensible way */
+class Pointer
+{
+public:
+
+  Pointer(IDllWaylandClient &,
+          struct wl_pointer *,
+          IPointerReceiver &);
+  ~Pointer();
+
+  struct wl_pointer * GetWlPointer();
+
+  /* This method changes the cursor to have the contents of
+   * an arbitrary surface on the server side. It can also hide
+   * the cursor if NULL is passed as "surface" */
+  void SetCursor(uint32_t serial,
+                 struct wl_surface *surface,
+                 int32_t hotspot_x,
+                 int32_t hotspot_y);
+
+  static void HandleEnterCallback(void *,
+                                  struct wl_pointer *,
+                                  uint32_t,
+                                  struct wl_surface *,
+                                  wl_fixed_t, 
+                                  wl_fixed_t);
+  static void HandleLeaveCallback(void *,
+                                  struct wl_pointer *,
+                                  uint32_t,
+                                  struct wl_surface *);
+  static void HandleMotionCallback(void *,
+                                   struct wl_pointer *,
+                                   uint32_t,
+                                   wl_fixed_t,
+                                   wl_fixed_t);
+  static void HandleButtonCallback(void *,
+                                   struct wl_pointer *,
+                                   uint32_t,
+                                   uint32_t,
+                                   uint32_t,
+                                   uint32_t);
+  static void HandleAxisCallback(void *,
+                                 struct wl_pointer *,
+                                 uint32_t,
+                                 uint32_t,
+                                 wl_fixed_t);
+
+private:
+
+  void HandleEnter(uint32_t serial,
+                   struct wl_surface *surface,
+                   wl_fixed_t surfaceXFixed,
+                   wl_fixed_t surfaceYFixed);
+  void HandleLeave(uint32_t serial,
+                   struct wl_surface *surface);
+  void HandleMotion(uint32_t time,
+                    wl_fixed_t surfaceXFixed,
+                    wl_fixed_t surfaceYFixed);
+  void HandleButton(uint32_t serial,
+                    uint32_t time,
+                    uint32_t button,
+                    uint32_t state);
+  void HandleAxis(uint32_t time,
+                  uint32_t axis,
+                  wl_fixed_t value);
+
+  static const struct wl_pointer_listener m_listener;
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_pointer *m_pointer;
+  IPointerReceiver &m_receiver;
+};
+}
+}
diff --git a/xbmc/windowing/wayland/PointerProcessor.cpp b/xbmc/windowing/wayland/PointerProcessor.cpp
new file mode 100644 (file)
index 0000000..c3cd377
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <wayland-client.h>
+#include <xkbcommon/xkbcommon.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/DllXKBCommon.h"
+
+#include "CursorManager.h"
+#include "EventListener.h"
+#include "Pointer.h"
+#include "PointerProcessor.h"
+
+xbmc::PointerProcessor::PointerProcessor(IEventListener &listener,
+                                         ICursorManager &manager) :
+  m_listener(listener),
+  m_cursorManager(manager)
+{
+}
+
+void xbmc::PointerProcessor::Motion(uint32_t time,
+                                    const float &x,
+                                    const float &y)
+{
+  XBMC_Event event;
+
+  event.type = XBMC_MOUSEMOTION;
+  event.motion.xrel = ::round(x);
+  event.motion.yrel = ::round(y);
+  event.motion.state = 0;
+  event.motion.type = XBMC_MOUSEMOTION;
+  event.motion.which = 0;
+  event.motion.x = event.motion.xrel;
+  event.motion.y = event.motion.yrel;
+
+  m_lastPointerX = x;
+  m_lastPointerY = y;
+
+  m_listener.OnEvent(event);
+}
+
+void xbmc::PointerProcessor::Button(uint32_t serial,
+                                    uint32_t time,
+                                    uint32_t button,
+                                    enum wl_pointer_button_state state)
+{
+  static const struct ButtonTable
+  {
+    unsigned int WaylandButton;
+    unsigned int XBMCButton;
+  } buttonTable[] =
+  {
+    { WaylandLeftButton, 1 },
+    { WaylandMiddleButton, 2 },
+    { WaylandRightButton, 3 }
+  };
+
+  size_t buttonTableSize = sizeof(buttonTable) / sizeof(buttonTable[0]);
+
+  /* Find the xbmc button number that corresponds to the evdev
+   * button that we just received. There may be some buttons we don't
+   * recognize so just ignore them */
+  unsigned int xbmcButton = 0;
+
+  for (size_t i = 0; i < buttonTableSize; ++i)
+    if (buttonTable[i].WaylandButton == button)
+      xbmcButton = buttonTable[i].XBMCButton;
+
+  if (!xbmcButton)
+    return;
+
+  /* Keep track of currently pressed buttons, we need that for
+   * motion events */
+  if (state & WL_POINTER_BUTTON_STATE_PRESSED)
+    m_currentlyPressedButton |= 1 << button;
+  else if (state & WL_POINTER_BUTTON_STATE_RELEASED)
+    m_currentlyPressedButton &= ~(1 << button);
+
+  XBMC_Event event;
+
+  event.type = state & WL_POINTER_BUTTON_STATE_PRESSED ?
+               XBMC_MOUSEBUTTONDOWN : XBMC_MOUSEBUTTONUP;
+  event.button.button = xbmcButton;
+  event.button.state = 0;
+  event.button.type = event.type;
+  event.button.which = 0;
+  event.button.x = ::round(m_lastPointerX);
+  event.button.y = ::round(m_lastPointerY);
+
+  m_listener.OnEvent(event);
+}
+
+void xbmc::PointerProcessor::Axis(uint32_t time,
+                                  uint32_t axis,
+                                  float value)
+{
+  if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
+  {
+    /* Negative is up */
+    bool direction = value < 0.0f;
+    int  button = direction ? WheelUpButton :
+                              WheelDownButton;
+
+    /* For axis events we only care about the vector direction
+     * and not the scalar magnitude. Every axis event callback
+     * generates one scroll button event for XBMC */
+    XBMC_Event event;
+
+    event.type = XBMC_MOUSEBUTTONDOWN;
+    event.button.button = button;
+    event.button.state = 0;
+    event.button.type = XBMC_MOUSEBUTTONDOWN;
+    event.button.which = 0;
+    event.button.x = ::round(m_lastPointerX);
+    event.button.y = ::round(m_lastPointerY);
+
+    m_listener.OnEvent(event);
+    
+    /* We must also send a button up on the same
+     * wheel "button" */
+    event.type = XBMC_MOUSEBUTTONUP;
+    event.button.type = XBMC_MOUSEBUTTONUP;
+    
+    m_listener.OnEvent(event);
+  }
+}
+
+void
+xbmc::PointerProcessor::Enter(struct wl_surface *surface,
+                              double surfaceX,
+                              double surfaceY)
+{
+  m_cursorManager.SetCursor(0, NULL, 0, 0);
+}
diff --git a/xbmc/windowing/wayland/PointerProcessor.h b/xbmc/windowing/wayland/PointerProcessor.h
new file mode 100644 (file)
index 0000000..d1f683a
--- /dev/null
@@ -0,0 +1,76 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include "Pointer.h"
+
+struct wl_surface;
+
+namespace xbmc
+{
+class IEventListener;
+class ICursorManager;
+
+/* PointerProcessor implements IPointerReceiver and transforms input
+ * wayland mouse event callbacks into XBMC events. It also handles
+ * changing the cursor image on surface entry */
+class PointerProcessor :
+  public wayland::IPointerReceiver
+{
+public:
+
+  PointerProcessor(IEventListener &,
+                   ICursorManager &);
+
+private:
+
+  void Motion(uint32_t time,
+              const float &x,
+              const float &y);
+  void Button(uint32_t serial,
+              uint32_t time,
+              uint32_t button,
+              enum wl_pointer_button_state state);
+  void Axis(uint32_t time,
+            uint32_t axis,
+            float value);
+  void Enter(struct wl_surface *surface,
+             double surfaceX,
+             double surfaceY);
+
+  IEventListener &m_listener;
+  ICursorManager &m_cursorManager;
+
+  uint32_t m_currentlyPressedButton;
+  float    m_lastPointerX;
+  float    m_lastPointerY;
+
+  /* There is no defined export for these buttons -
+   * wayland appears to just be using the evdev codes
+   * directly */
+  static const unsigned int WaylandLeftButton = 272;
+  static const unsigned int WaylandRightButton = 273;
+  static const unsigned int WaylandMiddleButton = 274;
+
+  static const unsigned int WheelUpButton = 4;
+  static const unsigned int WheelDownButton = 5;
+  
+};
+}
diff --git a/xbmc/windowing/wayland/PollThread.cpp b/xbmc/windowing/wayland/PollThread.cpp
new file mode 100644 (file)
index 0000000..dfd7ec3
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <sstream>
+#include <stdexcept>
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+
+#include "utils/log.h"
+
+#include "PollThread.h"
+
+namespace xwe = xbmc::wayland::events;
+
+xwe::PollThread::PollThread(const Dispatch &dispatch,
+                            const Dispatch &beforePoll,
+                            int fd) :
+  CThread("wayland-event-thread"),
+  m_dispatch(dispatch),
+  m_beforePoll(beforePoll),
+  m_fd(fd)
+{
+  /* Create wakeup pipe. We will poll on the read end of this. If
+   * there are any events, it means its time to shut down */
+  if (pipe2(m_wakeupPipe, O_CLOEXEC) == -1)
+  {
+    std::stringstream ss;
+    ss << strerror(errno);
+    throw std::runtime_error(ss.str());
+  }
+  
+  /* Create poll thread */
+  Create();
+}
+
+xwe::PollThread::~PollThread()
+{
+  /* Send a message to the reader thread that its time to shut down */
+  if (write(m_wakeupPipe[1], (const void *) "q", 1) == -1)
+    CLog::Log(LOGERROR, "%s: Failed to write to shutdown wakeup pipe. "
+                        "Application may hang. Reason was: %s",
+              __FUNCTION__, strerror(errno));
+
+  /* Close the write end, as we no longer need it */
+  if (close(m_wakeupPipe[1]) == -1)
+    CLog::Log(LOGERROR, "%s: Failed to close shutdown pipe write end. "
+                      "Leak may occurr. Reason was: %s",
+            __FUNCTION__, strerror(errno));
+
+  /* The destructor for CThread will cause it to join */
+}
+
+namespace
+{
+bool Ready(int revents)
+{
+  if (revents & (POLLHUP | POLLERR))
+    CLog::Log(LOGERROR, "%s: Error on fd. Reason was: %s",
+              __FUNCTION__, strerror(errno));
+  
+  return revents & POLLIN;
+}
+}
+
+void
+xwe::PollThread::Process()
+{
+  static const unsigned int MonitoredFdIndex = 0;
+  static const unsigned int ShutdownFdIndex = 1;
+  
+  while (1)
+  {
+    struct pollfd pfd[2] =
+    {
+      { m_fd, POLLIN | POLLHUP | POLLERR, 0 },
+      { m_wakeupPipe[0], POLLIN | POLLHUP | POLLERR, 0 }
+    };
+    
+    m_beforePoll();
+    
+    /* Sleep forever until something happens */
+    if (poll(pfd, 2, -1) == -1)
+      CLog::Log(LOGERROR, "%s: Poll failed. Reason was: %s",
+                __FUNCTION__, strerror(errno));
+    
+    /* Check the shutdown pipe first as we might need to
+     * shutdown */
+    if (Ready(pfd[ShutdownFdIndex].revents))
+    {
+      if (close(m_wakeupPipe[0]) == -1)
+        CLog::Log(LOGERROR, "%s: Failed to close shutdown pipe read end. "
+                            "Leak may occurr. Reason was: %s",
+                  __FUNCTION__, strerror(errno));
+      return;
+    }
+    else if (Ready(pfd[MonitoredFdIndex].revents))
+      m_dispatch();
+  }
+}
diff --git a/xbmc/windowing/wayland/PollThread.h b/xbmc/windowing/wayland/PollThread.h
new file mode 100644 (file)
index 0000000..31ba07e
--- /dev/null
@@ -0,0 +1,65 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+
+#include "threads/Thread.h"
+
+namespace xbmc
+{
+namespace wayland
+{
+namespace events
+{
+/* This is effectively a "reader" worker thread. It has two
+ * injected extension points - dispatch and beforePoll and takes
+ * a file descriptor related to those two extension points for polling.
+ * 
+ * Before polling occurrs, beforePoll() is called and then this thread
+ * will poll on two file descriptors - the provided one and an internal
+ * one to manage thread joins.  If data is ready on the file descriptor,
+ * then dispatch() will be called.
+ */
+class PollThread :
+  public CThread
+{
+public:
+
+  typedef boost::function<void()> Dispatch;
+
+  PollThread(const Dispatch &dispatch,
+             const Dispatch &beforePoll,
+             int fd);
+  ~PollThread();
+
+private:
+
+  void Process();
+
+  Dispatch m_dispatch;
+  Dispatch m_beforePoll;
+  int m_fd;
+  int m_wakeupPipe[2];
+};
+}
+}
+}
diff --git a/xbmc/windowing/wayland/Seat.cpp b/xbmc/windowing/wayland/Seat.cpp
new file mode 100644 (file)
index 0000000..15c5571
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <sstream>
+#include <iostream>
+#include <stdexcept>
+
+#include <wayland-client.h>
+
+#include "windowing/DllWaylandClient.h"
+#include "windowing/WaylandProtocol.h"
+#include "Seat.h"
+
+namespace xw = xbmc::wayland;
+
+/* We only support version 1 of this interface, the
+ * other struct members are impliedly set to NULL */
+const struct wl_seat_listener xw::Seat::m_listener =
+{
+  Seat::HandleCapabilitiesCallback
+};
+
+xw::Seat::Seat(IDllWaylandClient &clientLibrary,
+               struct wl_seat *seat,
+               IInputReceiver &reciever) :
+  m_clientLibrary(clientLibrary),
+  m_seat(seat),
+  m_input(reciever),
+  m_currentCapabilities(static_cast<enum wl_seat_capability>(0))
+{
+  protocol::AddListenerOnWaylandObject(m_clientLibrary,
+                                       m_seat,
+                                       &m_listener,
+                                       reinterpret_cast<void *>(this));
+}
+
+xw::Seat::~Seat()
+{
+  protocol::DestroyWaylandObject(m_clientLibrary,
+                                 m_seat);
+}
+
+void xw::Seat::HandleCapabilitiesCallback(void *data,
+                                          struct wl_seat *seat,
+                                          uint32_t cap)
+{
+  enum wl_seat_capability capabilities =
+    static_cast<enum wl_seat_capability>(cap);
+  static_cast<Seat *>(data)->HandleCapabilities(capabilities);
+}
+
+/* The capabilities callback is effectively like a mini-registry
+ * for all of the child objects of a Seat */
+void xw::Seat::HandleCapabilities(enum wl_seat_capability cap)
+{
+  enum wl_seat_capability newCaps =
+    static_cast<enum wl_seat_capability>(~m_currentCapabilities & cap);
+  enum wl_seat_capability lostCaps =
+    static_cast<enum wl_seat_capability>(m_currentCapabilities & ~cap);
+
+  if (newCaps & WL_SEAT_CAPABILITY_POINTER)
+  {
+    struct wl_pointer *pointer =
+      protocol::CreateWaylandObject<struct wl_pointer *,
+                                    struct wl_seat *>(m_clientLibrary,
+                                                      m_seat,
+                                                      m_clientLibrary.Get_wl_pointer_interface());
+    protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                        m_seat,
+                                        WL_SEAT_GET_POINTER,
+                                        pointer);
+    m_input.InsertPointer(pointer);
+  }
+
+  if (newCaps & WL_SEAT_CAPABILITY_KEYBOARD)
+  {
+    struct wl_keyboard *keyboard =
+      protocol::CreateWaylandObject<struct wl_keyboard *,
+                                    struct wl_seat *>(m_clientLibrary,
+                                                      m_seat,
+                                                      m_clientLibrary.Get_wl_keyboard_interface());
+    protocol::CallMethodOnWaylandObject(m_clientLibrary,
+                                        m_seat,
+                                        WL_SEAT_GET_KEYBOARD,
+                                        keyboard);
+    m_input.InsertKeyboard(keyboard);
+  }
+
+  if (lostCaps & WL_SEAT_CAPABILITY_POINTER)
+    m_input.RemovePointer();
+
+  if (lostCaps & WL_SEAT_CAPABILITY_KEYBOARD)
+    m_input.RemoveKeyboard();
+
+  m_currentCapabilities = cap;
+}
diff --git a/xbmc/windowing/wayland/Seat.h b/xbmc/windowing/wayland/Seat.h
new file mode 100644 (file)
index 0000000..4729ac4
--- /dev/null
@@ -0,0 +1,74 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <boost/noncopyable.hpp>
+
+#include <wayland-client.h>
+
+class IDllWaylandClient;
+
+namespace xbmc
+{
+namespace wayland
+{
+class IInputReceiver
+{
+public:
+
+  virtual ~IInputReceiver() {}
+
+  virtual bool InsertPointer(struct wl_pointer *pointer) = 0;
+  virtual bool InsertKeyboard(struct wl_keyboard *keyboard) = 0;
+
+  virtual void RemovePointer() = 0;
+  virtual void RemoveKeyboard() = 0;
+};
+
+class Seat :
+  public boost::noncopyable
+{
+public:
+
+  Seat(IDllWaylandClient &,
+       struct wl_seat *,
+       IInputReceiver &);
+  ~Seat();
+
+  struct wl_seat * GetWlSeat();
+
+  static void HandleCapabilitiesCallback(void *,
+                                         struct wl_seat *,
+                                         uint32_t);
+
+private:
+
+  static const struct wl_seat_listener m_listener;
+
+  void HandleCapabilities(enum wl_seat_capability);
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_seat * m_seat;
+  IInputReceiver &m_input;
+
+  enum wl_seat_capability m_currentCapabilities;
+};
+}
+}
diff --git a/xbmc/windowing/wayland/TimeoutManager.h b/xbmc/windowing/wayland/TimeoutManager.h
new file mode 100644 (file)
index 0000000..26bbc50
--- /dev/null
@@ -0,0 +1,45 @@
+#pragma once
+
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace xbmc
+{
+/* ITimeoutManager defines an interface for arbitary classes
+ * to register full closures to be called initially on a timeout
+ * specified by initial and then subsequently on a timeout specified
+ * by timeout. The interface is more or less artificial and exists to
+ * break the dependency between keyboard processing code and
+ * actual system timers, whcih is useful for testing purposes */
+class ITimeoutManager
+{
+public:
+  
+  typedef boost::function<void()> Callback;
+  typedef boost::shared_ptr <Callback> CallbackPtr;
+  
+  virtual ~ITimeoutManager() {}
+  virtual CallbackPtr RepeatAfterMs (const Callback &callback,
+                                     uint32_t initial, 
+                                     uint32_t timeout) = 0;
+};
+}
diff --git a/xbmc/windowing/wayland/Wayland11EventQueueStrategy.cpp b/xbmc/windowing/wayland/Wayland11EventQueueStrategy.cpp
new file mode 100644 (file)
index 0000000..5b69fe1
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <algorithm>
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "windowing/DllWaylandClient.h"
+#include "utils/log.h"
+
+#include "Wayland11EventQueueStrategy.h"
+
+namespace xwe = xbmc::wayland::events;
+namespace xw11 = xbmc::wayland::version_11;
+
+/* It is very important that these functions occurr in the order.
+ * that they are written below. Deadlocks might occurr otherwise.
+ * 
+ * The first function dispatches any pending events that have been
+ * determined from prior reads of the event queue without *also*
+ * reading the event queue.
+ * 
+ * The second function function reads the input buffer and dispatches
+ * any events that occurred, but only after the reading thread goes
+ * to sleep waiting for new data to arrive on the pipe.
+ * 
+ * The output buffer will be flushed periodically (on the render loop,
+ * which never sleeps) and will flush any pending requests after
+ * eglSwapBuffers that may have happened just before this thread starts
+ * polling.
+ * 
+ * If the functions are not called in this order, you might run into
+ * a situation where pending-dispatch events might have generated a
+ * write to the event queue in order to keep us awake (frame events
+ * are a particular culprit here), or where events that we need to
+ * dispatch in order to keep going are never read.
+ */
+namespace
+{
+void DispatchPendingEvents(IDllWaylandClient &clientLibrary,
+                           struct wl_display *display)
+{
+  clientLibrary.wl_display_dispatch_pending(display);
+  /* We flush the output queue in the main thread as that needs to
+   * happen after eglSwapBuffers */
+}
+
+void ReadAndDispatch(IDllWaylandClient &clientLibrary,
+                     struct wl_display *display)
+{
+  clientLibrary.wl_display_dispatch(display);
+}
+}
+
+xw11::EventQueueStrategy::EventQueueStrategy(IDllWaylandClient &clientLibrary,
+                                             struct wl_display *display) :
+  m_clientLibrary(clientLibrary),
+  m_display(display),
+  m_thread(boost::bind(ReadAndDispatch,
+                       boost::ref(m_clientLibrary),
+                       m_display),
+           boost::bind(DispatchPendingEvents,
+                       boost::ref(m_clientLibrary),
+                       m_display),
+           m_clientLibrary.wl_display_get_fd(m_display))
+{
+}
+
+namespace
+{
+void ExecuteAction(const xwe::IEventQueueStrategy::Action &action)
+{
+  action();
+}
+}
+
+void
+xw11::EventQueueStrategy::DispatchEventsFromMain()
+{
+  unsigned int numActions = 0;
+  std::vector<Action> pendingActions;
+  
+  /* We only need to hold the lock while we copy out actions from the
+   * queue */
+  {
+    CSingleLock lock(m_actionsMutex);
+    numActions = m_actions.size();
+    pendingActions.reserve(numActions);
+    
+    /* Only pump the initial queued event count otherwise if the UI
+     * keeps pushing events then the loop won't finish */
+    for (unsigned int index = 0; index < numActions; ++index)
+    {      
+      pendingActions.push_back(m_actions.front());
+      m_actions.pop();
+    }
+  }
+  
+  /* Execute each of the queued up actions */
+  std::for_each(pendingActions.begin(),
+                pendingActions.end(),
+                ExecuteAction);
+  
+  /* After we've done dispatching flush the event queue */
+  m_clientLibrary.wl_display_flush(m_display);
+}
+
+void
+xw11::EventQueueStrategy::PushAction(const Action &action)
+{
+  CSingleLock lock(m_actionsMutex);
+  m_actions.push(action);
+}
diff --git a/xbmc/windowing/wayland/Wayland11EventQueueStrategy.h b/xbmc/windowing/wayland/Wayland11EventQueueStrategy.h
new file mode 100644 (file)
index 0000000..90c11cd
--- /dev/null
@@ -0,0 +1,79 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <queue>
+
+#include <boost/noncopyable.hpp>
+
+#include "threads/CriticalSection.h"
+#include "EventQueueStrategy.h"
+#include "PollThread.h"
+
+class IDllWaylandClient;
+
+struct wl_display;
+
+namespace xbmc
+{
+namespace wayland
+{
+namespace version_11
+{
+/* The EventQueueStrategy for Wayland <= 1.1 requires that events
+ * be dispatched and initally processed in a separate thread. This
+ * means that all the wayland proxy object wrappers callbacks will
+ * be running in the same thread that reads the event queue for events.
+ * 
+ * When those events are initially processed, they will be put into the
+ * main WaylandEventLoop queue and dispatched sequentially from there
+ * periodically (once every redraw) into the main thread.
+ * 
+ * The reason for this is that Wayland versions prior to 1.1 provide
+ * no means to read the event queue without also dispatching pending
+ * events and callbacks on proxy objects. But we also cannot block the
+ * main thread, which may occurr if we call wl_display_dispatch
+ * and there is no pending frame callback because our surface is not
+ * visible.
+ */
+class EventQueueStrategy :
+  public events::IEventQueueStrategy
+{
+public:
+
+  EventQueueStrategy(IDllWaylandClient &clientLibrary,
+                     struct wl_display *display);
+
+  void PushAction(const Action &action);
+  void DispatchEventsFromMain();
+
+private:
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_display *m_display;
+
+  events::PollThread m_thread;
+  
+  CCriticalSection m_actionsMutex;
+  std::queue<Action> m_actions;
+};
+}
+}
+}
diff --git a/xbmc/windowing/wayland/Wayland12EventQueueStrategy.cpp b/xbmc/windowing/wayland/Wayland12EventQueueStrategy.cpp
new file mode 100644 (file)
index 0000000..adad629
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+*      Copyright (C) 2005-2013 Team XBMC
+*      http://www.xbmc.org
+*
+*  This Program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2, or (at your option)
+*  any later version.
+*
+*  This Program is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*  GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with XBMC; see the file COPYING.  If not, see
+*  <http://www.gnu.org/licenses/>.
+*
+*/
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/noncopyable.hpp>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "windowing/DllWaylandClient.h"
+#include "utils/log.h"
+
+#include "Wayland12EventQueueStrategy.h"
+
+namespace xw12 = xbmc::wayland::version_12;
+
+namespace
+{
+/* Pending events dispatch happens in the main thread, so there is
+ * no before-poll action that occurrs here */
+void Nothing()
+{
+}
+
+void Read(IDllWaylandClient &clientLibrary,
+          struct wl_display *display)
+{
+  /* If wl_display_prepare_read() returns a nonzero value it means
+   * that we still have more events to dispatch. So let the main thread
+   * dispatch all the pending events first before trying to read
+   * more events from the pipe */
+  if ((*(clientLibrary.wl_display_prepare_read_proc()))(display) == 0)
+    (*(clientLibrary.wl_display_read_events_proc()))(display);
+}
+}
+
+xw12::EventQueueStrategy::EventQueueStrategy(IDllWaylandClient &clientLibrary,
+                                             struct wl_display *display) :
+  m_clientLibrary(clientLibrary),
+  m_display(display),
+  m_thread(boost::bind(Read, boost::ref(m_clientLibrary), display),
+           boost::bind(Nothing),
+           m_clientLibrary.wl_display_get_fd(m_display))
+{
+}
+
+void
+xw12::EventQueueStrategy::DispatchEventsFromMain()
+{
+  /* It is very important that these functions occurr in the order.
+   * that they are written below. Deadlocks might occurr otherwise.
+   * 
+   * The first function dispatches any pending events that have been
+   * determined from prior reads of the event queue without *also*
+   * reading the event queue.
+   * 
+   * The second function function flushes the output buffer so that our
+   * just-dispatched events will cause data to be processed on the
+   * compositor which results in more events for us to read.
+   * 
+   * The input buffer will be read periodically (on the render loop,
+   * which never sleeps)
+   * 
+   * If the functions are not called in this order, you might run into
+   * a situation where pending-dispatch events might have generated a
+   * write to the event queue in order to keep us awake (frame events
+   * are a particular culprit here), or where events that we need to
+   * dispatch in order to keep going are never read.
+   */
+  m_clientLibrary.wl_display_dispatch_pending(m_display);
+  /* We perform the flush here and not in the reader thread
+   * as it needs to come after eglSwapBuffers */
+  m_clientLibrary.wl_display_flush(m_display);
+}
+
+void
+xw12::EventQueueStrategy::PushAction(const Action &action)
+{
+  action();
+}
diff --git a/xbmc/windowing/wayland/Wayland12EventQueueStrategy.h b/xbmc/windowing/wayland/Wayland12EventQueueStrategy.h
new file mode 100644 (file)
index 0000000..0387d83
--- /dev/null
@@ -0,0 +1,59 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2011-2013 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, see
+ *  <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <queue>
+
+#include <boost/noncopyable.hpp>
+
+#include "EventQueueStrategy.h"
+#include "PollThread.h"
+
+class IDllWaylandClient;
+
+struct wl_display;
+
+namespace xbmc
+{
+namespace wayland
+{
+namespace version_12
+{
+class EventQueueStrategy :
+  public events::IEventQueueStrategy
+{
+public:
+
+  EventQueueStrategy(IDllWaylandClient &clientLibrary,
+                     struct wl_display *display);
+
+  void PushAction(const Action &action);
+  void DispatchEventsFromMain();
+
+private:
+
+  IDllWaylandClient &m_clientLibrary;
+  struct wl_display *m_display;
+
+  events::PollThread m_thread;
+};
+}
+}
+}