libuv support for dali-adaptor for running in Node.JS 23/42823/5
authorNick Holland <nick.holland@partner.samsung.com>
Tue, 23 Jun 2015 07:32:26 +0000 (08:32 +0100)
committerNick Holland <nick.holland@partner.samsung.com>
Tue, 7 Jul 2015 06:41:31 +0000 (07:41 +0100)
Highlights:
libuv support for timers, callbacks, file descriptor monitoring
pure X11 support for touch / key events
Exposed SceneCreated(), SetViewMode() and SetStereoBase in adaptor.h

Change-Id: I62030ef76337c568852f07d0ef6418e708fee9a3

31 files changed:
adaptors/base/interfaces/window-event-interface.h [new file with mode: 0644]
adaptors/common/adaptor-impl.cpp
adaptors/common/adaptor-impl.h
adaptors/common/adaptor.cpp
adaptors/common/event-loop/ecore/ecore-callback-manager.cpp [moved from adaptors/common/ecore-callback-manager.cpp with 100% similarity]
adaptors/common/event-loop/ecore/ecore-callback-manager.h [moved from adaptors/common/ecore-callback-manager.h with 90% similarity]
adaptors/common/event-loop/ecore/ecore-file-descriptor-monitor.cpp [moved from adaptors/common/file-descriptor-monitor.cpp with 100% similarity]
adaptors/common/event-loop/ecore/ecore-timer-impl.cpp [moved from adaptors/common/timer-impl.cpp with 100% similarity]
adaptors/common/event-loop/lib-uv/uv-callback-manager.cpp [new file with mode: 0644]
adaptors/common/event-loop/lib-uv/uv-callback-manager.h [new file with mode: 0644]
adaptors/common/event-loop/lib-uv/uv-file-descriptor-monitor.cpp [new file with mode: 0644]
adaptors/common/event-loop/lib-uv/uv-timer-impl.cpp [new file with mode: 0644]
adaptors/common/file.list
adaptors/common/orientation-impl.cpp
adaptors/common/shared-file.cpp
adaptors/common/window-impl.h
adaptors/integration-api/adaptor.h
adaptors/x11/ecore-x-event-handler.cpp [moved from adaptors/x11/event-handler-x.cpp with 100% similarity]
adaptors/x11/file.list
adaptors/x11/window-impl-x.cpp
adaptors/x11/x-event-handler.cpp [new file with mode: 0644]
adaptors/x11/x-events/debug/x-input2-debug.cpp [new file with mode: 0644]
adaptors/x11/x-events/debug/x-input2-debug.h [new file with mode: 0644]
adaptors/x11/x-events/x-event-manager.cpp [new file with mode: 0644]
adaptors/x11/x-events/x-event-manager.h [new file with mode: 0644]
adaptors/x11/x-events/x-input2-device.cpp [new file with mode: 0644]
adaptors/x11/x-events/x-input2-device.h [new file with mode: 0644]
adaptors/x11/x-events/x-input2.cpp [new file with mode: 0644]
adaptors/x11/x-events/x-input2.h [new file with mode: 0644]
build/tizen/adaptor/Makefile.am
build/tizen/configure.ac

diff --git a/adaptors/base/interfaces/window-event-interface.h b/adaptors/base/interfaces/window-event-interface.h
new file mode 100644 (file)
index 0000000..b689d58
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef __DALI_INTERNAL_BASE_WINDOW_EVENT_INTERFACE_H__
+#define __DALI_INTERNAL_BASE_WINDOW_EVENT_INTERFACE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/events/wheel-event.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief Abstract interface for handling DALi events received from the native window system
+ *
+ */
+class WindowEventInterface
+{
+
+public:
+
+  /**
+   * @brief Touch Event callback
+   * @param[in] point touch point
+   * @param[in] timeStamp time stamp
+   */
+  virtual void TouchEvent( Dali::TouchPoint& point, unsigned long timeStamp ) = 0;
+
+  /**
+   * @brief Key Event callback
+   * @param[in] keyEvent key event
+   */
+  virtual void KeyEvent( Dali::KeyEvent& keyEvent ) = 0;
+
+  /**
+   * @brief Wheel Event callback
+   * @param[in] wheelEvent wheel event
+   */
+  virtual void WheelEvent( Dali::WheelEvent& wheelEvent ) = 0;
+
+  /**
+   * @brief Window damage callback
+   * @param[in] damageArea Window damage area
+   */
+  virtual void DamageEvent( Dali::Rect<int>& damageArea ) = 0;
+
+  /**
+   * @brief Window Focused
+   */
+  virtual void WindowFocusIn() = 0;
+
+  /**
+   * @brief Window lost focus
+   */
+  virtual void WindowFocusOut() = 0;
+
+protected:
+
+  /**
+   * @brief Constructor
+   */
+  WindowEventInterface()
+  {
+  }
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~WindowEventInterface()
+  {
+  }
+
+  // Undefined copy constructor.
+  WindowEventInterface( const WindowEventInterface& );
+
+  // Undefined assignment operator.
+  WindowEventInterface& operator=( const WindowEventInterface& );
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_BASE_WINDOW_EVENT_INTERFACE_H__
index 9df9d70..70c829d 100644 (file)
@@ -494,6 +494,11 @@ bool Adaptor::IsAvailable()
   return gThreadLocalAdaptor != NULL;
 }
 
+void Adaptor::SceneCreated()
+{
+  mCore->SceneCreated();
+}
+
 Dali::Integration::Core& Adaptor::GetCore()
 {
   return *mCore;
index 9bebb38..8f2bd9f 100644 (file)
@@ -132,6 +132,11 @@ public:
    */
   static bool IsAvailable();
 
+  /**
+   * @copydoc Dali::Core::SceneCreated();
+   */
+  void SceneCreated();
+
 public: // AdaptorInternalServices implementation
   /**
    * @copydoc Dali::Adaptor::Start()
index bb4658a..e0af921 100644 (file)
@@ -159,6 +159,22 @@ void Adaptor::FeedKeyEvent( KeyEvent& keyEvent )
   mImpl->FeedKeyEvent(keyEvent);
 }
 
+void Adaptor::SceneCreated()
+{
+  mImpl->SceneCreated();
+}
+
+void Adaptor::SetViewMode( ViewMode mode )
+{
+  mImpl->SetViewMode( mode );
+}
+
+void Adaptor::SetStereoBase(  float stereoBase )
+{
+  mImpl->SetStereoBase( stereoBase );
+}
+
+
 Adaptor::Adaptor()
 : mImpl( NULL )
 {
@@ -44,13 +44,13 @@ class EcoreCallbackManager : public CallbackManager
 
 public:
 
-     /**
-     * constructor
+    /**
+     * @brief constructor
      */
     EcoreCallbackManager();
 
     /**
-     * destructor
+     * @brief destructor
      */
     ~EcoreCallbackManager()
     {
@@ -74,21 +74,21 @@ public:
 private:
 
     /**
-     * Remove all idle call backs that are pending
+     * @brief Remove all idle call backs that are pending
      * Called by Stop()
      * Always called from the main thread
      */
     void RemoveAllCallbacks();
 
     /**
-     * Removes a single call back from the container
+     * @brief Removes a single call back from the container
      * Always called from main thread
      * @param callbackData callback data
      */
     void RemoveCallbackFromContainer(CallbackData *callbackData);
 
     /**
-     * Remove a standard call back from ecore
+     * @brief Remove a standard call back from ecore
      * Always called from main thread
      * @param callbackData callback data
      */
diff --git a/adaptors/common/event-loop/lib-uv/uv-callback-manager.cpp b/adaptors/common/event-loop/lib-uv/uv-callback-manager.cpp
new file mode 100644 (file)
index 0000000..ab8552d
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "uv-callback-manager.h"
+
+// EXTERNAL INCLUDES
+#include <uv.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+static void FreeHandleCallback(uv_handle_t* handle )
+{
+  delete handle;
+}
+
+}
+/**
+ * Structure contains the callback function and control options
+ */
+struct CallbackData
+{
+  typedef void (*CallbackFunction)(uv_idle_t*);
+
+  /**
+   * Constructor
+   */
+  CallbackData( CallbackBase* callback )
+  :  mCallback(callback),
+     mRemoveFromContainerFunction(NULL),
+     mIdleHandle( NULL),
+     mExecute(true)
+  {
+  }
+
+  /**
+   * Add the idle callback
+   */
+  void AddIdle( CallbackFunction callback)
+  {
+    // heap allocate a handle as it will be alive after the CallbackData object is deleted.
+    mIdleHandle = new uv_idle_t;
+
+    // Node.JS uses uv_default_loop
+    uv_idle_init( uv_default_loop() , mIdleHandle );
+
+    mIdleHandle->data = this;
+
+    uv_idle_start( mIdleHandle, callback);
+  }
+
+  /**
+   * Destructor
+   */
+  ~CallbackData()
+  {
+    // the handle will still be alive for a short period after calling uv_close
+    // set the data to NULL to avoid a dangling pointer
+    mIdleHandle->data = NULL;
+
+    uv_idle_stop( mIdleHandle );
+
+    uv_close( reinterpret_cast< uv_handle_t*>( mIdleHandle ) , FreeHandleCallback );
+
+    delete mCallback;
+    delete mRemoveFromContainerFunction;
+  }
+
+  // Data
+  CallbackBase*                   mCallback;      ///< call back
+  CallbackBase*                   mRemoveFromContainerFunction; ///< Called to remove the callbackdata from the callback container
+  uv_idle_t*                      mIdleHandle;   ///< idle handle
+  bool                            mExecute;      ///< whether to run the callback
+
+};
+
+namespace
+{
+void IdleCallback( uv_idle_t* handle )
+{
+  CallbackData *callbackData = static_cast<CallbackData *>(handle->data);
+
+  // remove callback data from the container first in case our callback tries to modify the container
+  CallbackBase::Execute( *callbackData->mRemoveFromContainerFunction, callbackData );
+
+  // run the function
+  CallbackBase::Execute( *callbackData->mCallback );
+
+  // will clear up the handle
+  delete callbackData;
+
+}
+}
+
+UvCallbackManager::UvCallbackManager()
+:mRunning(false)
+{
+}
+
+void UvCallbackManager::Start()
+{
+  DALI_ASSERT_DEBUG( mRunning == false );
+  mRunning = true;
+}
+
+void UvCallbackManager::Stop()
+{
+  // make sure we're not called twice
+  DALI_ASSERT_DEBUG( mRunning == true );
+
+  mRunning = false;
+
+  for( CallbackList::iterator  iter =  mCallbackContainer.begin(); iter != mCallbackContainer.end(); ++iter)
+  {
+    CallbackData* data = (*iter);
+
+    delete data;
+  }
+  mCallbackContainer.clear();
+}
+
+bool UvCallbackManager::AddIdleCallback( CallbackBase* callback )
+{
+  if( !mRunning )
+  {
+    return false;
+  }
+
+  CallbackData *callbackData = new CallbackData(callback );
+
+  // To inform the manager a callback has finished, we get it to call RemoveCallbackFromContainer
+  callbackData->mRemoveFromContainerFunction =  MakeCallback( this, &UvCallbackManager::RemoveCallbackFromContainer );
+
+  // add the call back to the container
+  mCallbackContainer.push_front(callbackData);
+
+  // init the callback
+  callbackData->AddIdle( &IdleCallback );
+
+  return true;
+}
+
+void UvCallbackManager::RemoveCallbackFromContainer(CallbackData *callbackData)
+{
+  mCallbackContainer.remove(callbackData);
+}
+
+// Creates a concrete interface for CallbackManager
+CallbackManager* CallbackManager::New()
+{
+  return new UvCallbackManager;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/event-loop/lib-uv/uv-callback-manager.h b/adaptors/common/event-loop/lib-uv/uv-callback-manager.h
new file mode 100644 (file)
index 0000000..78abab6
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef __DALI_UV_CALLBACK_MANAGER_H__
+#define __DALI_UV_CALLBACK_MANAGER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <list>
+
+// INTERNAL INCLUDES
+#include <callback-manager.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct CallbackData;
+
+/**
+ * @brief LibUV callback manager used to install call backs in the applications main loop.
+ * The manager keeps track of all callbacks, so that if Stop() is called it can remove them.
+ */
+class UvCallbackManager : public CallbackManager
+{
+
+public:
+
+     /**
+     * @brief constructor
+     */
+    UvCallbackManager();
+
+    /**
+     * @brief destructor
+     */
+    ~UvCallbackManager(){}
+
+    /**
+     * @copydoc CallbackManager::AddCallback()
+     */
+    virtual bool AddIdleCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::Start()
+     */
+    virtual void Start();
+
+    /**
+     * @copydoc CallbackManager::Stop()
+     */
+    virtual void Stop();
+
+private:
+
+    /**
+     * @brief Removes a single call back from the container
+     * Always called from main thread
+     * @param callbackData callback data
+     */
+    void RemoveCallbackFromContainer(CallbackData *callbackData);
+
+
+    typedef std::list<CallbackData *>  CallbackList;    ///< list of callbacks installed
+
+    bool                           mRunning;            ///< flag is set to true if when running
+    CallbackList                   mCallbackContainer;  ///< container of live callbacks
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_UV_CALLBACK_MANAGER_H__
diff --git a/adaptors/common/event-loop/lib-uv/uv-file-descriptor-monitor.cpp b/adaptors/common/event-loop/lib-uv/uv-file-descriptor-monitor.cpp
new file mode 100644 (file)
index 0000000..0ce27cb
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "file-descriptor-monitor.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <uv.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+void FreeHandleCallback(uv_handle_t* handle )
+{
+  delete handle;
+}
+
+}
+
+/**
+ * Using Impl to hide away UV specific members
+ */
+struct FileDescriptorMonitor::Impl
+{
+public:
+
+  // Constructor
+  Impl( int fileDescriptor, CallbackBase* callback )
+  : mFileDescriptor( fileDescriptor ),
+    mCallback( callback ),
+    pollHandle( NULL )
+  {
+
+    // heap allocate a handle as it will be alive after the FileDescriptorMonitor::Impl object is deleted.
+    pollHandle = new uv_poll_t;
+
+    // Node.JS uses uv_default_loop
+    uv_poll_init( uv_default_loop(), pollHandle, fileDescriptor);
+
+    pollHandle->data = this;
+
+    uv_poll_start( pollHandle, UV_READABLE, PollCabllack);
+  }
+
+  ~Impl()
+  {
+    uv_poll_stop( pollHandle );
+
+    // the handle will still be alive for a short period after calling uv_close
+    // set the data to NULL to avoid a dangling pointer
+    pollHandle->data = NULL;
+
+    uv_close(reinterpret_cast<uv_handle_t*> ( pollHandle ) , FreeHandleCallback );
+
+    delete mCallback;
+  }
+
+  static void PollCabllack(uv_poll_t* handle, int status, int events)
+  {
+     if( handle->data )
+     {
+        FileDescriptorMonitor::Impl* impl= static_cast<FileDescriptorMonitor::Impl* >(handle->data);
+        // run the function
+        CallbackBase::Execute( *impl->mCallback );
+     }
+  }
+  // Data
+  int mFileDescriptor;
+  CallbackBase* mCallback;
+  uv_poll_t* pollHandle;
+
+};
+
+
+FileDescriptorMonitor::FileDescriptorMonitor( int fileDescriptor, CallbackBase* callback )
+{
+  if (fileDescriptor < 0)
+  {
+    return;
+  }
+
+  // waiting for a write event on a file descriptor
+  mImpl = new Impl(fileDescriptor, callback);
+}
+
+FileDescriptorMonitor::~FileDescriptorMonitor()
+{
+  delete mImpl;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/event-loop/lib-uv/uv-timer-impl.cpp b/adaptors/common/event-loop/lib-uv/uv-timer-impl.cpp
new file mode 100644 (file)
index 0000000..01ec2f4
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "timer-impl.h"
+#include <dali/integration-api/debug.h>
+
+// EXTERNAL INCLUDES
+#include <uv.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+void TimerSourceFunc (uv_timer_t* handle)
+{
+  Timer* timer = static_cast<Timer*>(handle->data);
+
+  bool keepRunning = timer->Tick();
+  if( !keepRunning )
+  {
+    timer->Stop();
+  }
+}
+void FreeHandleCallback(uv_handle_t* handle )
+{
+  delete handle;
+}
+
+} // unnamed namespace
+
+/**
+ * Struct to hide away Ecore implementation details
+ */
+struct Timer::Impl
+{
+  Impl( unsigned int milliSec )
+  : mTimerHandle( NULL ),
+    mInterval( milliSec ),
+    mRunning( false )
+  {
+  }
+
+  ~Impl()
+  {
+    // the handle will still be alive for a short period after calling uv_close
+    // set the data to NULL to avoid a dangling pointer
+    mTimerHandle->data = NULL;
+
+    uv_close( reinterpret_cast< uv_handle_t* >( mTimerHandle ), FreeHandleCallback );
+  }
+
+  bool Running()
+  {
+    return mRunning;
+  }
+
+  void Start( void* internalTimerPtr )
+  {
+    Stop(); // make sure we stop first if its currently running
+
+    if( !mTimerHandle )
+    {
+      // heap allocate the handle as its lifetime will be longer than TimerImpl
+      mTimerHandle = new uv_timer_t;
+
+      // initialize the handle
+      uv_timer_init( uv_default_loop(), mTimerHandle);
+    }
+
+    mRunning = true;
+
+    mTimerHandle->data = internalTimerPtr;
+
+    uv_timer_start( mTimerHandle, TimerSourceFunc, mInterval, mInterval);
+  }
+
+  void Stop()
+  {
+    if( mRunning )
+    {
+      mTimerHandle->data = NULL;
+      uv_timer_stop( mTimerHandle );
+      mRunning = false;
+    }
+  }
+
+  uv_timer_t* mTimerHandle;
+  unsigned int mInterval;
+  bool      mRunning;
+};
+
+TimerPtr Timer::New( unsigned int milliSec )
+{
+  DALI_LOG_ERROR(" new timer");
+  TimerPtr timer( new Timer( milliSec ) );
+  return timer;
+}
+
+Timer::Timer( unsigned int milliSec )
+: mImpl(new Impl(milliSec))
+{
+}
+
+Timer::~Timer()
+{
+  // stop timers
+  Stop();
+
+  delete mImpl;
+}
+
+void Timer::Start()
+{
+  mImpl->Start( this );
+}
+
+void Timer::Stop()
+{
+  mImpl->Stop();
+}
+
+void Timer::SetInterval( unsigned int interval )
+{
+  // stop existing timer
+  Stop();
+
+  mImpl->mInterval = interval;
+
+  // start new tick
+  Start();
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return mImpl->mInterval;
+}
+
+bool Timer::Tick()
+{
+  // Guard against destruction during signal emission
+  Dali::Timer handle( this );
+
+  bool retVal( false );
+
+  // Override with new signal if used
+  if( !mTickSignal.Empty() )
+  {
+    retVal = mTickSignal.Emit();
+
+    // Timer stops if return value is false
+    if (retVal == false)
+    {
+      Stop();
+    }
+    else
+    {
+      retVal = true;   // continue emission
+    }
+  }
+  else // no callbacks registered
+  {
+    // periodic timer is started but nobody listens, continue
+    retVal = true;
+  }
+
+  return retVal;
+}
+
+Dali::Timer::TimerSignalType& Timer::TickSignal()
+{
+  return mTickSignal;
+}
+
+bool Timer::IsRunning() const
+{
+  return mImpl->mRunning;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
index 5cd748c..2560e25 100644 (file)
@@ -10,8 +10,6 @@ adaptor_common_internal_src_files = \
   $(adaptor_common_dir)/clipboard-event-notifier-impl.cpp \
   $(adaptor_common_dir)/command-line-options.cpp \
   $(adaptor_common_dir)/drag-and-drop-detector-impl.cpp \
-  $(adaptor_common_dir)/ecore-callback-manager.cpp \
-  $(adaptor_common_dir)/file-descriptor-monitor.cpp \
   $(adaptor_common_dir)/haptic-player-impl.cpp \
   $(adaptor_common_dir)/indicator-impl.cpp \
   $(adaptor_common_dir)/indicator-buffer.cpp \
@@ -29,7 +27,6 @@ adaptor_common_internal_src_files = \
   $(adaptor_common_dir)/singleton-service-impl.cpp \
   $(adaptor_common_dir)/sound-player-impl.cpp \
   $(adaptor_common_dir)/style-monitor-impl.cpp \
-  $(adaptor_common_dir)/timer-impl.cpp \
   $(adaptor_common_dir)/trigger-event.cpp \
   $(adaptor_common_dir)/trigger-event-factory.cpp \
   $(adaptor_common_dir)/virtual-keyboard-impl.cpp \
@@ -53,6 +50,17 @@ adaptor_common_internal_src_files = \
   $(adaptor_common_dir)/gl/gl-proxy-implementation.cpp \
   $(adaptor_common_dir)/gl/gl-extensions.cpp
 
+# Different files depending on the event loop being used
+adaptor_common_internal_ecore_src_files = \
+  $(adaptor_common_dir)/event-loop/ecore/ecore-callback-manager.cpp \
+  $(adaptor_common_dir)/event-loop/ecore/ecore-file-descriptor-monitor.cpp \
+  $(adaptor_common_dir)/event-loop/ecore/ecore-timer-impl.cpp
+
+ adaptor_common_internal_uv_src_files = \
+  $(adaptor_common_dir)/event-loop/lib-uv/uv-callback-manager.cpp \
+  $(adaptor_common_dir)/event-loop/lib-uv/uv-file-descriptor-monitor.cpp \
+  $(adaptor_common_dir)/event-loop/lib-uv/uv-timer-impl.cpp
+
 adaptor_common_internal_default_profile_src_files = \
   $(adaptor_common_dir)/color-controller-impl.cpp \
   $(adaptor_common_dir)/system-settings.cpp
index 73c2a4d..cbd705e 100644 (file)
@@ -19,7 +19,6 @@
 #include "orientation-impl.h"
 
 // EXTERNAL INCLUDES
-#include <Ecore.h>
 #include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
index 0a1bb5e..9504246 100644 (file)
@@ -30,7 +30,6 @@
 
 #include <cstring>
 
-#include <Ecore.h>
 
 namespace Dali
 {
index 3d63919..22f046e 100644 (file)
@@ -261,6 +261,7 @@ private:
   bool                             mStarted:1;
   bool                             mIsTransparent:1;
   bool                             mWMRotationAppSet:1;
+  bool                             mEcoreEventHander:1;
   Indicator*                       mIndicator;
   Dali::Window::WindowOrientation  mIndicatorOrientation;
   Dali::Window::WindowOrientation  mNextIndicatorOrientation;
index 6558e40..cc79c35 100644 (file)
 #include <dali/public-api/signals/dali-signal.h>
 #include <dali/public-api/math/rect.h>
 #include <dali/public-api/events/touch-event.h>
+#include <dali/public-api/common/view-mode.h>
 
 // INTERNAL INCLUDES
-#include "window.h"
-#include "application-configuration.h"
+
+
+#ifdef DALI_ADAPTOR_COMPILATION  // full path doesn't exist until adaptor is installed so we have to use relative
+// @todo Make dali-adaptor code folder structure mirror the folder structure installed to dali-env
+#include <window.h>
+#include <application-configuration.h>
+#else
+#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/adaptor-framework/application-configuration.h>
+#endif
+
 
 namespace Dali
 {
@@ -295,6 +305,21 @@ public:
    */
   void FeedKeyEvent( KeyEvent& keyEvent );
 
+  /**
+   * @copydoc Dali::Core::SceneCreated();
+   */
+  void SceneCreated();
+
+  /**
+   * @copydoc Dali::Application::SetViewMode();
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @copydoc Dali::Application::SetStereoBase();
+   */
+  void SetStereoBase( float stereoBase );
+
 public:  // Signals
 
   /**
index 9d66ebf..469fb2f 100644 (file)
@@ -8,13 +8,21 @@ _adaptor_x11_internal_src_files = \
   $(adaptor_x11_dir)/server-connection-x.cpp \
   $(adaptor_x11_dir)/virtual-keyboard-impl-x.cpp \
   $(adaptor_x11_dir)/window-impl-x.cpp \
-  $(adaptor_x11_dir)/event-handler-x.cpp \
   $(adaptor_x11_dir)/egl-implementation-x.cpp \
   $(adaptor_x11_dir)/pixmap-render-surface-x.cpp \
   $(adaptor_x11_dir)/ecore-x-render-surface.cpp \
   $(adaptor_x11_dir)/window-render-surface-x.cpp \
   $(adaptor_x11_dir)/ecore-x-window-interface.cpp
 
+adaptor_ecore_x_event_handler_internal_src_files = \
+  $(adaptor_x11_dir)/ecore-x-event-handler.cpp
+
+adaptor_uv_x_event_handler_internal_src_files = \
+  $(adaptor_x11_dir)/x-event-handler.cpp \
+  $(adaptor_x11_dir)/x-events/x-event-manager.cpp \
+  $(adaptor_x11_dir)/x-events/x-input2.cpp \
+  $(adaptor_x11_dir)/x-events/x-input2-device.cpp \
+  $(adaptor_x11_dir)/x-events/debug/x-input2-debug.cpp
 
 adaptor_x11_ubuntu_internal_src_files = \
   $(_adaptor_x11_internal_src_files)
@@ -36,4 +44,4 @@ adaptor_x11_internal_default_profile_src_files = \
   $(adaptor_x11_dir)/system-settings-x.cpp
 
 devel_api_adaptor_tizen_x11_header_files = \
-  $(adaptor_x11_dir)/window-extensions.h
+  $(adaptor_x11_dir)/window-extensions.h
\ No newline at end of file
index dca0fb1..b189872 100644 (file)
@@ -63,8 +63,8 @@ struct Window::EventHandler
    */
   EventHandler( Window* window )
   : mWindow( window ),
-    mWindowPropertyHandler( ecore_event_handler_add( ECORE_X_EVENT_WINDOW_PROPERTY,  EcoreEventWindowPropertyChanged, this ) ),
-    mClientMessagehandler( ecore_event_handler_add( ECORE_X_EVENT_CLIENT_MESSAGE,  EcoreEventClientMessage, this ) ),
+    mWindowPropertyHandler( NULL ),
+    mClientMessagehandler( NULL ),
     mEcoreWindow( 0 )
   {
     // store ecore window handle
@@ -83,7 +83,13 @@ struct Window::EventHandler
                              &tmp, 1);
 #endif // DALI_PROFILE_UBUNTU
 
-    ecore_x_input_multi_select( mEcoreWindow );
+    if( mWindow->mEcoreEventHander )
+    {
+      ecore_x_input_multi_select( mEcoreWindow );
+      mWindowPropertyHandler=  ecore_event_handler_add( ECORE_X_EVENT_WINDOW_PROPERTY,  EcoreEventWindowPropertyChanged, this );
+      mClientMessagehandler =  ecore_event_handler_add( ECORE_X_EVENT_CLIENT_MESSAGE,  EcoreEventClientMessage, this );
+    }
+
   }
 
   /**
@@ -318,6 +324,7 @@ Window::Window()
   mStarted(false),
   mIsTransparent(false),
   mWMRotationAppSet(false),
+  mEcoreEventHander(true),
   mIndicator(NULL),
   mIndicatorOrientation(Dali::Window::PORTRAIT),
   mNextIndicatorOrientation(Dali::Window::PORTRAIT),
@@ -327,6 +334,17 @@ Window::Window()
   mEventHandler(NULL),
   mPreferredOrientation(Dali::Window::PORTRAIT)
 {
+
+  // Detect if we're not running in a ecore main loop (e.g. libuv).
+  // Typically ecore_x_init is called by app_efl_main->elm_init
+  // but if we're not using app_efl_main then we have to call it ourselves
+  // This is a hack until we create a pure X Window class
+  if( ecore_x_display_get() == NULL )
+  {
+    mEcoreEventHander = false;
+    ecore_x_init (NULL); //  internally calls _ecore_x_input_init
+  }
+
 }
 
 Window::~Window()
diff --git a/adaptors/x11/x-event-handler.cpp b/adaptors/x11/x-event-handler.cpp
new file mode 100644 (file)
index 0000000..b801cb2
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <events/event-handler.h>
+
+// EXTERNAL INCLUDES
+#include <uv.h>
+#include <Ecore_X.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/XI2.h>
+
+#include <cstring>
+
+#include <sys/time.h>
+
+#ifndef DALI_PROFILE_UBUNTU
+#include <vconf.h>
+#include <vconf-keys.h>
+#endif // DALI_PROFILE_UBUNTU
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/events/wheel-event.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/integration-api/events/wheel-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <x-events/x-event-manager.h>
+#include <events/gesture-manager.h>
+#include <window-render-surface.h>
+#include <clipboard-impl.h>
+#include <key-impl.h>
+#include <physical-keyboard-impl.h>
+#include <style-monitor-impl.h>
+#include <base/core-event-interface.h>
+#include <base/interfaces/window-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#if defined(DEBUG_ENABLED)
+namespace
+{
+Integration::Log::Filter* gTouchEventLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_TOUCH");
+} // unnamed namespace
+#endif
+
+
+namespace
+{
+
+const unsigned int PRIMARY_TOUCH_BUTTON_ID( 1 );
+
+const unsigned int BYTES_PER_CHARACTER_FOR_ATTRIBUTES = 3;
+
+
+// Copied from x server
+static unsigned int GetCurrentMilliSeconds(void)
+{
+  struct timeval tv;
+
+  struct timespec tp;
+  static clockid_t clockid;
+
+  if (!clockid)
+  {
+#ifdef CLOCK_MONOTONIC_COARSE
+    if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
+      (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC_COARSE;
+    }
+    else
+#endif
+    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC;
+    }
+    else
+    {
+      clockid = ~0L;
+    }
+  }
+  if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
+  {
+    return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
+  }
+
+  gettimeofday(&tv, NULL);
+  return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
+} // unnamed namespace
+
+
+struct EventHandler::Impl : public WindowEventInterface
+{
+  // Construction & Destruction
+
+  /**
+   * Constructor
+   */
+  Impl( EventHandler* handler, XID window, Display* display )
+  : mXEventManager(window, display, this),
+    mHandler( handler )
+  {
+    mXEventManager.Initialize();
+  }
+  /**
+   * Destructor
+   */
+  ~Impl()
+  {
+  }
+  // @todo Consider allowing the EventHandler class to inherit from WindowEventInterface directly
+  virtual void TouchEvent( Dali::TouchPoint& point, unsigned long timeStamp )
+  {
+    mHandler->SendEvent( point, timeStamp );
+  }
+  virtual void KeyEvent( Dali::KeyEvent& keyEvent )
+  {
+    mHandler->SendEvent( keyEvent );
+  }
+  virtual void WheelEvent( Dali::WheelEvent& wheelEvent )
+  {
+    mHandler->SendWheelEvent( wheelEvent );
+  }
+  virtual void DamageEvent( Rect<int>& damageArea )
+  {
+    mHandler->SendEvent( damageArea );
+  }
+  virtual void WindowFocusOut( )
+  {
+    // used to do some work with ime
+  }
+  virtual void WindowFocusIn()
+  {
+    // used to do some work with ime
+  }
+
+  // Data
+  XEventManager mXEventManager;
+  EventHandler* mHandler;
+};
+
+EventHandler::EventHandler( RenderSurface* surface, CoreEventInterface& coreEventInterface, GestureManager& gestureManager, DamageObserver& damageObserver, DragAndDropDetectorPtr dndDetector )
+: mCoreEventInterface(coreEventInterface),
+  mGestureManager( gestureManager ),
+  mStyleMonitor( StyleMonitor::Get() ),
+  mDamageObserver( damageObserver ),
+  mRotationObserver( NULL ),
+  mDragAndDropDetector( dndDetector ),
+  mClipboardEventNotifier( ClipboardEventNotifier::Get() ),
+  mClipboard(Clipboard::Get()),
+  mImpl( NULL )
+{
+  Ecore_X_Window window = 0;
+
+  // this code only works with the EcoreX11 RenderSurface so need to downcast
+  ECore::WindowRenderSurface* ecoreSurface = dynamic_cast< ECore::WindowRenderSurface* >( surface );
+  if( ecoreSurface )
+  {
+    window = ecoreSurface->GetXWindow();
+    Display* display = static_cast< Display* >(ecore_x_display_get());
+
+    mImpl = new Impl(this, window, display );
+
+  }
+
+}
+
+EventHandler::~EventHandler()
+{
+  if(mImpl)
+  {
+    delete mImpl;
+  }
+
+  mGestureManager.Stop();
+}
+
+void EventHandler::SendEvent(TouchPoint& point, unsigned long timeStamp)
+{
+  if(timeStamp < 1)
+  {
+    timeStamp = GetCurrentMilliSeconds();
+  }
+
+  Integration::TouchEvent touchEvent;
+  Integration::HoverEvent hoverEvent;
+  Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent(point, timeStamp, touchEvent, hoverEvent);
+  if(type != Integration::TouchEventCombiner::DispatchNone )
+  {
+    DALI_LOG_INFO(gTouchEventLogFilter, Debug::General, "%d: Device %d: Button state %d (%.2f, %.2f)\n", timeStamp, point.deviceId, point.state, point.local.x, point.local.y);
+
+    // First the touch and/or hover event & related gesture events are queued
+    if(type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth)
+    {
+      mCoreEventInterface.QueueCoreEvent( touchEvent );
+      mGestureManager.SendEvent(touchEvent);
+    }
+
+    if(type == Integration::TouchEventCombiner::DispatchHover || type == Integration::TouchEventCombiner::DispatchBoth)
+    {
+      mCoreEventInterface.QueueCoreEvent( hoverEvent );
+    }
+
+    // Next the events are processed with a single call into Core
+    mCoreEventInterface.ProcessCoreEvents();
+  }
+}
+
+void EventHandler::SendEvent(KeyEvent& keyEvent)
+{
+  Dali::PhysicalKeyboard physicalKeyboard = PhysicalKeyboard::Get();
+  if ( physicalKeyboard )
+  {
+    if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ) )
+    {
+      GetImplementation( physicalKeyboard ).KeyReceived( keyEvent.time > 1 );
+    }
+  }
+
+  // Create KeyEvent and send to Core.
+  Integration::KeyEvent event(keyEvent.keyPressedName, keyEvent.keyPressed, keyEvent.keyCode,
+  keyEvent.keyModifier, keyEvent.time, static_cast<Integration::KeyEvent::State>(keyEvent.state));
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::SendWheelEvent( WheelEvent& wheelEvent )
+{
+  // Create WheelEvent and send to Core.
+  Integration::WheelEvent event( static_cast< Integration::WheelEvent::Type >(wheelEvent.type), wheelEvent.direction, wheelEvent.modifiers, wheelEvent.point, wheelEvent.z, wheelEvent.timeStamp );
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::SendEvent( StyleChange::Type styleChange )
+{
+  DALI_ASSERT_DEBUG( mStyleMonitor && "StyleMonitor Not Available" );
+  GetImplementation( mStyleMonitor ).StyleChanged(styleChange);
+}
+
+void EventHandler::SendEvent( const DamageArea& area )
+{
+  mDamageObserver.OnDamaged( area );
+}
+
+void EventHandler::SendRotationPrepareEvent( const RotationEvent& event )
+{
+  if( mRotationObserver != NULL )
+  {
+    mRotationObserver->OnRotationPrepare( event );
+  }
+}
+
+void EventHandler::SendRotationRequestEvent( )
+{
+  if( mRotationObserver != NULL )
+  {
+    mRotationObserver->OnRotationRequest( );
+  }
+}
+
+void EventHandler::FeedTouchPoint( TouchPoint& point, int timeStamp)
+{
+  SendEvent(point, timeStamp);
+}
+
+void EventHandler::FeedWheelEvent( WheelEvent& wheelEvent )
+{
+  SendWheelEvent( wheelEvent );
+}
+
+void EventHandler::FeedKeyEvent( KeyEvent& event )
+{
+  SendEvent( event );
+}
+
+void EventHandler::FeedEvent( Integration::Event& event )
+{
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::Reset()
+{
+  mCombiner.Reset();
+
+  // Any touch listeners should be told of the interruption.
+  Integration::TouchEvent event;
+  TouchPoint point(0, TouchPoint::Interrupted, 0, 0);
+  event.AddPoint( point );
+
+  // First the touch event & related gesture events are queued
+  mCoreEventInterface.QueueCoreEvent( event );
+  mGestureManager.SendEvent( event );
+
+  // Next the events are processed with a single call into Core
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::SetDragAndDropDetector( DragAndDropDetectorPtr detector )
+{
+  mDragAndDropDetector = detector;
+}
+
+void EventHandler::SetRotationObserver( RotationObserver* observer )
+{
+  mRotationObserver = observer;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/x-events/debug/x-input2-debug.cpp b/adaptors/x11/x-events/debug/x-input2-debug.cpp
new file mode 100644 (file)
index 0000000..8191e81
--- /dev/null
@@ -0,0 +1,289 @@
+ // EXTERNAL INCLUDES
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/XI2.h>
+
+#ifdef DEBUG_ENABLED
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <ostream>
+#include <iomanip>
+#endif
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace X11Debug
+{
+
+#ifdef DEBUG_ENABLED
+
+namespace
+{
+
+
+Integration::Log::Filter* gInputDeviceLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_X_INPUT_DEVICES");
+Integration::Log::Filter* gInputEventLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_X_INPUT_EVENTS");
+
+struct XNameId
+{
+  const char* const name;
+  int id;
+};
+
+const XNameId eventTable[]=
+{
+    { "XI_KeyPress"        ,XI_KeyPress         },
+    { "XI_KeyRelease"      ,XI_KeyRelease       },
+    { "XI_ButtonPress"     ,XI_ButtonPress      },
+    { "XI_ButtonRelease"   ,XI_ButtonRelease    },
+    { "XI_Motion"          ,XI_Motion           },
+    { "XI_Enter"           ,XI_Enter            },
+    { "XI_Leave"           ,XI_Leave            },
+    { "XI_FocusIn"         ,XI_FocusIn          },
+    { "XI_FocusOut"        ,XI_FocusOut         },
+    { "XI_HierarchyChanged",XI_HierarchyChanged },
+    { "XI_PropertyEvent"   ,XI_PropertyEvent    },
+    { "XI_RawKeyPress"     ,XI_RawKeyPress      },
+    { "XI_RawKeyRelease"   ,XI_RawKeyRelease    },
+    { "XI_RawButtonPress"  ,XI_RawButtonPress   },
+    { "XI_RawButtonRelease",XI_RawButtonRelease },
+    { "XI_RawMotion"       ,XI_RawMotion        },
+    { "XI_TouchBegin"      ,XI_TouchBegin       },
+    { "XI_TouchUpdate"     ,XI_TouchUpdate      },
+    { "XI_TouchEnd"        ,XI_TouchEnd         },
+    { "XI_TouchOwnership"  ,XI_TouchOwnership   },
+    { "XI_RawTouchBegin"   ,XI_RawTouchBegin    },
+    { "XI_RawTouchUpdate"  ,XI_RawTouchUpdate   },
+    { "XI_RawTouchEnd"     ,XI_RawTouchEnd      }
+};
+
+const XNameId deviceTypeTable[]=
+{
+    { "Master Pointer "    ,XIMasterPointer     },
+    { "Master Keyboard"    ,XIMasterKeyboard    },
+    { "Slave Pointer  "    ,XISlavePointer      },
+    { "Slave Keyboard "    ,XISlaveKeyboard     },
+    { "Floating Slave "    ,XIFloatingSlave     }
+};
+
+const XNameId inputClassTable[]=
+{
+    { "Key"      ,XIKeyClass       },
+    { "Button"   ,XIButtonClass    },
+    { "Valuator" ,XIValuatorClass  },
+    { "Scroll"   ,XIScrollClass    },
+    { "Touch"    ,XITouchClass     }
+};
+
+const unsigned int numberEvents = sizeof( eventTable ) / sizeof( eventTable[0] );
+const unsigned int numberDevices = sizeof( deviceTypeTable ) / sizeof( deviceTypeTable[0] );
+const unsigned int numberInputClasses = sizeof( inputClassTable ) / sizeof( inputClassTable[0] );
+
+const char* GetEventName( int eventId )
+{
+  for( unsigned int i = 0; i < numberEvents; ++i )
+  {
+    if( eventTable[i].id == eventId )
+    {
+      return eventTable[i].name;
+    }
+  }
+  return "unknown event";
+}
+const char* GetDeviceHierachyName( int deviceType )
+{
+  for( unsigned int i = 0; i < numberDevices; ++i )
+  {
+    if( deviceTypeTable[i].id == deviceType )
+    {
+      return deviceTypeTable[i].name;
+    }
+  }
+  return "unknown device";
+}
+const char* GetInputClassName( int classId )
+{
+  for( unsigned int i = 0; i < numberInputClasses; ++i )
+  {
+    if( inputClassTable[i].id == classId )
+    {
+      return inputClassTable[i].name;
+    }
+  }
+  return "unknown input class name";
+}
+
+std::string GetInputDeviceInfo( const XIDeviceInfo* device, bool master )
+{
+  // formatted output similar to xinput -list except it includes class + source information
+  int startWidth = 45;
+
+  std::string slavePadding="  â†³ ";
+  if( master )
+  {
+    // slave entries are shifted to the right
+    startWidth += 4;
+    slavePadding="";
+  }
+
+  std::ostringstream oss;
+  oss << "⎜" << slavePadding << std::setw(startWidth) <<  std::left << device->name ;
+  oss << std::setw(1) << " id= " << std::setw(1) << device->deviceid ;
+  oss << "\t[" << GetDeviceHierachyName( device->use ) << " ("<< device->attachment << ") ]";
+  oss << std::setw(1) << "\t Classes: ";
+
+  for( int n = 0; n < device->num_classes; ++n )
+  {
+    XIAnyClassInfo *classInfo = device->classes[n];
+    oss << GetInputClassName( classInfo->type ) << ", source ( "<< classInfo->sourceid << ")";
+  }
+  oss << "\n";
+
+  return oss.str();
+}
+
+
+}// unanmed namespace
+
+void LogInputDeviceInfo( const XIDeviceInfo* devices, unsigned int numberOfDevices )
+{
+  // early exit if the filter is not enabled in debug mode
+  if( ! gInputDeviceLogFilter->IsEnabledFor( Debug::General ) )
+  {
+    return;
+  }
+
+  const XIDeviceInfo* device = devices;
+  const  XIDeviceInfo* masterKeyboard = NULL;
+  const XIDeviceInfo* masterPointer  = NULL;
+  Dali::Vector< const XIDeviceInfo* > slaveKeyboards;
+  Dali::Vector< const XIDeviceInfo* > slavePointers;
+  Dali::Vector< const XIDeviceInfo* > floatingSlaves;
+
+  // go through the device list and sort by type
+  for( unsigned int i = 0; i < numberOfDevices; ++i, ++device )
+  {
+    switch( device->use )
+    {
+      case XIMasterPointer:
+      {
+        masterPointer = device;
+        break;
+      }
+      case XIMasterKeyboard:
+      {
+        masterKeyboard = device;
+        break;
+      }
+      case XISlavePointer:
+      {
+        slavePointers.PushBack( device );
+        break;
+      }
+      case XISlaveKeyboard:
+      {
+        slaveKeyboards.PushBack( device );
+        break;
+      }
+      case XIFloatingSlave:
+      {
+        floatingSlaves.PushBack( device );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+
+  std::ostringstream oss;
+
+  oss << "\n" << GetInputDeviceInfo( masterKeyboard , true);
+  for( VectorBase::SizeType i = 0; i < slaveKeyboards.Count(); ++i )
+  {
+    oss << GetInputDeviceInfo( slaveKeyboards[i], false );
+  }
+  oss <<  "\n" << GetInputDeviceInfo( masterPointer, true );
+  for( VectorBase::SizeType i = 0; i < slavePointers.Count(); ++i )
+  {
+    oss << GetInputDeviceInfo( slavePointers[i], false);
+  }
+  for( VectorBase::SizeType i = 0; i < floatingSlaves.Count(); ++i )
+  {
+    oss <<  GetInputDeviceInfo( floatingSlaves[i], false );
+  }
+
+ // DALI_LOG_ERROR_NOFN( "%s \n",oss.str().c_str() );
+  DALI_LOG_INFO( gInputDeviceLogFilter, Debug::General, "%s\n", oss.str().c_str() );
+}
+
+void LogXI2Event( XGenericEventCookie* cookie )
+{
+  // early exit if the filter is not enabled
+  if( ! gInputEventLogFilter->IsEnabledFor( Debug::General ) )
+  {
+    return;
+  }
+
+  std::ostringstream oss;
+  oss << "XI2 event:" << GetEventName( cookie->evtype );
+
+  XIDeviceEvent *event = static_cast< XIDeviceEvent* >(cookie->data);
+
+  oss << ", device_id("<< event->deviceid << ")  source_id( "<< event->sourceid << ")" << ", flags: " << event->flags;
+  oss << ", root-window: " << event->root << ", event-window: "<< event->event << ", child-window:" << event->child;
+  if( cookie->evtype == XI_KeyPress)
+  {
+    oss << "base " << event->mods.base << "latched " << event->mods.latched;
+    oss << "locked " << event->mods.locked << "effective " << event->mods.effective;
+
+    if(  event->mods.effective & ShiftMask) oss << "Shift";
+    if(  event->mods.effective & LockMask) oss << "LockMask"; // caps lock
+    if(  event->mods.effective & ControlMask) oss << "ControlMask";
+    if(  event->mods.effective & Mod1Mask) oss << "Mod1Mask";  // alt
+    if(  event->mods.effective & Mod2Mask) oss << "Mod2Mask";  // num lock
+    if(  event->mods.effective & Mod3Mask) oss << "Mod3Mask";
+    if(  event->mods.effective & Mod4Mask) oss << "Mod4Mask";  // WINDOWS
+    if(  event->mods.effective & Mod5Mask) oss << "Mod5Mask";  // Alt gr
+
+  }
+
+   // Mouse button state
+  oss << " button state\n";
+  for( int i =0; i< event->buttons.mask_len ; i++)
+  {
+    oss << "," << int(event->buttons.mask[i]);
+  }
+
+ // DALI_LOG_ERROR_NOFN( "%s \n",oss.str().c_str() );
+  DALI_LOG_INFO( gInputEventLogFilter, Debug::General, "%s\n", oss.str().c_str() );
+
+}
+
+
+
+#else
+
+void LogDeviceInfo( Display* display, XIDeviceInfo* device )
+{
+}
+void LogXI2Event( XGenericEventCookie* cookie )
+{
+}
+
+#endif
+
+
+} // X11 Debug
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/adaptors/x11/x-events/debug/x-input2-debug.h b/adaptors/x11/x-events/debug/x-input2-debug.h
new file mode 100644 (file)
index 0000000..cbabe68
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __DALI_INTERNAL_X_INPUT_2_DEBUG_H__
+#define __DALI_INTERNAL_X_INPUT_2_DEBUG_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace X11Debug
+{
+
+/**
+ * To log input devices found on the system buid DALi in debug mode.
+ * Then on the command line:
+ *
+ * export LOG_X_INPUT_DEVICES=2
+ * dali-demo
+ *
+ *
+ * To log XInput events
+ *
+ * export LOG_X_INPUT_EVENTS=2
+ * dali-demo
+ *
+ * 2 = LogLevel::General
+ */
+
+
+/**
+ * @brief Debug log input device information.
+ * Similar output to command line tool 'xinput -list' except it includes class + source information
+ * Useful if the device doesn't have xinput tool installed
+ * @param devices array of XIDeviceInfo
+ * @param numberOfDevices number of devices
+ */
+void LogInputDeviceInfo( const XIDeviceInfo* devices, unsigned int numberOfDevices );
+
+/**
+ * @brief Debug log input event information.
+ * @param cookie input event cookie
+ */
+void LogXI2Event( XGenericEventCookie* cookie );
+
+} // X11 Debug
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif
diff --git a/adaptors/x11/x-events/x-event-manager.cpp b/adaptors/x11/x-events/x-event-manager.cpp
new file mode 100644 (file)
index 0000000..36ab25d
--- /dev/null
@@ -0,0 +1,86 @@
+// CLASS HEADER
+#include "x-event-manager.h"
+
+// EXTERNAL INCLUDES
+#include <stdio.h>
+#include <cstring>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/signals/callback.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+//Dali::Integration::Log::Filter* gInputDeviceLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_X_EVENT");
+#endif
+
+}
+
+XEventManager::XEventManager( XID window, Display* display, WindowEventInterface* eventInterface )
+: mXInput2( window, display, eventInterface ),
+  mFileDescriptorMonitor( NULL ),
+  mDisplay( display ),
+  mWindow( window ),
+  mInitialized( false )
+{
+
+}
+XEventManager::~XEventManager()
+{
+  delete mFileDescriptorMonitor;
+}
+
+void XEventManager::Initialize()
+{
+  if( mInitialized )
+  {
+    return;
+  }
+
+  mXInput2.Initialize();
+
+  // Start monitoring for X events on a file descriptor return via ConnectionNumber.
+  int fileDescriptor = ConnectionNumber( mDisplay );
+
+  CallbackBase* callback =  MakeCallback( this, &XEventManager::XEventReceived);
+
+  mFileDescriptorMonitor = new FileDescriptorMonitor( fileDescriptor, callback );
+
+  mInitialized = true;
+}
+
+
+void XEventManager::XEventReceived()
+{
+  while( XPending( mDisplay) )
+  {
+    XEvent xEvent;
+    XNextEvent( mDisplay, &xEvent );
+
+    // cookie data pointer is undefined until XGetEventData is called.
+    XGenericEventCookie* cookie = &xEvent.xcookie;
+
+    if (XGetEventData( mDisplay, cookie))
+    {
+      if( cookie->extension == mXInput2.GetExtensionId() )
+      {
+        mXInput2.ProcessEvent( cookie );
+      }
+      XFreeEventData( mDisplay, cookie );
+    }
+  }
+}
+
+
+} // namespace internal
+} // namespace adaptor
+} // namespace dali
diff --git a/adaptors/x11/x-events/x-event-manager.h b/adaptors/x11/x-events/x-event-manager.h
new file mode 100644 (file)
index 0000000..d4dd963
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef __DALI_INTERNAL_X_EVENT_MANAGER_H__
+#define __DALI_INTERNAL_X_EVENT_MANAGER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// EXTERNAL INCLUDES
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <file-descriptor-monitor.h>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/window-event-interface.h>
+#include "x-input2.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ *
+ * @brief Used to handle X events.
+ * The code is mainloop agnostic, so the monitoring of the X event file descriptor
+ * for X events is external to this class.
+ *
+ */
+class XEventManager
+{
+
+public:
+
+  /**
+   * Constructor
+   * @param[in] window ID
+   * @param[in] display x-connection
+   * @param[in] eventInterface window event interface
+   */
+  XEventManager( XID window, Display* display, WindowEventInterface* eventInterface );
+
+  /**
+   * @brief non virtual destructor
+   */
+  ~XEventManager();
+
+  /**
+   * @brief Initialize
+   */
+  void Initialize();
+
+private:
+
+  /**
+   * @brief Should be called when the Event file descriptor signals data is available
+   */
+  void XEventReceived();
+
+  // Undefined copy constructor.
+  XEventManager( const XEventManager& );
+
+  // Undefined assignment operator.
+  XEventManager& operator=( const XEventManager& );
+
+private:
+
+  XInput2 mXInput2;                                       ///< XInput2 handler
+  FileDescriptorMonitor* mFileDescriptorMonitor;          ///< File descriptor monitor for X events
+  Display* mDisplay;                                      ///< X connection
+  XID mWindow;                                            ///< Window to receive events for
+  bool mInitialized:1;
+
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_X_EVENT_MANAGER_H__
diff --git a/adaptors/x11/x-events/x-input2-device.cpp b/adaptors/x11/x-events/x-input2-device.cpp
new file mode 100644 (file)
index 0000000..a1b4ede
--- /dev/null
@@ -0,0 +1,66 @@
+//CLASS HEADER
+#include "x-input2-device.h"
+
+// EXTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+void XInput2Device::AssignDeviceInfo( const XIDeviceInfo* device )
+{
+  deviceId = device->deviceid;
+  attachment = device->attachment;
+  use = device->use;
+
+  for( int n = 0; n < device->num_classes; ++n )
+  {
+    XIAnyClassInfo *classInfo = device->classes[n];
+    switch( classInfo->type  )
+    {
+      case XITouchClass:
+      {
+        touchClass = true;
+        break;
+      }
+      case XIButtonClass:
+      {
+        buttonClass = true;
+        break;
+      }
+      case XIValuatorClass:
+      {
+        valuatorClass = true;
+        break;
+      }
+      case XIScrollClass:
+      {
+        scrollClass = true;
+        break;
+      }
+      case XIKeyClass:
+      {
+        keyClass = true;
+        break;
+      }
+      default:
+      {
+        // unknown
+        break;
+      }
+    }
+  }
+
+
+}
+
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/adaptors/x11/x-events/x-input2-device.h b/adaptors/x11/x-events/x-input2-device.h
new file mode 100644 (file)
index 0000000..59d0e52
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef __DALI_INTERNAL_X_INPUT2_DEVICE_H__
+#define __DALI_INTERNAL_X_INPUT2_DEVICE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <X11/extensions/XInput2.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * @brief struct used to encpasulate XIDeviceInfo information.
+ * Kept as a POD so it can be used in a Dali::Vector
+ */
+struct XInput2Device
+{
+  /**
+   * @brief constructor
+   */
+  XInput2Device()
+  : deviceId(0),
+  attachment(0),
+  use(0),
+  keyClass(false),
+  touchClass(false),
+  buttonClass(false),
+  valuatorClass(false),
+  scrollClass(false)
+  {}
+
+  /**
+   * Assign device information to the object
+   */
+  void AssignDeviceInfo( const XIDeviceInfo* device );
+
+  int deviceId;           ///< X device ID
+  int attachment;         ///< see XI2 DEVICEINFO struct for details
+  int use;                ///< see XI2 DEVICEINFO struct for details
+  bool keyClass:1;        ///< device supports key input
+  bool touchClass:1;      ///< device supports touch input
+  bool buttonClass:1;     ///< device supports button input
+  bool valuatorClass:1;   ///< device supports an axis, e.g. mouse axis, tablet pen tilt angle..
+  bool scrollClass:1;     ///< device supports scroll
+
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif
diff --git a/adaptors/x11/x-events/x-input2.cpp b/adaptors/x11/x-events/x-input2.cpp
new file mode 100644 (file)
index 0000000..b965609
--- /dev/null
@@ -0,0 +1,315 @@
+// CLASS HEADER
+#include "x-input2.h"
+
+// EXTERNAL INCLUDES
+#include <X11/XKBlib.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include "debug/x-input2-debug.h"
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+// For multi-touch we need XI2 version 2.2
+int XI2MinorVersionRequired = 2;
+int XI2MajorVersionRequired = 2;
+}
+
+XInput2::XInput2( XID window, Display* display, WindowEventInterface* eventInterface )
+: mEventInterface( eventInterface ),
+  mDisplay( display ),
+  mWindow( window ),
+  mXI2ExtensionId(-1),
+  mMultiTouchSupport( false )
+{
+
+}
+XInput2::~XInput2()
+{
+}
+
+void XInput2::Initialize()
+{
+  // Check if X supports the multi-touch protocol
+  QueryMultiTouchSupport();
+
+  // Query what input devices are available on the system.
+  QueryDevices();
+
+  // Select the input events we want to receive from the input devices available
+  SelectInputEvents();
+
+}
+
+int XInput2::GetExtensionId() const
+{
+  return mXI2ExtensionId;
+}
+
+bool XInput2::FilteredDevice( int deviceId ) const
+{
+  for( VectorBase::SizeType i = 0; i < mInputDeviceInfo.Count(); ++i )
+  {
+    if( mInputDeviceInfo[i].deviceId == deviceId )
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool XInput2::PreProcessEvent( XIDeviceEvent *deviceEvent ) const
+{
+  // @todo need to do some testing to see if this check is actually required
+  // E.g. if IME window is sending events, this check may fail
+  if( deviceEvent->event != mWindow )
+  {
+    return false;
+  }
+  // emulated flags means that the event has been emulated from another XI 2.x event for legacy client support
+  // We don't call XISelectEvents on these events so hopefully shouldn't get them.
+  if( ( deviceEvent->flags & XIPointerEmulated ) || ( deviceEvent->flags & XITouchEmulatingPointer ) )
+  {
+    return false;
+  }
+
+  if( !FilteredDevice( deviceEvent->deviceid ))
+  {
+    return false;
+  }
+  return true;
+}
+
+void XInput2::CreateKeyEvent( const XIDeviceEvent* deviceEvent, KeyEvent& keyEvent ) const
+{
+  // get the physical key code ( range 8..255)
+  KeyCode keycode = deviceEvent->detail;
+
+  keyEvent.keyCode = keycode;
+  keyEvent.state = KeyEvent::Down;
+  keyEvent.keyModifier = deviceEvent->mods.effective;
+
+  // extract key symbol. The symbol is typically the name visible on the key
+  // e.g. key code 201 might = Brightness increase, or a Korean character depending on the keyboard mapping.
+  // @todo For XKbKeycodeToKeysym to work correctly we need the group and level.
+  // investigate using XkbGetState to get initial state then start monitoring for XkbStateNotify events
+  KeySym sym = XkbKeycodeToKeysym( mDisplay, keycode, 0 /* group */ , keyEvent.IsShiftModifier() );
+  char* keyname = XKeysymToString( sym );
+
+  keyEvent.keyPressedName = keyname;
+  keyEvent.time = deviceEvent->time;
+
+}
+
+void XInput2::ProcessEvent( XGenericEventCookie* cookie )
+{
+  XIDeviceEvent* deviceEvent = static_cast< XIDeviceEvent* >(cookie->data);
+
+  X11Debug::LogXI2Event( cookie );
+
+  bool requiresProcessing  = PreProcessEvent( deviceEvent );
+
+  if( ! requiresProcessing )
+  {
+    return;
+  }
+
+  TouchPoint point ( deviceEvent->deviceid, TouchPoint::Last, deviceEvent->event_x, deviceEvent->event_y );
+  Time time( deviceEvent->time ); // X is using uint32 for time field ( see XI2proto.h )
+
+  switch( cookie->evtype)
+  {
+    case XI_TouchUpdate:
+    case XI_Motion:
+    {
+      point.state = TouchPoint::Motion;
+      mEventInterface->TouchEvent( point, time );
+      break;
+    }
+    case XI_TouchBegin:
+    case XI_ButtonPress:
+    {
+      point.state = TouchPoint::Down;
+      mEventInterface->TouchEvent( point, time );
+      break;
+    }
+    case XI_TouchEnd:
+    case XI_ButtonRelease:
+    {
+      point.state = TouchPoint::Up;
+      mEventInterface->TouchEvent( point, time );
+      break;
+    }
+    case XI_FocusIn:
+    {
+      mEventInterface->WindowFocusIn();
+      break;
+    }
+    case XI_FocusOut:
+    {
+      mEventInterface->WindowFocusOut();
+      break;
+    }
+    case XI_KeyPress:
+    {
+      KeyEvent keyEvent;
+      CreateKeyEvent( deviceEvent, keyEvent );
+      mEventInterface->KeyEvent( keyEvent );
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+}
+
+void XInput2::QueryMultiTouchSupport()
+{
+  int minor = XI2MinorVersionRequired;
+  int major = XI2MajorVersionRequired;
+  int firstEventCode, firstErrorCode;
+
+  // Check if the extension is available and get the extension id
+  if( !XQueryExtension(mDisplay, "XInputExtension",  &mXI2ExtensionId, &firstEventCode, &firstErrorCode) )
+  {
+    DALI_LOG_ERROR(" XInputExtension not available \n");
+    return;
+  }
+
+  // inform X that DALi ( the client ) supports XI2 version 2.2
+  // it will assign the X servers supported version to the parameters
+  int ret = XIQueryVersion( mDisplay, &major, &minor);
+  if( ret == BadValue )
+  {
+    DALI_LOG_ERROR(" XIQueryVersion %d,%d failed \n", major, minor );
+    return;
+  }
+
+  // check the version is supports multi-touch
+  if( ( major * 1000 + minor ) >= ( XI2MajorVersionRequired * 1000 + XI2MinorVersionRequired ) )
+  {
+      mMultiTouchSupport = true;
+  }
+  else
+  {
+    DALI_LOG_ERROR( "XInput 2.2 or greater required for multi-touch\n");
+  }
+
+}
+void XInput2::QueryDevices()
+ {
+   int numberOfDevices( 0 );
+
+   // QueryDevice returns information about one or more input devices
+   XIDeviceInfo* deviceInfoArray = XIQueryDevice( mDisplay, XIAllDevices, &numberOfDevices);
+   XIDeviceInfo* device = deviceInfoArray;
+
+   X11Debug::LogInputDeviceInfo( deviceInfoArray, numberOfDevices );
+
+   mInputDeviceInfo.Resize( numberOfDevices );
+
+   for( int i = 0; i < numberOfDevices; ++i, ++device )
+   {
+     XInput2Device info;
+
+     info.AssignDeviceInfo( device );
+
+     mInputDeviceInfo.PushBack( info );
+   }
+
+   XIFreeDeviceInfo( deviceInfoArray );
+ }
+
+void XInput2::SelectEvents( int deviceId, const Dali::Vector< unsigned int >& filter )
+{
+  if( filter.Size() ==  0)
+  {
+    return;
+  }
+
+  // each event like XI_ButtonPress is stored as unique bit, so if there's 32 events we need 4 bytes
+  // the XIMaskLen macro provides the length for us at compile time.
+  unsigned char mask[ XIMaskLen( XI_LASTEVENT ) ] = {};
+  XIEventMask eventMask;
+
+  eventMask.deviceid = deviceId;
+  eventMask.mask_len = sizeof( mask);
+  eventMask.mask = mask;
+
+  for( VectorBase::SizeType i = 0; i< filter.Count(); ++i )
+  {
+      XISetMask( mask, filter[i] );
+  }
+
+  XISelectEvents( mDisplay, mWindow, &eventMask, 1);
+
+}
+void XInput2::SelectInputEvents()
+{
+  /*
+   * From the X documentation:
+   * "A master pointer is a virtual pointer device that does not represent a physical device.
+   * If a slave device generates an event, the event is also generated by the respective master device.
+   * Multiple slave devices can be attached to a single master device."
+   * master = cursor / keyboard focus,
+   * slave = physical device
+   *
+   * For motion events, we currently just listen to the slave devices. This allows us the ability to
+   * perform a XIGrabDevice on the slave if we need to, which will temporarily detach it from the master.
+   * In DALi we currently don't perform a grab as typically we just have a single x-window displayed.
+   * Where as other toolkits may have a window for a popup and want do know when the mouse is clicked outside
+   * of the popup, to close it.
+   */
+  Dali::Vector< unsigned int > eventFilter;
+  eventFilter.Reserve( 6 );    // typically filter no more than 6 events
+
+  for( VectorBase::SizeType i = 0; i < mInputDeviceInfo.Count(); ++i )
+  {
+    const XInput2Device& device( mInputDeviceInfo[ i ] );
+
+    eventFilter.Clear();
+
+    if( ( device.use == XIFloatingSlave ) || ( device.use == XISlavePointer ))
+    {
+      if( device.buttonClass )
+      {
+        eventFilter.PushBack( XI_ButtonPress );
+        eventFilter.PushBack( XI_ButtonRelease );
+        eventFilter.PushBack( XI_Motion );
+      }
+      if( device.touchClass )
+      {
+        eventFilter.PushBack( XI_TouchUpdate );
+        eventFilter.PushBack( XI_TouchBegin );
+        eventFilter.PushBack( XI_TouchEnd );
+      }
+      SelectEvents( device.deviceId, eventFilter );
+    }
+    // @todo work out if we should just be listening to MasterKeyboard
+    else if( device.use == XISlaveKeyboard )
+    {
+      if( device.keyClass )
+      {
+        eventFilter.PushBack( XI_KeyPress );
+        eventFilter.PushBack( XI_KeyRelease );
+
+        SelectEvents( device.deviceId, eventFilter );
+      }
+
+    }
+  }
+}
+} // namespace internal
+} // namespace adaptor
+} // namespace dali
diff --git a/adaptors/x11/x-events/x-input2.h b/adaptors/x11/x-events/x-input2.h
new file mode 100644 (file)
index 0000000..abc3f5b
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef __DALI_INTERNAL_X_INPUT_2_MANAGER_H__
+#define __DALI_INTERNAL_X_INPUT_2_MANAGER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/XI2.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/window-event-interface.h>
+#include "x-input2-device.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ *
+ * @brief Used to setup and process XInput2 events.
+ *
+ * For help with debugging, build DALi in debug mode then set the environment variables
+ * export LOG_X_INPUT_EVENTS=2
+ * export LOG_X_INPUT_DEVICES=2
+ */
+class XInput2
+{
+
+public:
+
+  /**
+   * @brief Constructor
+   */
+  XInput2( XID window, Display* display, WindowEventInterface* eventInterface );
+
+  /**
+   * @brief destructor
+   */
+  ~XInput2();
+
+  /**
+   * @brief enumerates input devices using XIQueryDevice then sets up event filtering using XISelectEvents
+   */
+  void Initialize();
+
+  /**
+   * @brief get X the extension id
+   * @return the Id
+   */
+  int GetExtensionId() const;
+
+  /**
+   * @brief process an XInput2 event
+   * @param cookie X cookie
+   */
+  void ProcessEvent( XGenericEventCookie* cookie );
+
+
+private:
+
+  /**
+   * @brief query x input devices
+   */
+  void QueryDevices();
+
+  /**
+   * @brief query multi-touch support
+   */
+  void QueryMultiTouchSupport();
+
+  /**
+   * Uses XISelectEvents to select the events we want to recieve from each input device
+   */
+  void SelectInputEvents();
+
+  /**
+   * @brief checks if we are filtering events from a specific device
+   * @param[in] deviceId device id
+   * @return true if the device is being filtered
+   */
+  bool FilteredDevice( int deviceId ) const;
+
+  /**
+   * @brief Select specific events to be filtered on a device
+   * @param[in] device id
+   * @param[in] filter vector of X input events like XI_ButtonPress
+   */
+  void SelectEvents( int deviceId, const Dali::Vector< unsigned int >& filter );
+
+  /**
+   * @brief checks if the event should be processed
+   * @param[in] deviceEvent device event
+   * @return true if should be processed
+   */
+  bool PreProcessEvent( XIDeviceEvent *deviceEvent ) const;
+
+  /**
+   * @brief creates a DALi key event given a XIDeviceEvent for a key press
+   * @param[in] deviceEvent device event
+   * @param[out] keyEvent DALi key event
+   */
+  void CreateKeyEvent( const XIDeviceEvent* deviceEvent, KeyEvent& keyEvent ) const;
+
+private:
+
+  Dali::Vector< XInput2Device > mInputDeviceInfo;   ///< list of input devices
+  WindowEventInterface* mEventInterface;            ///< window event interface
+  Display* mDisplay;                                ///< X display
+  XID mWindow;                                      ///< X window
+  int mXI2ExtensionId;                              ///< XI2 extension id
+  bool mMultiTouchSupport:1;                        ///< whether multi-touch is supported
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif
index f39980d..85df3fc 100644 (file)
@@ -164,6 +164,18 @@ endif # WAYLAND
 
 endif
 
+# Node JS support for using an external libuv main loop. If not enabled then just use e-core as normal
+# Used for things like callbacks, file-monintors, x input handling
+if LIB_UV_EVENT_LOOP
+main_loop_integration_src_files = $(adaptor_common_internal_uv_src_files)
+input_event_handler_src_files = $(adaptor_uv_x_event_handler_internal_src_files)
+else
+main_loop_integration_src_files = $(adaptor_common_internal_ecore_src_files)
+input_event_handler_src_files = $(adaptor_ecore_x_event_handler_internal_src_files)
+endif
+
+
+
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = dali-adaptor-integration.pc
 
@@ -179,11 +191,14 @@ lib_LTLIBRARIES = libdali-adaptor.la
 
 libdali_adaptor_la_SOURCES = \
                      $(base_adaptor_src_files) \
+                     $(main_loop_integration_src_files) \
                      $(tizen_platform_abstraction_src_files) \
                      $(text_abstraction_src_files) \
                      $(devel_api_src_files) \
                      $(public_api_src_files) \
-                     $(adaptor_internal_src_files)
+                     $(adaptor_internal_src_files) \
+                     $(input_event_handler_src_files)
+
 
 libdali_adaptor_la_DEPENDENCIES =
 
@@ -381,14 +396,19 @@ bin_SCRIPTS = ../../../adaptors/scripts/dalireslog.sh
 
 # linking test
 
+# turn off the linker test if were building for libuv
+# We can't link to LibUV becase it is statically linked to Node.JS (by default)
+if !LIB_UV_EVENT_LOOP
 noinst_PROGRAMS = linker.test
+endif # NOT LIB_UV_EVENT_LOOP
 
 linker_test_SOURCES = linker-test.cpp
 
 linker_test_CXXFLAGS = \
+  -DDALI_ADAPTOR_COMPILATION \
   -I../../../adaptors/common \
   -I../../../adaptors/public-api \
-    -I../../../adaptors/integration-api \
+  -I../../../adaptors/integration-api \
   -I../../../adaptors/base/interfaces \
   -I../../../adaptors/public-api/adaptor-framework \
   -I../../../adaptors/devel-api/adaptor-framework \
index 67566e6..0270fe1 100644 (file)
@@ -136,6 +136,32 @@ AC_ARG_ENABLE([gles],
 
 DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DDALI_GLES_VERSION=${enable_gles}"
 
+# node.js by default statically links against libuv, so it doesn't need to install
+# a libuv headers/ shared library. So we can't use pkg-config to access any headers.
+# As a work around we pass the node deps path so we can access the libuv headers inside nodes
+# directory
+AC_ARG_WITH([node-js],
+              [AC_HELP_STRING([--with-node-js],
+                              [Node.JS path that contains Lib UV headers. Setting this configures DALi to work with LibUV mainloop used in Node.JS.
+                              For example /usr/tmp/downloads/node-v0.12.4/deps/uv/include/ ])],
+              [with_node_js=$withval],
+              [with_node_js=no])
+
+# Node.JS already has a libuv main loop running,so we have to integrate with it
+AM_CONDITIONAL(LIB_UV_EVENT_LOOP, test x$with_node_js != xno)
+
+
+build_for_node_js=no
+if test "x$with_node_js" != "xno"; then
+  AC_MSG_NOTICE("build for node_js == yes");
+  [build_for_node_js=yes]
+  DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DNODE_JS_SUPPORT  -I${with_node_js}"
+else
+ #not using node.js build
+  AC_MSG_NOTICE("build for node_js == no");
+fi
+
+
 AC_ARG_WITH([over-tizen_2_2],
             [AC_HELP_STRING([--with-over-tizen_2_2],
                             [Use tizen API over ver. 2.2])],
@@ -271,4 +297,9 @@ Configuration
   Data Dir (Read Only):             $dataReadOnlyDir
   OVERTIZEN2.2:                     $with_over_tizen_2_2
   EldBus:                           $eldbus_available
+  Build for Node.JS (LibUV)         $build_for_node_js
 "
+# optional output of node.js source path if we're building for node.js
+if test "x$build_for_node_js" != "xno"; then
+echo "  Node.JS LibUV header path         $with_node_js"
+fi