/xbmc/guilib/Profile
/xbmc/guilib/Profile_FastCap
+# /xbmc/input
+/xbmc/input/linux/Makefile
+
# /xbmc/interfaces/
/xbmc/interfaces/Makefile
/xbmc/interfaces/python/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
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 '-----------------------'
check: testsuite
for check_program in $(CHECK_PROGRAMS); do $(CURDIR)/$$check_program; done
-testsuite: $(CHECK_PROGRAMS)
+testsuite: $(CHECK_EXTENSIONS) $(CHECK_PROGRAMS)
testframework: $(GTEST_LIBS)
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.
<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>
<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>
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. =="
[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'])],
AC_PROG_AWK
AC_PROG_LN_S
AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
MAKE="${MAKE:-make}"
OBJDUMP="${OBJDUMP:-objdump}"
use_gles=yes
use_sdl=no
use_x11=no
+ use_wayland=no
;;
arm*-*linux-android*)
target_platform=target_android
use_optical_drive=no
use_sdl=no
use_x11=no
+ use_wayland=no
build_shared_lib=yes
;;
*)
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"
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
xbmc/music/karaoke/Makefile \
xbmc/osx/Makefile \
xbmc/guilib/Makefile \
+ xbmc/input/linux/Makefile \
xbmc/interfaces/Makefile \
xbmc/network/Makefile \
xbmc/network/upnp/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 \
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
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)
%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"
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"
echo %DIETEXT%
SET exitcode=1
ECHO ------------------------------------------------------------
+ GOTO END
:VIEWLOG_EXE
SET log="%CD%\..\vs2010express\XBMC\%buildconfig%\objs\XBMC.log"
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
--- /dev/null
+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
--- /dev/null
+WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )}
+XBMC_PLATFORM_DIR=android
+. $WORKSPACE/tools/buildsteps/defaultenv
+
+make -C $WORKSPACE/tools/depends/target/xbmc
--- /dev/null
+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
+
--- /dev/null
+WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )}
+XBMC_PLATFORM_DIR=android
+. $WORKSPACE/tools/buildsteps/defaultenv
+
+cd $WORKSPACE;make -j$BUILDTHREADS
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )}
+XBMC_PLATFORM_DIR=android
+. $WORKSPACE/tools/buildsteps/defaultenv
+
+#nothing on android
#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
}
ifeq ($(OS),android)
DEPENDS += mdnsresponder android-sources-ics
+ EXCLUDED_DEPENDS = gmp nettle gnutls
endif
DEPENDS := $(filter-out $(EXCLUDED_DEPENDS),$(DEPENDS))
# lib name, version
LIBNAME=libass
-VERSION=0.9.13
+VERSION=0.10.1
SOURCE=$(LIBNAME)-$(VERSION)
ARCHIVE=$(SOURCE).tar.gz
/* 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
#pragma once
-
/*
* Copyright (C) 2005-2013 Team XBMC
* http://xbmc.org
#define BEGIN_METHOD_RESOLVE() \
protected: \
virtual bool ResolveExports() \
- { \
- return (
+ {
#define END_METHOD_RESOLVE() \
- 1 \
- ); \
+ return true; \
}
///////////////////////////////////////////////////////////
// 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 );
+
+
///////////////////////////////////////////////////////////
//
// 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;
////////////////////////////////////////////////////////////////////
CJNIContext::~CJNIContext()
{
m_appInstance = NULL;
- m_context.release();
xbmc_jni_on_unload();
}
{
static std::string cast(jhstring const &v)
{
- return jcast_helper<std::string, jstring>::cast(v);
+ return jcast_helper<std::string, jstring>::cast(v.get());
}
};
{
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());
}
};
{
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());
}
};
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;
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;
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 */
{
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;
}
/* 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)
{
// 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());
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);
}
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 */
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 */
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; }
{
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);
{
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;
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;
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);
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);
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;
}
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)
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);
}
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)
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());
}
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;
}
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); };
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;
--- /dev/null
+#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;
+};
+++ /dev/null
-SRCS=LIRC.cpp \
- LinuxInputDevices.cpp
-
-LIB=input_linux.a
-
-include ../../../Makefile.include
--include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
--- /dev/null
+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)))
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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;
+};
"\"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"
"}"
};
"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
}
}
// ============================================================
// ============================================================
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,
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 );
(CStdString)strTextureFocus,
(CStdString)strTextureNoFocus,
label,
- (CStdString)strTextureRadioFocus,
- (CStdString)strTextureRadioNoFocus);
+ (CStdString)strTextureRadioOnFocus,
+ (CStdString)strTextureRadioOnNoFocus,
+ (CStdString)strTextureRadioOffFocus,
+ (CStdString)strTextureRadioOffNoFocus);
CGUIRadioButtonControl* pGuiButtonControl =
(CGUIRadioButtonControl*)pGUIControl;
#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,
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;
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();
}
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();
}
| static
+---------------------------------------------------------------------*/
CUPnP* CUPnP::upnp = NULL;
+static NPT_List<void*> g_UserData;
+static NPT_Mutex g_UserDataLock;
/*----------------------------------------------------------------------
| CDeviceHostReferenceHolder class
{
}
+#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 )
{
((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 */
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);
#include "music/tags/MusicInfoTag.h"
#include "TextureCache.h"
#include "ThumbLoader.h"
+#include "utils/URIUtils.h"
using namespace MUSIC_INFO;
using namespace XFILE;
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;
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
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);
}
CUPnPPlayer::~CUPnPPlayer()
{
CloseFile();
+ CUPnP::UnregisterUserdata(m_delegate);
delete m_delegate;
}
pDlgProgress->Progress();
/* reset the EPG pointers */
- m_database->ResetEPG();
+ if (m_database)
+ m_database->ResetEPG();
/* stop the thread */
Stop();
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");
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");
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");
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");
user.clear();
pass.clear();
name.clear();
+ key.clear();
+ cert.clear();
+ ca.clear();
+ capath.clear();
+ ciphers.clear();
};
CStdString type;
CStdString host;
CStdString user;
CStdString pass;
CStdString name;
+ CStdString key;
+ CStdString cert;
+ CStdString ca;
+ CStdString capath;
+ CStdString ciphers;
};
struct TVShowRegexp
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;
}
--- /dev/null
+#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;
+ }
+};
--- /dev/null
+#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()
+};
--- /dev/null
+#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()
+};
+++ /dev/null
-SRCS=WinEventsSDL.cpp \
- WinEventsLinux.cpp \
- WinSystem.cpp \
- WinEvents.cpp
-
-LIB=windowing.a
-
-include ../../Makefile.include
--include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
--- /dev/null
+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)))
--- /dev/null
+#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);
+}
+}
+}
+}
#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
static size_t GetQueueSize();
};
-
#endif // WINDOW_EVENTS_H
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+#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;
+};
*
*/
-#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)
#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);
// 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)))
{
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;
}
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;
};
+++ /dev/null
-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)))
--- /dev/null
+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)))
}
}
- 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[] =
{
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+ * 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 ®istration) :
+ 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);
+}
--- /dev/null
+#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 ®istration);
+ ~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);
+};
+}
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+ * 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()
+{
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+#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();
+}
+}
+}
--- /dev/null
+/*
+ * 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 ®istry);
+
+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 ®istry);
+ Implementations & Get(Registry ®istry);
+
+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 ®istry)
+{
+ /* 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 ®istry)
+{
+ /* 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 ®istry)
+{
+ 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 ¤t(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();
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+ * 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)));
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+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
--- /dev/null
+/*
+* 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)
+{
+}
--- /dev/null
+#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);
+};
--- /dev/null
+/*
+* 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);
+}
--- /dev/null
+#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;
+};
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+* 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);
+}
--- /dev/null
+/*
+* 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);
--- /dev/null
+/*
+* 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);
+}
--- /dev/null
+#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;
+};
--- /dev/null
+/*
+* 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, ¤tTime);
+
+ 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, ¤tTime);
+
+ 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());
+ }
+}
+
+
+
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+* 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);
+}
--- /dev/null
+#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;
+};
--- /dev/null
+/*
+* 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
--- /dev/null
+#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
--- /dev/null
+/*
+* 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;
+}
+}
+
--- /dev/null
+<?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
+ <http://www.gnu.org/licenses/>
+
+ </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>
--- /dev/null
+#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;
+};
+}
--- /dev/null
+#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;
+};
+}
--- /dev/null
+/*
+* 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;
+}
--- /dev/null
+#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;
+};
+}
+}
+}
--- /dev/null
+#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;
+};
+}
+}
+}
--- /dev/null
+/*
+* 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();
+}
--- /dev/null
+#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;
+};
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+* 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);
+}
--- /dev/null
+#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;
+};
+}
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+/*
+* 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);
+}
--- /dev/null
+#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;
+
+};
+}
--- /dev/null
+/*
+* 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();
+ }
+}
--- /dev/null
+#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];
+};
+}
+}
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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;
+};
+}
+}
--- /dev/null
+#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;
+};
+}
--- /dev/null
+/*
+* 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);
+}
--- /dev/null
+#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;
+};
+}
+}
+}
--- /dev/null
+/*
+* 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();
+}
--- /dev/null
+#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;
+};
+}
+}
+}