add_subdirectory(config)
+include_directories ("${PROJECT_SOURCE_DIR}/config")
include_directories ("${PROJECT_SOURCE_DIR}/3rdParty/")
# ilm_types are used internally to LM, so we can include them by default
include_directories ("${PROJECT_SOURCE_DIR}/LayerManagerClient/ilmClient/include")
virtual void doScreenShot(std::string fileToSave) = 0;
virtual uint getLayerTypeCapabilities(LayerType layerType);
+ virtual InputManager* getInputManager() const {return m_pInputManager;}
virtual Shader* createShader(const string* vertexName, const string* fragmentName);
protected:
Scene* m_pScene;
+ InputManager* m_pInputManager;
private:
static bool debugMode;
#include "LayerCapabilities.h"
#include "BaseRenderer.h"
+#include "InputManager.h"
#include "Log.h"
bool BaseRenderer::debugMode = true;
BaseRenderer::BaseRenderer(Scene* pScene) : m_pScene(pScene)
{
LOG_DEBUG("BaseRenderer", "Creating Renderer");
+ m_pInputManager = new InputManager(pScene);
}
BaseRenderer::~BaseRenderer()
class BaseWindowSystem
{
public:
- BaseWindowSystem(Scene* pScene)
+ BaseWindowSystem(Scene* pScene, InputManager* pInputManager )
: m_pScene(pScene)
- , m_damaged(false)
+ , m_pInputManager(pInputManager)
+ , m_damaged(false)
{
}
protected:
Scene* m_pScene;
+ InputManager* m_pInputManager;
public:
bool m_damaged;
{
public:
NullWindowSystem(Scene* pScene, int width, int height)
- : BaseWindowSystem(pScene)
+ : BaseWindowSystem(pScene, NULL)
, windowWidth(width)
, windowHeight(height)
, resolutionWidth(width)
}
WaylandBaseWindowSystem::WaylandBaseWindowSystem(const char* displayname, int width, int height, Scene* pScene)
-: BaseWindowSystem(pScene)
+: BaseWindowSystem(pScene, NULL)
, m_wlDisplay(NULL)
, m_wlDisplayClient(NULL)
, m_wlCompositorClient(NULL)
bool X11WindowSystem::m_xerror = false;
X11WindowSystem::X11WindowSystem(const char* displayname, int width, int height, Scene* pScene,GetVisualInfoFunction func)
-: BaseWindowSystem(pScene)
+: BaseWindowSystem(pScene, NULL)
, takeScreenshot(ScreenShotNone)
, screenShotFile()
, screenShotSurfaceID(0)
* @return TRUE if the coordinates have been translated
* FALSE if an error occured, exp: The position is not in the destination region
*/
- bool DestToSourceCoordinates(unsigned int *x, unsigned int *y, bool check) const;
+ bool DestToSourceCoordinates(int *x, int *y, bool check) const;
int OriginalSourceWidth;
int OriginalSourceHeight;
#include "LayerType.h"
#include "Shader.h"
+
+class InputManager;
+
+
/**
* Abstract Base of all CompositingControllers, ie Renderers.
* \defgroup RendererAPI Layer Management Renderer API
* \ingroup RendererAPI
*/
virtual void forceCompositionWindowSystem() = 0;
+
+ /**
+ * \brief Get the InputManager associated to the Scene
+ * \ingroup RendererAPI
+ */
+ virtual InputManager* getInputManager() const = 0;
};
#endif /* _IRENDERER_H_ */
+
--- /dev/null
+/***************************************************************************
+*
+* Copyright 2012 Valeo
+*
+*
+* 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.
+*
+****************************************************************************/
+
+#include "config.h"
+
+#ifndef _INPUTMANAGER_H_
+#define _INPUTMANAGER_H_
+
+
+#include <map>
+#include <vector>
+#include <pthread.h>
+
+
+class IScene;
+class Surface;
+
+#include "ilm_types.h"
+
+/**
+ * @brief Identifier for the different type of input devices supported by LayerManager.
+ * Fields can be used as a bit mask
+ */
+typedef unsigned int InputDevice;
+#define INPUT_DEVICE_KEYBOARD ((InputDevice) 1 << 0)
+#define INPUT_DEVICE_POINTER ((InputDevice) 1 << 1)
+#define INPUT_DEVICE_TOUCH ((InputDevice) 1 << 2)
+#define INPUT_DEVICE_ALL ((InputDevice) ~0)
+
+
+/**
+ * @brief List the different states an input can be.
+ */
+typedef enum
+{
+ INPUT_STATE_PRESSED, /*!< input is pressed */
+ INPUT_STATE_MOTION, /*!< input is in motion */
+ INPUT_STATE_RELEASED, /*!< input is released */
+ INPUT_STATE_OTHER /*!< input is in an other, not listed, state */
+} InputEventState;
+
+
+/**
+ * @brief Type that describe a point.
+ * Keep it POD (Plain Old Datatype) for performance reasons when dealing with touch event
+ */
+typedef struct
+{
+ InputEventState state; /*<! State of the point */
+ int x; /*<! X position of the point */
+ int y; /*<! Y position of the point */
+} Point;
+
+
+/**
+ * @brief Type to hold list of points
+ */
+typedef std::vector<Point> PointVect;
+typedef PointVect::iterator PointVectIterator;
+
+
+class InputManager
+{
+ public:
+ /** Ctor / Dtor
+ */
+ InputManager(IScene* s);
+ ~InputManager();
+
+
+ /** Methods to report input events
+ * They all return the surface to transfer the event to, or NULL if the event should not be dispatched
+ */
+ Surface * reportKeyboardEvent(InputEventState state, long keyId);
+ Surface * reportTouchEvent(PointVect& pv);
+ Surface * reportPointerEvent(Point& p);
+
+
+ /** Methods to control the focus
+ */
+ bool setKeyboardFocusOn(unsigned int surfId);
+ bool updateInputEventAcceptanceOn(unsigned int surfId, InputDevice devices, bool accept);
+
+ /** Few getters
+ */
+ unsigned int getKeyboardFocusSurfaceId();
+
+ private:
+ Surface * electSurfaceForPointerEvent(int& x, int& y);
+ void transformGlobalToLocalCoordinates(Surface* surf, int& x, int& y);
+
+
+ /*
+ * Private Getters / Setters
+ * Needed because access to their associated member requires exclusive area
+ */
+
+ /** \brief Set the keyboard focus on a particular surface */
+ void _setKbdFocus(Surface * s);
+ /** \brief Get the surface which has keyboard focus */
+ Surface * _getKbdFocus();
+ /** \brief Set the pointer focus on a particular surface */
+ void _setPointerFocus(Surface * s);
+ /** \brief Get the surface which has pointer focus */
+ Surface * _getPointerFocus();
+ /** \brief Set the touch focus on a particular surface */
+ void _setTouchFocus(Surface * s);
+ /** \brief Get the surface which has touch focus */
+ Surface * _getTouchFocus();
+
+
+ private:
+ IScene * m_pScene; /*!< Pointer to the scene */
+ std::map<long, Surface*> m_KeyMap; /*!< Map that associate keypressed event to the surface it has been forward to. See @ref<InputManager-KeypressedMap>. */
+ pthread_mutex_t m_mutex; /*!< Mutex to avoid concurrent access to shared variables */
+
+ /* Access to the below members must be protected by mutex to avoid concurrent accesses */
+ Surface * m_KbdFocus; /*!< Pointer to the surface which has the focus for keyboard event.
+ Should only be accessed via its getter / setter */
+ Surface * m_PointerFocus; /*!< Pointer to the surface which has the focus for pointer event.
+ Should only be accessed via its getter / setter */
+ Surface * m_TouchFocus; /*!< Pointer to the surface which has the focus for touch event.
+ Should only be accessed via its getter / setter */
+
+};
+
+
+/**
+ * @section <InputManager-extra-documentation> (InputManager extra documentation)
+ *
+ * @subsection <InputManager-Requirements> (InputManager Requirements)
+ * <ul>
+ * \anchor<LM_INPUT_REQ_01>
+ * <li>
+ * LM_INPUT_REQ_01:
+ * LM should support input events dispatching to the relevant surface.
+ * Input devices can be keyboard, mouse or (multi)touch foil.
+ * </li>
+ *
+ * \anchor<LM_INPUT_REQ_02>
+ * <li>
+ * LM_INPUT_REQ_02:
+ * Keyboard pressed events will be dispatched to the surface elected as being
+ * the "keyboard focused" surface.
+ * Keyboard released events will be dispatched to the surface which received
+ * the same key pressed event.
+ * </li>
+ *
+ * \anchor<LM_INPUT_REQ_03>
+ * <li>
+ * LM_INPUT_REQ_03:
+ * A surface gain the Keyboard focus if the LM command "surfaceSetKeyboardFocus"
+ * is called on that surface. The elected surface can be changed at any time.
+ * </li>
+ *
+ * \anchor<LM_INPUT_REQ_04>
+ * <li>
+ * LM_INPUT_REQ_04:
+ * Mouse & touch events will be dispatched to the surface elected as being the "Pointed" surface,
+ * even if theses events are outside of the surface. Coordinates will be adjusted relatively to the surface.
+ * </li>
+ *
+ * \anchor<LM_INPUT_REQ_05>
+ * <li>
+ * LM_INPUT_REQ_05:
+ * A surface gain the "Pointed surface" status as soon as a Pointer event in "Pressed"
+ * state is reported under it.
+ * The conditions to gain this status is that the surface or its containing layer should:
+ * + be visible
+ * + be opaque (opacity != 0).
+ * + has a native content
+ * </li>
+ *
+ * \anchor<LM_INPUT_REQ_06>
+ * <li>
+ * LM_INPUT_REQ_06:
+ * A surface can request to not receive particular input events. In this case, the surface should not be considered for focus election & the events
+ * must be dispatched to an other surface, if relevant.
+ * </li>
+ *
+ * </ul>
+ *
+ *
+ *
+ *
+ * @subsection <InputManager-KeypressedMap> (InputManager KeyPressed map)
+ *
+ * Note that reportKeyboardEvent() method takes a long as 2nd argument.
+ * This is actually an identifier of the key being reported. It's purpose is to avoid a race in the following scenario :
+ * 1- Surface S1 is the keyboard elected surface
+ * 2- Key X is pressed, so we indicate the renderer to forward to S1
+ * 3- The command "surfaceSetKeyboardFocus" is called on S2, so the surface S2 is now the keyboard elected one
+ * 4- Key X is released.
+ * We should then forward the KeyRelased event to S1 since we have reported the pressed event to it.
+ * So we need a map that associate keyPressed -> Surface. When the same key is released, we must forward that event to the original surface, and not to the elected one.
+ *
+ *
+ */
+
+
+#endif /* ! #ifndef _INPUTMANAGER_H_ */
+
#ifndef _SURFACE_H_
#define _SURFACE_H_
-#include "GraphicalSurface.h"
#include <stdlib.h>
+#include <pthread.h>
+
+#include "GraphicalSurface.h"
#include "PlatformSurface.h"
#include "PixelFormat.h"
+#include "InputManager.h"
/**
* Represents a graphical surface generated by an application. Always contained in layers.
}
/**
+ * Indicate from which input devices the Surface can accept events.
+ *
+ * \param[in] devices Bit masks of supported devices
+ * \param[in] accept Indicate if the surface should accept or reject input events from the specified list of devices
+ */
+ void updateInputEventAcceptanceFrom(InputDevice devices, bool accept)
+ {
+ if (accept)
+ {
+ pthread_mutex_lock(&m_inputAcceptMutex);
+ m_acceptInputFrom = (InputDevice) (m_acceptInputFrom | devices);
+ pthread_mutex_unlock(&m_inputAcceptMutex);
+ }
+ else
+ {
+ pthread_mutex_lock(&m_inputAcceptMutex);
+ m_acceptInputFrom = (InputDevice) (m_acceptInputFrom & ~devices);
+ pthread_mutex_unlock(&m_inputAcceptMutex);
+ }
+ }
+
+
+ /**
+ * Indicate if the surface accepts input events from the specified list of devices.
+ *
+ * \param[in] devices Bit masks of devices
+ * \return true if input events are accepted for ALL of the specified devices
+ * \return false if input events are not accepted for at least ONE of the specified devices
+ */
+ bool isInputEventAcceptedFrom(InputDevice devices)
+ {
+ bool ret;
+
+ pthread_mutex_lock(&m_inputAcceptMutex);
+ ret = ((m_acceptInputFrom & devices) == devices);
+ pthread_mutex_unlock(&m_inputAcceptMutex);
+
+ return ret;
+ }
+
+ /**
+ * Get the set of devices from which the surface can accept input events
+ *
+ * \return Bitmask of InputDevice
+ */
+ InputDevice getInputEventAcceptanceOnDevices() const
+ {
+ return m_acceptInputFrom;
+ }
+
+ /**
* Platform specific Object containing surface information specific to a used platform.
* This typically contains a native window handle/surface handle or information only used
* by a specific renderer.unsigned
, m_pixformat(PIXELFORMAT_UNKNOWN)
, m_layerId(INVALID_ID)
, m_hasNativeContent(false)
+ , m_acceptInputFrom(INPUT_DEVICE_ALL)
{
+ pthread_mutex_init(&m_inputAcceptMutex, NULL);
}
Surface(int id)
, m_pixformat(PIXELFORMAT_UNKNOWN)
, m_layerId(INVALID_ID)
, m_hasNativeContent(false)
+ , m_acceptInputFrom(INPUT_DEVICE_ALL)
{
+ pthread_mutex_init(&m_inputAcceptMutex, NULL);
}
+ ~Surface()
+ {
+ pthread_mutex_destroy(&m_inputAcceptMutex);
+ }
+
private:
long m_nativeHandle;
PixelFormat m_pixformat;
unsigned int m_layerId;
bool m_hasNativeContent;
+ /** \brief Bitmask to represent from which kind of devices the surface can accept
+ * input events. By default, all devices are accepted. */
+ InputDevice m_acceptInputFrom;
+ /** \brief m_acceptInputFrom can be accessed concurently. To make it thread safe, we need a mutex */
+ pthread_mutex_t m_inputAcceptMutex;
};
#endif /* _SURFACE_H_ */
+
* - rotation (not yet implemented)
*
*/
-bool GraphicalSurface::DestToSourceCoordinates(unsigned int *x, unsigned int *y, bool check) const
+bool GraphicalSurface::DestToSourceCoordinates(int *x, int *y, bool check) const
{
bool ret;
int TVxD, TVyD; /* Translation vector x,y in destination system */
--- /dev/null
+/***************************************************************************
+*
+* Copyright 2012 Valeo
+*
+*
+* 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.
+*
+****************************************************************************/
+
+
+#include <cassert>
+
+#include "Log.h"
+#include "config.h"
+#include "IScene.h"
+#include "InputManager.h"
+
+
+InputManager::InputManager(IScene* s) :
+ m_pScene(s),
+ m_KbdFocus(NULL),
+ m_PointerFocus(NULL),
+ m_TouchFocus(NULL)
+{
+ assert(s != NULL);
+ pthread_mutex_init(&m_mutex, NULL);
+}
+
+
+InputManager::~InputManager()
+{
+ m_pScene = NULL;
+ pthread_mutex_destroy(&m_mutex);
+}
+
+
+/**
+ * @brief Set the keyboard focus on a specific surface.
+ */
+bool InputManager::setKeyboardFocusOn(unsigned int surfId)
+{
+ bool ret;
+ Surface * surf;
+
+ surf = m_pScene->getSurface(surfId);
+ if (surf == NULL)
+ {
+ LOG_ERROR("InputManager", "setKeyboardFocusOn() called on an unknown surface id: " << surfId);
+ ret = false;
+ }
+ else
+ {
+ if (surf->isInputEventAcceptedFrom(INPUT_DEVICE_KEYBOARD))
+ {
+ _setKbdFocus(surf);
+ ret = true;
+ }
+ else
+ {
+ // Hum, the surface does not accept kbd events but we've been asked to set the focus on it
+ _setKbdFocus(NULL);
+ ret = false;
+ LOG_ERROR("InputManager", "setKeyboardFocusOn() called on surface " << surfId << ". This surface does not accept keyboard event !");
+ }
+ }
+
+
+ return ret;
+}
+
+/**
+ * @brief Get the identifier of the surface which has the keyboard focus
+ */
+unsigned int InputManager::getKeyboardFocusSurfaceId()
+{
+ Surface *surf;
+ unsigned int surfId;
+
+ surf = _getKbdFocus();
+ if (!surf)
+ {
+ surfId = GraphicalObject::INVALID_ID;
+ }
+ else
+ {
+ surfId = surf->getID();
+ }
+
+ return surfId;
+}
+
+
+bool InputManager::updateInputEventAcceptanceOn(unsigned int surfId, InputDevice devices, bool accept)
+{
+ bool ret;
+ Surface * surf;
+
+ surf = m_pScene->getSurface(surfId);
+ if (surf == NULL)
+ {
+ LOG_ERROR("InputManager", "setInputAcceptanceOn() called on an unknown surface id: " << surfId);
+ ret = false;
+ }
+ else
+ {
+ surf->updateInputEventAcceptanceFrom(devices, accept);
+ ret = true;
+ }
+
+ return ret;
+}
+
+
+
+/**
+ * @brief Report keyboard event.
+ * @param[in] state The state of the key. Can be either INPUT_STATE_PRESSED or INPUT_STATE_RELEASED
+ * @param[in] keyId A uniq identifier for the key being reported. See @ref<InputManager-KeypressedMap>.
+ * @return The Surface to which to report the event, or NULL
+ */
+Surface * InputManager::reportKeyboardEvent(InputEventState state, long keyId)
+{
+ Surface * elected;
+
+ switch (state)
+ {
+ case INPUT_STATE_PRESSED:
+ elected = _getKbdFocus();
+ m_KeyMap[keyId] = elected;
+ break;
+
+ case INPUT_STATE_RELEASED:
+ elected = m_KeyMap[keyId];
+ break;
+
+ default:
+ elected = NULL;
+ LOG_WARNING("InputManager", "Invalid input state reported for reportKeyboardEvent() : " << state);
+ break;
+ }
+
+ return elected;
+}
+
+
+/**
+ * @return The Surface to which to report the event, or NULL
+ */
+Surface * InputManager::reportPointerEvent(Point& p)
+{
+ Surface * elected;
+
+ switch (p.state)
+ {
+ case INPUT_STATE_PRESSED:
+ elected = electSurfaceForPointerEvent(p.x, p.y);
+ _setPointerFocus(elected);
+ /* Pointer pressed also assigns the focus for touch events */
+ _setTouchFocus(elected);
+ break;
+
+ case INPUT_STATE_OTHER:
+ case INPUT_STATE_MOTION:
+ case INPUT_STATE_RELEASED:
+ elected = _getPointerFocus();
+ if (elected != NULL)
+ {
+ transformGlobalToLocalCoordinates(elected, p.x, p.y);
+ }
+ break;
+
+ default:
+ elected = NULL;
+ LOG_WARNING("InputManager", "Invalid input state reported for reportPointerEvent() : " << p.state);
+ }
+
+ return elected;
+}
+
+
+Surface * InputManager::reportTouchEvent(PointVect& pv)
+{
+ Surface * elected;
+
+ elected = _getTouchFocus();
+ if (elected != NULL)
+ {
+ PointVectIterator it;
+ for (it = pv.begin(); it != pv.end(); it++)
+ {
+ transformGlobalToLocalCoordinates(elected, it->x, it->y);
+ }
+ }
+
+ return elected;
+}
+
+
+Surface * InputManager::electSurfaceForPointerEvent(int& x, int& y)
+{
+ Surface* surf;
+ LayerList &ll = m_pScene->getCurrentRenderOrder();
+ LayerListConstReverseIterator currentLayer;
+ SurfaceListConstReverseIterator currentSurf;
+ int x_SurfCoordinate, y_SurfCoordinate;
+
+ surf = NULL;
+ /* Need to browse for all layers. 1st layer of m_currentRenderOrder is rendered
+ * on bottom, last one is rendrered on top. So we have to reverse iterate */
+ for (currentLayer = ll.rbegin();
+ currentLayer != ll.rend() && surf == NULL;
+ currentLayer++)
+ {
+ if ( ((*currentLayer)->visibility) && ((*currentLayer)->getOpacity() != 0) )
+ {
+ if ((*currentLayer)->isInside(x, y))
+ {
+ x_SurfCoordinate = x;
+ y_SurfCoordinate = y;
+ (*currentLayer)->DestToSourceCoordinates(&x_SurfCoordinate, &y_SurfCoordinate, false);
+ /* Need to browse for all surfaces */
+ for (currentSurf = (*currentLayer)->getAllSurfaces().rbegin();
+ currentSurf != (*currentLayer)->getAllSurfaces().rend() && surf == NULL;
+ currentSurf++)
+ {
+ if ( ((*currentSurf)->hasNativeContent()) && ((*currentSurf)->visibility) && ((*currentSurf)->getOpacity() != 0) )
+ {
+ if ((*currentSurf)->isInside(x_SurfCoordinate, y_SurfCoordinate))
+ {
+ if ((*currentSurf)->isInputEventAcceptedFrom(INPUT_DEVICE_POINTER))
+ {
+ surf = *currentSurf;
+ (*currentSurf)->DestToSourceCoordinates(&x_SurfCoordinate, &y_SurfCoordinate, false);
+ x = x_SurfCoordinate;
+ y = y_SurfCoordinate;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return surf;
+}
+
+
+void InputManager::transformGlobalToLocalCoordinates(Surface* surf, int& x, int& y)
+{
+ Layer* layer;
+
+ assert(surf != NULL);
+
+ layer = m_pScene->getLayer(surf->getContainingLayerId());
+ if (layer != NULL)
+ {
+ layer->DestToSourceCoordinates(&x,&y, false);
+ surf->DestToSourceCoordinates(&x,&y, false);
+ }
+}
+
+
+//@{
+/*
+ * m_KbdFocus can be concurrently accessed by :
+ * - reportKeyboardEvent(), called in the renderer thread context
+ * - setKeyboardFocusOn(), called in the IPC mechanism context
+ *
+ * So read & Write to this variable must be protected by exclusive to avoid
+ * race conditions
+ */
+
+void InputManager::_setKbdFocus(Surface * s)
+{
+ pthread_mutex_lock(&m_mutex);
+ m_KbdFocus = s;
+ pthread_mutex_unlock(&m_mutex);
+}
+
+Surface * InputManager::_getKbdFocus()
+{
+ Surface * s;
+ pthread_mutex_lock(&m_mutex);
+ s = m_KbdFocus;
+ pthread_mutex_unlock(&m_mutex);
+
+ return s;
+}
+//@}
+
+
+
+//@{
+/*
+ * m_PointerFocus can NOT be concurrently accessed as of today :
+ * It is only accessed by reportPointerEvent(), called in the renderer thread context
+ *
+ * But it's cheap to add getter / setter if needed in the future & at least to have
+ * a similar access mechanism than m_KbdFocus
+ */
+void InputManager::_setPointerFocus(Surface * s)
+{
+ m_PointerFocus = s;
+}
+
+Surface * InputManager::_getPointerFocus()
+{
+ return m_PointerFocus;
+}
+//@}
+
+
+//@{
+/*
+ * m_TouchFocus can NOT be concurrently accessed as of today.
+ * It is only accessed by reportPointerEvent() & reportTouchEvent(), both called in the renderer thread context.
+ *
+ * But it's cheap to add getter / setter if needed in the future & at least to have
+ * a similar access mechanism than m_KbdFocus
+ */
+void InputManager::_setTouchFocus(Surface * s)
+{
+ m_TouchFocus = s;
+}
+
+Surface * InputManager::_getTouchFocus()
+{
+ return m_TouchFocus;
+}
+
+