From: dongsug.song Date: Tue, 17 Sep 2019 09:34:03 +0000 (+0900) Subject: [Tizen](ATSPI) squashed implementation X-Git-Tag: submit/tizen/20190917.102651^0 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git;a=commitdiff_plain;h=94544683debb6c663293c39eac5e091f27e1a4e7 [Tizen](ATSPI) squashed implementation Author: Radoslaw Cybulski Change-Id: I79d6adf9133da0912adda8383b3205ba9a5ba508 --- diff --git a/.gitignore b/.gitignore index 3480ca9..7ac2864 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ tags /debuglinks.list /debugsources.list /dali/internal/adaptor/common/system-cache-path.cpp +/.vscode/* diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-application.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-application.h index 99f24d7..86a9809 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-application.h +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-application.h @@ -21,6 +21,7 @@ // INTERNAL INCLUDES #include "test-application.h" #include "adaptor-test-adaptor-impl.h" +#include namespace Dali { @@ -38,6 +39,8 @@ public: float verticalDpi = DEFAULT_VERTICAL_DPI ) : TestApplication( surfaceWidth, surfaceHeight, horizontalDpi, verticalDpi ) { + //Dali::Accessibility::DBusWrapper::Install(std::unique_ptr(new Dali::Accessibility::TestDBusWrapper())); + Internal::Adaptor::Adaptor::SetAvailable(); } diff --git a/build/tizen/adaptor/Makefile.am b/build/tizen/adaptor/Makefile.am index aec1ab8..b549138 100644 --- a/build/tizen/adaptor/Makefile.am +++ b/build/tizen/adaptor/Makefile.am @@ -30,13 +30,13 @@ pkgconfig_DATA = dali-adaptor.pc dali-adaptor-integration.pc if UBUNTU_PROFILE LIBDALI_ADAPTOR_LA_SOURCES = \ $(adaptor_accessibility_common_src_files) \ - $(adaptor_accessibility_ubuntu_src_files) \ $(adaptor_adaptor_common_src_files) \ $(adaptor_adaptor_ubuntu_src_files) \ $(adaptor_clipboard_common_src_files) \ $(adaptor_clipboard_ubuntu_x11_src_files) \ $(adaptor_framework_generic_src_files) \ $(devel_api_src_files) \ + $(bridge_src_files) \ $(adaptor_devel_api_text_abstraction_src_files) \ $(adaptor_graphics_common_src_files) \ $(adaptor_graphics_gles_src_files) \ @@ -87,14 +87,13 @@ endif if MOBILE_PROFILE LIBDALI_ADAPTOR_LA_SOURCES = \ $(adaptor_accessibility_common_src_files) \ - $(adaptor_accessibility_tizen_wayland_src_files) \ - $(adaptor_accessibility_tizen_mobile_src_files) \ $(adaptor_adaptor_common_src_files) \ $(adaptor_adaptor_tizen_wayland_src_files) \ $(adaptor_clipboard_common_src_files) \ $(adaptor_clipboard_tizen_wayland_src_files) \ $(adaptor_framework_generic_src_files) \ $(devel_api_src_files) \ + $(bridge_src_files) \ $(adaptor_devel_api_text_abstraction_src_files) \ $(adaptor_graphics_common_src_files) \ $(adaptor_graphics_gles_src_files) \ @@ -153,14 +152,13 @@ endif if IVI_PROFILE LIBDALI_ADAPTOR_LA_SOURCES = \ $(adaptor_accessibility_common_src_files) \ - $(adaptor_accessibility_tizen_wayland_src_files) \ - $(adaptor_accessibility_tizen_ivi_src_files) \ $(adaptor_adaptor_common_src_files) \ $(adaptor_adaptor_tizen_wayland_src_files) \ $(adaptor_clipboard_common_src_files) \ $(adaptor_clipboard_tizen_wayland_src_files) \ $(adaptor_framework_generic_src_files) \ $(devel_api_src_files) \ + $(bridge_src_files) \ $(adaptor_devel_api_text_abstraction_src_files) \ $(adaptor_graphics_common_src_files) \ $(adaptor_graphics_gles_src_files) \ @@ -220,14 +218,13 @@ endif if TV_PROFILE LIBDALI_ADAPTOR_LA_SOURCES = \ $(adaptor_accessibility_common_src_files) \ - $(adaptor_accessibility_tizen_wayland_src_files) \ - $(adaptor_accessibility_tizen_tv_src_files) \ $(adaptor_adaptor_common_src_files) \ $(adaptor_adaptor_tizen_wayland_src_files) \ $(adaptor_clipboard_common_src_files) \ $(adaptor_clipboard_tizen_wayland_src_files) \ $(adaptor_framework_generic_src_files) \ $(devel_api_src_files) \ + $(bridge_src_files) \ $(adaptor_devel_api_text_abstraction_src_files) \ $(adaptor_graphics_common_src_files) \ $(adaptor_graphics_gles_src_files) \ @@ -285,14 +282,13 @@ endif if COMMON_PROFILE LIBDALI_ADAPTOR_LA_SOURCES = \ $(adaptor_accessibility_common_src_files) \ - $(adaptor_accessibility_tizen_wayland_src_files) \ - $(adaptor_accessibility_tizen_common_src_files) \ $(adaptor_adaptor_common_src_files) \ $(adaptor_adaptor_tizen_wayland_src_files) \ $(adaptor_clipboard_common_src_files) \ $(adaptor_clipboard_tizen_wayland_src_files) \ $(adaptor_framework_generic_src_files) \ $(devel_api_src_files) \ + $(bridge_src_files) \ $(adaptor_devel_api_text_abstraction_src_files) \ $(adaptor_graphics_common_src_files) \ $(adaptor_graphics_gles_src_files) \ @@ -352,8 +348,6 @@ endif if WEARABLE_PROFILE LIBDALI_ADAPTOR_LA_SOURCES = \ $(adaptor_accessibility_common_src_files) \ - $(adaptor_accessibility_tizen_wayland_src_files) \ - $(adaptor_accessibility_tizen_wearable_src_files) \ $(adaptor_adaptor_common_src_files) \ $(adaptor_adaptor_tizen_wayland_src_files) \ $(adaptor_adaptor_tizen_wearable_src_files) \ @@ -361,6 +355,7 @@ LIBDALI_ADAPTOR_LA_SOURCES = \ $(adaptor_clipboard_tizen_wayland_src_files) \ $(adaptor_framework_generic_src_files) \ $(devel_api_src_files) \ + $(bridge_src_files) \ $(adaptor_devel_api_text_abstraction_src_files) \ $(adaptor_graphics_common_src_files) \ $(adaptor_graphics_gles_src_files) \ diff --git a/build/tizen/adaptor/configure.ac b/build/tizen/adaptor/configure.ac index b182ba7..2dedcbe 100644 --- a/build/tizen/adaptor/configure.ac +++ b/build/tizen/adaptor/configure.ac @@ -58,8 +58,8 @@ PKG_CHECK_MODULES(TTRACE, ttrace, AC_DEFINE(ENABLE_TTRACE, 1, [ttrace available PKG_CHECK_MODULES(ECORE, ecore) PKG_CHECK_MODULES(ECORE_IPC, ecore-ipc) PKG_CHECK_MODULES(ECORE_IMF, [ecore-imf >= 1.13], [ecore_imf_1_13=yes], [ecore_imf_1_13=no]) -# Check for EldBus.h in ECore -PKG_CHECK_MODULES(ELDBUS, eldbus, [ eldbus_available=yes ], [ eldbus_available=no ] ) +# Check for EldBus.h in ECore, required for ATSPI +PKG_CHECK_MODULES(ELDBUS, eldbus, [ eldbus_available=yes ]) DALI_ELDBUS_AVAILABLE= if test "x$eldbus_available" = "xyes"; then diff --git a/dali/devel-api/adaptor-framework/accessibility-adaptor.cpp b/dali/devel-api/adaptor-framework/accessibility-adaptor.cpp deleted file mode 100644 index f635aba..0000000 --- a/dali/devel-api/adaptor-framework/accessibility-adaptor.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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. - * - */ - -// CLASS HEADER -#include - -// INTERNAL INCLUDES -#include - -namespace Dali -{ - -AccessibilityAdaptor::AccessibilityAdaptor() -{ -} - -AccessibilityAdaptor AccessibilityAdaptor::Get() -{ - return Internal::Adaptor::AccessibilityAdaptor::Get(); -} - -AccessibilityAdaptor::~AccessibilityAdaptor() -{ -} - -Vector2 AccessibilityAdaptor::GetReadPosition() const -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).GetReadPosition(); -} - -bool AccessibilityAdaptor::IsEnabled() const -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).IsEnabled(); -} - -void AccessibilityAdaptor::SetActionHandler(AccessibilityActionHandler& handler) -{ - Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).SetActionHandler(handler); -} - -void AccessibilityAdaptor::SetGestureHandler(AccessibilityGestureHandler& handler) -{ - Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).SetGestureHandler(handler); -} - -bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback) -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionNextEvent(allowEndFeedback); -} - -bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback) -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPreviousEvent(allowEndFeedback); -} - -bool AccessibilityAdaptor::HandleActionActivateEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionActivateEvent(); -} - -bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain) -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadEvent(x, y, allowReadAgain); -} - -bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback) -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadNextEvent(allowEndFeedback); -} - -bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback) -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadPreviousEvent(allowEndFeedback); -} - -bool AccessibilityAdaptor::HandleActionUpEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionUpEvent(); -} - -bool AccessibilityAdaptor::HandleActionDownEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionDownEvent(); -} - -bool AccessibilityAdaptor::HandleActionClearFocusEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionClearFocusEvent(); -} - -bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp) -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionScrollEvent(point, timeStamp); -} - -bool AccessibilityAdaptor::HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp) -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionTouchEvent(point, timeStamp); -} - -bool AccessibilityAdaptor::HandleActionBackEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionBackEvent(); -} - -void AccessibilityAdaptor::HandleActionEnableEvent() -{ - Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionEnableEvent(); -} - -void AccessibilityAdaptor::HandleActionDisableEvent() -{ - Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionDisableEvent(); -} - -bool AccessibilityAdaptor::HandleActionScrollUpEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionScrollUpEvent(); -} - -bool AccessibilityAdaptor::HandleActionScrollDownEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionScrollDownEvent(); -} - -bool AccessibilityAdaptor::HandleActionPageLeftEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageLeftEvent(); -} - -bool AccessibilityAdaptor::HandleActionPageRightEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageRightEvent(); -} - -bool AccessibilityAdaptor::HandleActionPageUpEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageUpEvent(); -} - -bool AccessibilityAdaptor::HandleActionPageDownEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageDownEvent(); -} - -bool AccessibilityAdaptor::HandleActionMoveToFirstEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionMoveToFirstEvent(); -} - -bool AccessibilityAdaptor::HandleActionMoveToLastEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionMoveToLastEvent(); -} - -bool AccessibilityAdaptor::HandleActionReadFromTopEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadFromTopEvent(); -} - -bool AccessibilityAdaptor::HandleActionReadFromNextEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadFromNextEvent(); -} - -bool AccessibilityAdaptor::HandleActionZoomEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionZoomEvent(); -} - -bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadPauseResumeEvent(); -} - -bool AccessibilityAdaptor::HandleActionStartStopEvent() -{ - return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionStartStopEvent(); -} - -AccessibilityAdaptor::AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor& manager ) -: BaseHandle( &manager ) -{ -} - -AccessibilityAdaptor::AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor* manager ) -: BaseHandle( manager ) -{ -} - -} // namespace Dali diff --git a/dali/devel-api/adaptor-framework/accessibility-adaptor.h b/dali/devel-api/adaptor-framework/accessibility-adaptor.h deleted file mode 100755 index 251f591..0000000 --- a/dali/devel-api/adaptor-framework/accessibility-adaptor.h +++ /dev/null @@ -1,341 +0,0 @@ -#ifndef DALI_ACCESSIBILITY_ADAPTOR_H -#define DALI_ACCESSIBILITY_ADAPTOR_H - -/* - * Copyright (c) 2019 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 -#include -#include - -namespace Dali -{ - -namespace Internal DALI_INTERNAL -{ -namespace Adaptor -{ -class AccessibilityAdaptor; -} -} - -class AccessibilityActionHandler; -class AccessibilityGestureHandler; -class TouchPoint; - -/** - * @brief The AccessibilityAdaptor provides communication to the accessibility manager interface (implemented in toolkit). - * - */ -class DALI_ADAPTOR_API AccessibilityAdaptor : public BaseHandle -{ -public: - - /** - * @brief Create an uninitialized handle. - * - * This can be initialized by calling getting the adaptor from Dali::Adaptor. - */ - AccessibilityAdaptor(); - - /** - * @brief Retrieve a handle to the AccessibilityAdaptor. - * - * @return A handle to the AccessibilityAdaptor. - */ - static AccessibilityAdaptor Get(); - - /** - * @brief Destructor - * - * This is non-virtual since derived Handle types must not contain data or virtual methods. - */ - ~AccessibilityAdaptor(); - - /** - * @brief Returns the current position of the read action. - * @return The current event position. - */ - Vector2 GetReadPosition() const; - - /** - * @brief Query whether the accessibility(screen-reader) is enabled. - * - * The accessibility will be enabled by system setting. - * @return True if the accessibility(screen-reader) is enabled. - */ - bool IsEnabled() const; - - /** - * @brief Set the handler to handle accessibility actions. - * - * @param[in] handler The Accessibility action handler. - * @note Handlers should remove themselves when they are destroyed. - */ - void SetActionHandler(AccessibilityActionHandler& handler); - - /** - * @brief Set the handler to handle accessibility gestures. - * - * @param[in] handler The Accessibility gesture handler. - * @note Handlers should remove themselves when they are destroyed. - */ - void SetGestureHandler(AccessibilityGestureHandler& handler); - - /** - * @brief Handle the accessibility action to move focus to the next focusable actor - * (by one finger flick down). - * - * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end - * @return Whether the action is performed successfully or not. - */ - bool HandleActionNextEvent(bool allowEndFeedback = true); - - /** - * @brief Handle the accessibility action to move focus to the previous focusable actor - * (by one finger flick up). - * - * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end - * @return Whether the action is performed successfully or not. - */ - bool HandleActionPreviousEvent(bool allowEndFeedback = true); - - /** - * @brief Handle the accessibility action to activate the current focused actor (by one - * finger ) - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionActivateEvent(); - - /** - * @brief Handle the accessibility action to focus and read the actor (by one finger tap or move). - * - * @param x x position of event - * @param y y position of event - * @param allowReadAgain true if the action read again the same object (i.e. read action) - * false if the action just read when the focus object is changed (i.e. over action) - * @return Whether the action is performed successfully or not. - */ - bool HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain); - - /** - * @brief Handle the accessibility action to move focus to the next focusable actor - * (by one finger flick right). - * - * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end - * @return Whether the action is performed successfully or not. - */ - bool HandleActionReadNextEvent(bool allowEndFeedback = true); - - /** - * @brief Handle the accessibility action to move focus to the previous focusable actor - * (by one finger flick up). - * - * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the front - * @return Whether the action is performed successfully or not. - */ - bool HandleActionReadPreviousEvent(bool allowEndFeedback = true); - - /** - * @brief Handle the accessibility action to change the value when the current focused - * actor is a slider (by double finger down and move up and right). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionUpEvent(); - - /** - * @brief Handle the accessibility action to change the value when the current focused - * actor is a slider (by double finger down and move down and left). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionDownEvent(); - - /** - * @brief Handle the accessibility action to clear the focus from the current focused - * actor if any, so that no actor is focused in the focus chain. - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionClearFocusEvent(); - - /** - * @brief Handle the accessibility action to scroll when there is a scroller on the touched position - * (by 2 finger touch & move, 2 finger flick). - * - * @param[in] point The touch point information. - * @param[in] timeStamp The time the touch occurred. - * @return Whether the action is performed successfully or not. - */ - bool HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp); - - /** - * @brief Handle the accessibility action to move for the current focused actor - * (by 1 finger tap & hold and move). - * - * @param[in] point The touch point information. - * @param[in] timeStamp The time the touch occurred. - * @return Whether the action is performed successfully or not. - */ - bool HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp); - - /** - * @brief Handle the accessibility action to navigate back (by two fingers circle draw). - * @return Whether the action is performed successfully or not. - */ - bool HandleActionBackEvent(); - - /** - * @brief Handle the accessibility action to enable the feature. - */ - void HandleActionEnableEvent(); - - /** - * @brief Handle the accessibility action to disable the feature. - */ - void HandleActionDisableEvent(); - - /** - * @brief Handle the accessibility action to scroll up the list and focus on - * the first item on the list after the scrolling and read the item - * (by two finger swipe up). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionScrollUpEvent(); - - /** - * @brief Handle the accessibility action to scroll down the list and focus on - * the first item on the list after the scrolling and read the item - * (by two finger swipe down). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionScrollDownEvent(); - - /** - * @brief Handle the accessibility action to scroll left to the previous page - * (by two finger swipe left). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionPageLeftEvent(); - - /** - * @brief Handle the accessibility action to scroll right to the next page - * (by two finger swipe right). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionPageRightEvent(); - - /** - * @brief Handle the accessibility action to scroll up to the previous page - * (by one finger swipe left and right). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionPageUpEvent(); - - /** - * @brief Handle the accessibility action to scroll down to the next page - * (by one finger swipe right and left). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionPageDownEvent(); - - /** - * @brief Handle the accessibility action to move the focus to the first item on the screen - * (by one finger swipe up and down). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionMoveToFirstEvent(); - - /** - * @brief Handle the accessibility action to move the focus to the last item on the screen - * (by one finger swipe down and up). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionMoveToLastEvent(); - - /** - * @brief Handle the accessibility action to move the focus to the first item on the top - * and read from the top item continuously (by three fingers single tap). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionReadFromTopEvent(); - - /** - * @brief Handle the accessibility action to move focus to and read from the next focusable - * actor continuously (by three fingers double tap). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionReadFromNextEvent(); - - /** - * @brief Handle the accessibility action to do the zooming - * (by one finger triple tap). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionZoomEvent(); - - /** - * @brief Handle the accessibility action to pause/resume the current speech - * (by two fingers single tap). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionReadPauseResumeEvent(); - - /** - * @brief Handle the accessibility action to start/stop the current action - * (by two fingers double tap). - * - * @return Whether the action is performed successfully or not. - */ - bool HandleActionStartStopEvent(); - -public: // Not intended for application developers - - /** - * @brief Creates a handle using the Adaptor::Internal implementation. - * - * @param[in] adaptor The AccessibilityAdaptor implementation. - */ - DALI_INTERNAL AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor& adaptor ); - - /** - * @brief This constructor is used by AccessibilityAdaptor::Get(). - * - * @param[in] adaptor A pointer to the accessibility adaptor. - */ - explicit DALI_INTERNAL AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor* adaptor ); -}; - -} // namespace Dali - -#endif // DALI_ACCESSIBILITY_ADAPTOR_H diff --git a/dali/devel-api/adaptor-framework/accessibility-gesture-handler.h b/dali/devel-api/adaptor-framework/accessibility-gesture-handler.h deleted file mode 100644 index 4b8c859..0000000 --- a/dali/devel-api/adaptor-framework/accessibility-gesture-handler.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef DALI_ACCESSIBILITY_GESTURE_HANDLER_H -#define DALI_ACCESSIBILITY_GESTURE_HANDLER_H - -/* - * Copyright (c) 2019 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 - -namespace Dali -{ - -/** - * AccessibilityGestureHandler is an interface used by Dali to handle accessibility gestures - * passed by the accessibility manager. - */ -class AccessibilityGestureHandler -{ -public: - - /** - * Handle the accessibility pan gesture. - * @param[in] panEvent The pan event to be handled. - * @return whether the gesture is handled successfully or not. - */ - virtual bool HandlePanGesture( const AccessibilityGestureEvent& panEvent ) = 0; - -}; // class AccessibilityGestureHandler - -} // namespace Dali - -#endif // DALI_ACCESSIBILITY_GESTURE_HANDLER_H diff --git a/dali/devel-api/adaptor-framework/accessibility.h b/dali/devel-api/adaptor-framework/accessibility.h new file mode 100644 index 0000000..8ffe231 --- /dev/null +++ b/dali/devel-api/adaptor-framework/accessibility.h @@ -0,0 +1,965 @@ +#ifndef DALI_ACCESSIBILITY_DEVEL_H +#define DALI_ACCESSIBILITY_DEVEL_H + +/* + * Copyright (c) 2019 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//INTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Accessibility +{ +class Accessible; +class Text; +class Value; +class Component; +class Collection; +class Action; + +/** + * @brief Base class for different accessibility bridges + * + * Bridge is resposible for initializing and managing connection on accessibility bus. + * Accessibility clients will not get any information about UI without initialized and upraised bridge. + * Concrete implementation depends on the accessibility technology available on the platform. + * + * @note This class is singleton. + */ +struct DALI_ADAPTOR_API Bridge +{ + enum class ForceUpResult + { + JUST_STARTED, + ALREADY_UP + }; + + /** + * @brief Destructor + */ + virtual ~Bridge() = default; + + /** + * @brief Get bus name which bridge is initialized on + */ + virtual const std::string& GetBusName() const = 0; + + /** + * @brief Registers top level window + * + * Hierarchy of objects visible for accessibility clients is based on tree-like + * structure created from Actors objects. This method allows to connect chosen + * object as direct ancestor of application and therefore make it visible for + * accessibility clients. + */ + virtual void AddTopLevelWindow( Accessible* ) = 0; + + /** + * @brief Removes top level window + * + * Hierarchy of objects visible for accessibility clients is based on tree-like + * structure created from Actors objects. This method removes previously added + * window from visible accessibility objects. + */ + virtual void RemoveTopLevelWindow( Accessible* ) = 0; + + /** + * @brief Adds popup window + * + * Hierarchy of objects visible for accessibility clients is based on tree-like + * structure created from Actors objects. This method adds new popup to the tree. + */ + virtual void AddPopup( Accessible* ) = 0; + + /** + * @brief Removes popup window + * + * Hierarchy of objects visible for accessibility clients is based on tree-like + * structure created from Actors objects. This method removes previously added + * popup window. + */ + virtual void RemovePopup( Accessible* ) = 0; + + /** + * @brief Set name of current application which will be visible on accessibility bus + */ + virtual void SetApplicationName( std::string ) = 0; + + /** + * @brief Get object being root of accessibility tree + * + * @return handler to accessibility object + */ + virtual Accessible* GetApplication() const = 0; + + /** + * @brief Find an object in accessibility tree + * + * @param[in] s path to object + * + * @return handler to accessibility object + */ + virtual Accessible* FindByPath( const std::string& s) const = 0; + + /** + * @brief Show application on accessibility bus + */ + virtual void ApplicationShown() = 0; + + /** + * @brief Hide application on accessibility bus + */ + virtual void ApplicationHidden() = 0; + + /** + * @brief Initialize accessibility bus + */ + virtual void Initialize() = 0; + + /** + * @brief Terminate accessibility bus + */ + virtual void Terminate() = 0; + + /** + * @brief This method is called, when bridge is being activated. + */ + virtual ForceUpResult ForceUp() + { + if( data ) + return ForceUpResult::ALREADY_UP; + data = std::make_shared< Data >(); + data->bridge = this; + return ForceUpResult::JUST_STARTED; + } + virtual void ForceDown(); + bool IsUp() const { return bool(data); } + + /** + * @brief Emits caret-moved event on at-spi bus. + **/ + virtual void EmitCaretMoved( Accessible* obj, unsigned int cursorPosition ) = 0; + + /** + * @brief Emits active-descendant-changed event on at-spi bus. + **/ + virtual void EmitActiveDescendantChanged( Accessible* obj, Accessible *child ) = 0; + + /** + * @brief Emits text-changed event on at-spi bus. + **/ + virtual void EmitTextChanged( Accessible* obj, TextChangedState state, unsigned int position, unsigned int length, const std::string &content ) = 0; + + /** + * @brief Emits state-changed event on at-spi bus. + **/ + virtual void EmitStateChanged( Accessible* obj, State state, int val1, int val2 = 0 ) = 0; + + /** + * @brief Emits window event on at-spi bus. + **/ + virtual void Emit( Accessible* obj, WindowEvent we, unsigned int detail1 = 0 ) = 0; + + /** + * @brief Emits property-changed event on at-spi bus. + **/ + virtual void Emit( Accessible* obj, ObjectPropertyChangeEvent ev ) = 0; + + /** + * @brief Emits bounds-changed event on at-spi bus. + **/ + virtual void EmitBoundsChanged( Accessible* obj, Rect<> rect ) = 0; + + /** + * @brief Emits key event on at-spi bus. + * + * Screen-reader might receive this event and reply, that given keycode is consumed. In that case + * further processing of the keycode should be ignored. + **/ + virtual Consumed Emit( KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText ) = 0; + + /** + * @brief Force accessibility client to read provided text. + * + * @note Text can be read only if accessibility client uses Text To Speach module + * + * @param[in] text string that should be read + * @param[in] discardable flag pointing if text can be discarded by subsequent reading request + * @param[in] callback function called every time the status of reading has changed, callback type + * specifies one parameter (of type std::string), which can be one of the following signals: + * “ReadingCancelled” + * “ReadingStopped” + * “ReadingSkipped” + */ + virtual void Say( const std::string& text, bool discardable, std::function callback ) = 0; + + /** + * @brief Force accessibility client to pause / resume. + * + * @param[in] pause true if you want to pause, false if you want to resume + */ + virtual void PauseResume( bool pause ) = 0; + + /** + * @brief Returns instance of bridge singleton object. + **/ + static Bridge* GetCurrentBridge(); + +protected: + struct Data + { + std::unordered_set< Accessible* > knownObjects; + std::string busName; + Bridge* bridge = nullptr; + Actor highlightActor, currentlyHighlightedActor; + }; + std::shared_ptr< Data > data; + friend class Accessible; + + /** + * @brief Registers accessible object to be known in bridge object + * + * Bridge must known about all currently alive accessible objects, as some requst + * might come and object will be identified by number id (it's memory address). + * To avoid memory corruption number id is checked against set of known objects. + **/ + void RegisterOnBridge( Accessible* ); + + /** + * @brief Tells bridge, that given object is considered root (doesn't have any parents). + * + * All root objects will have the same parent - application object. Application object + * is controlled by bridge and private. + **/ + void SetIsOnRootLevel( Accessible* ); +}; + +inline bool IsUp() +{ + return Bridge::GetCurrentBridge()->IsUp(); +} + +/** + * @brief Basic interface implemented by all accessibility objects + */ +class DALI_IMPORT_API Accessible +{ +protected: + Accessible(); + + Accessible( const Accessible& ) = delete; + Accessible( Accessible&& ) = delete; + + Accessible& operator=( const Accessible& ) = delete; + Accessible& operator=( Accessible&& ) = delete; + +public: + virtual ~Accessible(); + + using utf8_t = unsigned char; + + /** + * @brief Calculaties word boundaries in given utf8 text. + * + * s and length represents source text pointer and it's length respectively. langauge represents + * language to use. Word boundaries are returned as non-zero values in table breaks, which + * must be of size at least length. + **/ + void FindWordSeparationsUtf8( const utf8_t *s, size_t length, const char *language, char *breaks ); + + /** + * @brief Calculaties line boundaries in given utf8 text. + * + * s and length represents source text pointer and it's length respectively. langauge represents + * language to use. Line boundaries are returned as non-zero values in table breaks, which + * must be of size at least length. + **/ + void FindLineSeparationsUtf8( const utf8_t *s, size_t length, const char *language, char *breaks ); + + /** + * @brief Helper function for emiting active-descendant-changed event + **/ + void EmitActiveDescendantChanged( Accessible* obj, Accessible *child ); + + /** + * @brief Helper function for emiting state-changed event + **/ + void EmitStateChanged( State state, int newValue1, int newValue2 = 0 ); + + /** + * @brief Helper function for emiting bounds-changed event + **/ + void EmitBoundsChanged( Rect<> rect ); + + /** + * @brief Emit "showing" event. + * The method inform accessibility clients about "showing" state + * + * @param[in] showing flag pointing if object is showing + */ + void EmitShowing( bool showing ); + + /** + * @brief Emit "visible" event. + * The method inform accessibility clients about "visible" state + * + * @param[in] visible flag pointing if object is visible + */ + void EmitVisible( bool visible ); + + /** + * @brief Emit "highlighted" event. + * The method inform accessibility clients about "highlighted" state + * + * @param[in] set flag pointing if object is highlighted + */ + void EmitHighlighted( bool set ); + + /** + * @brief Emit "focused" event. + * The method inform accessibility clients about "focused" state + * + * @param[in] set flag pointing if object is focused + */ + void EmitFocused( bool set ); + + /** + * @brief Emit "text inserted" event + * + * @param[in] position caret position + * @param[in] length text length + * @param[in] content inserted text + */ + void EmitTextInserted( unsigned int position, unsigned int length, const std::string &content ); + + /** + * @brief Emit "text deleted" event + * + * @param[in] position caret position + * @param[in] length text length + * @param[in] content deleted text + */ + void EmitTextDeleted( unsigned int position, unsigned int length, const std::string &content ); + + /** + * @brief Emit "caret moved" event + * + * @param[in] cursorPosition new caret position + */ + void EmitTextCaretMoved( unsigned int cursorPosition ); + + /** + * @brief Emit "highlighted" event + * + * @param[in] we enumerated window event + * @param[in] detail1 additional parameter which interpretation depends on chosen event + */ + void Emit( WindowEvent we, unsigned int detail1 = 0 ); + + void Emit( ObjectPropertyChangeEvent ev ); + /** + * @brief Get accessibility name + * + * @return string with name + */ + virtual std::string GetName() = 0; + + /** + * @brief Get accessibility description + * + * @return string with description + */ + virtual std::string GetDescription() = 0; + + /** + * @brief Get parent + * + * @return handler to accessibility object + */ + virtual Accessible* GetParent() = 0; + + /** + * @brief Get count of children + * + * @return unsigned integer value + */ + virtual size_t GetChildCount() = 0; + + /** + * @brief Get collection with all children + * + * @return collection of accessibility objects + */ + virtual std::vector< Accessible* > GetChildren(); + + /** + * @brief Get nth child + * + * @return accessibility object + */ + virtual Accessible* GetChildAtIndex( size_t index ) = 0; + + /** + * @brief Get index that current object has in its parent's children collection + * + * @return unsigned integer index + */ + virtual size_t GetIndexInParent() = 0; + + /** + * @brief Get accessibility role + * + * @return Role enumeration + * + * @see Dali::Accessibility::Role + */ + virtual Role GetRole() = 0; + + /** + * @brief Get name of accessibility role + * + * @return string with human readable role converted from enumeration + * + * @see Dali::Accessibility::Role + * @see Accessibility::Accessible::GetRole + */ + virtual std::string GetRoleName(); + + /** + * @brief Get localized name of accessibility role + * + * @return string with human readable role translated according to current + * translation domain + * + * @see Dali::Accessibility::Role + * @see Accessibility::Accessible::GetRole + * @see Accessibility::Accessible::GetRoleName + * + * @note translation is not supported in this version + */ + virtual std::string GetLocalizedRoleName(); + + /** + * @brief Get accessibility states + * + * @return collection of states + * + * @note States class is instatation of ArrayBitset template class + * + * @see Dali::Accessibility::State + * @see Dali::Accessibility::ArrayBitset + */ + virtual States GetStates() = 0; + + /** + * @brief Get accessibility attributes + * + * @return map of attributes and their values + */ + virtual Attributes GetAttributes() = 0; + + //TODO probably shouldn't be public + virtual bool IsProxy(); + + /** + * @brief Get unique address on accessibility bus + * + * @return class containing address + * + * @see Dali::Accessibility::Address + */ + virtual Address GetAddress(); + + /** + * @brief Get accessibility object, which is "default label" for this object + */ + virtual Accessible* GetDefaultLabel(); + + /** + * @brief Depute an object to perform provided gesture + * + * @param[in] gestureInfo structure describing the gesture + * + * @return true on success, false otherwise + * + * @see Dali::Accessibility::GestureInfo + */ + virtual bool DoGesture(const GestureInfo &gestureInfo) = 0; + + /** + * @brief Re-emits selected states of an Accessibility Object + * + * @param[in] states chosen states to re-emit + * @param[in] doRecursive if true all children of the Accessibility Object will also re-emit the states + */ + void NotifyAccessibilityStateChange( Dali::Accessibility::States states, bool doRecursive ); + + /** + * @brief Get information about current object and all relations that connects + * it with other accessibility objects + * + * @return iterable collection of Relation objects + * + * @see Dali::Accessibility::Relation + */ + virtual std::vector GetRelationSet() = 0; + + /** + * @brief Get all implemented interfaces + * + * @return collection of strings with implemented interfaces + */ + std::vector< std::string > GetInterfaces(); + + /** + * @brief Check if object is on root level + */ + bool GetIsOnRootLevel() const { return isOnRootLevel; } + + /** + * @brief The method registers functor resposible for converting Actor into Accessible + * @param functor returning Accessible handle from Actor object + */ + static void RegisterControlAccessibilityGetter( std::function< Accessible*( Dali::Actor ) > functor); + + /** + * @brief Acquire Accessible object from Actor object + * + * @param[in] actor Actor object + * @param[in] root true, if it's top level object (window) + * + * @return handle to Accessible object + */ + static Accessible* Get( Dali::Actor actor, bool root = false ); + +protected: + std::shared_ptr< Bridge::Data > GetBridgeData(); + static Dali::Actor GetHighlightActor(); + static void SetHighlightActor(Dali::Actor actor); + static Dali::Actor GetCurrentlyHighlightedActor(); + static void SetCurrentlyHighlightedActor(Dali::Actor); +private: + friend class Bridge; + + std::weak_ptr< Bridge::Data > bridgeData; + bool isOnRootLevel = false; +}; + +/** + * @brief Interface enabling to perform provided actions + */ +class DALI_IMPORT_API Action : public virtual Accessible +{ +public: + /** + * @brief Get name of action with given index + * + * @param[in] index index of action + * + * @return string with name of action + */ + virtual std::string GetActionName( size_t index ) = 0; + + /** + * @brief Get translated name of action with given index + * + * @param[in] index index of action + * + * @return string with name of action translated according to current translation domain + * + * @note translation is not supported in this version + */ + virtual std::string GetLocalizedActionName( size_t index ) = 0; + + /** + * @brief Get description of action with given index + * + * @param[in] index index of action + * + * @return string with description of action + */ + virtual std::string GetActionDescription( size_t index ) = 0; + + /** + * @brief Get key code binded to action with given index + * + * @param[in] index index of action + * + * @return string with key name + */ + virtual std::string GetActionKeyBinding( size_t index ) = 0; + + /** + * @brief Get number of provided actions + * + * @return unsigned integer with number of actions + */ + virtual size_t GetActionCount() = 0; + + /** + * @brief Perform an action with given index + * + * @param index index of action + * + * @return true on success, false otherwise + */ + virtual bool DoAction( size_t index ) = 0; + + /** + * @brief Perform an action with given name + * + * @param name name of action + * + * @return true on success, false otherwise + */ + virtual bool DoAction( const std::string& name ) = 0; + + //TODO DoActionName +}; + +/** + * @brief Interface enabling advanced quering of accessibility objects + * + * @note since all mathods can be implemented inside bridge, + * none methods have to be overrided + */ +class DALI_IMPORT_API Collection : public virtual Accessible +{ +public: +}; + +/** + * @brief Interface representing objects having screen coordinates + */ +class DALI_IMPORT_API Component : public virtual Accessible +{ +public: + /** + * @brief Get rectangle describing size + * + * @param[in] ctype enumeration with type of coordinate systems + * + * @return Rect<> object + * + * @see Dali::Rect + */ + virtual Rect<> GetExtents( CoordType ctype ) = 0; + + /** + * @brief Get layer current object is localized on + * + * @return enumeration pointing layer + * + * @see Dali::Accessibility::ComponentLayer + */ + virtual ComponentLayer GetLayer() = 0; + + /** + * @brief Get value of z-order + * + * @return value of z-order + */ + virtual int16_t GetMdiZOrder() = 0; + + /** + * @brief Set current object as "focused" + * + * @return true on success, false otherwise + */ + virtual bool GrabFocus() = 0; + + /** + * @brief Get value of alpha channel + * + * @return alpha channel value in range [0.0, 1.0] + */ + virtual double GetAlpha() = 0; + + /** + * @brief Set current object as "highlighted" + * + * The method assings "highlighted" state, simultaneously removing it + * from currently highlighted object. + * + * @return true on success, false otherwise + */ + virtual bool GrabHighlight() = 0; + + /** + * @brief Set current object as "unhighlighted" + * + * The method removes "highlighted" state from object. + * + * @return true on success, false otherwise + * + * @see Dali:Accessibility::State + */ + virtual bool ClearHighlight() = 0; + + //TODO remove + virtual int GetHighlightIndex() = 0; + + /** + * @brief Check whether object can be scrolled + * + * @return true if object is scrollable, false otherwise + * + * @see Dali:Accessibility::State + */ + virtual bool IsScrollable(); + + /** + * @brief Get Accessible object containing given point + * + * @param[in] p two-dimensional point + * @param[in] ctype enumeration with type of coordinate system + * + * @return handle to last child of current object which contains given point + * + * @see Dali::Accessibility::Point + */ + virtual Accessible* GetAccessibleAtPoint( Point p, CoordType ctype ); + + /** + * @brief Check if current object contains given point + * + * @param[in] p two-dimensional point + * @param[in] ctype enumeration with type of coordinate system + * + * @return handle to Accessible object + * + * @see Dali::Accessibility::Point + */ + virtual bool Contains( Point p, CoordType ctype ); +}; + +/** + * @brief Interface representing objects which can store numeric value + */ +class DALI_IMPORT_API Value : public virtual Accessible +{ +public: + /** + * @brief Get the lowest possible value + * + * @return double value + */ + virtual double GetMinimum() = 0; + + /** + * @brief Get current value + * + * @return double value + */ + virtual double GetCurrent() = 0; + + /** + * @brief Get the highest possible value + * + * @return double value + */ + virtual double GetMaximum() = 0; + + /** + * @brief Set value + * + * @param[in] val double value + * + * @return true if value could have been assigned, false otherwise + */ + virtual bool SetCurrent( double val) = 0; + + /** + * @brief Get the lowest increment that can be distinguished + * + * @return double value + */ + virtual double GetMinimumIncrement() = 0; +}; + +/** + * @brief Interface representing objects which can store immutable texts + * + * @see Dali::Accessibility::EditableText + */ +class DALI_IMPORT_API Text : public virtual Accessible +{ +public: + /** + * @brief Get stored text in given range + * + * @param[in] startOffset index of first character + * @param[in] endOffset index of first character after the last one expected + * + * @return substring of stored text + */ + virtual std::string GetText( size_t startOffset, size_t endOffset ) = 0; + + /** + * @brief Get number of all stored characters + * + * @return number of characters + */ + virtual size_t GetCharacterCount() = 0; + + virtual size_t GetCaretOffset() = 0; + virtual bool SetCaretOffset(size_t offset) = 0; + + /** + * @brief Get substring of stored text truncated in concrete gradation + * + * @param[in] offset position in stored text + * @param[in] boundary enumeration describing text gradation + * + * @return Range structure containing acquired text and offsets in original string + * + * @see Dali::Accessibility::Range + */ + virtual Range GetTextAtOffset( size_t offset, TextBoundary boundary ) = 0; + + /** + * @brief Get selected text + * + * @param[in] selectionNum selection index + * @note Currently only one selection (i.e. with index = 0) is supported + * + * @return Range structure containing acquired text and offsets in original string + * + * @see Dali::Accessibility::Range + */ + virtual Range GetSelection( size_t selectionNum ) = 0; + + /** + * @brief Remove selection + * + * @param[in] selectionNum selection index + * @note Currently only one selection (i.e. with index = 0) is supported + * + * @return bool on success, false otherwise + */ + virtual bool RemoveSelection( size_t selectionNum ) = 0; + + /** + * @brief Get selected text + * + * @param[in] selectionNum selection index + * @param[in] startOffset index of first character + * @param[in] endOffset index of first character after the last one expected + * + * @note Currently only one selection (i.e. with index = 0) is supported + * + * @return true on success, false otherwise + */ + virtual bool SetSelection( size_t selectionNum, size_t startOffset, size_t endOffset ) = 0; +}; + +/** + * @brief Interface representing objects which can store editable texts + * + * @note Paste method is entirely implemented inside bridge + * + * @see Dali::Accessibility::EditableText + */ +class DALI_IMPORT_API EditableText : public virtual Accessible +{ +public: + /** + * @brief Copy text in range to system clipboard + * + * @param[in] startPosition index of first character + * @param[in] endPosition index of first character after the last one expected + * + * @return true on success, false otherwise + */ + virtual bool CopyText( size_t startPosition, size_t endPosition ) = 0; + + /** + * @brief Cut text in range to system clipboard + * + * @param[in] startPosition index of first character + * @param[in] endPosition index of first character after the last one expected + * + * @return true on success, false otherwise + */ + virtual bool CutText( size_t startPosition, size_t endPosition ) = 0; +}; + +/** + * @brief minimalistic, always empty Accessible object with settable address + * + * For those situations, where you want to return address in different bridge + * (embedding for example), but the object itself ain't planned to be used otherwise. + * This object has null parent, no children, empty name and so on + */ +class DALI_IMPORT_API EmptyAccessibleWithAddress : public virtual Accessible +{ +public: + EmptyAccessibleWithAddress() = default; + EmptyAccessibleWithAddress( Address address ) : address( std::move( address ) ) {} + + void SetAddress( Address address ) { this->address = std::move( address ); } + + std::string GetName() override { return ""; } + std::string GetDescription() override { return ""; } + Accessible* GetParent() override { return nullptr; } + size_t GetChildCount() override { return 0; } + std::vector< Accessible* > GetChildren() override { return {}; } + Accessible* GetChildAtIndex( size_t index ) override + { + throw std::domain_error{"out of bounds index (" + std::to_string( index ) + ") - no children"}; + } + size_t GetIndexInParent() override { return static_cast< size_t >( -1 ); } + Role GetRole() override { return {}; } + std::string GetRoleName() override; + States GetStates() override { return {}; } + Attributes GetAttributes() override { return {}; } + Address GetAddress() override + { + return address; + } + bool DoGesture(const GestureInfo &gestureInfo) override + { + return false; + } + std::vector GetRelationSet() override + { + return {}; + } + +private: + Address address; +}; + +} +} + +#endif // DALI_ACCESSIBILITY_DEVEL_H diff --git a/dali/devel-api/file.list b/dali/devel-api/file.list index 7f88752..e0851be 100755 --- a/dali/devel-api/file.list +++ b/dali/devel-api/file.list @@ -1,5 +1,4 @@ devel_api_src_files = \ - $(adaptor_devel_api_dir)/adaptor-framework/accessibility-adaptor.cpp \ $(adaptor_devel_api_dir)/adaptor-framework/application-devel.cpp \ $(adaptor_devel_api_dir)/adaptor-framework/autofill-group.cpp \ $(adaptor_devel_api_dir)/adaptor-framework/autofill-item.cpp \ @@ -39,10 +38,6 @@ devel_api_src_files = \ devel_api_adaptor_framework_header_files = \ - $(adaptor_devel_api_dir)/adaptor-framework/accessibility-adaptor.h \ - $(adaptor_devel_api_dir)/adaptor-framework/accessibility-action-handler.h \ - $(adaptor_devel_api_dir)/adaptor-framework/accessibility-gesture-handler.h \ - $(adaptor_devel_api_dir)/adaptor-framework/accessibility-gesture-event.h \ $(adaptor_devel_api_dir)/adaptor-framework/application-devel.h \ $(adaptor_devel_api_dir)/adaptor-framework/autofill-group.h \ $(adaptor_devel_api_dir)/adaptor-framework/autofill-item.h \ @@ -86,7 +81,8 @@ devel_api_adaptor_framework_header_files = \ $(adaptor_devel_api_dir)/adaptor-framework/physical-keyboard.h \ $(adaptor_devel_api_dir)/adaptor-framework/key-devel.h \ $(adaptor_devel_api_dir)/adaptor-framework/thread-settings.h \ - $(adaptor_devel_api_dir)/adaptor-framework/window-devel.h + $(adaptor_devel_api_dir)/adaptor-framework/window-devel.h \ + $(adaptor_devel_api_dir)/adaptor-framework/accessibility.h devel_api_text_abstraction_src_files = \ $(adaptor_devel_api_dir)/text-abstraction/bidirectional-support.cpp \ @@ -115,4 +111,3 @@ text_abstraction_header_files = \ $(adaptor_devel_api_dir)/text-abstraction/text-abstraction-definitions.h \ $(adaptor_devel_api_dir)/text-abstraction/text-renderer.h \ $(adaptor_devel_api_dir)/text-abstraction/text-renderer-layout-helper.h - diff --git a/dali/internal/accessibility/accessibility-impl.cpp b/dali/internal/accessibility/accessibility-impl.cpp new file mode 100644 index 0000000..2a7da00 --- /dev/null +++ b/dali/internal/accessibility/accessibility-impl.cpp @@ -0,0 +1,765 @@ +/* + * Copyright 2019 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 + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +using namespace Dali::Accessibility; +using namespace Dali; + +const std::string& Dali::Accessibility::Address::GetBus() const +{ + return bus.empty() && Bridge::GetCurrentBridge() ? Bridge::GetCurrentBridge()->GetBusName() : bus; +} + +std::string EmptyAccessibleWithAddress::GetRoleName() +{ + return ""; +} + +std::string Accessible::GetLocalizedRoleName() +{ + return GetRoleName(); +} + +std::string Accessible::GetRoleName() +{ + switch( GetRole() ) + { + case Role::INVALID: + { + return "invalid"; + } + case Role::ACCELERATOR_LABEL: + { + return "accelerator label"; + } + case Role::ALERT: + { + return "alert"; + } + case Role::ANIMATION: + { + return "animation"; + } + case Role::ARROW: + { + return "arrow"; + } + case Role::CALENDAR: + { + return "calendar"; + } + case Role::CANVAS: + { + return "canvas"; + } + case Role::CHECK_BOX: + { + return "check box"; + } + case Role::CHECK_MENU_ITEM: + { + return "check menu item"; + } + case Role::COLOR_CHOOSER: + { + return "color chooser"; + } + case Role::COLUMN_HEADER: + { + return "column header"; + } + case Role::COMBO_BOX: + { + return "combo box"; + } + case Role::DATE_EDITOR: + { + return "date editor"; + } + case Role::DESKTOP_ICON: + { + return "desktop icon"; + } + case Role::DESKTOP_FRAME: + { + return "desktop frame"; + } + case Role::DIAL: + { + return "dial"; + } + case Role::DIALOG: + { + return "dialog"; + } + case Role::DIRECTORY_PANE: + { + return "directory pane"; + } + case Role::DRAWING_AREA: + { + return "drawing area"; + } + case Role::FILE_CHOOSER: + { + return "file chooser"; + } + case Role::FILLER: + { + return "filler"; + } + case Role::FOCUS_TRAVERSABLE: + { + return "focus traversable"; + } + case Role::FONT_CHOOSER: + { + return "font chooser"; + } + case Role::FRAME: + { + return "frame"; + } + case Role::GLASS_PANE: + { + return "glass pane"; + } + case Role::HTML_CONTAINER: + { + return "html container"; + } + case Role::ICON: + { + return "icon"; + } + case Role::IMAGE: + { + return "image"; + } + case Role::INTERNAL_FRAME: + { + return "internal frame"; + } + case Role::LABEL: + { + return "label"; + } + case Role::LAYERED_PANE: + { + return "layered pane"; + } + case Role::LIST: + { + return "list"; + } + case Role::LIST_ITEM: + { + return "list item"; + } + case Role::MENU: + { + return "menu"; + } + case Role::MENU_BAR: + { + return "menu bar"; + } + case Role::MENU_ITEM: + { + return "menu item"; + } + case Role::OPTION_PANE: + { + return "option pane"; + } + case Role::PAGE_TAB: + { + return "page tab"; + } + case Role::PAGE_TAB_LIST: + { + return "page tab list"; + } + case Role::PANEL: + { + return "panel"; + } + case Role::PASSWORD_TEXT: + { + return "password text"; + } + case Role::POPUP_MENU: + { + return "popup menu"; + } + case Role::PROGRESS_BAR: + { + return "progress bar"; + } + case Role::PUSH_BUTTON: + { + return "push button"; + } + case Role::RADIO_BUTTON: + { + return "radio button"; + } + case Role::RADIO_MENU_ITEM: + { + return "radio menu item"; + } + case Role::ROOT_PANE: + { + return "root pane"; + } + case Role::ROW_HEADER: + { + return "row header"; + } + case Role::SCROLL_BAR: + { + return "scroll bar"; + } + case Role::SCROLL_PANE: + { + return "scroll pane"; + } + case Role::SEPARATOR: + { + return "separator"; + } + case Role::SLIDER: + { + return "slider"; + } + case Role::SPIN_BUTTON: + { + return "spin button"; + } + case Role::SPLIT_PANE: + { + return "split pane"; + } + case Role::STATUS_BAR: + { + return "status bar"; + } + case Role::TABLE: + { + return "table"; + } + case Role::TABLE_CELL: + { + return "table cell"; + } + case Role::TABLE_COLUMN_HEADER: + { + return "table column header"; + } + case Role::TABLE_ROW_HEADER: + { + return "table row header"; + } + case Role::TEAROFF_MENU_ITEM: + { + return "tearoff menu item"; + } + case Role::TERMINAL: + { + return "terminal"; + } + case Role::TEXT: + { + return "text"; + } + case Role::TOGGLE_BUTTON: + { + return "toggle button"; + } + case Role::TOOL_BAR: + { + return "tool bar"; + } + case Role::TOOL_TIP: + { + return "tool tip"; + } + case Role::TREE: + { + return "tree"; + } + case Role::TREE_TABLE: + { + return "tree table"; + } + case Role::UNKNOWN: + { + return "unknown"; + } + case Role::VIEWPORT: + { + return "viewport"; + } + case Role::WINDOW: + { + return "window"; + } + case Role::EXTENDED: + { + return "extended"; + } + case Role::HEADER: + { + return "header"; + } + case Role::FOOTER: + { + return "footer"; + } + case Role::PARAGRAPH: + { + return "paragraph"; + } + case Role::RULER: + { + return "ruler"; + } + case Role::APPLICATION: + { + return "application"; + } + case Role::AUTOCOMPLETE: + { + return "autocomplete"; + } + case Role::EDITBAR: + { + return "edit bar"; + } + case Role::EMBEDDED: + { + return "embedded"; + } + case Role::ENTRY: + { + return "entry"; + } + case Role::CHART: + { + return "chart"; + } + case Role::CAPTION: + { + return "caution"; + } + case Role::DOCUMENT_FRAME: + { + return "document frame"; + } + case Role::HEADING: + { + return "heading"; + } + case Role::PAGE: + { + return "page"; + } + case Role::SECTION: + { + return "section"; + } + case Role::REDUNDANT_OBJECT: + { + return "redundant object"; + } + case Role::FORM: + { + return "form"; + } + case Role::LINK: + { + return "link"; + } + case Role::INPUT_METHOD_WINDOW: + { + return "input method window"; + } + case Role::TABLE_ROW: + { + return "table row"; + } + case Role::TREE_ITEM: + { + return "tree item"; + } + case Role::DOCUMENT_SPREADSHEET: + { + return "document spreadsheet"; + } + case Role::DOCUMENT_PRESENTATION: + { + return "document presentation"; + } + case Role::DOCUMENT_TEXT: + { + return "document text"; + } + case Role::DOCUMENT_WEB: + { + return "document web"; + } + case Role::DOCUMENT_EMAIL: + { + return "document email"; + } + case Role::COMMENT: + { + return "comment"; + } + case Role::LIST_BOX: + { + return "list box"; + } + case Role::GROUPING: + { + return "grouping"; + } + case Role::IMAGE_MAP: + { + return "image map"; + } + case Role::NOTIFICATION: + { + return "notification"; + } + case Role::INFO_BAR: + { + return "info bar"; + } + case Role::LEVEL_BAR: + { + return "level bar"; + } + case Role::TITLE_BAR: + { + return "title bar"; + } + case Role::BLOCK_QUOTE: + { + return "block quote"; + } + case Role::AUDIO: + { + return "audio"; + } + case Role::VIDEO: + { + return "video"; + } + case Role::DEFINITION: + { + return "definition"; + } + case Role::ARTICLE: + { + return "article"; + } + case Role::LANDMARK: + { + return "landmark"; + } + case Role::LOG: + { + return "log"; + } + case Role::MARQUEE: + { + return "marquee"; + } + case Role::MATH: + { + return "math"; + } + case Role::RATING: + { + return "rating"; + } + case Role::TIMER: + { + return "timer"; + } + case Role::STATIC: + { + return "static"; + } + case Role::MATH_FRACTION: + { + return "math fraction"; + } + case Role::MATH_ROOT: + { + return "math root"; + } + case Role::SUBSCRIPT: + { + return "subscript"; + } + case Role::SUPERSCRIPT: + { + return "superscript"; + } + case Role::_COUNT: + { + break; + } + } + return ""; +} + +Dali::Actor Accessible::GetCurrentlyHighlightedActor() +{ + return IsUp() ? Bridge::GetCurrentBridge()->data->currentlyHighlightedActor : Dali::Actor{}; +} + +void Accessible::SetCurrentlyHighlightedActor(Dali::Actor actor) +{ + if (IsUp()) { + Bridge::GetCurrentBridge()->data->currentlyHighlightedActor = actor; + } +} + +Dali::Actor Accessible::GetHighlightActor() +{ + return IsUp() ? Bridge::GetCurrentBridge()->data->highlightActor : Dali::Actor{}; +} + +void Accessible::SetHighlightActor(Dali::Actor actor) +{ + if (IsUp()) { + Bridge::GetCurrentBridge()->data->highlightActor = actor; + } +} + +void Bridge::ForceDown() +{ + auto highlighted = Accessible::GetCurrentlyHighlightedActor(); + if( highlighted ) + { + auto p = dynamic_cast< Component* >( Accessible::Get( highlighted ) ); + if( p ) + p->ClearHighlight(); + } + data = {}; +} + +void Bridge::SetIsOnRootLevel( Accessible* o ) +{ + o->isOnRootLevel = true; +} + +class NonControlAccessible : public virtual Accessible, public virtual Collection, public virtual Component +{ +public: + Dali::Actor actor; + bool root = false; + + NonControlAccessible( Dali::Actor actor, bool root ) : actor( actor ), root( root ) + { + } + + Dali::Rect<> GetExtents( Dali::Accessibility::CoordType ctype ) override + { + Vector2 screenPosition = actor.GetProperty( Dali::DevelActor::Property::SCREEN_POSITION ).Get< Vector2 >(); + Vector3 size = actor.GetCurrentSize() * actor.GetCurrentWorldScale(); + bool positionUsesAnchorPoint = + actor.GetProperty( Dali::DevelActor::Property::POSITION_USES_ANCHOR_POINT ) + .Get< bool >(); + Vector3 anchorPointOffSet = + size * ( positionUsesAnchorPoint ? actor.GetCurrentAnchorPoint() + : AnchorPoint::TOP_LEFT ); + Vector2 position = Vector2( screenPosition.x - anchorPointOffSet.x, + screenPosition.y - anchorPointOffSet.y ); + + return { position.x, position.y, size.x, size.y }; + } + Dali::Accessibility::ComponentLayer GetLayer() override + { + return Dali::Accessibility::ComponentLayer::WINDOW; + } + int16_t GetMdiZOrder() + { + return 0; + } + double GetAlpha() + { + return 0; + } + bool GrabFocus() override + { + return false; + } + bool GrabHighlight() override + { + return false; + } + bool ClearHighlight() override + { + return false; + } + int GetHighlightIndex() override + { + return 0; + } + bool IsScrollable() override + { + return false; + } + std::string GetName() override + { + return actor.GetName(); + } + std::string GetDescription() override + { + return ""; + } + Accessible* GetParent() override + { + if( GetIsOnRootLevel() ) + { + auto b = GetBridgeData(); + return b->bridge->GetApplication(); + } + return Get( actor.GetParent() ); + } + size_t GetChildCount() override + { + return static_cast< size_t >( actor.GetChildCount() ); + } + Accessible* GetChildAtIndex( size_t index ) override + { + auto s = static_cast< size_t >( actor.GetChildCount() ); + if( index >= s ) + throw std::domain_error{"invalid index " + std::to_string( index ) + " for object with " + std::to_string( s ) + " children"}; + return Get( actor.GetChildAt( static_cast< unsigned int >( index ) ) ); + } + size_t GetIndexInParent() override + { + auto p = actor.GetParent(); + if( !p ) + return 0; + auto s = static_cast< size_t >( p.GetChildCount() ); + for( auto i = 0u; i < s; ++i ) + { + if( p.GetChildAt( i ) == actor ) + return i; + } + throw std::domain_error{"actor is not a child of it's parent"}; + } + Role GetRole() override + { + return root ? Role::WINDOW : Role::REDUNDANT_OBJECT; + } + States GetStates() override + { + States s; + if( root ) + { + s[State::HIGHLIGHTABLE] = true; + s[State::ENABLED] = true; + s[State::SENSITIVE] = true; + s[State::SHOWING] = true; + s[State::VISIBLE] = true; + s[State::ACTIVE] = true; + } + else + { + auto t = GetParent()->GetStates(); + s[State::SHOWING] = t[State::SHOWING]; + s[State::VISIBLE] = t[State::VISIBLE]; + } + return s; + } + Attributes GetAttributes() override + { + Dali::TypeInfo type; + actor.GetTypeInfo( type ); + return { + {"t", type.GetName()}, + }; + } + bool DoGesture(const GestureInfo &gestureInfo) override + { + return false; + } + std::vector GetRelationSet() override + { + return {}; + } +}; + +using NonControlAccessiblesType = std::unordered_map< const Dali::RefObject*, std::unique_ptr< NonControlAccessible > >; +static NonControlAccessiblesType nonControlAccessibles; + +static std::function< Accessible*( Dali::Actor ) > convertingFunctor = []( Dali::Actor ) -> Accessible* { + return nullptr; +}; + +void Accessible::RegisterControlAccessibilityGetter( std::function< Accessible*( Dali::Actor ) > functor ) +{ + convertingFunctor = functor; +} + +Accessible* Accessible::Get( Dali::Actor actor, bool root ) +{ + if( !actor ) + { + return nullptr; + } + auto p = convertingFunctor( actor ); + if( !p ) + { + if( nonControlAccessibles.empty() ) + { + auto registry = Dali::Stage::GetCurrent().GetObjectRegistry(); + registry.ObjectDestroyedSignal().Connect( []( const Dali::RefObject* obj ) { + nonControlAccessibles.erase( obj ); + } ); + } + auto it = nonControlAccessibles.emplace( &actor.GetBaseObject(), nullptr ); + if( it.second ) + { + it.first->second.reset( new NonControlAccessible( actor, root ) ); + } + p = it.first->second.get(); + } + return p; +} diff --git a/dali/internal/accessibility/bridge/accessibility-common.h b/dali/internal/accessibility/bridge/accessibility-common.h new file mode 100644 index 0000000..03f3146 --- /dev/null +++ b/dali/internal/accessibility/bridge/accessibility-common.h @@ -0,0 +1,339 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_COMMON_H +#define DALI_INTERNAL_ACCESSIBILITY_COMMON_H + +/* + * Copyright (c) 2019 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 +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include + +#define A11yDbusName "org.a11y.Bus" +#define A11yDbusPath "/org/a11y/bus" +#define A11yDbusStatusInterface "org.a11y.Status" +#define AtspiDbusNameRegistry "org.a11y.atspi.Registry" +#define AtspiDbusPathRoot "/org/a11y/atspi/accessible/root" +#define AtspiDbusInterfaceSocket "org.a11y.atspi.Socket" +#define AtspiPath "/org/a11y/atspi/accessible" +#define AtspiDbusInterfaceAccessible "org.a11y.atspi.Accessible" +#define AtspiDbusInterfaceAction "org.a11y.atspi.Action" +#define AtspiDbusInterfaceApplication "org.a11y.atspi.Application" +#define AtspiDbusInterfaceCollection "org.a11y.atspi.Collection" +#define AtspiDbusInterfaceComponent "org.a11y.atspi.Component" +#define AtspiDbusInterfaceDocument "org.a11y.atspi.Document" +#define AtspiDbusInterfaceEditableText "org.a11y.atspi.EditableText" +#define AtspiDbusInterfaceEventKeyboard "org.a11y.atspi.Event.Keyboard" +#define AtspiDbusInterfaceEventMouse "org.a11y.atspi.Event.Mouse" +#define AtspiDbusInterfaceEventObject "org.a11y.atspi.Event.Object" +#define AtspiDbusInterfaceHyperlink "org.a11y.atspi.Hyperlink" +#define AtspiDbusInterfaceHypertext "org.a11y.atspi.Hypertext" +#define AtspiDbusInterfaceImage "org.a11y.atspi.Image" +#define AtspiDbusInterfaceSelection "org.a11y.atspi.Selection" +#define AtspiDbusInterfaceTable "org.a11y.atspi.Table" +#define AtspiDbusInterfaceTableCell "org.a11y.atspi.TableCell" +#define AtspiDbusInterfaceText "org.a11y.atspi.Text" +#define AtspiDbusInterfaceValue "org.a11y.atspi.Value" +#define AtspiDbusInterfaceSocket "org.a11y.atspi.Socket" +#define AtspiDbusInterfaceEventWindow "org.a11y.atspi.Event.Window" + +#define AtspiDbusPathDec "/org/a11y/atspi/registry/deviceeventcontroller" +#define AtspiDbusInterfaceDec "org.a11y.atspi.DeviceEventController" +#define AtspiDbusInterfaceDeviceEventListener "org.a11y.atspi.DeviceEventListener" + +#define DirectReadingDBusName "org.tizen.ScreenReader" +#define DirectReadingDBusPath "/org/tizen/DirectReading" +#define DirectReadingDBusInterface "org.tizen.DirectReading" + +struct ObjectPath; + +/** + * @brief Enumeration used for quering Accessibility objects + */ +enum class MatchType : int32_t +{ + INVALID, + ALL, + ANY, + NONE, //FIXME Underscore was added because "None" has been defined in another library + EMPTY +}; + +/** + * @brief Enumeration used for quering Accessibility objects + * + * SortOrder::Canonical uses breadth-first search and sort objects in order of indexes in parent + * SortOrder::ReverseCanonical uses SortOrder::Canonical and reverse collection + * The rest of orders is not supported. + */ +enum class SortOrder : uint32_t +{ + INVALID, + CANONICAL, + FLOW, + TAB, + REVERSE_CANONICAL, + REVERSE_FLOW, + REVERSE_TAB, + LAST_DEFINED +}; + +namespace DBus +{ +class CurrentBridgePtr +{ + static Dali::Accessibility::Bridge*& get() + { + static thread_local Dali::Accessibility::Bridge* b = nullptr; + return b; + } + Dali::Accessibility::Bridge* prev; + CurrentBridgePtr( const CurrentBridgePtr& ) = delete; + CurrentBridgePtr( CurrentBridgePtr&& ) = delete; + CurrentBridgePtr& operator=( const CurrentBridgePtr& ) = delete; + CurrentBridgePtr& operator=( CurrentBridgePtr&& ) = delete; + +public: + CurrentBridgePtr( Dali::Accessibility::Bridge* b ) : prev( get() ) { get() = b; } + ~CurrentBridgePtr() { get() = prev; } + + static Dali::Accessibility::Bridge* current() { return get(); } +}; + +namespace detail +{ +template < typename T > +struct signature_accessible_impl +{ + using subtype = std::pair< std::string, ObjectPath >; + + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "AtspiAccessiblePtr"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "(so)"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, T* t ) + { + if( t ) + { + auto v = t->GetAddress(); + signature< subtype >::set( iter, {v.GetBus(), ObjectPath{std::string{ATSPI_PREFIX_PATH} + v.GetPath()}} ); + } + else + { + signature< subtype >::set( iter, {"", ObjectPath{ATSPI_NULL_PATH}} ); + } + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, T*& v ) + { + subtype tmp; + if( !signature< subtype >::get( iter, tmp ) ) + return false; + if( tmp.second.value == ATSPI_NULL_PATH ) + { + v = nullptr; + return true; + } + if( tmp.second.value.substr( 0, strlen( ATSPI_PREFIX_PATH ) ) != ATSPI_PREFIX_PATH ) + return false; + auto b = CurrentBridgePtr::current(); + if( b->GetBusName() != tmp.first ) + return false; + v = b->FindByPath( tmp.second.value.substr( strlen( ATSPI_PREFIX_PATH ) ) ); + return v != nullptr; + } +}; + +template <> +struct signature< Dali::Accessibility::Accessible* > : public signature_accessible_impl< Dali::Accessibility::Accessible > +{ +}; + +template <> +struct signature< Dali::Accessibility::Address > +{ + using subtype = std::pair< std::string, ObjectPath >; + + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "AtspiAccessiblePtr"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "(so)"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const Dali::Accessibility::Address& v ) + { + if( v ) + { + signature< subtype >::set( iter, {v.GetBus(), ObjectPath{std::string{ATSPI_PREFIX_PATH} + v.GetPath()}} ); + } + else + { + signature< subtype >::set( iter, {v.GetBus(), ObjectPath{ATSPI_NULL_PATH}} ); + } + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, Dali::Accessibility::Address& v ) + { + subtype tmp; + if( !signature< subtype >::get( iter, tmp ) ) + return false; + if( tmp.second.value == ATSPI_NULL_PATH ) + { + v = {}; + return true; + } + if( tmp.second.value.substr( 0, strlen( ATSPI_PREFIX_PATH ) ) != ATSPI_PREFIX_PATH ) + return false; + v = {std::move( tmp.first ), tmp.second.value.substr( strlen( ATSPI_PREFIX_PATH ) )}; + return true; + } +}; + +template <> +struct signature< Dali::Accessibility::States > +{ + using subtype = std::array< uint32_t, 2 >; + + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return signature< subtype >::name(); + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature< subtype >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const Dali::Accessibility::States& v ) + { + signature< subtype >::set( iter, v.GetRawData() ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, Dali::Accessibility::States& v ) + { + subtype tmp; + if( !signature< subtype >::get( iter, tmp ) ) + return false; + v = Dali::Accessibility::States{tmp}; + return true; + } +}; +} +} + +struct _Logger +{ + const char* file; + int line; + std::ostringstream tmp; + + _Logger( const char* f, int l ) : file( f ), line( l ) {} + + ~_Logger() + { + Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s:%d: %s", file, line, tmp.str().c_str() ); + } + + template < typename T > + _Logger& operator<<( T&& t ) + { + tmp << std::forward< T >( t ); + return *this; + } +}; + +struct _LoggerEmpty +{ + template < typename T > + _LoggerEmpty& operator<<( T&& t ) + { + return *this; + } +}; + +struct _LoggerScope +{ + const char* file; + int line; + + _LoggerScope( const char* f, int l ) : file( f ), line( l ) + { + Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s:%d: +", file, line ); + } + ~_LoggerScope() + { + Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s:%d: -", file, line ); + } +}; + +#define LOG() _Logger( __FILE__, __LINE__ ) +#define SCOPE() _LoggerScope _l##__LINE__( __FILE__, __LINE__ ) + +#endif // DALI_INTERNAL_ACCESSIBILITY_COMMON_H diff --git a/dali/internal/accessibility/bridge/accessible.cpp b/dali/internal/accessibility/bridge/accessible.cpp new file mode 100644 index 0000000..c30116d --- /dev/null +++ b/dali/internal/accessibility/bridge/accessible.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2019 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 + +//INTERNAL INCLUDES +#include +#include +#include + +using namespace Dali::Accessibility; + +std::vector< std::string > Accessible::GetInterfaces() +{ + std::vector< std::string > tmp; + tmp.push_back( AtspiDbusInterfaceAccessible ); + if( dynamic_cast< Collection* >( this ) ) + tmp.push_back( AtspiDbusInterfaceCollection ); + if( dynamic_cast< Text* >( this ) ) + tmp.push_back( AtspiDbusInterfaceText ); + if( dynamic_cast< Value* >( this ) ) + tmp.push_back( AtspiDbusInterfaceValue ); + if( dynamic_cast< Component* >( this ) ) + tmp.push_back( AtspiDbusInterfaceComponent ); + if( auto d = dynamic_cast< Action* >( this ) ) + { + if( d->GetActionCount() > 0 ) + tmp.push_back( AtspiDbusInterfaceAction ); + } + return tmp; +} + +Accessible::Accessible() +{ +} + +Accessible::~Accessible() +{ + auto b = bridgeData.lock(); + if( b ) + b->knownObjects.erase( this ); +} + +void Accessible::EmitActiveDescendantChanged( Accessible* obj, Accessible *child ) +{ + if( auto b = GetBridgeData() ) + { + b->bridge->EmitActiveDescendantChanged( obj, child ); + } +} + +void Accessible::EmitStateChanged( State state, int newValue1, int newValue2 ) +{ + if( auto b = GetBridgeData() ) + { + b->bridge->EmitStateChanged( this, state, newValue1, newValue2 ); + } +} + +void Accessible::EmitShowing( bool showing ) +{ + if( auto b = GetBridgeData() ) + { + b->bridge->EmitStateChanged( this, State::SHOWING, showing ? 1 : 0, 0 ); + } +} + +void Accessible::EmitVisible( bool visible ) +{ + if( auto b = GetBridgeData() ) + { + b->bridge->EmitStateChanged( this, State::VISIBLE, visible ? 1 : 0, 0 ); + } +} + +void Accessible::EmitHighlighted( bool set ) +{ + if( auto b = GetBridgeData() ) + { + b->bridge->EmitStateChanged( this, State::HIGHLIGHTED, set ? 1 : 0, 0 ); + } +} + +void Accessible::EmitFocused( bool set ) +{ + if ( auto b = GetBridgeData() ) { + b->bridge->EmitStateChanged( this, State::FOCUSED, set ? 1 : 0, 0 ); + } +} +void Accessible::EmitTextInserted( unsigned int position, unsigned int length, const std::string &content ) +{ + if ( auto b = GetBridgeData() ) { + b->bridge->EmitTextChanged( this, TextChangedState::INSERT, position, length, content ); + } +} +void Accessible::EmitTextDeleted( unsigned int position, unsigned int length, const std::string &content ) +{ + if ( auto b = GetBridgeData() ) { + b->bridge->EmitTextChanged( this, TextChangedState::DELETE, position, length, content ); + } +} +void Accessible::EmitTextCaretMoved( unsigned int cursorPosition ) +{ + if ( auto b = GetBridgeData() ) { + b->bridge->EmitCaretMoved( this, cursorPosition ); + } +} +void Accessible::Emit( WindowEvent we, unsigned int detail1 ) +{ + if( auto b = GetBridgeData() ) + { + b->bridge->Emit( this, we, detail1 ); + } +} +void Accessible::Emit( ObjectPropertyChangeEvent ev ) +{ + if( auto b = GetBridgeData() ) + { + b->bridge->Emit( this, ev ); + } +} + +void Accessible::EmitBoundsChanged( Rect<> rect ) +{ + if( auto b = GetBridgeData() ) + { + b->bridge->EmitBoundsChanged( this, rect ); + } +} + +std::vector< Accessible* > Accessible::GetChildren() +{ + std::vector< Accessible* > tmp( GetChildCount() ); + for( auto i = 0u; i < tmp.size(); ++i ) + { + tmp[i] = GetChildAtIndex( i ); + } + return tmp; +} + +std::shared_ptr< Bridge::Data > Accessible::GetBridgeData() +{ + auto b = bridgeData.lock(); + if( !b ) + { + auto p = Bridge::GetCurrentBridge(); + b = p->data; + } + return b; +} + +Address Accessible::GetAddress() +{ + auto b = bridgeData.lock(); + if( !b ) + { + b = GetBridgeData(); + if ( b ) + b->bridge->RegisterOnBridge( this ); + } + std::ostringstream tmp; + tmp << this; + return {b ? b->busName : "", tmp.str() }; +} + +void Bridge::RegisterOnBridge( Accessible* obj ) +{ + assert( !obj->bridgeData.lock() || obj->bridgeData.lock() == data ); + if( !obj->bridgeData.lock() ) + { + assert( data ); + data->knownObjects.insert( obj ); + obj->bridgeData = data; + } +} + +bool Accessible::IsProxy() +{ + return false; +} + +Accessible* Accessible::GetDefaultLabel() +{ + return this; +} + +void Accessible::NotifyAccessibilityStateChange( Dali::Accessibility::States states, bool doRecursive ) +{ + if( auto b = GetBridgeData() ) + { + auto s = GetStates() & states; + for( auto i = 0u; i < s.size(); i++ ) + { + auto index = static_cast< Dali::Accessibility::State >( i ); + if( s[index] ) + b->bridge->EmitStateChanged( this, index, 1, 0 ); + } + if( doRecursive ) + { + auto children = GetChildren(); + for( auto c : children ) + c->NotifyAccessibilityStateChange( states, doRecursive ); + } + } +} + +void Accessible::FindWordSeparationsUtf8( const utf8_t *s, size_t length, const char *language, char *breaks ) +{ + set_wordbreaks_utf8( s, length, language, breaks ); +} + +void Accessible::FindLineSeparationsUtf8( const utf8_t *s, size_t length, const char *language, char *breaks ) +{ + set_linebreaks_utf8( s, length, language, breaks ); +} diff --git a/dali/internal/accessibility/bridge/bridge-accessible.cpp b/dali/internal/accessibility/bridge/bridge-accessible.cpp new file mode 100644 index 0000000..c7cbcb3 --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-accessible.cpp @@ -0,0 +1,803 @@ +/* + * Copyright (c) 2019 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 + +// EXTERNAL INCLUDES +#include + +//comment out 2 lines below to get more logs +#undef LOG +#define LOG() _LoggerEmpty() + +using namespace Dali::Accessibility; + +#define GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH 10000 + +BridgeAccessible::BridgeAccessible() +{ +} + +void BridgeAccessible::RegisterInterfaces() +{ + DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceAccessible}; + AddGetPropertyToInterface( desc, "ChildCount", &BridgeAccessible::GetChildCount ); + AddGetPropertyToInterface( desc, "Name", &BridgeAccessible::GetName ); + AddGetPropertyToInterface( desc, "Description", &BridgeAccessible::GetDescription ); + AddGetPropertyToInterface( desc, "Parent", &BridgeAccessible::GetParent ); + AddFunctionToInterface( desc, "GetRole", &BridgeAccessible::GetRole ); + AddFunctionToInterface( desc, "GetRoleName", &BridgeAccessible::GetRoleName ); + AddFunctionToInterface( desc, "GetLocalizedRoleName", &BridgeAccessible::GetLocalizedRoleName ); + AddFunctionToInterface( desc, "GetState", &BridgeAccessible::GetStates ); + AddFunctionToInterface( desc, "GetAttributes", &BridgeAccessible::GetAttributes ); + AddFunctionToInterface( desc, "GetInterfaces", &BridgeAccessible::GetInterfaces ); + AddFunctionToInterface( desc, "GetChildAtIndex", &BridgeAccessible::GetChildAtIndex ); + AddFunctionToInterface( desc, "GetChildren", &BridgeAccessible::GetChildren ); + AddFunctionToInterface( desc, "GetIndexInParent", &BridgeAccessible::GetIndexInParent ); + AddFunctionToInterface( desc, "GetNavigableAtPoint", &BridgeAccessible::GetNavigableAtPoint ); + AddFunctionToInterface( desc, "GetNeighbor", &BridgeAccessible::GetNeighbor ); + AddFunctionToInterface( desc, "GetDefaultLabelInfo", &BridgeAccessible::GetDefaultLabelInfo ); + AddFunctionToInterface( desc, "DoGesture", &BridgeAccessible::DoGesture ); + AddFunctionToInterface( desc, "GetReadingMaterial", &BridgeAccessible::GetReadingMaterial ); + AddFunctionToInterface( desc, "GetRelationSet", &BridgeAccessible::GetRelationSet ); + dbusServer.addInterface( "/", desc, true ); +} + +static bool AcceptObjectCheckRole( Component* obj ) +{ + if( !obj ) + return false; + switch( obj->GetRole() ) + { + case Role::APPLICATION: + case Role::FILLER: + case Role::SCROLL_PANE: + case Role::SPLIT_PANE: + case Role::WINDOW: + case Role::IMAGE: + case Role::IMAGE_MAP: + case Role::LIST: + case Role::ICON: + case Role::TOOL_BAR: + case Role::REDUNDANT_OBJECT: + case Role::COLOR_CHOOSER: + case Role::TREE_TABLE: + case Role::PAGE_TAB_LIST: + case Role::PAGE_TAB: + case Role::SPIN_BUTTON: + case Role::INPUT_METHOD_WINDOW: + case Role::EMBEDDED: + case Role::INVALID: + case Role::NOTIFICATION: + case Role::DATE_EDITOR: + case Role::TABLE: + { + return false; + } + default: + { + break; + } + } + + return true; +} + +static bool AcceptObjectCheckRelations( Component* obj) +{ + auto r = obj->GetRelationSet(); + + for (const auto& it : r) + if (it.relationType == RelationType::CONTROLLED_BY) + return false; + + return true; +} + +static Component* GetScrollableParent( Accessible* obj ) +{ + while( obj ) + { + obj = obj->GetParent(); + auto comp = dynamic_cast< Component* >( obj ); + if( comp && comp->IsScrollable() ) + return comp; + } + return nullptr; +} + +static bool ObjectIsItem( Component* obj ) +{ + if( !obj ) + return false; + auto role = obj->GetRole(); + return role == Role::LIST_ITEM || role == Role::MENU_ITEM; +} + +static bool ObjectIsCollapsed( Component* obj ) +{ + if( !obj ) + return false; + const auto states = obj->GetStates(); + return states[State::EXPANDABLE] && !states[State::EXPANDED]; +} + +static bool OobjectIsZeroSize( Component* obj ) +{ + if( !obj ) + return false; + auto extents = obj->GetExtents( CoordType::WINDOW ); + return extents.height == 0 || extents.width == 0; +} + +static bool AcceptObject( Component* obj ) +{ + if( !obj ) + return false; + const auto states = obj->GetStates(); + if( !states[State::VISIBLE] ) + return false; + if( !AcceptObjectCheckRole( obj ) ) + return false; + if ( !AcceptObjectCheckRelations( obj ) ) + return false; + // if (CALL(get_object_in_relation_by_type, obj, ATSPI_RELATION_CONTROLLED_BY) != NULL) return 0; + if ( !AcceptObjectCheckRelations( obj ) ) + return false; + if( !states[State::HIGHLIGHTABLE] ) + return false; + + if( GetScrollableParent( obj ) != nullptr ) + { + auto parent = dynamic_cast< Component* >( obj->GetParent() ); + + if( parent ) + { + return !ObjectIsItem( obj ) || !ObjectIsCollapsed( parent ); + } + } + else + { + if( OobjectIsZeroSize( obj ) ) + { + return false; + } + if( !states[State::SHOWING] ) + { + return false; + } + } + return true; +} + +static bool AcceptObject( Accessible* obj ) +{ + auto c = dynamic_cast< Component* >( obj ); + return AcceptObject( c ); +} + +static std::string objDump( Component* obj ) +{ + if ( !obj ) + return "nullptr"; + std::ostringstream o; + auto e = obj->GetExtents( CoordType::SCREEN ); + o << "name: " << obj->GetName() << " extent: (" << e.x << ", " + << e.y << "), [" << e.width << ", " << e.height << "]"; + return o.str(); +} + +Component * BridgeAccessible::GetObjectInRelation( Accessible * obj, RelationType ralationType ) +{ + if ( !obj ) + return nullptr; + for ( auto &relation : obj->GetRelationSet() ) + { + if ( relation.relationType == ralationType ) + { + for ( auto &address : relation.targets ) + { + auto component = dynamic_cast( Find( address ) ); + if ( component ) + return component; + } + } + } + return nullptr; +} + +static std::string makeIndent( unsigned int maxRecursionDepth ) +{ + return std::string( GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH - maxRecursionDepth, ' ' ); +} + +Component* BridgeAccessible::CalculateNavigableAccessibleAtPoint( Accessible* root, Point p, CoordType cType, unsigned int maxRecursionDepth ) +{ + if( !root || maxRecursionDepth == 0 ) + return nullptr; + auto root_component = dynamic_cast< Component* >( root ); + LOG() << "CalculateNavigableAccessibleAtPoint: checking: " << makeIndent(maxRecursionDepth) << objDump(root_component); + + if( root_component && !root_component->Contains( p, cType ) ) + return nullptr; + + auto children = root->GetChildren(); + for( auto childIt = children.rbegin(); childIt != children.rend(); childIt++ ) + { + //check recursively all children first + auto result = CalculateNavigableAccessibleAtPoint( *childIt, p, cType, maxRecursionDepth - 1 ); + if( result ) + return result; + } + if( root_component ) + { + //Found a candidate, all its children are already checked + auto controledBy = GetObjectInRelation( root_component, RelationType::CONTROLLED_BY ); + if ( !controledBy ) + controledBy = root_component; + + if ( controledBy->IsProxy() || AcceptObject( controledBy ) ) + { + LOG() << "CalculateNavigableAccessibleAtPoint: found: " << makeIndent(maxRecursionDepth) << objDump( root_component ); + return controledBy; + } + } + return nullptr; +} + +BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial() +{ + auto self = FindSelf(); + auto attributes = self->GetAttributes(); + auto name = self->GetName(); + std::string labeledByName = ""; + std::string textIfceName = ""; + auto role = static_cast< uint32_t >( self->GetRole() ); + auto states = self->GetStates(); + auto localizedName = self->GetLocalizedRoleName(); + auto childCount = static_cast< int32_t >( self->GetChildCount() ); + + double currentValue = 0.0; + double minimumIncrement = 0.0; + double maximumValue = 0.0; + double minimumValue = 0.0; + + auto description = self->GetDescription(); + auto indexInParent = static_cast< int32_t >( self->GetIndexInParent() ); + bool isSelectedInParent = false; + bool hasCheckBoxChild = false; + int32_t firstSelectedChildIndex = 0; + int32_t selectedChildCount = 0; + + for( auto i = 0u; i < static_cast< size_t >( childCount ); ++i ) + { + auto q = self->GetChildAtIndex( i ); + auto s = q->GetStates(); + if( s[State::SELECTABLE] ) + { + ++selectedChildCount; + if( s[State::SELECTED] ) + { + if( firstSelectedChildIndex < 0 ) + firstSelectedChildIndex = static_cast< int32_t >( i ); + } + } + if( q->GetRole() == Role::CHECK_BOX ) + hasCheckBoxChild = true; + } + + int32_t listChildrenCount = 0; + Accessible* parent = self->GetParent(); + auto parentStateSet = parent ? parent->GetStates() : States{}; + auto parentChildCount = parent ? static_cast< int32_t >( parent->GetChildCount() ) : 0; + auto parentRole = static_cast< uint32_t >( parent ? parent->GetRole() : Role{} ); + Accessible* describedByObject = nullptr; + + return { + attributes, + name, + labeledByName, + textIfceName, + role, + states, + localizedName, + childCount, + currentValue, + minimumIncrement, + maximumValue, + minimumValue, + description, + indexInParent, + isSelectedInParent, + hasCheckBoxChild, + listChildrenCount, + firstSelectedChildIndex, + parent, + parentStateSet, + parentChildCount, + parentRole, + selectedChildCount, + describedByObject}; +} + +DBus::ValueOrError< bool > BridgeAccessible::DoGesture( Dali::Accessibility::Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime ) +{ + return FindSelf()->DoGesture( Dali::Accessibility::GestureInfo {type, xBeg, xEnd, yBeg, yEnd, state, eventTime}); +} + +DBus::ValueOrError< Accessible*, uint8_t, Accessible* > BridgeAccessible::GetNavigableAtPoint( int32_t x, int32_t y, uint32_t coordType ) +{ + Accessible* deputy = nullptr; + auto accessible = FindSelf(); + auto cType = static_cast< CoordType >( coordType ); + LOG() << "GetNavigableAtPoint: " << x << ", " << y << " type: " << coordType; + auto component = CalculateNavigableAccessibleAtPoint( accessible, {x, y}, cType, GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH ); + bool recurse = false; + if( component ) + { + const auto states = component->GetStates(); + if( states[State::MODAL] ) + { + component = nullptr; + } + } + if( component ) + { + recurse = component->IsProxy(); + } + //TODO: add deputy + return {component, recurse, deputy}; +} + +static bool CheckChainEndWithAttribute( Accessible* obj, unsigned char forward ) +{ + if( !obj ) + return false; + auto attrs = obj->GetAttributes(); + for( auto& attr : attrs ) + { + if( attr.first == "relation_chain_end" ) + { + if( ( attr.second == "prev,end" && forward == 0 ) || ( attr.second == "next,end" && forward == 1 ) || attr.second == "prev,next,end" ) + { + return true; + } + } + } + return false; +} + +static Accessible* DeputyOfProxyInParentGet( Accessible* obj ) +{ + return nullptr; + // if (!obj) + // return nullptr; + // Accessible *deputy = nullptr; + // auto children = obj->GetChildren(); + // unsigned int index = 0; + // for (auto child : children) { + // if (child->IsProxy()) { + // if (index == 0) { + // //WRN("Proxy does not have deputy object"); + // break; + // } + // deputy = children[index - 1]; + // break; + // } + // index++; + // } + // return deputy; +} + +Accessible* BridgeAccessible::GetCurrentlyHighlighted() +{ + //TODO: add currently highlighted object + return nullptr; +} + +std::vector< Accessible* > BridgeAccessible::ValidChildrenGet( const std::vector< Accessible* >& children, Accessible* start, Accessible* root ) +{ + /* condition to find first(last) object regardless of scrollable parent. + looping navigation does not care scrollable parent. + 1. currently highlighted object exists + 2. both start and root are same */ + + /* TODO: add code, we need a scrollable implementation first + Accessible *current = GetCurrentlyHighlighted(); + if (current && start == root) return children; + if(children.size() == 0) return {}; + + Eo *child = children[0]; + + if (child) + { + Evas_Coord x = 0, y = 0, w = 0, h = 0; + Evas_Coord sx = 0, sy = 0, sw = 0, sh = 0; + + if (_new_scrollable_parent_viewport_geometry_get(child, start, + &sx, &sy, &sw, &sh)) + { + Eina_List *l, *l_next; + EINA_LIST_FOREACH_SAFE(children, l, l_next, child) + { + eo_do(child, + elm_interface_atspi_component_extents_get(EINA_FALSE, + &x, &y, &w, &h)); + if (w == 0 || h == 0 || + !ELM_RECTS_INTERSECT(x, y, w, h, sx, sy, sw, sh)) + children = eina_list_remove_list(children, l); + } + } + } + */ + return children; +} + +static bool DeputyIs( Accessible* obj ) +{ + //TODO: add deputy + return false; +} + +static Accessible* ProxyInParentGet( Accessible* obj ) +{ + if( !obj ) + return nullptr; + auto children = obj->GetChildren(); + for( auto& child : children ) + { + if( child->IsProxy() ) + return child; + } + return nullptr; +} + +static bool ObjectRoleIsAcceptableWhenNavigatingNextPrev( Accessible* obj ) +{ + if( !obj ) + return false; + auto role = obj->GetRole(); + return role != Role::POPUP_MENU && role != Role::DIALOG; +} + +template < class T > +struct CycleDetection +{ + CycleDetection( const T value ) : key( value ), currentSearchSize( 1 ), counter( 1 ) {} + bool check( const T value ) + { + if( key == value ) + return true; + if( --counter == 0 ) + { + currentSearchSize <<= 1; + if( currentSearchSize == 0 ) + return true; // UNDEFINED BEHAVIOR + counter = currentSearchSize; + key = value; + } + return false; + } + T key; + unsigned int currentSearchSize; + unsigned int counter; +}; + +static Accessible* FindNonDefunctChild( const std::vector< Accessible* >& children, unsigned int currentIndex, unsigned char forward ) +{ + unsigned int childrenCount = children.size(); + for( ; currentIndex < childrenCount; forward ? ++currentIndex : --currentIndex ) + { + Accessible* n = children[currentIndex]; + if( n && !n->GetStates()[State::DEFUNCT] ) + return n; + } + return nullptr; +} + +static Accessible* DirectionalDepthFirstSearchTryNonDefunctChild( Accessible* node, const std::vector< Accessible* >& children, unsigned char forward ) +{ + if( !node ) + return nullptr; + auto childrenCount = children.size(); + if( childrenCount > 0 ) + { + const bool isShowing = GetScrollableParent( node ) == nullptr ? node->GetStates()[State::SHOWING] : true; + if( isShowing ) + { + return FindNonDefunctChild( children, forward ? 0 : childrenCount - 1, forward ); + } + } + return nullptr; +} + +Accessible* BridgeAccessible::GetNextNonDefunctSibling( Accessible* obj, Accessible* start, Accessible* root, unsigned char forward ) +{ + if( !obj ) + return nullptr; + auto parent = obj->GetParent(); + if( !parent ) + return nullptr; + + auto children = ValidChildrenGet( parent->GetChildren(), start, root ); + + unsigned int children_count = children.size(); + if( children_count == 0 ) + { + return nullptr; + } + unsigned int current = 0; + for( ; current < children_count && children[current] != obj; ++current ) + ; + if( current >= children_count ) + { + return nullptr; + } + forward ? ++current : --current; + auto ret = FindNonDefunctChild( children, current, forward ); + return ret; +} + +Accessible* BridgeAccessible::DirectionalDepthFirstSearchTryNonDefunctSibling( bool& all_children_visited, Accessible* node, Accessible* start, Accessible* root, unsigned char forward ) +{ + while( true ) + { + Accessible* sibling = GetNextNonDefunctSibling( node, start, root, forward ); + if( sibling ) + { + node = sibling; + all_children_visited = false; + break; + } + // walk up... + node = node->GetParent(); + if( node == nullptr || node == root ) + return nullptr; + + // in backward traversing stop the walk up on parent + if( !forward ) + break; + } + return node; +} + +Accessible* BridgeAccessible::CalculateNeighbor( Accessible* root, Accessible* start, unsigned char forward, BridgeAccessible::GetNeighborSearchMode search_mode ) +{ + if( start && CheckChainEndWithAttribute( start, forward ) ) + return start; + if( root && root->GetStates()[State::DEFUNCT] ) + return NULL; + if( start && start->GetStates()[State::DEFUNCT] ) + { + start = NULL; + forward = 1; + } + + if( search_mode == BridgeAccessible::GetNeighborSearchMode::recurseToOutside ) + { + /* This only works if we navigate backward, and it is not possible to + find in embedded process. In this case the deputy should be used */ + return DeputyOfProxyInParentGet( start ); + } + + Accessible* node = start ? start : root; + if( !node ) + return nullptr; + + // initialization of all-children-visited flag for start node - we assume + // that when we begin at start node and we navigate backward, then all children + // are visited, so navigation will ignore start's children and go to + // previous sibling available. + /* Regarding condtion (start != root): + The last object can be found only if all_children_visited is false. + The start is same with root, when looking for the last object. */ + bool all_children_visited = ( start != root ) && ( search_mode != BridgeAccessible::GetNeighborSearchMode::recurseFromRoot && !forward ); + // true, if starting element should be ignored. this is only used in rare case of + // recursive search failing to find an object. + // consider tree, where element A on bus BUS_A has child B on bus BUS_B. when going "next" from + // element A algorithm has to descend into BUS_B and search element B and its children. this is done + // by returning to our caller object B with special flag set (meaning - continue the search from B on bus BUS_B). + // if next object will be found there (on BUS_B), then search ends. but if not, then our caller will find it out + // and will call us again with object A and flag search_mode set to NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING. + // this flag means, that object A was already checked previously and we should skip it and its children. + bool force_next = ( search_mode == BridgeAccessible::GetNeighborSearchMode::continueAfterFailedRecursion ); + + CycleDetection< Accessible* > cycleDetection( node ); + while( node ) + { + if( node->GetStates()[State::DEFUNCT] ) + return nullptr; + + // always accept proxy object from different world + if( !force_next && node->IsProxy() ) + return node; + + auto children = node->GetChildren(); + children = ValidChildrenGet( children, start, root ); + + // do accept: + // 1. not start node + // 2. parent after all children in backward traversing + // 3. Nodes with roles: ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_POPUP_MENU and ATSPI_ROLE_DIALOG, only when looking for first or last element. + // Objects with those roles shouldnt be reachable, when navigating next / prev. + bool all_children_visited_or_moving_forward = ( children.size() == 0 || forward || all_children_visited ); + if( !force_next && node != start && all_children_visited_or_moving_forward && AcceptObject( node ) ) + { + if( start == NULL || ObjectRoleIsAcceptableWhenNavigatingNextPrev( node ) ) + return node; + } + + Accessible* next_related_in_direction = !force_next ? GetObjectInRelation( node, forward ? RelationType::FLOWS_TO : RelationType::FLOWS_FROM ) : nullptr; + /* force_next means that the search_mode is NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING + in this case the node is elm_layout which is parent of proxy object. + There is an access object working for the proxy object, and the access + object could have relation information. This relation information should + be checked first before using the elm_layout as a node. */ + if( force_next && forward ) + { + auto deputy = DeputyOfProxyInParentGet( node ); + next_related_in_direction = + GetObjectInRelation( deputy, forward ? RelationType::FLOWS_TO : RelationType::FLOWS_FROM ); + } + + if( next_related_in_direction && start->GetStates()[State::DEFUNCT] ) + next_related_in_direction = NULL; + unsigned char want_cycle_detection = 0; + if( next_related_in_direction ) + { + /* Check next_related_in_direction is deputy object */ + Accessible* parent; + if( !forward ) + { + /* If the prev object is deputy, then go to inside of its proxy first */ + if( DeputyIs( next_related_in_direction ) ) + { + parent = next_related_in_direction->GetParent(); + next_related_in_direction = ProxyInParentGet( parent ); + } + } + else + { + /* If current object is deputy, and it has relation next object, + then do not use the relation next object, and use proxy first */ + if( DeputyIs( node ) ) + { + parent = node->GetParent(); + next_related_in_direction = ProxyInParentGet( parent ); + } + } + node = next_related_in_direction; + want_cycle_detection = 1; + } + else + { + auto child = !force_next && !all_children_visited ? DirectionalDepthFirstSearchTryNonDefunctChild( node, children, forward ) : nullptr; + if( child ) + { + want_cycle_detection = 1; + } + else + { + if( !force_next && node == root ) + return NULL; + all_children_visited = true; + child = DirectionalDepthFirstSearchTryNonDefunctSibling( all_children_visited, node, start, root, forward ); + } + node = child; + } + force_next = 0; + if( want_cycle_detection && cycleDetection.check( node ) ) + { + return NULL; + } + } + return NULL; +} + +DBus::ValueOrError< Accessible*, uint8_t > BridgeAccessible::GetNeighbor( std::string rootPath, int32_t direction, int32_t search_mode ) +{ + auto start = FindSelf(); + rootPath = StripPrefix( rootPath ); + auto root = !rootPath.empty() ? Find( rootPath ) : nullptr; + auto accessible = CalculateNeighbor( root, start, direction == 1, static_cast< GetNeighborSearchMode >( search_mode ) ); + unsigned char recurse = 0; + if( accessible ) + { + recurse = accessible->IsProxy(); + } + return {accessible, recurse}; +} + +Accessible* BridgeAccessible::GetParent() +{ + // NOTE: currently bridge supports single application root element. + // only element set as application root might return nullptr from GetParent + // if you want more, then you need to change setApplicationRoot to + // add/remove ApplicationRoot and make roots a vector. + auto p = FindSelf()->GetParent(); + assert( p ); + return p; +} +DBus::ValueOrError< std::vector< Accessible* > > BridgeAccessible::GetChildren() +{ + return FindSelf()->GetChildren(); +} +std::string BridgeAccessible::GetDescription() +{ + return FindSelf()->GetDescription(); +} +DBus::ValueOrError< uint32_t > BridgeAccessible::GetRole() +{ + return static_cast< unsigned int >( FindSelf()->GetRole() ); +} +DBus::ValueOrError< std::string > BridgeAccessible::GetRoleName() +{ + return FindSelf()->GetRoleName(); +} +DBus::ValueOrError< std::string > BridgeAccessible::GetLocalizedRoleName() +{ + return FindSelf()->GetLocalizedRoleName(); +} +DBus::ValueOrError< int32_t > BridgeAccessible::GetIndexInParent() +{ + return FindSelf()->GetIndexInParent(); +} +DBus::ValueOrError< std::array< uint32_t, 2 > > BridgeAccessible::GetStates() +{ + return FindSelf()->GetStates().GetRawData(); +} +DBus::ValueOrError< std::unordered_map< std::string, std::string > > BridgeAccessible::GetAttributes() +{ + return FindSelf()->GetAttributes(); +} +DBus::ValueOrError< std::vector< std::string > > BridgeAccessible::GetInterfaces() +{ + return FindSelf()->GetInterfaces(); +} +int BridgeAccessible::GetChildCount() +{ + return FindSelf()->GetChildCount(); +} +DBus::ValueOrError< Accessible* > BridgeAccessible::GetChildAtIndex( int index ) +{ + if( index < 0 ) + throw std::domain_error{"negative index (" + std::to_string( index ) + ")"}; + return FindSelf()->GetChildAtIndex( static_cast< size_t >( index ) ); +} + +std::string BridgeAccessible::GetName() +{ + return FindSelf()->GetName(); +} + +DBus::ValueOrError< Accessible*, uint32_t , std::unordered_map< std::string, std::string > > BridgeAccessible::GetDefaultLabelInfo() +{ + auto defaultLabel = FindSelf()->GetDefaultLabel(); + return {defaultLabel, static_cast< uint32_t >( defaultLabel->GetRole() ) , defaultLabel->GetAttributes()}; +} + +DBus::ValueOrError> BridgeAccessible::GetRelationSet() +{ + auto relations = FindSelf()->GetRelationSet(); + std::vector< BridgeAccessible::Relation > ret; + + for (auto &it : relations) + ret.emplace_back(Relation{static_cast(it.relationType), it.targets}); + + return ret; +} diff --git a/dali/internal/accessibility/bridge/bridge-accessible.h b/dali/internal/accessibility/bridge/bridge-accessible.h new file mode 100644 index 0000000..9abdd36 --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-accessible.h @@ -0,0 +1,105 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACCESSIBLE_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACCESSIBLE_H + +/* + * Copyright (c) 2019 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 +#include +#include +#include + +// INTERNAL INCLUDES +#include "bridge-base.h" + +class BridgeAccessible : public virtual BridgeBase +{ +protected: + BridgeAccessible(); + + void RegisterInterfaces(); + +public: + enum class GetNeighborSearchMode + { + normal = 0, + recurseFromRoot = 1, + continueAfterFailedRecursion = 2, + recurseToOutside = 3, + }; + int GetChildCount(); + DBus::ValueOrError< Dali::Accessibility::Accessible* > GetChildAtIndex( int index ); + Dali::Accessibility::Accessible* GetParent(); + DBus::ValueOrError< std::vector< Dali::Accessibility::Accessible* > > GetChildren(); + std::string GetName(); + std::string GetDescription(); + DBus::ValueOrError< uint32_t > GetRole(); + DBus::ValueOrError< std::string > GetRoleName(); + DBus::ValueOrError< std::string > GetLocalizedRoleName(); + DBus::ValueOrError< int32_t > GetIndexInParent(); + DBus::ValueOrError< std::array< uint32_t, 2 > > GetStates(); + DBus::ValueOrError< std::unordered_map< std::string, std::string > > GetAttributes(); + DBus::ValueOrError< std::vector< std::string > > GetInterfaces(); + DBus::ValueOrError< Dali::Accessibility::Accessible*, uint8_t, Dali::Accessibility::Accessible* > GetNavigableAtPoint( int32_t x, int32_t y, uint32_t coordType ); + DBus::ValueOrError< Dali::Accessibility::Accessible*, uint8_t > GetNeighbor( std::string root_path, int32_t direction, int32_t search_mode ); + DBus::ValueOrError< Dali::Accessibility::Accessible*, uint32_t , std::unordered_map< std::string, std::string > > GetDefaultLabelInfo(); + using ReadingMaterialType = DBus::ValueOrError< + std::unordered_map< std::string, std::string >, // attributes + std::string, // name + std::string, // labeledByName + std::string, // textIfceName + uint32_t, + Dali::Accessibility::States, + std::string, // localized name + int32_t, // child count + double, // current value + double, // minimum increment + double, // maximum value + double, // minimum value + std::string, // description + int32_t, // index in parent + bool, // isSelectedInParent + bool, // hasCheckBoxChild + int32_t, // listChildrenCount + int32_t, // firstSelectedChildIndex + Dali::Accessibility::Accessible*, // parent + Dali::Accessibility::States, // parentStateSet + int32_t, // parentChildCount + uint32_t, // parentRole + int32_t, // selectedChildCount, + Dali::Accessibility::Accessible* // describedByObject + >; + + ReadingMaterialType GetReadingMaterial(); + + DBus::ValueOrError< bool > DoGesture( Dali::Accessibility::Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime ); + + using Relation = std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > >; + DBus::ValueOrError> GetRelationSet(); + +private: + Dali::Accessibility::Accessible* CalculateNeighbor( Dali::Accessibility::Accessible* root, Dali::Accessibility::Accessible* start, unsigned char forward, GetNeighborSearchMode search_mode ); + std::vector< Dali::Accessibility::Accessible* > ValidChildrenGet( const std::vector< Dali::Accessibility::Accessible* >& children, Dali::Accessibility::Accessible* start, Dali::Accessibility::Accessible* root ); + Dali::Accessibility::Accessible* GetCurrentlyHighlighted(); + Dali::Accessibility::Accessible* DirectionalDepthFirstSearchTryNonDefunctSibling( bool& all_children_visited, Dali::Accessibility::Accessible* node, Dali::Accessibility::Accessible* start, Dali::Accessibility::Accessible* root, unsigned char forward ); + Dali::Accessibility::Accessible* GetNextNonDefunctSibling( Dali::Accessibility::Accessible* obj, Dali::Accessibility::Accessible* start, Dali::Accessibility::Accessible* root, unsigned char forward ); + Dali::Accessibility::Component* CalculateNavigableAccessibleAtPoint( Dali::Accessibility::Accessible* root, Dali::Accessibility::Point p, Dali::Accessibility::CoordType cType, unsigned int maxRecursionDepth ); + Dali::Accessibility::Component * GetObjectInRelation(Dali::Accessibility::Accessible * obj, Dali::Accessibility::RelationType ralationType); +}; + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACCESSIBLE_H diff --git a/dali/internal/accessibility/bridge/bridge-action.cpp b/dali/internal/accessibility/bridge/bridge-action.cpp new file mode 100644 index 0000000..47c5eae --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-action.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019 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 + +// EXTERNAL INCLUDES +#include + +using namespace Dali::Accessibility; + +void BridgeAction::RegisterInterfaces() +{ + DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceAction}; + + AddGetPropertyToInterface( desc, "NActions", &BridgeAction::GetActionCount ); + + AddFunctionToInterface( desc, "GetName", &BridgeAction::GetActionName ); + AddFunctionToInterface( desc, "GetLocalizedName", &BridgeAction::GetLocalizedActionName ); + AddFunctionToInterface( desc, "GetDescription", &BridgeAction::GetActionDescription ); + AddFunctionToInterface( desc, "GetKeyBinding", &BridgeAction::GetActionKeyBinding ); + AddFunctionToInterface( desc, "DoAction", &BridgeAction::DoAction ); + AddFunctionToInterface( desc, "DoActionName", &BridgeAction::DoActionName ); + dbusServer.addInterface( "/", desc, true ); +} + +Action* BridgeAction::FindSelf() const +{ + auto s = BridgeBase::FindSelf(); + assert( s ); + auto s2 = dynamic_cast< Action* >( s ); + if( !s2 ) + throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Action interface"}; + return s2; +} + +DBus::ValueOrError< std::string > BridgeAction::GetActionName( int32_t index ) +{ + return FindSelf()->GetActionName( index ); +} + +DBus::ValueOrError< std::string > BridgeAction::GetLocalizedActionName( int32_t index ) +{ + return FindSelf()->GetLocalizedActionName( index ); +} + +DBus::ValueOrError< std::string > BridgeAction::GetActionDescription( int32_t index ) +{ + return FindSelf()->GetActionDescription( index ); +} + +DBus::ValueOrError< std::string > BridgeAction::GetActionKeyBinding( int32_t index ) +{ + return FindSelf()->GetActionKeyBinding( index ); +} + +DBus::ValueOrError< int32_t > BridgeAction::GetActionCount() +{ + return FindSelf()->GetActionCount(); + ; +} + +DBus::ValueOrError< bool > BridgeAction::DoAction( int32_t index ) +{ + return FindSelf()->DoAction( index ); +} + +DBus::ValueOrError< bool > BridgeAction::DoActionName( std::string name ) +{ + auto self = FindSelf(); + auto cnt = self->GetActionCount(); + for( auto i = 0u; i < cnt; ++i ) + { + if( self->GetActionName( i ) == name ) + { + return self->DoAction( i ); + } + } + throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have action '" + name + "'"}; +} diff --git a/dali/internal/accessibility/bridge/bridge-action.h b/dali/internal/accessibility/bridge/bridge-action.h new file mode 100644 index 0000000..a47eb82 --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-action.h @@ -0,0 +1,47 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACTION_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACTION_H + +/* + * Copyright (c) 2019 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 +#include + +// INTERNAL INCLUDES +#include + +class BridgeAction : public virtual BridgeBase +{ +protected: + BridgeAction() = default; + + void RegisterInterfaces(); + + Dali::Accessibility::Action* FindSelf() const; + +public: + DBus::ValueOrError< std::string > GetActionName( int32_t index ); + DBus::ValueOrError< std::string > GetLocalizedActionName( int32_t index ); + DBus::ValueOrError< std::string > GetActionDescription( int32_t index ); + DBus::ValueOrError< std::string > GetActionKeyBinding( int32_t index ); + DBus::ValueOrError< int32_t > GetActionCount(); + DBus::ValueOrError< bool > DoAction( int32_t index ); + DBus::ValueOrError< bool > DoActionName( std::string name ); +}; + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACTION_H diff --git a/dali/internal/accessibility/bridge/bridge-base.cpp b/dali/internal/accessibility/bridge/bridge-base.cpp new file mode 100644 index 0000000..1662b98 --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-base.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2019 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 + +// EXTERNAL INCLUDES +#include +#include +#include + +// INTERNAL INCLUDES +#include + +using namespace Dali::Accessibility; + +static Dali::Timer tickTimer; + +BridgeBase::~BridgeBase() +{ +} + +BridgeBase::BridgeBase() +{ +} + +void BridgeBase::addFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function functor) +{ + if (delay < 0) + delay = 0; + auto it = filteredEvents.insert({ { kind, obj }, { static_cast(delay * 10), {} } }); + if (it.second) + functor(); + else + it.first->second.second = std::move(functor); + if (!tickTimer) { + tickTimer = Dali::Timer::New(100); + tickTimer.TickSignal().Connect(this, &BridgeBase::tickFilteredEvents); + } +} + +bool BridgeBase::tickFilteredEvents() +{ + for(auto it = filteredEvents.begin(); it != filteredEvents.end(); ) { + if (it->second.first) { + --it->second.first; + } + else { + if (it->second.second) { + it->second.second(); + it->second.second = {}; + } + else { + it = filteredEvents.erase(it); + continue; + } + } + ++it; + } + return !filteredEvents.empty(); +} + +BridgeBase::ForceUpResult BridgeBase::ForceUp() +{ + if( Bridge::ForceUp() == ForceUpResult::ALREADY_UP ) + return ForceUpResult::ALREADY_UP; + auto proxy = DBus::DBusClient{dbusLocators::atspi::BUS, dbusLocators::atspi::OBJ_PATH, + dbusLocators::atspi::BUS_INTERFACE, DBus::ConnectionType::SESSION}; + auto addr = proxy.method< std::string() >( dbusLocators::atspi::GET_ADDRESS ).call(); + + if( !addr ) + throw std::domain_error{std::string( "failed at call '" ) + dbusLocators::atspi::GET_ADDRESS + + "': " + addr.getError().message}; + + con = DBusWrapper::Installed()->eldbus_address_connection_get_impl( std::get< 0 >( addr ) ); + data->busName = DBus::getConnectionName( con ); + dbusServer = {con}; + + { + DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Cache"}; + AddFunctionToInterface( desc, "GetItems", &BridgeBase::GetItems ); + dbusServer.addInterface( "/org/a11y/atspi/cache", desc ); + } + { + DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Application"}; + AddGetSetPropertyToInterface( desc, "Id", &BridgeBase::IdGet, &BridgeBase::IdSet ); + dbusServer.addInterface( AtspiPath, desc ); + } + return ForceUpResult::JUST_STARTED; +} + +void BridgeBase::ForceDown() +{ + Bridge::ForceDown(); + dbusServer = {}; + con = {}; +} + +const std::string& BridgeBase::GetBusName() const +{ + static std::string empty; + return data ? data->busName : empty; +} + +Accessible* BridgeBase::FindByPath( const std::string& name ) const +{ + try + { + return Find( name ); + } + catch( std::domain_error ) + { + return nullptr; + } +} + +void BridgeBase::AddPopup( Accessible* obj ) +{ + if( std::find( popups.begin(), popups.end(), obj ) != popups.end() ) return; + popups.push_back( obj ); + if (IsUp()) + { + obj->Emit( WindowEvent::ACTIVATE, 0 ); + } +} + +void BridgeBase::RemovePopup( Accessible* obj ) +{ + auto it = std::find( popups.begin(), popups.end(), obj ); + if( it == popups.end() ) return; + popups.erase( it ); + if (IsUp()) + { + obj->Emit( WindowEvent::DEACTIVATE, 0 ); + if( popups.empty() ) + { + application.children.back()->Emit( WindowEvent::ACTIVATE, 0 ); + } + else + { + popups.back()->Emit( WindowEvent::ACTIVATE, 0 ); + } + } + +} + +void BridgeBase::AddTopLevelWindow( Accessible* root ) +{ + application.children.push_back( root ); + SetIsOnRootLevel( root ); +} + +void BridgeBase::RemoveTopLevelWindow( Accessible* root ) +{ + for(auto i = 0u; i < application.children.size(); ++i) { + if( application.children[i] == root ) + { + application.children.erase(application.children.begin() + i); + break; + } + } +} + +// Accessible *BridgeBase::getApplicationRoot() const +// { +// return rootElement; +// } + +std::string BridgeBase::StripPrefix( const std::string& path ) +{ + auto size = strlen( AtspiPath ); + return path.substr( size + 1 ); +} + +Accessible* BridgeBase::Find( const std::string& path ) const +{ + if( path == "root" ) + return &application; + void* p; + std::istringstream tmp{ path }; + if (! ( tmp >> p) ) + throw std::domain_error{"invalid path '" + path + "'"}; + auto it = data->knownObjects.find( static_cast( p ) ); + if( it == data->knownObjects.end() ) + throw std::domain_error{"unknown object '" + path + "'"}; + return static_cast( p ); +} + +Accessible* BridgeBase::Find( const Address& ptr ) const +{ + assert( ptr.GetBus() == data->busName ); + return Find( ptr.GetPath() ); +} + +Accessible* BridgeBase::FindSelf() const +{ + auto pth = DBus::DBusServer::getCurrentObjectPath(); + auto size = strlen( AtspiPath ); + if( pth.size() <= size ) + throw std::domain_error{"invalid path '" + pth + "'"}; + if( pth.substr( 0, size ) != AtspiPath ) + throw std::domain_error{"invalid path '" + pth + "'"}; + if( pth[size] != '/' ) + throw std::domain_error{"invalid path '" + pth + "'"}; + return Find( StripPrefix( pth ) ); +} + +void BridgeBase::IdSet( int id ) +{ + this->id = id; +} +int BridgeBase::IdGet() +{ + return this->id; +} + +auto BridgeBase::GetItems() -> DBus::ValueOrError< std::vector< CacheElementType > > +{ + auto root = &application; + + std::vector< CacheElementType > res; + + std::function< void(Accessible*) > proc = [&]( Accessible* item ) { + res.emplace_back( std::move( CreateCacheElement( root ) ) ); + + for( auto i = 0u; i < item->GetChildCount(); ++i ) + { + proc( item->GetChildAtIndex( i ) ); + } + }; + + return res; +} + +auto BridgeBase::CreateCacheElement( Accessible* item ) -> CacheElementType +{ + if( !item ) + return {}; + + auto root = &application; + auto parent = item->GetParent(); + + std::vector< Address > children; + for( auto i = 0u; i < item->GetChildCount(); ++i ) + { + children.emplace_back( item->GetChildAtIndex( i )->GetAddress() ); + } + + return std::make_tuple( + item->GetAddress(), + root->GetAddress(), + parent ? parent->GetAddress() : Address{}, + children, + item->GetInterfaces(), + item->GetName(), + item->GetRole(), + item->GetDescription(), + item->GetStates().GetRawData() ); +} diff --git a/dali/internal/accessibility/bridge/bridge-base.h b/dali/internal/accessibility/bridge/bridge-base.h new file mode 100644 index 0000000..7c413db --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-base.h @@ -0,0 +1,274 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H + +/* + * Copyright (c) 2019 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 +#include + +// INTERNAL INCLUDES +#include + +class AppAccessible : public virtual Dali::Accessibility::Accessible, public virtual Dali::Accessibility::Collection +{ +public: + Dali::Accessibility::EmptyAccessibleWithAddress parent; + std::vector< Dali::Accessibility::Accessible* > children; + std::string name; + + std::string GetName() override + { + return name; + } + std::string GetDescription() override + { + return ""; + } + Dali::Accessibility::Accessible* GetParent() override + { + return &parent; + } + size_t GetChildCount() override + { + return children.size(); + } + Dali::Accessibility::Accessible* GetChildAtIndex( size_t index ) override + { + auto s = children.size(); + if( index >= s ) + throw std::domain_error{"invalid index " + std::to_string( index ) + " for object with " + std::to_string( s ) + " children"}; + return children[index]; + } + size_t GetIndexInParent() override + { + throw std::domain_error{"can't call GetIndexInParent on application object"}; + } + Dali::Accessibility::Role GetRole() override + { + return Dali::Accessibility::Role::APPLICATION; + } + Dali::Accessibility::States GetStates() override + { + return {}; + } + Dali::Accessibility::Attributes GetAttributes() override + { + return {}; + } + Dali::Accessibility::Accessible* getActiveWindow() + { + return children.empty() ? nullptr : children[0]; + } + bool DoGesture(const Dali::Accessibility::GestureInfo &gestureInfo) override + { + return false; + } + std::vector GetRelationSet() override + { + return {}; + } + Dali::Accessibility::Address GetAddress() override { + return { "", "root" }; + } +}; + +enum class FilteredEvents { + boundsChanged +}; + +namespace std { + template <> struct hash> { + size_t operator () (std::pair v) const { + return (static_cast(v.first) * 131) ^ reinterpret_cast(v.second); + } + }; +} + +class BridgeBase : public Dali::Accessibility::Bridge, public Dali::ConnectionTracker +{ + std::unordered_map, std::pair>> filteredEvents; + + bool tickFilteredEvents(); +public: + + void addFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function functor); + + const std::string& GetBusName() const override; + void AddTopLevelWindow( Dali::Accessibility::Accessible* window ) override; + void RemoveTopLevelWindow( Dali::Accessibility::Accessible* window ) override; + void AddPopup( Dali::Accessibility::Accessible* ) override; + void RemovePopup( Dali::Accessibility::Accessible* ) override; + + Dali::Accessibility::Accessible* GetApplication() const override + { + return &application; + } + + template < typename SELF, typename... RET, typename... ARGS > + void AddFunctionToInterface( + DBus::DBusInterfaceDescription& desc, const std::string& funcName, + DBus::ValueOrError< RET... > ( SELF::*funcPtr )( ARGS... ) ) + { + if ( auto self = dynamic_cast< SELF* >( this ) ) + desc.addMethod< DBus::ValueOrError< RET... >( ARGS... ) >( funcName, + [=]( ARGS... args ) -> DBus::ValueOrError< RET... > { + try + { + return ( self->*funcPtr )( std::move( args )... ); + } + catch( std::domain_error& e ) + { + return DBus::Error{e.what()}; + } + } ); + } + template < typename T, typename SELF > + void AddGetPropertyToInterface( DBus::DBusInterfaceDescription& desc, + const std::string& funcName, T ( SELF::*funcPtr )() ) + { + if ( auto self = dynamic_cast< SELF* >( this ) ) + desc.addProperty< T >( funcName, + [=]() -> DBus::ValueOrError< T > { + try + { + return ( self->*funcPtr )(); + } + catch( std::domain_error& e ) + { + return DBus::Error{e.what()}; + } + }, + {} ); + } + template < typename T, typename SELF > + void AddSetPropertyToInterface( DBus::DBusInterfaceDescription& desc, + const std::string& funcName, void ( SELF::*funcPtr )( T ) ) + { + if ( auto self = dynamic_cast< SELF* >( this ) ) + desc.addProperty< T >( funcName, {}, + [=]( T t ) -> DBus::ValueOrError< void > { + try + { + ( self->*funcPtr )( std::move( t ) ); + return {}; + } + catch( std::domain_error& e ) + { + return DBus::Error{e.what()}; + } + } ); + } + template < typename T, typename T1, typename SELF > + void AddGetSetPropertyToInterface( DBus::DBusInterfaceDescription& desc, + const std::string& funcName, T1 ( SELF::*funcPtrGet )(), DBus::ValueOrError< void > ( SELF::*funcPtrSet )( T ) ) + { + if ( auto self = dynamic_cast< SELF* >( this ) ) + desc.addProperty< T >( funcName, + [=]() -> DBus::ValueOrError< T > { + try + { + return ( self->*funcPtrGet )(); + } + catch( std::domain_error& e ) + { + return DBus::Error{e.what()}; + } + }, + [=]( T t ) -> DBus::ValueOrError< void > { + try + { + ( self->*funcPtrSet )( std::move( t ) ); + return {}; + } + catch( std::domain_error& e ) + { + return DBus::Error{e.what()}; + } + } ); + } + template < typename T, typename T1, typename SELF > + void AddGetSetPropertyToInterface( DBus::DBusInterfaceDescription& desc, + const std::string& funcName, T1 ( SELF::*funcPtrGet )(), void ( SELF::*funcPtrSet )( T ) ) + { + if ( auto self = dynamic_cast< SELF* >( this ) ) + desc.addProperty< T >( funcName, + [=]() -> DBus::ValueOrError< T > { + try + { + return ( self->*funcPtrGet )(); + } + catch( std::domain_error& e ) + { + return DBus::Error{e.what()}; + } + }, + [=]( T t ) -> DBus::ValueOrError< void > { + try + { + ( self->*funcPtrSet )( std::move( t ) ); + return {}; + } + catch( std::domain_error& e ) + { + return DBus::Error{e.what()}; + } + } ); + } + static std::string StripPrefix( const std::string& path ); + + Dali::Accessibility::Accessible* Find( const std::string& path ) const; + Dali::Accessibility::Accessible* Find( const Dali::Accessibility::Address& ptr ) const; + Dali::Accessibility::Accessible* FindSelf() const; + Dali::Accessibility::Accessible* FindByPath( const std::string& name ) const override; + void SetApplicationName( std::string name ) override + { + application.name = std::move( name ); + } + +protected: + mutable AppAccessible application; + std::vector popups; +private: + void IdSet( int id ); + int IdGet(); + + using CacheElementType = std::tuple< + Dali::Accessibility::Address, Dali::Accessibility::Address, Dali::Accessibility::Address, + std::vector< Dali::Accessibility::Address >, + std::vector< std::string >, + std::string, + Dali::Accessibility::Role, + std::string, + std::array< uint32_t, 2 > >; + DBus::ValueOrError< std::vector< CacheElementType > > GetItems(); + CacheElementType CreateCacheElement( Dali::Accessibility::Accessible* item ); + +protected: + BridgeBase(); + virtual ~BridgeBase(); + + ForceUpResult ForceUp() override; + void ForceDown() override; + + DBus::DBusServer dbusServer; + DBusWrapper::ConnectionPtr con; + int id = 0; +}; + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H diff --git a/dali/internal/accessibility/bridge/bridge-collection.cpp b/dali/internal/accessibility/bridge/bridge-collection.cpp new file mode 100644 index 0000000..8c590ef --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-collection.cpp @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2019 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 + +// EXTERNAL INCLUDES +#include +#include +#include +#include + +using namespace Dali::Accessibility; + +void BridgeCollection::RegisterInterfaces() +{ + DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceCollection}; + AddFunctionToInterface( desc, "GetMatches", &BridgeCollection::GetMatches ); + dbusServer.addInterface( "/", desc, true ); +} + +Collection* BridgeCollection::FindSelf() const +{ + auto s = BridgeBase::FindSelf(); + assert( s ); + auto s2 = dynamic_cast< Collection* >( s ); + if( !s2 ) + throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Collection interface"}; + return s2; +} + +enum +{ + ATSPI_Collection_MATCH_INVALID, + ATSPI_Collection_MATCH_ALL, + ATSPI_Collection_MATCH_ANY, + ATSPI_Collection_MATCH_NONE, + ATSPI_Collection_MATCH_EMPTY, + ATSPI_Collection_MATCH_LAST_DEFINED, +}; + +struct BridgeCollection::Comparer +{ + using Mode = MatchType; + + enum class CompareFuncExit + { + FIRST_FOUND, + FIRST_NOT_FOUND + }; + + static Mode ConvertToMatchType( int32_t mode ) + { + switch( mode ) + { + case ATSPI_Collection_MATCH_INVALID: + { + return Mode::INVALID; + } + case ATSPI_Collection_MATCH_ALL: + { + return Mode::ALL; + } + case ATSPI_Collection_MATCH_ANY: + { + return Mode::ANY; + } + case ATSPI_Collection_MATCH_NONE: + { + return Mode::NONE; + } + case ATSPI_Collection_MATCH_EMPTY: + { + return Mode::EMPTY; + } + } + return Mode::INVALID; + } + + struct ComparerInterfaces + { + std::unordered_set< std::string > object; + std::vector< std::string > requested; + Mode mode = Mode::INVALID; + + ComparerInterfaces( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::InterfacesMatchType >( *rule ) ) ) + { + requested = {std::get< Index::Interfaces >( *rule ).begin(), std::get< Index::Interfaces >( *rule ).end()}; + } + void Update( Accessible* obj ) + { + object.clear(); + for( auto& q : obj->GetInterfaces() ) + object.insert( std::move( q ) ); + } + bool RequestEmpty() const { return requested.empty(); } + bool ObjectEmpty() const { return object.empty(); } + bool Compare( CompareFuncExit exit ) + { + bool foundAny = false; + for( auto& iname : requested ) + { + bool found = ( object.find( iname ) != object.end() ); + if( found ) + foundAny = true; + if( found == ( exit == CompareFuncExit::FIRST_FOUND ) ) + return found; + } + return foundAny; + } + }; + struct ComparerAttributes + { + std::unordered_map< std::string, std::string > requested, object; + Mode mode = Mode::INVALID; + + ComparerAttributes( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::AttributesMatchType >( *rule ) ) ) + { + requested = std::get< Index::Attributes >( *rule ); + } + void Update( Accessible* obj ) + { + object = obj->GetAttributes(); + } + bool RequestEmpty() const { return requested.empty(); } + bool ObjectEmpty() const { return object.empty(); } + bool Compare( CompareFuncExit exit ) + { + bool foundAny = false; + for( auto& iname : requested ) + { + auto it = object.find( iname.first ); + bool found = it != object.end() && iname.second == it->second; + if( found ) + foundAny = true; + if( found == ( exit == CompareFuncExit::FIRST_FOUND ) ) + { + return found; + } + } + return foundAny; + } + }; + struct ComparerRoles + { + using Roles = BitSets< 4, Role >; + Roles requested, object; + Mode mode = Mode::INVALID; + + ComparerRoles( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::RolesMatchType >( *rule ) ) ) + { + requested = Roles{std::get< Index::Roles >( *rule )}; + } + void Update( Accessible* obj ) + { + object = {}; + object[obj->GetRole()] = true; + assert( object ); + } + bool RequestEmpty() const { return !requested; } + bool ObjectEmpty() const { return !object; } + bool Compare( CompareFuncExit exit ) + { + switch( mode ) + { + case Mode::INVALID: + { + return true; + } + case Mode::EMPTY: + case Mode::ALL: + { + return requested == ( object & requested ); + } + case Mode::ANY: + { + return bool( object & requested ); + } + case Mode::NONE: + { + return bool( object & requested ); + } + } + return false; + } + }; + struct ComparerStates + { + States requested, object; + Mode mode = Mode::INVALID; + + ComparerStates( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::StatesMatchType >( *rule ) ) ) + { + requested = States{std::get< Index::States >( *rule )}; + } + void Update( Accessible* obj ) + { + object = obj->GetStates(); + } + bool RequestEmpty() const { return !requested; } + bool ObjectEmpty() const { return !object; } + bool Compare( CompareFuncExit exit ) + { + switch( mode ) + { + case Mode::INVALID: + { + return true; + } + case Mode::EMPTY: + case Mode::ALL: + { + return requested == ( object & requested ); + } + case Mode::ANY: + { + return bool( object & requested ); + } + case Mode::NONE: + { + return bool( object & requested ); + } + } + return false; + } + }; + + template < typename T > + bool compareFunc( T& cmp, Accessible* obj ) + { + if( cmp.mode == Mode::INVALID ) + return true; + cmp.Update( obj ); + switch( cmp.mode ) + { + case Mode::ANY: + { + if( cmp.RequestEmpty() || cmp.ObjectEmpty() ) + return false; + break; + } + case Mode::ALL: + { + if( cmp.RequestEmpty() ) + return true; + if( cmp.ObjectEmpty() ) + return false; + break; + } + case Mode::NONE: + { + if( cmp.RequestEmpty() || cmp.ObjectEmpty() ) + return true; + break; + } + case Mode::EMPTY: + { + if( cmp.RequestEmpty() && cmp.ObjectEmpty() ) + return true; + if( cmp.RequestEmpty() || cmp.ObjectEmpty() ) + return false; + break; + } + case Mode::INVALID: + { + return true; + } + } + + switch( cmp.mode ) + { + case Mode::EMPTY: + case Mode::ALL: + { + if( !cmp.Compare( CompareFuncExit::FIRST_NOT_FOUND ) ) + return false; + break; + } + case Mode::ANY: + { + if( cmp.Compare( CompareFuncExit::FIRST_FOUND ) ) + return true; + break; + } + case Mode::NONE: + { + if( cmp.Compare( CompareFuncExit::FIRST_FOUND ) ) + return false; + break; + } + case Mode::INVALID: + { + return true; + } + } + switch( cmp.mode ) + { + case Mode::EMPTY: + case Mode::ALL: + case Mode::NONE: + { + return true; + } + case Mode::ANY: + { + return false; + } + case Mode::INVALID: + { + return true; + } + } + return false; + } + + ComparerInterfaces ci; + ComparerAttributes ca; + ComparerRoles cr; + ComparerStates cs; + + Comparer( MatchRule* mr ) : ci( mr ), ca( mr ), cr( mr ), cs( mr ) {} + + bool operator()( Accessible* obj ) + { + return compareFunc( ci, obj ) && + compareFunc( ca, obj ) && + compareFunc( cr, obj ) && + compareFunc( cs, obj ); + } +}; + +void BridgeCollection::VisitNodes( Accessible* obj, std::vector< Accessible* >& result, Comparer& cmp, size_t maxCount ) +{ + if( result.size() >= maxCount ) + return; + + if( cmp( obj ) ) + result.emplace_back( obj ); + + for( auto i = 0u; i < obj->GetChildCount(); ++i ) + VisitNodes( obj->GetChildAtIndex( i ), result, cmp, maxCount ); +} + +DBus::ValueOrError< std::vector< Accessible* > > BridgeCollection::GetMatches( MatchRule rule, uint32_t sortBy, int32_t count, bool traverse ) +{ + std::vector< Accessible* > res; + auto self = BridgeBase::FindSelf(); + auto matcher = Comparer{&rule}; + VisitNodes( self, res, matcher, count ); + + switch( static_cast< SortOrder >( sortBy ) ) + { + case SortOrder::CANONICAL: + { + break; + } + + case SortOrder::REVERSE_CANONICAL: + { + std::reverse( res.begin(), res.end() ); + break; + } + + default: + { + throw std::domain_error{"unsupported sorting order"}; + } + //TODO: other cases + } + + return res; +} diff --git a/dali/internal/accessibility/bridge/bridge-collection.h b/dali/internal/accessibility/bridge/bridge-collection.h new file mode 100644 index 0000000..c4a279d --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-collection.h @@ -0,0 +1,68 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COLLECTION_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COLLECTION_H + +/* + * Copyright (c) 2019 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 +#include +#include +#include + +// INTERNAL INCLUDES +#include + +class BridgeCollection : public virtual BridgeBase +{ +private: + struct Comparer; + static void VisitNodes( Dali::Accessibility::Accessible* obj, std::vector< Dali::Accessibility::Accessible* >& result, Comparer& cmp, size_t maxCount ); + +protected: + BridgeCollection() = default; + + void RegisterInterfaces(); + + Dali::Accessibility::Collection* FindSelf() const; + +public: + using MatchRule = std::tuple< + std::array< int32_t, 2 >, int32_t, + std::unordered_map< std::string, std::string >, int32_t, + std::array< int32_t, 4 >, int32_t, + std::vector< std::string >, int32_t, + bool >; + struct Index + { + enum + { + States, + StatesMatchType, + Attributes, + AttributesMatchType, + Roles, + RolesMatchType, + Interfaces, + InterfacesMatchType, + }; + }; + + DBus::ValueOrError< std::vector< Dali::Accessibility::Accessible* > > GetMatches( MatchRule rule, uint32_t sortBy, int32_t count, bool traverse ); +}; + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COLLECTION_H diff --git a/dali/internal/accessibility/bridge/bridge-component.cpp b/dali/internal/accessibility/bridge/bridge-component.cpp new file mode 100644 index 0000000..1e65ddc --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-component.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2019 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 + +// EXTERNAL INCLUDES +#include + +#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" + +using namespace Dali::Accessibility; + +BridgeComponent::BridgeComponent() +{ +} + +void BridgeComponent::RegisterInterfaces() +{ + DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceComponent}; + AddFunctionToInterface( desc, "Contains", &BridgeComponent::Contains ); + AddFunctionToInterface( desc, "GetAccessibleAtPoint", &BridgeComponent::GetAccessibleAtPoint ); + AddFunctionToInterface( desc, "GetExtents", &BridgeComponent::GetExtents ); + AddFunctionToInterface( desc, "GetPosition", &BridgeComponent::GetPosition ); + AddFunctionToInterface( desc, "GetSize", &BridgeComponent::GetSize ); + AddFunctionToInterface( desc, "GetLayer", &BridgeComponent::GetLayer ); + AddFunctionToInterface( desc, "GetAlpha", &BridgeComponent::GetAlpha ); + AddFunctionToInterface( desc, "GetMDIZOrder", &BridgeComponent::GetMdiZOrder ); + AddFunctionToInterface( desc, "GrabHighlight", &BridgeComponent::GrabHighlight ); + AddFunctionToInterface( desc, "GrabFocus", &BridgeComponent::GrabFocus ); + AddFunctionToInterface( desc, "ClearHighlight", &BridgeComponent::ClearHighlight ); + dbusServer.addInterface( "/", desc, true ); +} + +Component* BridgeComponent::FindSelf() const +{ + auto s = BridgeBase::FindSelf(); + assert( s ); + auto s2 = dynamic_cast< Component* >( s ); + if( !s2 ) + throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Component interface"}; + return s2; +} + +DBus::ValueOrError< bool > BridgeComponent::Contains( int32_t x, int32_t y, uint32_t coordType ) +{ + return FindSelf()->Contains( {x, y}, static_cast< CoordType >( coordType ) ); +} +DBus::ValueOrError< Accessible* > BridgeComponent::GetAccessibleAtPoint( int32_t x, int32_t y, uint32_t coordType ) +{ + return FindSelf()->GetAccessibleAtPoint( {x, y}, static_cast< CoordType >( coordType ) ); +} +DBus::ValueOrError< std::tuple< int32_t, int32_t, int32_t, int32_t > > BridgeComponent::GetExtents( uint32_t coordType ) +{ + auto p = FindSelf()->GetExtents( static_cast< CoordType >( coordType ) ); + return std::tuple< int32_t, int32_t, int32_t, int32_t >{p.x, p.y, p.width, p.height}; +} +DBus::ValueOrError< int32_t, int32_t > BridgeComponent::GetPosition( uint32_t coordType ) +{ + auto p = FindSelf()->GetExtents( static_cast< CoordType >( coordType ) ); + return { static_cast(p.x), static_cast(p.y) }; +} +DBus::ValueOrError< int32_t, int32_t > BridgeComponent::GetSize( uint32_t coordType ) +{ + auto p = FindSelf()->GetExtents( static_cast< CoordType >( coordType ) ); + return { static_cast(p.width), static_cast(p.height) }; +} +DBus::ValueOrError< ComponentLayer > BridgeComponent::GetLayer() +{ + return FindSelf()->GetLayer(); +} +DBus::ValueOrError< double > BridgeComponent::GetAlpha() +{ + return FindSelf()->GetAlpha(); +} +DBus::ValueOrError< bool > BridgeComponent::GrabFocus() +{ + return FindSelf()->GrabFocus(); +} +DBus::ValueOrError< bool > BridgeComponent::GrabHighlight() +{ + return FindSelf()->GrabHighlight(); +} +DBus::ValueOrError< bool > BridgeComponent::ClearHighlight() +{ + return FindSelf()->ClearHighlight(); +} +DBus::ValueOrError< int16_t > BridgeComponent::GetMdiZOrder() +{ + return FindSelf()->GetMdiZOrder(); +} diff --git a/dali/internal/accessibility/bridge/bridge-component.h b/dali/internal/accessibility/bridge/bridge-component.h new file mode 100644 index 0000000..dcc8f49 --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-component.h @@ -0,0 +1,54 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COMPONENT_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COMPONENT_H + +/* + * Copyright (c) 2019 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 +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include + +class BridgeComponent : public virtual BridgeBase +{ +protected: + BridgeComponent(); + + void RegisterInterfaces(); + + Dali::Accessibility::Component* FindSelf() const; + +public: + DBus::ValueOrError< bool > Contains( int32_t x, int32_t y, uint32_t coordType ); + DBus::ValueOrError< Dali::Accessibility::Accessible* > GetAccessibleAtPoint( int32_t x, int32_t y, uint32_t coordType ); + DBus::ValueOrError< std::tuple< int32_t, int32_t, int32_t, int32_t > > GetExtents( uint32_t coordType ); + DBus::ValueOrError< int32_t, int32_t > GetPosition( uint32_t coordType ); + DBus::ValueOrError< int32_t, int32_t > GetSize( uint32_t coordType ); + DBus::ValueOrError< Dali::Accessibility::ComponentLayer > GetLayer(); + DBus::ValueOrError< double > GetAlpha(); + DBus::ValueOrError< bool > GrabFocus(); + DBus::ValueOrError< bool > GrabHighlight(); + DBus::ValueOrError< bool > ClearHighlight(); + DBus::ValueOrError< int16_t > GetMdiZOrder(); +}; + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COMPONENT_H diff --git a/dali/internal/accessibility/bridge/bridge-editable-text.cpp b/dali/internal/accessibility/bridge/bridge-editable-text.cpp new file mode 100644 index 0000000..5f18775 --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-editable-text.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 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 + +// INTERNAL INCLUDES +#include +//#include + +using namespace Dali::Accessibility; + +void BridgeEditableText::RegisterInterfaces() +{ + DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceEditableText}; + AddFunctionToInterface( desc, "CopyText", &BridgeEditableText::CopyText ); + AddFunctionToInterface( desc, "CutText", &BridgeEditableText::CutText ); + AddFunctionToInterface( desc, "PasteText", &BridgeEditableText::PasteText ); + dbusServer.addInterface( "/", desc, true ); +} + +EditableText* BridgeEditableText::FindSelf() const +{ + auto s = BridgeBase::FindSelf(); + assert( s ); + auto s2 = dynamic_cast< EditableText* >( s ); + if( !s2 ) + throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Text interface"}; + return s2; +} + +DBus::ValueOrError< bool > BridgeEditableText::CopyText( int32_t startPos, int32_t endPos ) +{ + return FindSelf()->CopyText( startPos, endPos ); +} + +DBus::ValueOrError< bool > BridgeEditableText::CutText( int32_t startPos, int32_t endPos ) +{ + return FindSelf()->CutText( startPos, endPos ); +} + +DBus::ValueOrError< bool > BridgeEditableText::PasteText( int32_t pos ) +{ + // auto imfManager = Dali::Internal::Adaptor::ImfManager::Get(); + // imfManager.SetCursorPosition( pos ); + // auto clipboard = Dali::Internal::Adaptor::Clipboard::Get(); + // clipboard.RequestItem(); + // return true; + return false; +} diff --git a/dali/internal/accessibility/bridge/bridge-editable-text.h b/dali/internal/accessibility/bridge/bridge-editable-text.h new file mode 100644 index 0000000..e7d707b --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-editable-text.h @@ -0,0 +1,39 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_EDITABLE_TEXT_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_EDITABLE_TEXT_H + +/* + * Copyright (c) 2019 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. + * + */ + +// INTERNAL INCLUDES +#include + +class BridgeEditableText : public virtual BridgeBase +{ +protected: + BridgeEditableText() = default; + + void RegisterInterfaces(); + + Dali::Accessibility::EditableText* FindSelf() const; + +public: + DBus::ValueOrError< bool > CopyText( int32_t startPos, int32_t endPos ); + DBus::ValueOrError< bool > CutText( int32_t startPos, int32_t endPos ); + DBus::ValueOrError< bool > PasteText( int32_t pos ); +}; + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_EDITABLE_TEXT_H diff --git a/dali/internal/accessibility/bridge/bridge-impl.cpp b/dali/internal/accessibility/bridge/bridge-impl.cpp new file mode 100644 index 0000000..3f621c1 --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-impl.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2019 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 + +// EXTERNAL INCLUDES +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Dali::Accessibility; + +class BridgeImpl : public virtual BridgeBase, + public BridgeAccessible, + public BridgeObject, + public BridgeComponent, + public BridgeCollection, + public BridgeAction, + public BridgeValue, + public BridgeText, + public BridgeEditableText +{ + DBus::DBusClient listenOnAtspiEnabledSignalClient; + DBus::DBusClient registryClient, directReadingClient; + bool screenReaderEnabled = false, isEnabled = false, isShown = false; + std::unordered_map > directReadingCallbacks; + Dali::Actor highlightedActor; + std::function highlightClearAction; +public: + BridgeImpl() + { + listenOnAtspiEnabledSignalClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, + DBus::ConnectionType::SESSION}; + listenOnAtspiEnabledSignalClient.addPropertyChangedEvent< bool >( "ScreenReaderEnabled", [this]( bool res ) { + screenReaderEnabled = res; + if( screenReaderEnabled || isEnabled ) + ForceUp(); + else + ForceDown(); + } ); + listenOnAtspiEnabledSignalClient.addPropertyChangedEvent< bool >( "IsEnabled", [this]( bool res ) { + isEnabled = res; + if( screenReaderEnabled || isEnabled ) + ForceUp(); + else + ForceDown(); + } ); + } + + Consumed Emit( KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText ) override + { + if (!IsUp()) return Consumed::NO; + unsigned int evType = 0; + + switch( type ) + { + case KeyEventType::KEY_PRESSED: + evType = 0; + { + break; + } + case KeyEventType::KEY_RELEASED: + evType = 1; + { + break; + } + default: + { + return Consumed::NO; + } + } + auto m = registryClient.method< bool( std::tuple< uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool > ) >( "NotifyListenersSync" ); + auto result = m.call( std::tuple< uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool >{evType, 0, static_cast< int32_t >( keyCode ), 0, static_cast< int32_t >( timeStamp ), keyName, isText ? 1 : 0} ); + if( !result ) + { + LOG() << result.getError().message; + return Consumed::NO; + } + return std::get< 0 >( result ) ? Consumed::YES : Consumed::NO; + } + + void PauseResume( bool pause ) override + { + auto r = directReadingClient.method< DBus::ValueOrError< void >( bool ) > ( "PauseResume" ).call( pause ); + if (!r) { + LOG() << "Direct reading command failed (" << r.getError().message << ")"; + } + } + + void Say( const std::string& text, bool discardable, std::function< void(std::string) > callback ) override + { + auto commandId = directReadingClient.method< DBus::ValueOrError< std::string, bool, int32_t >( std::string, bool ) > ( "ReadCommand" ).call( text, discardable ); + if ( !commandId ) { + LOG() << "Direct reading command failed (" << commandId.getError().message << ")"; + } else if( callback ) { + directReadingCallbacks.emplace( std::get< 2 >( commandId ), callback); + } + } + + void ForceDown() override + { + if (data) { + if (data->currentlyHighlightedActor && data->highlightActor) { + data->currentlyHighlightedActor.Remove(data->highlightActor); + } + data->currentlyHighlightedActor = {}; + data->highlightActor = {}; + } + highlightedActor = {}; + highlightClearAction = {}; + BridgeAccessible::ForceDown(); + registryClient = {}; + directReadingClient = {}; + directReadingCallbacks.clear(); + } + void Terminate() override + { + if (data) { + data->currentlyHighlightedActor = {}; + data->highlightActor = {}; + } + ForceDown(); + listenOnAtspiEnabledSignalClient = {}; + dbusServer = {}; + con = {}; + } + + ForceUpResult ForceUp() override + { + if( BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP ) + return ForceUpResult::ALREADY_UP; + + BridgeObject::RegisterInterfaces(); + BridgeAccessible::RegisterInterfaces(); + BridgeComponent::RegisterInterfaces(); + BridgeCollection::RegisterInterfaces(); + BridgeAction::RegisterInterfaces(); + BridgeValue::RegisterInterfaces(); + BridgeText::RegisterInterfaces(); + BridgeEditableText::RegisterInterfaces(); + + RegisterOnBridge( &application ); + + registryClient = { AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, con }; + directReadingClient = DBus::DBusClient{ DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, con }; + directReadingClient.addSignal< void(int32_t, std::string) >( "ReadingStateChanged", [=]( int32_t id, std::string readingState ) { + auto it = directReadingCallbacks.find( id ); + if (it != directReadingCallbacks.end()) + { + it->second( readingState ); + directReadingCallbacks.erase( it ); + } + }); + auto proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, con}; + Address root{"", "root"}; + auto res = proxy.method< Address( Address ) >( "Embed" ).call( root ); + if (!res) + LOG() << "Call to Embed failed: " << res.getError().message; + assert( res ); + application.parent.SetAddress( std::move( std::get< 0 >( res ) ) ); + if (isShown) { + EmitActivate(); + } + return ForceUpResult::JUST_STARTED; + } + + void EmitActivate() + { + auto win = application.getActiveWindow(); + if (win) { + win->Emit( WindowEvent::ACTIVATE, 0 ); + } + } + void EmitDeactivate() + { + auto win = application.getActiveWindow(); + if (win) { + win->Emit( WindowEvent::DEACTIVATE, 0 ); + } + } + void ApplicationHidden() override + { + if ( isShown && IsUp() ) + EmitDeactivate(); + isShown = false; + } + void ApplicationShown() override + { + if ( !isShown && IsUp() ) + EmitActivate(); + isShown = true; + } + void Initialize() override + { + auto req = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION}; + auto p = req.property< bool >( "ScreenReaderEnabled" ).get(); + if( p ) + screenReaderEnabled = std::get< 0 >( p ); + p = req.property< bool >( "IsEnabled" ).get(); + if( p ) + isEnabled = std::get< 0 >( p ); + if( screenReaderEnabled || isEnabled ) + ForceUp(); + } +}; + +Bridge* Bridge::GetCurrentBridge() +{ + static BridgeImpl *bridge = new BridgeImpl; + return bridge; +} diff --git a/dali/internal/accessibility/bridge/bridge-object.cpp b/dali/internal/accessibility/bridge/bridge-object.cpp new file mode 100644 index 0000000..762329e --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-object.cpp @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2019 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 + +// EXTERNAL INCLUDES +#include +#include + +using namespace Dali::Accessibility; + +BridgeObject::BridgeObject() +{ +} + +void BridgeObject::RegisterInterfaces() +{ + // DBus::DBusInterfaceDescription desc{ AtspiDbusInterfaceEventObject }; + // stateChanged = addSignal, Accessible*>(desc, "StateChanged"); + // dbusServer.addInterface("/", desc, true); +} + +void BridgeObject::EmitActiveDescendantChanged( Accessible* obj, Accessible *child ) +{ + if (!IsUp()) return; + auto index = child->GetIndexInParent(); + + auto addr = obj->GetAddress(); + const auto prefixPath = "/org/a11y/atspi/accessible/"; + const auto nullPath = "/org/a11y/atspi/null"; + std::string p; + if( addr ) + p = prefixPath + addr.GetPath(); + else + p = nullPath; + dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< Address >, Address >( + p, + AtspiDbusInterfaceEventObject, + "ActiveDescendantChanged", + "", + index, + 0, + { child->GetAddress() }, + {"", "root"} ); +} + +void BridgeObject::Emit( Accessible* obj, Dali::Accessibility::ObjectPropertyChangeEvent ev ) +{ + if (!IsUp()) return; + const char* name = nullptr; + switch( ev ) + { + case ObjectPropertyChangeEvent::NAME: + { + name = "accessible-name"; + break; + } + case ObjectPropertyChangeEvent::DESCRIPTION: + { + name = "accessible-description"; + break; + } + case ObjectPropertyChangeEvent::VALUE: + { + name = "accessible-value"; + break; + } + case ObjectPropertyChangeEvent::PARENT: + { + name = "accessible-parent"; + break; + } + case ObjectPropertyChangeEvent::ROLE: + { + name = "accessible-role"; + break; + } + } + if( name ) + { + auto addr = obj->GetAddress(); + std::string p; + if( addr ) + p = ATSPI_PREFIX_PATH + addr.GetPath(); + else + p = ATSPI_NULL_PATH; + dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< int >, Address >( + p, + AtspiDbusInterfaceEventObject, + "PropertyChange", + name, + 0, + 0, + {0}, + {"", "root"} ); + } +} + +void BridgeObject::Emit( Accessible* obj, WindowEvent we, unsigned int detail1 ) +{ + if (!IsUp()) return; + const char* name = nullptr; + switch( we ) + { + case WindowEvent::PROPERTY_CHANGE: + { + name = "PropertyChange"; + break; + } + case WindowEvent::MINIMIZE: + { + name = "Minimize"; + break; + } + case WindowEvent::MAXIMIZE: + { + name = "Maximize"; + break; + } + case WindowEvent::RESTORE: + { + name = "Restore"; + break; + } + case WindowEvent::CLOSE: + { + name = "Close"; + break; + } + case WindowEvent::CREATE: + { + name = "Create"; + break; + } + case WindowEvent::REPARENT: + { + name = "Reparent"; + break; + } + case WindowEvent::DESKTOP_CREATE: + { + name = "DesktopCreate"; + break; + } + case WindowEvent::DESKTOP_DESTROY: + { + name = "DesktopDestroy"; + break; + } + case WindowEvent::DESTROY: + { + name = "Destroy"; + break; + } + case WindowEvent::ACTIVATE: + { + name = "Activate"; + break; + } + case WindowEvent::DEACTIVATE: + { + name = "Deactivate"; + break; + } + case WindowEvent::RAISE: + { + name = "Raise"; + break; + } + case WindowEvent::LOWER: + { + name = "Lower"; + break; + } + case WindowEvent::MOVE: + { + name = "Move"; + break; + } + case WindowEvent::RESIZE: + { + name = "Resize"; + break; + } + case WindowEvent::SHADE: + { + name = "Shade"; + break; + } + case WindowEvent::UU_SHADE: + { + name = "uUshade"; + break; + } + case WindowEvent::RESTYLE: + { + name = "Restyle"; + break; + } + } + if( name ) + { + auto addr = obj->GetAddress(); + std::string p; + if( addr ) + p = ATSPI_PREFIX_PATH + addr.GetPath(); + else + p = ATSPI_NULL_PATH; + dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< int >, Address >( + p, + AtspiDbusInterfaceEventWindow, + name, + "", + detail1, + 0, + {0}, + {"", "root"} ); + } +} + +void BridgeObject::EmitStateChanged( Accessible* obj, State state, int newValue1, int newValue2 ) +{ + if (!IsUp()) return; + const char* stateName = nullptr; + switch( state ) + { + case State::INVALID: + { + stateName = "invalid"; + break; + } + case State::ACTIVE: + { + stateName = "active"; + break; + } + case State::ARMED: + { + stateName = "armed"; + break; + } + case State::BUSY: + { + stateName = "busy"; + break; + } + case State::CHECKED: + { + stateName = "checked"; + break; + } + case State::COLLAPSED: + { + stateName = "collapsed"; + break; + } + case State::DEFUNCT: + { + stateName = "defunct"; + break; + } + case State::EDITABLE: + { + stateName = "editable"; + break; + } + case State::ENABLED: + { + stateName = "enabled"; + break; + } + case State::EXPANDABLE: + { + stateName = "expandable"; + break; + } + case State::EXPANDED: + { + stateName = "expanded"; + break; + } + case State::FOCUSABLE: + { + stateName = "focusable"; + break; + } + case State::FOCUSED: + { + stateName = "focused"; + break; + } + case State::HAS_TOOLTIP: + { + stateName = "has-tooltip"; + break; + } + case State::HORIZONTAL: + { + stateName = "horizontal"; + break; + } + case State::ICONIFIED: + { + stateName = "iconified"; + break; + } + case State::MODAL: + { + stateName = "modal"; + break; + } + case State::MULTI_LINE: + { + stateName = "multi-line"; + break; + } + case State::MULTI_SELECTABLE: + { + stateName = "multiselectable"; + break; + } + case State::OPAQUE: + { + stateName = "opaque"; + break; + } + case State::PRESSED: + { + stateName = "pressed"; + break; + } + case State::RESIZEABLE: + { + stateName = "resizable"; + break; + } + case State::SELECTABLE: + { + stateName = "selectable"; + break; + } + case State::SELECTED: + { + stateName = "selected"; + break; + } + case State::SENSITIVE: + { + stateName = "sensitive"; + break; + } + case State::SHOWING: + { + stateName = "showing"; + break; + } + case State::SINGLE_LINE: + { + stateName = "single-line"; + break; + } + case State::STALE: + { + stateName = "stale"; + break; + } + case State::TRANSIENT: + { + stateName = "transient"; + break; + } + case State::VERTICAL: + { + stateName = "vertical"; + break; + } + case State::VISIBLE: + { + stateName = "visible"; + break; + } + case State::MANAGES_DESCENDANTS: + { + stateName = "manages-descendants"; + break; + } + case State::INDETERMINATE: + { + stateName = "indeterminate"; + break; + } + case State::REQUIRED: + { + stateName = "required"; + break; + } + case State::TRUNCATED: + { + stateName = "truncated"; + break; + } + case State::ANIMATED: + { + stateName = "animated"; + break; + } + case State::INVALID_ENTRY: + { + stateName = "invalid-entry"; + break; + } + case State::SUPPORTS_AUTOCOMPLETION: + { + stateName = "supports-autocompletion"; + break; + } + case State::SELECTABLE_TEXT: + { + stateName = "selectable-text"; + break; + } + case State::IS_DEFAULT: + { + stateName = "is-default"; + break; + } + case State::VISITED: + { + stateName = "visited"; + break; + } + case State::CHECKABLE: + { + stateName = "checkable"; + break; + } + case State::HAS_POPUP: + { + stateName = "has-popup"; + break; + } + case State::READ_ONLY: + { + stateName = "read-only"; + break; + } + case State::HIGHLIGHTED: + { + stateName = "highlighted"; + break; + } + case State::HIGHLIGHTABLE: + { + stateName = "highlightable"; + break; + } + case State::_COUNT: + { + break; + } + } + if( stateName ) + { + auto addr = obj->GetAddress(); + std::string p; + if( addr ) + p = ATSPI_PREFIX_PATH + addr.GetPath(); + else + p = ATSPI_NULL_PATH; + dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< int >, Address >( + p, + AtspiDbusInterfaceEventObject, + "StateChanged", + stateName, + newValue1, + newValue2, + {0}, + {"", "root"} ); + } +} + +void BridgeObject::EmitBoundsChanged( Accessible* obj, Dali::Rect<> rect ) +{ + auto addr = obj->GetAddress(); + const auto prefixPath = "/org/a11y/atspi/accessible/"; + const auto nullPath = "/org/a11y/atspi/null"; + std::string p; + if( addr ) + p = prefixPath + addr.GetPath(); + else + p = nullPath; + DBus::EldbusVariant< std::tuple > tmp { + std::tuple{ rect.x, rect.y, rect.width, rect.height } }; + addFilteredEvent(FilteredEvents::boundsChanged, obj, 1.0f, [=]() { + dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< std::tuple >, Address >( + p, + AtspiDbusInterfaceEventObject, + "BoundsChanged", + "", + 0, + 0, + tmp, + {"", "root"} ); + }); +} + +void BridgeObject::EmitCaretMoved( Accessible* obj, unsigned int cursorPosition ) +{ + auto addr = obj->GetAddress(); + std::string p = addr ? ATSPI_PREFIX_PATH + addr.GetPath() : ATSPI_NULL_PATH; + dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< int >, Address >( + p, + AtspiDbusInterfaceEventObject, + "TextCaretMoved", + "", + cursorPosition, + 0, + {0}, + {"", "root"} ); +} + +void BridgeObject::EmitTextChanged( Accessible* obj, TextChangedState state, unsigned int position, unsigned int length, const std::string &content ) +{ + const char* stateName = nullptr; + switch( state ) + { + case TextChangedState::INSERT: + { + stateName = "insert"; + break; + } + case TextChangedState::DELETE: + { + stateName = "delete"; + break; + } + case TextChangedState::_COUNT: + { + break; + } + } + if( stateName ) + { + auto addr = obj->GetAddress(); + std::string p = addr ? ATSPI_PREFIX_PATH + addr.GetPath() : ATSPI_NULL_PATH; + dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< std::string >, Address >( + p, + AtspiDbusInterfaceEventObject, + "TextChanged", + stateName, + position, + length, + {content}, + {"", "root"} ); + } +} diff --git a/dali/internal/accessibility/bridge/bridge-object.h b/dali/internal/accessibility/bridge/bridge-object.h new file mode 100644 index 0000000..18fa86b --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-object.h @@ -0,0 +1,64 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_OBJECT_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_OBJECT_H + +/* + * Copyright (c) 2019 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 +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +class BridgeObject : public virtual BridgeBase +{ +protected: + BridgeObject(); + + void RegisterInterfaces(); + + DBus::DBusInterfaceDescription::SignalId stateChanged; + + void EmitActiveDescendantChanged( Dali::Accessibility::Accessible* obj, Dali::Accessibility::Accessible *child ) override; + void EmitCaretMoved( Dali::Accessibility::Accessible* obj, unsigned int cursorPosition ) override; + void EmitTextChanged( Dali::Accessibility::Accessible* obj, Dali::Accessibility::TextChangedState state, unsigned int position, unsigned int length, const std::string &content ) override; + void EmitStateChanged( Dali::Accessibility::Accessible* obj, Dali::Accessibility::State state, int val1, int val2 ) override; + void Emit( Dali::Accessibility::Accessible* obj, Dali::Accessibility::WindowEvent we, unsigned int detail1 ) override; + void Emit( Dali::Accessibility::Accessible* obj, Dali::Accessibility::ObjectPropertyChangeEvent we ) override; + void EmitBoundsChanged( Dali::Accessibility::Accessible* obj, Dali::Rect<> rect ) override; + +public: + int GetChildCount(); + DBus::ValueOrError< Dali::Accessibility::Accessible* > GetChildAtIndex( int index ); + Dali::Accessibility::Accessible* GetParent(); + DBus::ValueOrError< std::vector< Dali::Accessibility::Accessible* > > GetChildren(); + std::string GetName(); + std::string GetDescription(); + DBus::ValueOrError< uint32_t > GetRole(); + DBus::ValueOrError< std::string > GetRoleName(); + DBus::ValueOrError< std::string > GetLocalizedRoleName(); + DBus::ValueOrError< int32_t > GetIndexInParent(); + DBus::ValueOrError< std::array< uint32_t, 2 > > GetStates(); + DBus::ValueOrError< std::unordered_map< std::string, std::string > > GetAttributes(); + DBus::ValueOrError< std::vector< std::string > > GetInterfaces(); +}; + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_OBJECT_H diff --git a/dali/internal/accessibility/bridge/bridge-text.cpp b/dali/internal/accessibility/bridge/bridge-text.cpp new file mode 100644 index 0000000..0c3ed82 --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-text.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019 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 + +// INTERNAL INCLUDES +#include + +using namespace Dali::Accessibility; + +void BridgeText::RegisterInterfaces() +{ + DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceText}; + AddFunctionToInterface( desc, "GetText", &BridgeText::GetText ); + AddGetPropertyToInterface( desc, "CharacterCount", &BridgeText::GetCharacterCount ); + AddGetPropertyToInterface( desc, "CaretOffset", &BridgeText::GetCaretOffset ); + AddFunctionToInterface( desc, "SetCaretOffset", &BridgeText::SetCaretOffset ); + AddFunctionToInterface( desc, "GetTextAtOffset", &BridgeText::GetTextAtOffset ); + AddFunctionToInterface( desc, "GetSelection", &BridgeText::GetSelection ); + AddFunctionToInterface( desc, "SetSelection", &BridgeText::SetSelection ); + AddFunctionToInterface( desc, "RemoveSelection", &BridgeText::RemoveSelection ); + dbusServer.addInterface( "/", desc, true ); +} + +Text* BridgeText::FindSelf() const +{ + auto s = BridgeBase::FindSelf(); + assert( s ); + auto s2 = dynamic_cast< Text* >( s ); + if( !s2 ) + throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Text interface"}; + return s2; +} + +DBus::ValueOrError< std::string > BridgeText::GetText( int startOffset, int endOffset ) +{ + return FindSelf()->GetText( startOffset, endOffset ); +} + +DBus::ValueOrError< int32_t > BridgeText::GetCharacterCount() +{ + return FindSelf()->GetCharacterCount(); +} + +DBus::ValueOrError< int32_t > BridgeText::GetCaretOffset() +{ + return FindSelf()->GetCaretOffset(); +} + +DBus::ValueOrError< bool > BridgeText::SetCaretOffset( int32_t offset ) +{ + return FindSelf()->SetCaretOffset(offset); +} + +DBus::ValueOrError< std::string, int, int > BridgeText::GetTextAtOffset( int32_t offset, uint32_t boundary ) +{ + auto r = FindSelf()->GetTextAtOffset( offset, static_cast< TextBoundary >( boundary ) ); + return {r.content, static_cast< int >( r.startOffset ), static_cast< int >( r.endOffset )}; +} + +DBus::ValueOrError< int, int > BridgeText::GetSelection( int32_t selectionNum ) +{ + auto r = FindSelf()->GetSelection( selectionNum ); + return {static_cast< int >( r.startOffset ), static_cast< int >( r.endOffset )}; +} + +DBus::ValueOrError< bool > BridgeText::RemoveSelection( int32_t selectionNum ) +{ + return FindSelf()->RemoveSelection( selectionNum ); +} + +DBus::ValueOrError< bool > BridgeText::SetSelection( int32_t selectionNum, int32_t startOffset, int32_t endOffset ) +{ + return FindSelf()->SetSelection( selectionNum, startOffset, endOffset ); +} diff --git a/dali/internal/accessibility/bridge/bridge-text.h b/dali/internal/accessibility/bridge/bridge-text.h new file mode 100644 index 0000000..f8661a7 --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-text.h @@ -0,0 +1,44 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_TEXT_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_TEXT_H + +/* + * Copyright (c) 2019 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. + * + */ + +// INTERNAL INCLUDES +#include + +class BridgeText : public virtual BridgeBase +{ +protected: + BridgeText() = default; + + void RegisterInterfaces(); + + Dali::Accessibility::Text* FindSelf() const; + +public: + DBus::ValueOrError< std::string > GetText( int startOffset, int endOffset ); + DBus::ValueOrError< int32_t > GetCharacterCount(); + DBus::ValueOrError< int32_t > GetCaretOffset(); + DBus::ValueOrError< bool > SetCaretOffset( int32_t offset ); + DBus::ValueOrError< std::string, int, int > GetTextAtOffset( int32_t offset, uint32_t boundary ); + DBus::ValueOrError< int, int > GetSelection( int32_t selectionNum ); + DBus::ValueOrError< bool > RemoveSelection( int32_t selectionNum ); + DBus::ValueOrError< bool > SetSelection( int32_t selectionNum, int32_t startOffset, int32_t endOffset ); +}; + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_TEXT_H diff --git a/dali/internal/accessibility/bridge/bridge-value.cpp b/dali/internal/accessibility/bridge/bridge-value.cpp new file mode 100644 index 0000000..aa1a34c --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-value.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 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 + +// EXTERNAL INCLUDES +#include + +using namespace Dali::Accessibility; + +BridgeValue::BridgeValue() +{ +} + +void BridgeValue::RegisterInterfaces() +{ + DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceValue}; + AddGetSetPropertyToInterface( desc, "CurrentValue", &BridgeValue::GetCurrentValue, &BridgeValue::SetCurrentValue ); + AddGetPropertyToInterface( desc, "MaximumValue", &BridgeValue::GetMaximumValue ); + AddGetPropertyToInterface( desc, "MinimumIncrement", &BridgeValue::GetMinimumIncrement ); + AddGetPropertyToInterface( desc, "MinimumValue", &BridgeValue::GetMinimumValue ); + dbusServer.addInterface( "/", desc, true ); +} + +Value* BridgeValue::FindSelf() const +{ + auto s = BridgeBase::FindSelf(); + assert( s ); + auto s2 = dynamic_cast< Value* >( s ); + if( !s2 ) + throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Value interface"}; + return s2; +} +double BridgeValue::GetCurrentValue() +{ + return FindSelf()->GetCurrent(); +} +void BridgeValue::SetCurrentValue( double new_value ) +{ + FindSelf()->SetCurrent( new_value ); +} +double BridgeValue::GetMaximumValue() +{ + return FindSelf()->GetMaximum(); +} +double BridgeValue::GetMinimumIncrement() +{ + return FindSelf()->GetMinimumIncrement(); +} +double BridgeValue::GetMinimumValue() +{ + return FindSelf()->GetMinimum(); +} diff --git a/dali/internal/accessibility/bridge/bridge-value.h b/dali/internal/accessibility/bridge/bridge-value.h new file mode 100644 index 0000000..0fb921f --- /dev/null +++ b/dali/internal/accessibility/bridge/bridge-value.h @@ -0,0 +1,48 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_VALUE_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_VALUE_H + +/* + * Copyright (c) 2019 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 +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include + +class BridgeValue : public virtual BridgeBase +{ +protected: + BridgeValue(); + + void RegisterInterfaces(); + + Dali::Accessibility::Value* FindSelf() const; + +public: + double GetCurrentValue(); + void SetCurrentValue( double new_value ); + double GetMaximumValue(); + double GetMinimumIncrement(); + double GetMinimumValue(); +}; + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_VALUE_H diff --git a/dali/internal/accessibility/bridge/component.cpp b/dali/internal/accessibility/bridge/component.cpp new file mode 100644 index 0000000..73334a1 --- /dev/null +++ b/dali/internal/accessibility/bridge/component.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 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 + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include + +using namespace Dali::Accessibility; + +bool Component::Contains( Point p, CoordType ctype ) +{ + auto extents = GetExtents( ctype ); + return p.x >= extents.x && p.y >= extents.y && p.x <= extents.x + extents.width && p.y <= extents.y + extents.height; +} + +Accessible* Component::GetAccessibleAtPoint( Point p, CoordType ctype ) +{ + auto children = GetChildren(); + for( auto childIt = children.rbegin(); childIt != children.rend(); childIt++ ) + { + auto component = dynamic_cast< Component* >( *childIt ); + if( component && component->Contains( p, ctype ) ) + { + return component; + } + } + return nullptr; +} + +bool Component::IsScrollable() +{ + return false; +} diff --git a/dali/internal/accessibility/bridge/dbus-locators.h b/dali/internal/accessibility/bridge/dbus-locators.h new file mode 100644 index 0000000..1bfb8ec --- /dev/null +++ b/dali/internal/accessibility/bridge/dbus-locators.h @@ -0,0 +1,98 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_LOCATORS_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_LOCATORS_H + +/* + * Copyright 2019 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 dbusLocators +{ +namespace callmgr +{ +static constexpr const char* BUS = "org.tizen.callmgr"; +static constexpr const char* OBJ_PATH = "/org/tizen/callmgr"; +static constexpr const char* INTERFACE = "org.tizen.callmgr"; +} + +namespace accessibilityEMod +{ +static constexpr const char* BUS = "org.enlightenment.wm-screen-reader"; +static constexpr const char* OBJ_PATH = "/org/tizen/GestureNavigation"; +static constexpr const char* INTERFACE = "org.tizen.GestureNavigation"; + +static constexpr const char* ACCESSORIES_SP_ENABLED = "AccessoriesSwitchProviderEnabled"; +static constexpr const char* KEY_DOWN_SIGNAL = "KeyDown"; +static constexpr const char* KEY_UP_SIGNAL = "KeyUp"; + +static constexpr const char* SCREEN_SP_ENABLED = "ScreenSwitchProviderEnabled"; +static constexpr const char* MOUSE_DOWN_SIGNAL = "MouseDown"; +static constexpr const char* MOUSE_UP_SIGNAL = "MouseUp"; + +static constexpr const char* BACK_BUTTON_INTERCEPTION_ENABLED = "BackButtonInterceptionEnabled"; +static constexpr const char* BACK_BUTTON_DOWN_SIGNAL = "BackButtonDown"; +static constexpr const char* BACK_BUTTON_UP_SIGNAL = "BackButtonUp"; +} + +namespace freeDesktop +{ +static constexpr const char* BUS = "org.freedesktop.DBus"; +static constexpr const char* OBJ_PATH = "/org/freedesktop/DBus"; +static constexpr const char* INTERFACE = "org.freedesktop.DBus"; +static constexpr const char* PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties"; +static constexpr const char* GET_CONNECTION_UNIX_PROCESS_ID = "GetConnectionUnixProcessID"; +static constexpr const char* SET = "Set"; +static constexpr const char* GET = "Get"; +} + +namespace windowManager +{ +static constexpr const char* BUS = "org.enlightenment.wm"; +static constexpr const char* OBJ_PATH = "/org/enlightenment/wm"; +static constexpr const char* INTERFACE = "org.enlightenment.wm.proc"; +static constexpr const char* GET_VISIBLE_WIN_INFO = "GetVisibleWinInfo"; +static constexpr const char* GET_FOCUS_PROC = "GetFocusProc"; +} + +namespace atspi +{ +static constexpr const char* BUS = "org.a11y.Bus"; +static constexpr const char* OBJ_PATH = "/org/a11y/bus"; +static constexpr const char* BUS_INTERFACE = "org.a11y.Bus"; +static constexpr const char* STATUS_INTERFACE = "org.a11y.Status"; + +static constexpr const char* GET_ADDRESS = "GetAddress"; +static constexpr const char* IS_ENABLED = "IsEnabled"; +static constexpr const char* GET_ATTRIBUTES = "GetAttributes"; +static constexpr const char* DO_ACTION_NAME = "DoActionName"; +static constexpr const char* PARENT = "Parent"; +static constexpr const char* GET_MATCHES = "GetMatches"; +static constexpr const char* GET_INDEX_IN_PARENT = "GetIndexInParent"; +static constexpr const char* SELECT_CHILD = "SelectChild"; +static constexpr const char* NAME = "Name"; +static constexpr const char* GET_ROLE = "GetRole"; +static constexpr const char* CHILD_COUNT = "ChildCount"; +static constexpr const char* GET_CHILD_AT_INDEX = "GetChildAtIndex"; +static constexpr const char* GET_STATE = "GetState"; +static constexpr const char* GET_RELATION_SET = "GetRelationSet"; +static constexpr const char* GET_EXTENTS = "GetExtents"; +static constexpr const char* CURRENT_VALUE = "CurrentValue"; +static constexpr const char* MAXIMUM_VALUE = "MaximumValue"; +static constexpr const char* MINIMUM_VALUE = "MinimumValue"; +static constexpr const char* GET_INTERFACES = "GetInterfaces"; +static constexpr const char* GET_NAVIGABLE_AT_POINT = "GetNavigableAtPoint"; +} +} + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_LOCATORS_H diff --git a/dali/internal/accessibility/bridge/dbus.cpp b/dali/internal/accessibility/bridge/dbus.cpp new file mode 100644 index 0000000..6353296 --- /dev/null +++ b/dali/internal/accessibility/bridge/dbus.cpp @@ -0,0 +1,1075 @@ +/* + * Copyright 2019 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 + +#include + +// EXTERNAL INCLUDES +#include +#include +#include + +#include +#include + +// INTERNAL INCLUDES +#include + +#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" + +#undef EINA_FALSE +#undef EINA_TRUE +#define EINA_TRUE static_cast< Eina_Bool >( 1 ) +#define EINA_FALSE static_cast< Eina_Bool >( 0 ) + +//#define DBUS_DEBUG(...) do { DBus::debugPrint(__FILE__, __LINE__, __VA_ARGS__); } while (0) + +std::atomic< unsigned int > DBus::detail::CallId::LastId{0}; +static std::function< void( const char*, size_t ) > debugPrinter; +static std::mutex debugLock; + +thread_local std::string DBus::DBusServer::currentObjectPath; +thread_local DBusWrapper::ConnectionPtr DBus::DBusServer::currentConnection; + +void DBus::setDebugPrinter( std::function< void( const char*, size_t ) > printer ) +{ + std::lock_guard< std::mutex > lock( debugLock ); + debugPrinter = std::move( printer ); +} + +void DBus::debugPrint( const char* file, size_t line, const char* format, ... ) +{ + std::function< void( const char*, size_t ) > debugPrintFunc; + { + std::lock_guard< std::mutex > lock( debugLock ); + if( !debugPrinter ) + return; + debugPrintFunc = debugPrinter; + } + std::vector< char > buf( 4096 ); + int offset; + while( true ) + { + offset = snprintf( buf.data(), buf.size(), "%s:%u: ", file, static_cast< unsigned int >( line ) ); + if( offset < 0 ) + return; + if( static_cast< size_t >( offset ) < buf.size() ) + break; + buf.resize( offset + 1 ); + } + + while( true ) + { + va_list args; + va_start( args, format ); + int z = vsnprintf( buf.data() + offset, buf.size() - offset, format, args ); + va_end( args ); + if( z < 0 ) + return; + bool done = static_cast< size_t >( z ) + static_cast< size_t >( offset ) < buf.size(); + buf.resize( static_cast< size_t >( z ) + static_cast< size_t >( offset ) ); + if( done ) + break; + } + debugPrintFunc( buf.data(), buf.size() ); +} + +DBusWrapper::ConnectionPtr DBus::getDBusConnectionByName( const std::string& name ) +{ + return DBUS_W->eldbus_address_connection_get_impl( name ); +} + +DBusWrapper::ConnectionPtr DBus::getDBusConnectionByType( ConnectionType connectionType ) +{ + return DBUS_W->eldbus_connection_get_impl(connectionType); +} + +DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, ConnectionType tp ) : DBusClient( std::move( busName ), std::move( pathName ), std::move( interfaceName ), getDBusConnectionByType( tp ) ) +{ +} + +DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, const DBusWrapper::ConnectionPtr &conn ) +{ + if( !conn ) + connectionState->connection = getDBusConnectionByType( ConnectionType::SESSION ); + else + connectionState->connection = conn; + + std::ostringstream o; + o << "bus = " << busName << " path = " << pathName << " connection = " << DBUS_W->eldbus_connection_unique_name_get_impl( connectionState->connection ); + info = o.str(); + + connectionState->object = DBUS_W->eldbus_object_get_impl( connectionState->connection, busName.c_str(), pathName.c_str() ); + if( connectionState->object ) + { + connectionState->proxy = DBUS_W->eldbus_proxy_get_impl( connectionState->object, interfaceName ); + if( interfaceName != DBUS_INTERFACE_PROPERTIES ) + { + connectionState->propertiesProxy = DBUS_W->eldbus_proxy_get_impl( connectionState->object, DBUS_INTERFACE_PROPERTIES ); + } + else + { + connectionState->propertiesProxy = DBUS_W->eldbus_proxy_copy_impl( connectionState->proxy ); + } + } + connectionInfo = std::make_shared< ConnectionInfo >(); + connectionInfo->busName = std::move( busName ); + connectionInfo->pathName = std::move( pathName ); + connectionInfo->interfaceName = std::move( interfaceName ); +} + +DBus::DBusServer::DBusServer( ConnectionType tp ) : DBus::DBusServer( DBus::getDBusConnectionByType( tp ) ) +{ +} + +DBus::DBusServer::DBusServer( const DBusWrapper::ConnectionPtr &conn ) +{ + if( !conn ) + connection = getDBusConnectionByType( ConnectionType::SESSION ); + else + connection = conn; +} + +DBus::DBusInterfaceDescription::DBusInterfaceDescription( std::string interfaceName ) : interfaceName( std::move( interfaceName ) ) +{ +} + +void DBus::DBusServer::addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback ) +{ + DBUS_W->add_interface_impl( fallback, pathName, connection, destructorObject->destructors, dscr.interfaceName, dscr.methods, dscr.properties, dscr.signals ); +} + +std::string DBus::DBusServer::getBusName() const +{ + return getConnectionName( connection ); +} + +std::string DBus::getConnectionName( const DBusWrapper::ConnectionPtr &c ) +{ + return DBUS_W->eldbus_connection_unique_name_get_impl( c ); +} + +bool DBus::DBusClient::getFromEinaValue(const _Eina_Value *v, void *dst) +{ + return eina_value_get(const_cast(v), dst); +} + +/// \cond +static std::unique_ptr InstalledWrapper; + +struct DefaultDBusWrapper : public DBusWrapper { + constexpr static int ELDBUS_CALL_TIMEOUT = 1000; + + DefaultDBusWrapper() { + } + ~DefaultDBusWrapper() { + } + #define DEFINE_GS(name, eldbus_name, unref_call) \ + static eldbus_name *get(const std::shared_ptr &a) { \ + return static_cast(a.get())->Value; \ + } \ + static eldbus_name *release(const std::shared_ptr &a) { \ + auto z = static_cast(a.get())->Value; \ + static_cast(a.get())->Value = nullptr; \ + return z; \ + } \ + template static std::shared_ptr create(const eldbus_name *v, ARGS && ... args) { \ + return std::make_shared(const_cast(v), std::forward(args)...); \ + } + + #define DEFINE_TYPE(name, eldbus_name, unref_call) \ + struct name ## Impl : public name { \ + eldbus_name *Value = nullptr; \ + bool EraseOnExit = false; \ + name ## Impl(eldbus_name *Value, bool EraseOnExit = false) : Value(Value), EraseOnExit(EraseOnExit) { } \ + ~name ## Impl() { \ + if (EraseOnExit && Value) { unref_call; } \ + } \ + }; \ + DEFINE_GS(name, eldbus_name, unref_call) + + struct ConnectionImpl : public Connection { + Eldbus_Connection *Value = nullptr; + bool EraseOnExit = false; + ConnectionImpl(Eldbus_Connection *Value, bool EraseOnExit = false) : Value(Value), EraseOnExit(EraseOnExit) { + ecore_event_init(); + eldbus_init(); + } + ~ConnectionImpl() { + if (EraseOnExit && Value) { + eldbus_connection_unref( Value ); + } + eldbus_shutdown(); + ecore_event_shutdown(); + } + }; + struct MessageIterImpl : public MessageIter { + Eldbus_Message_Iter *Value = nullptr, *Parent = nullptr; + bool EraseOnExit = false; + MessageIterImpl(Eldbus_Message_Iter *Value, Eldbus_Message_Iter *Parent, bool EraseOnExit = false) : Value(Value), Parent(Parent), EraseOnExit(EraseOnExit) { } + ~MessageIterImpl() { + if (EraseOnExit && Value && Parent) + eldbus_message_iter_container_close(Parent, Value); + } + }; + + DEFINE_GS(Connection, Eldbus_Connection, ) + DEFINE_GS(MessageIter, Eldbus_Message_Iter, ) + DEFINE_TYPE(Message, Eldbus_Message, eldbus_message_unref( Value )) + DEFINE_TYPE(Proxy, Eldbus_Proxy, ) + DEFINE_TYPE(Object, Eldbus_Object, eldbus_object_unref( Value )) + DEFINE_TYPE(Pending, Eldbus_Pending, ) + DEFINE_TYPE(EventPropertyChanged, Eldbus_Proxy_Event_Property_Changed, ) + #undef DEFINE_TYPE + + std::shared_ptr eldbus_address_connection_get_impl(const std::string &addr) override { + eldbus_init(); + auto p = eldbus_address_connection_get(addr.c_str()); + auto w = create(p, true); + eldbus_shutdown(); + return w; + } + +#define eldbus_message_iter_arguments_append_impl_basic(type, sig) \ + void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type src) override { \ + eldbus_message_iter_arguments_append( get(it), #sig, src ); \ + } \ + bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type &dst) override { \ + return eldbus_message_iter_get_and_next( get(it), (#sig)[0], &dst ); \ + } + + eldbus_message_iter_arguments_append_impl_basic(uint8_t, y) + eldbus_message_iter_arguments_append_impl_basic(uint16_t, q) + eldbus_message_iter_arguments_append_impl_basic(uint32_t, u) + eldbus_message_iter_arguments_append_impl_basic(uint64_t, t) + eldbus_message_iter_arguments_append_impl_basic(int16_t, n) + eldbus_message_iter_arguments_append_impl_basic(int32_t, i) + eldbus_message_iter_arguments_append_impl_basic(int64_t, x) + eldbus_message_iter_arguments_append_impl_basic(double, d) + +#undef eldbus_message_iter_arguments_append_impl_basic + + void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, bool src) override { + eldbus_message_iter_arguments_append( get(it), "b", src ? 1 : 0 ); + } + bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, bool &dst) override { + unsigned char q; + auto z = eldbus_message_iter_get_and_next( get(it), 'b', &q ); + dst = q != 0; + return z; + } + void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, const std::string &src) override { + eldbus_message_iter_arguments_append( get(it), "s", src.c_str() ); + } + bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, std::string &dst) override { + auto iter = get(it); + const char* q; + if( !eldbus_message_iter_get_and_next( iter, 's', &q ) ) + { + if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) ) + return false; + } + dst = q; + return true; + } + void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, const ObjectPath &src) override { + eldbus_message_iter_arguments_append( get(it), "o", src.value.c_str() ); + } + bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, ObjectPath &dst) override { + const char* q; + if( !eldbus_message_iter_get_and_next( get(it), 'o', &q ) ) + return false; + dst.value = q; + return true; + } + + MessageIterPtr eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) override { + auto z = eldbus_message_iter_container_new( get(it), type, !sig.empty() ? sig.c_str() : NULL ); + return create(z, get(it), true); + } + MessageIterPtr eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) override { + Eldbus_Message_Iter* entry; + if (!eldbus_message_iter_get_and_next( get(it), type, &entry ) ) return {}; + return create(entry, get(it), false); + } + MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr &msg, bool) override { + return create(eldbus_message_iter_get(get(msg)), nullptr, false); + } + MessagePtr eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) { + return create(eldbus_proxy_method_call_new( get(proxy), funcName.c_str() ) ); + } + MessagePtr eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) override { + return create(eldbus_proxy_send_and_block(get(proxy), release(msg), ELDBUS_CALL_TIMEOUT) ); + } + bool eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) override { + const char *errname, *errmsg; + if( eldbus_message_error_get( get(msg), &errname, &errmsg ) ) { + name = errname; + text = errmsg; + return true; + } + return false; + } + std::string eldbus_message_signature_get_impl(const MessagePtr &msg) override { + return eldbus_message_signature_get(get(msg)); + } + + static void callAsyncCb( void* data, const Eldbus_Message *msg, Eldbus_Pending *pending ) + { + auto d = static_cast< SendCallback* >( data ); + (*d)( create(msg, false) ); + } + static void pendingFreeCb( void* data, const void* ) + { + auto d = static_cast< SendCallback* >( data ); + delete d; + } + static void listenerCallbackFree( void* data, const void* ) + { + auto d = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data ); + delete d; + } + + PendingPtr eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) override { + auto cb = new SendCallback{ callback }; + auto pending = eldbus_proxy_send( get(proxy), release(msg), callAsyncCb, cb, ELDBUS_CALL_TIMEOUT ); + if( pending ) + { + eldbus_pending_free_cb_add( pending, pendingFreeCb, cb ); + } + else + { + delete cb; + } + return create(pending, false); + } + std::string eldbus_proxy_interface_get_impl(const ProxyPtr &proxy) override { + return eldbus_proxy_interface_get( get(proxy) ); + } + static void listenerCallback( void* data, const Eldbus_Message* msg ) + { + auto p = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data ); + ( *p )( msg ); + } + void eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function &cb) override { + auto tmp = new std::function< void( const Eldbus_Message* msg ) >{ + [cb](const Eldbus_Message* msg) { + cb(create(msg, false)); + } + }; + auto handler = eldbus_proxy_signal_handler_add( get(proxy), member.c_str(), listenerCallback, tmp ); + if( handler ) + eldbus_proxy_free_cb_add( get(proxy), listenerCallbackFree, tmp ); + else + delete tmp; + } + std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) override { + return eldbus_message_iter_signature_get( get(iter) ); + } + MessagePtr eldbus_message_method_return_new_impl( const MessagePtr &msg) override { + return create(eldbus_message_method_return_new( get(msg) ) ); + } + MessagePtr eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) override { + return create(eldbus_message_error_new( get(msg), err.c_str(), txt.c_str() ) ); + } + PendingPtr eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) override { + return create(eldbus_connection_send( get(conn), get(msg), NULL, NULL, -1 ) ); + } + MessagePtr eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) override { + return create(eldbus_message_signal_new( path.c_str(), iface.c_str(), name.c_str() ) ); + } + MessagePtr eldbus_message_ref_impl(const MessagePtr &msg) override { + return create(eldbus_message_ref( get(msg) ), true ); + } + ConnectionPtr eldbus_connection_get_impl(ConnectionType type) override { + Eldbus_Connection_Type eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM; + + switch( type ) + { + case ConnectionType::SYSTEM: + { + eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM; + break; + } + case ConnectionType::SESSION: + { + eldbusType = ELDBUS_CONNECTION_TYPE_SESSION; + break; + } + } + + eldbus_init(); + auto p = eldbus_connection_get( eldbusType ); + auto w = create(p, true); + eldbus_shutdown(); + return w; + } + std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) override { + return eldbus_connection_unique_name_get( get(conn) ); + } + ObjectPtr eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) override { + return create(eldbus_object_get(get(conn), bus.c_str(), path.c_str() ), true ); + } + ProxyPtr eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) override { + return create(eldbus_proxy_get(get(obj), interface.c_str() ), false ); + } + ProxyPtr eldbus_proxy_copy_impl( const ProxyPtr &ptr) override { + return create(get(ptr), false ); + } + + + + + + + struct Implementation + { + Eldbus_Service_Interface_Desc dsc; + std::vector< std::vector< Eldbus_Arg_Info > > argsInfos; + std::vector< Eldbus_Method > methods; + std::vector< Eldbus_Signal > signals; + std::vector< Eldbus_Property > properties; + + std::unordered_map< std::string, DBusWrapper::MethodInfo > methodsMap; + std::unordered_map< std::string, DBusWrapper::PropertyInfo > propertiesMap; + std::unordered_map< unsigned int, DBusWrapper::SignalInfo > signalsMap; + + DBusWrapper::ConnectionWeakPtr connection; + }; + + static std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< Implementation > > globalEntries; + static std::mutex globalEntriesMutex; + +#undef EINA_FALSE +#undef EINA_TRUE +#define EINA_FALSE static_cast(0) +#define EINA_TRUE static_cast(1) + + static Eina_Bool property_get_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter, + const Eldbus_Message* message, Eldbus_Message** error ) + { + Implementation* impl = nullptr; + { + std::lock_guard< std::mutex > lock( globalEntriesMutex ); + auto it = globalEntries.find( iface ); + if( it != globalEntries.end() ) + impl = it->second.get(); + } + if( !impl ) + return EINA_FALSE; + + auto it = impl->propertiesMap.find( propertyName ); + if( it == impl->propertiesMap.end() || !it->second.getCallback ) + return EINA_FALSE; + + auto connection = impl->connection.lock(); + if( !connection ) + return EINA_FALSE; + + DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) ); + auto reply = it->second.getCallback( create(message, false), create(iter, nullptr, false) ); + if( !reply.empty() ) + { + if( error ) + *error = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.c_str() ); + return EINA_FALSE; + } + + return EINA_TRUE; + } + + static Eldbus_Message* property_set_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter, + const Eldbus_Message* message ) + { + Implementation* impl = nullptr; + { + std::lock_guard< std::mutex > lock( globalEntriesMutex ); + auto it = globalEntries.find( iface ); + if( it != globalEntries.end() ) + impl = it->second.get(); + } + if( !impl ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" ); + return ret; + } + auto it = impl->propertiesMap.find( propertyName ); + if( it == impl->propertiesMap.end() || !it->second.setCallback ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown setter" ); + return ret; + } + auto connection = impl->connection.lock(); + if( !connection ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Connection lost" ); + return ret; + } + + DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) ); + auto reply = it->second.setCallback( create(message, false), create(iter, nullptr, false) ); + + Eldbus_Message* ret = nullptr; + if( !reply.empty() ) + { + ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.c_str() ); + } + else + { + ret = eldbus_message_method_return_new( message ); + } + return ret; + } + + static Eldbus_Message* method_callback( const Eldbus_Service_Interface* iface, const Eldbus_Message* message ) + { + Implementation* impl = nullptr; + { + std::lock_guard< std::mutex > lock( globalEntriesMutex ); + auto it = globalEntries.find( iface ); + if( it != globalEntries.end() ) + impl = it->second.get(); + } + if( !impl ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" ); + return ret; + } + std::string memberName = eldbus_message_member_get( message ); + auto it = impl->methodsMap.find( memberName ); + if( it == impl->methodsMap.end() ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown method" ); + return ret; + } + auto connection = impl->connection.lock(); + if( !connection ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Connection lost" ); + return ret; + } + DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) ); + auto reply = it->second.callback( create(message) ); + return release(reply); + } + + void add_interface_impl( bool fallback, const std::string& pathName, + const ConnectionPtr &connection, + std::vector> &destructors, + const std::string& interfaceName, + std::vector< MethodInfo >& dscrMethods, + std::vector< PropertyInfo >& dscrProperties, + std::vector< SignalInfo >& dscrSignals ) override + { + std::vector< Eldbus_Method > methods; + std::vector< Eldbus_Signal > signals; + std::vector< Eldbus_Property > properties; + std::vector< std::vector< Eldbus_Arg_Info > > argsInfos; + std::unordered_map< std::string, DBus::DBusInterfaceDescription::MethodInfo > methodsMap; + std::unordered_map< std::string, DBus::DBusInterfaceDescription::PropertyInfo > propertiesMap; + std::unordered_map< unsigned int, DBus::DBusInterfaceDescription::SignalInfo > signalsMap; + + DBUS_DEBUG( "interface %s path %s on bus %s", interfaceName.c_str(), pathName.c_str(), DBus::getConnectionName( connection ).c_str() ); + auto makeArgInfo = [&](const std::vector> &input) { + argsInfos.push_back({}); + auto &dst = argsInfos.back(); + for(auto &s : input) { + auto a = Strings.add(s.first); + auto b = Strings.add(s.second); + dst.push_back({ a, b }); + } + dst.push_back({ nullptr, nullptr }); + return dst.data(); + }; + for( auto& ee : dscrMethods ) + { + auto key = ee.memberName; + DBUS_DEBUG( "adding method %s", ee.memberName.c_str() ); + for( auto& r : ee.in ) + { + DBUS_DEBUG( "in %s '%s'", r.first.c_str(), r.second.c_str() ); + } + for( auto& r : ee.out ) + { + DBUS_DEBUG( "out %s '%s'", r.first.c_str(), r.second.c_str() ); + } + auto& e = ( methodsMap[key] = std::move( ee ) ); + methods.push_back( {} ); + auto& m = methods.back(); + m.member = e.memberName.c_str(); + m.in = makeArgInfo(e.in); + m.out = makeArgInfo(e.out); + m.cb = method_callback; + m.flags = 0; + } + for( auto& ee : dscrProperties ) + { + auto key = ee.memberName; + DBUS_DEBUG( "adding property %s", ee.memberName.c_str() ); + auto& e = ( propertiesMap[key] = std::move( ee ) ); + properties.push_back( {} ); + auto& m = properties.back(); + m.name = e.memberName.c_str(); + m.type = e.typeSignature.c_str(); + m.get_func = e.getCallback ? property_get_callback : nullptr; + m.set_func = e.setCallback ? property_set_callback : nullptr; + m.flags = 0; + } + dscrMethods.clear(); + dscrProperties.clear(); + dscrSignals.clear(); + + methods.push_back( {nullptr, nullptr, nullptr, nullptr, 0} ); + signals.push_back( {nullptr, nullptr, 0} ); + properties.push_back( {nullptr, nullptr, nullptr, nullptr, 0} ); + + auto impl = std::unique_ptr< Implementation >( new Implementation{ + {interfaceName.c_str(), + methods.data(), + signals.data(), + properties.data(), + nullptr, + nullptr}, + std::move( argsInfos ), + std::move( methods ), + std::move( signals ), + std::move( properties ), + std::move( methodsMap ), + std::move( propertiesMap ), + std::move( signalsMap ), + connection} ); + + { + std::lock_guard< std::mutex > lock( globalEntriesMutex ); + auto v = fallback ? eldbus_service_interface_fallback_register( get(connection), pathName.c_str(), &impl->dsc ) : eldbus_service_interface_register( get(connection), pathName.c_str(), &impl->dsc ); + assert( v ); + globalEntries[v] = std::move( impl ); + DBUS_DEBUG( "registering interface %p (%d)", v, fallback ? 1 : 0 ); + destructors.push_back([=]() { + DBUS_DEBUG( "unregistering interface %p", v ); + eldbus_service_interface_unregister( v ); + std::lock_guard< std::mutex > lock( globalEntriesMutex ); + globalEntries.erase( v ); + }); + } + } + static void listenerEventChangedCallback( void* data, Eldbus_Proxy* proxy EINA_UNUSED, void* event ) + { + auto p = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data ); + ( *p )( static_cast< Eldbus_Proxy_Event_Property_Changed* >( event ) ); + } + static void ProxyEventCallbackDelCb( void* data, const void *obj ) + { + auto d = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data ); + delete d; + } + void add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const Eina_Value * ) > cb) override { + auto callbackLambdaPtr = new std::function< void( Eldbus_Proxy_Event_Property_Changed *epc ) >{ + [cb, name, interface]( Eldbus_Proxy_Event_Property_Changed *ev ) { + const char* ifc = eldbus_proxy_interface_get( ev->proxy ); + if( ev->name && ev->name == name && ifc && interface == ifc ) + { + cb(ev->value); + } + } }; + auto p = get(proxy); + eldbus_proxy_event_callback_add( p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED, + listenerEventChangedCallback, callbackLambdaPtr ); + eldbus_proxy_free_cb_add( p, ProxyEventCallbackDelCb, callbackLambdaPtr ); + } +}; + +std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< DefaultDBusWrapper::Implementation > > DefaultDBusWrapper::globalEntries; +std::mutex DefaultDBusWrapper::globalEntriesMutex; + +DBusWrapper *DBusWrapper::Installed() +{ + if (!InstalledWrapper) + InstalledWrapper.reset(new DefaultDBusWrapper); + return InstalledWrapper.get(); +} + +void DBusWrapper::Install(std::unique_ptr w) +{ + InstalledWrapper = std::move(w); +} + +/* +// struct TestDBusWrapper::ConnectionImpl : public TestDBusWrapper::Connection { +// }; + +// TestDBusWrapper::TestDBusWrapper() +// { +// eina_init(); +// connection = std::make_shared(); +// testMethods[std::tuple{"/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", MethodType::Getter}] = +// testMethods[std::tuple{"/org/a11y/bus", "org.a11y.Status", "IsEnabled", MethodType::Getter}] = +// [this](const DBusWrapper::MessagePtr &m) -> MessagePtr { +// auto reply = newReplyMessage(m); +// Encode(reply, std::tuple>{ TestDBusWrapper::Variant{ false} }); +// return reply; +// }; +// } +// TestDBusWrapper::~TestDBusWrapper() +// { +// eina_shutdown(); +// } + +// TestDBusWrapper::ConnectionPtr TestDBusWrapper::eldbus_address_connection_get_impl(const std::string &addr) +// { +// return connection; +// } + +// struct TestDBusWrapper::MessageIterImpl : public TestDBusWrapper::MessageIter { +// MessagePtr msg; +// Element *elem; +// bool write; +// std::list::iterator it; +// MessageIterImpl(MessagePtr msg, Element *elem, bool write) : msg(std::move(msg)), elem(elem), write(write) { +// if (!write) it = elem->get().begin(); +// } +// MessageIterImpl(MessagePtr msg, Element *elem, bool write, std::list::iterator it) : msg(std::move(msg)), elem(elem), write(write), it(it) { } +// }; +// struct TestDBusWrapper::MessageImpl : public TestDBusWrapper::Message { +// std::string bus, path, interface, name; +// Element data; +// bool reply, error = false; +// std::string error_a, error_b; + +// MessageImpl(std::string bus, std::string path, std::string interface, std::string name, bool reply) : +// bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)), name(std::move(name)), data{ ElementList{} }, reply(reply) { } +// MessageImpl(std::string bus, std::string path, std::string interface, std::string name, std::string error_a, std::string error_b) : +// bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)), name(std::move(name)), data{ ElementList{} }, +// reply(true), error(true), error_a(std::move(error_a)), error_b(std::move(error_b)) { } +// }; +// struct TestDBusWrapper::ProxyImpl : public TestDBusWrapper::Proxy { +// std::string bus, path, interface; +// ProxyImpl(std::string bus, std::string path, std::string interface) : bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)) { } +// }; +// struct TestDBusWrapper::ObjectImpl : public TestDBusWrapper::Object { +// std::string bus, path; +// ObjectImpl(std::string bus, std::string path) : bus(std::move(bus)), path(std::move(path)) { } +// }; +// #define DEFINE_TYPE(name) TestDBusWrapper::name ## Impl *TestDBusWrapper::get(const name ## Ptr &v) { return static_cast(v.get()); } +// DEFINE_TYPE(Connection) +// DEFINE_TYPE(Proxy) +// DEFINE_TYPE(Object) +// DEFINE_TYPE(Message) +// DEFINE_TYPE(MessageIter) +// #undef DEFINE_TYPE + +// template void TestDBusWrapperAppendBasic(const TestDBusWrapper::MessageIterPtr &it, T src) { +// auto m = TestDBusWrapper::get(it); +// if (!m->write) throw TestDBusWrapper::error{}; +// if (!m->elem->isContainer()) throw TestDBusWrapper::error{}; +// m->elem->get().push_back(TestDBusWrapper::Element{ src }); +// } +// template bool TestDBusWrapperGetBasicAndNext(const TestDBusWrapper::MessageIterPtr &it, T &src) { +// auto m = TestDBusWrapper::get(it); +// if (m->write) throw TestDBusWrapper::error{}; +// if (!m->elem->isContainer()) return false; +// auto &lst = m->elem->get(); +// if (m->it == lst.end()) return false; +// if (!m->it->is()) return false; +// src = m->it->get(); +// ++m->it; +// return true; +// } + +// #define eldbus_message_iter_arguments_append_impl_basic_impl(type_set, type_get, sig) \ +// void TestDBusWrapper::eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type_set src) { \ +// TestDBusWrapperAppendBasic(it, src); \ +// } \ +// bool TestDBusWrapper::eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type_get &dst) { \ +// return TestDBusWrapperGetBasicAndNext(it, dst); \ +// } +// #define eldbus_message_iter_arguments_append_impl_basic(type, sig) \ +// eldbus_message_iter_arguments_append_impl_basic_impl(type, type, sig) + +// eldbus_message_iter_arguments_append_impl_basic(uint8_t, y) +// eldbus_message_iter_arguments_append_impl_basic(uint16_t, q) +// eldbus_message_iter_arguments_append_impl_basic(uint32_t, u) +// eldbus_message_iter_arguments_append_impl_basic(uint64_t, t) +// eldbus_message_iter_arguments_append_impl_basic(int16_t, n) +// eldbus_message_iter_arguments_append_impl_basic(int32_t, i) +// eldbus_message_iter_arguments_append_impl_basic(int64_t, x) +// eldbus_message_iter_arguments_append_impl_basic(double, d) +// eldbus_message_iter_arguments_append_impl_basic(bool, b) +// eldbus_message_iter_arguments_append_impl_basic_impl(const std::string &, std::string, s) +// eldbus_message_iter_arguments_append_impl_basic_impl(const ObjectPath &, ObjectPath, o) + +// #undef eldbus_message_iter_arguments_append_impl_basic +// #undef eldbus_message_iter_arguments_append_impl_basic_impl + +// TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) { +// auto m = get(it); +// if (!m->write) throw error{}; +// if (!m->elem->isContainer()) throw error{}; +// auto &lst = m->elem->get(); +// if (type == 'r' || type == 'e' || type == 'a' || type == 'v') { +// lst.push_back({ ElementList{}, type }); +// return std::make_shared(MessageIterImpl{ m->msg, &lst.back(), true }); +// } +// throw error{}; +// } + +// TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) { +// auto m = get(it); +// if (m->write) throw error{}; +// if (!m->elem->isContainer()) throw error{} << "not a container"; +// auto &lst = m->elem->get(); +// if (m->it == lst.end()) return {}; +// if (m->it->signature() != type) return {}; +// auto v = std::make_shared(MessageIterImpl{ m->msg, &*m->it, false }); +// ++m->it; +// return v; +// } + +// TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_get_impl(const MessagePtr &it, bool write) { +// auto m = get(it); +// return std::make_shared(MessageIterImpl{ it, &m->data, write, m->data.get().begin() }); +// } + +// bool TestDBusWrapper::completed(const MessageIterPtr &iter) +// { +// auto m = get(iter); +// assert(!m->write); +// return m->it == m->elem->get().end(); +// } + +// TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) { +// auto p = get(proxy); +// return std::make_shared(MessageImpl{ +// p->bus, p->path, p->interface, funcName, false +// }); +// } +// TestDBusWrapper::MessagePtr TestDBusWrapper::call( +// std::unordered_map, std::function> &mp, +// const std::string &mpName, const MessagePtr &msg, MethodType type) { +// auto m = get(msg); +// auto findMethod = [&](std::string path, const std::string &iname, const std::string &name, MethodType type) { +// if (path.empty()) throw error{}; +// if (path[0] != '/') { +// path = "/org/a11y/atspi/accessible/" + path; +// m->path = path; +// } +// while(!path.empty()) { +// auto it = mp.find(std::tuple { path, iname, name, type }); +// if (it != mp.end()) return it; +// auto index = path.rfind('/'); +// if (index == std::string::npos) break; +// path.resize(index); +// } +// return mp.end(); +// }; +// std::string iname, name; +// if (type == MethodType::Method && m->interface == "org.freedesktop.DBus.Properties") { +// type = m->name == "Get" ? MethodType::Getter : MethodType::Setter; +// auto &lst = m->data.get(); +// assert(lst.size() >= 2); +// iname = lst.front().get(); +// lst.pop_front(); +// name = lst.front().get(); +// lst.pop_front(); +// } +// else { +// iname = m->interface; +// name = m->name; +// } +// auto it = findMethod(m->path, iname, name, type); +// if (it == mp.end()) { +// const char *mt; +// if (type == MethodType::Method) mt = "MethodType::Method"; +// else if (type == MethodType::Getter) mt = "MethodType::Getter"; +// else if (type == MethodType::Setter) mt = "MethodType::Setter"; +// else assert(0); +// throw error{} << "missing {\"" << m->path << "\", \"" << iname << "\", \"" << name << "\", " << mt << "} in " << mpName; +// } +// DBus::DBusServer::CurrentObjectSetter setter{ connection, m->path }; +// return it->second(msg); +// } +// TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) { +// auto p = get(proxy); +// auto m = get(msg); +// assert(p->bus == m->bus); +// assert(p->path == m->path); +// assert(p->interface == m->interface); +// return call(testMethods, "testMethods", msg, MethodType::Method); +// } + +// bool TestDBusWrapper::eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) { +// auto m = get(msg); +// name = m->error_a; +// text = m->error_b; +// return m->error; +// } +// static void calculate_signature(std::ostringstream &ostr, TestDBusWrapper::Element &e) +// { +// ostr << static_cast(e.signature()); +// if (e.isContainer()) { +// ostr << "("; +// auto &lst = e.get(); +// for(auto &q : lst) calculate_signature(ostr, q); +// ostr << ")"; +// } +// } +// std::string TestDBusWrapper::eldbus_message_signature_get_impl(const MessagePtr &msg) { +// auto m = get(msg); +// std::ostringstream ostr; +// for(auto &q : m->data.get()) +// calculate_signature(ostr, q); +// return ostr.str(); +// } +// TestDBusWrapper::PendingPtr TestDBusWrapper::eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) { +// auto p = get(proxy); +// auto m = get(msg); +// assert(p->bus == m->bus); +// assert(p->path == m->path); +// assert(p->interface == m->interface); +// asyncCalls.push_back([this, msg, callback]() { +// auto r = call(testMethods, "testMethods", msg, MethodType::Method); +// callback(r); +// }); +// return {}; +// } +// std::string TestDBusWrapper::eldbus_proxy_interface_get_impl(const ProxyPtr &proxy) { +// auto p = get(proxy); +// return p->interface; +// } +// void TestDBusWrapper::eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function &cb) { +// auto p = get(proxy); +// daliSignals[std::tuple { p->path, p->interface, member }] = cb; +// } +// std::string TestDBusWrapper::eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) { +// auto m = get(iter); +// if (m->write) throw error{}; +// if (!m->elem->isContainer()) throw error{}; +// std::ostringstream ostr; +// auto &lst = m->elem->get(); +// for(auto it = m->it; it != lst.end(); ++it) +// calculate_signature(ostr, *it); +// return ostr.str(); +// } +// TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_method_return_new_impl( const MessagePtr &msg) { +// auto m = get(msg); +// return std::make_shared(MessageImpl{ +// m->bus, m->path, m->interface, m->name, true +// }); +// } +// TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) { +// auto m = get(msg); +// return std::make_shared(MessageImpl{ +// m->bus, m->path, m->interface, m->name, err, txt +// }); +// } +// TestDBusWrapper::PendingPtr TestDBusWrapper::eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) { +// call(testMethods, "testMethods", msg, MethodType::Method); +// return {}; +// } +// std::shared_ptr TestDBusWrapper::createEinaValue(bool b) { +// Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_UCHAR); +// eina_value_set(value, b); +// return std::shared_ptr(value, [](Eina_Value *v) { +// eina_value_free(v); +// }); +// } +// TestDBusWrapper::MessagePtr TestDBusWrapper::newMessage(const std::string &path, const std::string &interface, const std::string &name, bool reply) { +// return std::make_shared(MessageImpl{ +// "bus", path, interface, name, reply +// }); +// } +// TestDBusWrapper::MessagePtr TestDBusWrapper::newReplyMessage(const MessagePtr &msg) { +// auto m = get(msg); +// return newMessage(m->path, m->interface, m->name, true); +// } +// TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) { +// return std::make_shared(MessageImpl{ +// "bus", path, iface, name, true +// }); +// } +// TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_ref_impl(const MessagePtr &msg) { +// return msg; +// } +// TestDBusWrapper::ConnectionPtr TestDBusWrapper::eldbus_connection_get_impl(ConnectionType type) { +// return connection; +// } +// std::string TestDBusWrapper::eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) { +// return "bus"; +// } +// TestDBusWrapper::ObjectPtr TestDBusWrapper::eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) { +// return std::make_shared(ObjectImpl{ +// bus, path +// }); +// } +// TestDBusWrapper::ProxyPtr TestDBusWrapper::eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) { +// auto o = get(obj); +// return std::make_shared(ProxyImpl{ o->bus, o->path, interface }); +// } +// TestDBusWrapper::ProxyPtr TestDBusWrapper::eldbus_proxy_copy_impl( const ProxyPtr &ptr) { +// return ptr; +// } +// void TestDBusWrapper::add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const Eina_Value * ) > cb) { +// auto p = get(proxy); +// propertyChangeListeners[std::tuple{ p->path, interface, name }] = cb; +// } +// void TestDBusWrapper::add_interface_impl( bool fallback, const std::string& path_, +// const ConnectionPtr &connection, +// std::vector> &destructors, +// const std::string& interface, +// std::vector< MethodInfo >& dscrMethods, +// std::vector< PropertyInfo >& dscrProperties, +// std::vector< SignalInfo >& dscrSignals ) { +// std::string bus = "bus"; +// std::string path = path_; +// while(!path.empty() && path.back() == '/') path.pop_back(); +// for(auto &m : dscrMethods) { +// auto key = std::make_tuple( "/org/a11y/atspi/accessible" + path, interface, m.memberName, MethodType::Method ); +// daliMethods[key] = m.callback; +// } +// for(auto &m : dscrProperties) { +// auto key = std::make_tuple( "/org/a11y/atspi/accessible" + path, interface, m.memberName, MethodType::Getter ); +// daliMethods[key] = [=](const MessagePtr &msg) -> MessagePtr { +// auto ret = std::make_shared(MessageImpl{ +// "bus", path, interface, m.memberName, true +// }); +// auto v = m.getCallback(msg, std::make_shared(MessageIterImpl{ ret, &ret->data, true })); +// ret->error = !v.empty(); +// if (ret->error) { +// ret->error_a = "call failed"; +// ret->error_b = std::move(v); +// } +// return ret; +// }; +// std::get<3>(key) = MethodType::Setter; +// daliMethods[key] = [=](const MessagePtr &msg) -> MessagePtr { +// auto v = m.setCallback(msg, std::make_shared(MessageIterImpl{ msg, &get(msg)->data, false })); +// return v.empty() ? std::make_shared(MessageImpl{ +// "bus", path, interface, m.memberName, true, +// }) : std::make_shared(MessageImpl{ +// "bus", path, interface, m.memberName, "call failed", v +// }); +// // interface is probably wrong, due to retarded way properties are handlded by dbus +// }; +// } +// for(auto &m : dscrSignals) { +// daliSignalsMap[std::tuple{ "/org/a11y/atspi/accessible" + path, interface, m.uniqueId }] = m.memberName; +// } +// } +*/ + +/// \endcond \ No newline at end of file diff --git a/dali/internal/accessibility/bridge/dbus.h b/dali/internal/accessibility/bridge/dbus.h new file mode 100644 index 0000000..4aa28fb --- /dev/null +++ b/dali/internal/accessibility/bridge/dbus.h @@ -0,0 +1,3322 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_H + +/* + * Copyright 2019 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +#define ATSPI_PREFIX_PATH "/org/a11y/atspi/accessible/" +#define ATSPI_NULL_PATH "/org/a11y/atspi/null" + +struct _Eina_Value; + +/// \cond +struct ObjectPath +{ + std::string value; +}; + +struct DALI_ADAPTOR_API DBusWrapper +{ + virtual ~DBusWrapper() = default; + + enum class ConnectionType + { + SYSTEM, + SESSION + }; + +#define DEFINE_TYPE(name, eldbus_name, unref_call) \ + struct name { virtual ~name() = default; }; \ + using name ## Ptr = std::shared_ptr; \ + using name ## WeakPtr = std::weak_ptr; \ + + DEFINE_TYPE(Connection, Eldbus_Connection, ) + DEFINE_TYPE(MessageIter, Eldbus_Message_Iter, eldbus_message_iter_container_close( Value )) + DEFINE_TYPE(Message, Eldbus_Message, eldbus_message_unref( Value )) + DEFINE_TYPE(Proxy, Eldbus_Proxy, eldbus_proxy_unref( Value )) + DEFINE_TYPE(Object, Eldbus_Object, eldbus_object_unref( Value )) + DEFINE_TYPE(Pending, Eldbus_Pending, ) + DEFINE_TYPE(EventPropertyChanged, Eldbus_Proxy_Event_Property_Changed, ) + +#undef DEFINE_TYPE + virtual ConnectionPtr eldbus_address_connection_get_impl(const std::string &addr) = 0; + +#define eldbus_message_iter_arguments_append_impl_basic_impl(type_set, type_get, sig) \ + virtual void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type_set src) = 0; \ + virtual bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type_get &dst) = 0; +#define eldbus_message_iter_arguments_append_impl_basic(type, sig) \ + eldbus_message_iter_arguments_append_impl_basic_impl(type, type, sig) + + eldbus_message_iter_arguments_append_impl_basic(uint8_t, y) + eldbus_message_iter_arguments_append_impl_basic(uint16_t, q) + eldbus_message_iter_arguments_append_impl_basic(uint32_t, u) + eldbus_message_iter_arguments_append_impl_basic(uint64_t, t) + eldbus_message_iter_arguments_append_impl_basic(int16_t, n) + eldbus_message_iter_arguments_append_impl_basic(int32_t, i) + eldbus_message_iter_arguments_append_impl_basic(int64_t, x) + eldbus_message_iter_arguments_append_impl_basic(double, d) + eldbus_message_iter_arguments_append_impl_basic(bool, b) + eldbus_message_iter_arguments_append_impl_basic_impl(const std::string &, std::string, s) + eldbus_message_iter_arguments_append_impl_basic_impl(const ObjectPath &, ObjectPath, o) + +#undef eldbus_message_iter_arguments_append_impl_basic +#undef eldbus_message_iter_arguments_append_impl_basic_impl + + virtual MessageIterPtr eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) = 0; + virtual MessageIterPtr eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) = 0; + virtual MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr &it, bool write) = 0; + virtual MessagePtr eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) = 0; + virtual MessagePtr eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) = 0; + virtual bool eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) = 0; + virtual std::string eldbus_message_signature_get_impl(const MessagePtr &msg) = 0; + + using SendCallback = std::function; + virtual PendingPtr eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) = 0; + virtual std::string eldbus_proxy_interface_get_impl(const ProxyPtr &) = 0; + virtual void eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function &cb) = 0; + virtual std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) = 0; + virtual MessagePtr eldbus_message_method_return_new_impl( const MessagePtr &msg) = 0; + virtual MessagePtr eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) = 0; + virtual PendingPtr eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) = 0; + virtual MessagePtr eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) = 0; + virtual MessagePtr eldbus_message_ref_impl(const MessagePtr &msg) = 0; + virtual ConnectionPtr eldbus_connection_get_impl(ConnectionType type) = 0; + virtual std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) = 0; + virtual ObjectPtr eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) = 0; + virtual ProxyPtr eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) = 0; + virtual ProxyPtr eldbus_proxy_copy_impl( const ProxyPtr &ptr) = 0; + + class StringStorage + { + public: + struct char_ptr_deleter + { + void operator()( char* p ) + { + free( p ); + } + }; + std::vector< std::unique_ptr< char, char_ptr_deleter > > storage; + + const char* add( const char* txt ) + { + auto ptr = strdup( txt ); + storage.push_back( std::unique_ptr< char, char_ptr_deleter >( ptr ) ); + return storage.back().get(); + } + const char* add( const std::string& txt ) + { + return add( txt.c_str() ); + } + }; + + struct CallId + { + static std::atomic< unsigned int > LastId; + unsigned int id = ++LastId; + }; + struct MethodInfo + { + CallId id; + std::string memberName; + std::vector< std::pair > in, out; // _Eldbus_Arg_Info + std::function< DBusWrapper::MessagePtr( const DBusWrapper::MessagePtr &msg ) > callback; + }; + struct SignalInfo + { + CallId id; + std::string memberName; + std::vector< std::pair > args; + unsigned int uniqueId; + }; + struct PropertyInfo + { + CallId setterId, getterId; + std::string memberName, typeSignature; + std::function< std::string( const DBusWrapper::MessagePtr &src, const DBusWrapper::MessageIterPtr &dst ) > getCallback, setCallback; + }; + struct SignalId + { + CallId id; + + SignalId() = default; + SignalId( CallId id ) : id( id ) {} + }; + virtual void add_interface_impl( bool fallback, const std::string& pathName, + const ConnectionPtr &connection, + std::vector> &destructors, + const std::string& interfaceName, + std::vector< MethodInfo >& dscrMethods, + std::vector< PropertyInfo >& dscrProperties, + std::vector< SignalInfo >& dscrSignals ) = 0; + virtual void add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const _Eina_Value * ) > cb) = 0; + static DBusWrapper *Installed(); + static void Install(std::unique_ptr); + + StringStorage Strings; +}; + +namespace detail { + enum class MethodType { + Method, Getter, Setter + }; +} + +namespace std { + template <> struct hash> { + size_t operator () (const std::tuple &a) const { + auto a1 = std::hash()(std::get<0>(a)); + auto a2 = std::hash()(std::get<1>(a)); + auto a3 = std::hash()(std::get<2>(a)); + size_t v = a1; + v = (v * 11400714819323198485llu) + a2; + v = (v * 11400714819323198485llu) + a3; + return v; + } + }; + template <> struct hash> { + size_t operator () (const std::tuple &a) const { + auto a1 = std::hash()(std::get<0>(a)); + auto a2 = std::hash()(std::get<1>(a)); + auto a3 = std::hash()(std::get<2>(a)); + auto a4 = static_cast(std::get<3>(a)); + size_t v = a1; + v = (v * 11400714819323198485llu) + a2; + v = (v * 11400714819323198485llu) + a3; + v = (v * 11400714819323198485llu) + a4; + return v; + } + }; + template <> struct hash> { + size_t operator () (const std::tuple &a) const { + auto a1 = std::hash()(std::get<0>(a)); + auto a2 = std::hash()(std::get<1>(a)); + auto a3 = std::get<2>(a); + size_t v = a1; + v = (v * 11400714819323198485llu) + a2; + v = (v * 11400714819323198485llu) + a3; + return v; + } + }; +} +namespace detail { + template struct DBusSigImpl { enum { value = 0, end = 0 }; }; + template struct DBusSig { enum { value = DBusSigImpl::type>::value, end = DBusSigImpl::type>::end }; }; + template struct IndexFromTypeTupleImpl { + enum { value = std::is_same::type>::type, Q>::value ? I : IndexFromTypeTupleImpl::value }; + }; + template struct IndexFromTypeTupleImpl { enum { value = S }; }; + template struct IndexFromTypeTuple { + enum { value = IndexFromTypeTupleImpl::type, 0, std::tuple_size::value>::value }; + }; + template struct Encoder; + template struct EncoderTuple; +} +struct DALI_ADAPTOR_API TestDBusWrapper : public DBusWrapper +{ + using MethodType = detail::MethodType; + ConnectionPtr connection; + std::unordered_map, std::function> testMethods; + std::unordered_map, std::function> daliMethods; + std::unordered_map, std::string> daliSignalsMap; + std::unordered_map, std::function> daliSignals; + std::unordered_map, std::function> propertyChangeListeners; + + std::vector> asyncCalls; + + template struct Variant { + T value; + Variant() = default; + Variant(T t) : value(std::move(t)) { } + }; + template void Encode(const MessagePtr &m, const std::tuple &args) { + auto iter = eldbus_message_iter_get_impl(m, true); + detail::EncoderTuple<0, sizeof...(ARGS), ARGS...>::encode(*this, iter, args); + } + template void Decode(const MessagePtr &m, std::tuple &args) { + auto iter = eldbus_message_iter_get_impl(m, false); + detail::EncoderTuple<0, sizeof...(ARGS), ARGS...>::decode(*this, args, iter); + } + MessagePtr newMessage(const std::string &path, const std::string &interface, const std::string &name, bool reply); + MessagePtr newReplyMessage(const MessagePtr &m); + + template void fromTestEmitSignal(std::string path, const std::string &interface, const std::string &name, const std::tuple &args) { + if (path.empty()) throw error{}; + if (path[0] != '/') path = "/org/a11y/atspi/accessible/" + path; + auto msg = newMessage(path, interface, name, false); + Encode(msg, args); + auto it = daliSignals.find(std::tuple{ path, interface, name }); + if (it == daliSignals.end()) throw error{}; + it->second(msg); + } + static std::shared_ptr<_Eina_Value> createEinaValue(bool); + template void fromTestChangeProperty(std::string path, const std::string &interface, const std::string &name, T new_value) { + auto v = createEinaValue(new_value); + if (path.empty()) throw error{}; + if (path[0] != '/') path = "/org/a11y/atspi/accessible/" + path; + auto it = propertyChangeListeners.find(std::tuple{ path, interface, name }); + if (it == propertyChangeListeners.end()) throw error{}; + it->second(v.get()); + } + template std::tuple fromTestCall(const std::string &path, const std::string &interface, const std::string &name, const std::tuple &args) { + auto msg = newMessage(path, interface, name, false); + Encode(msg, args); + auto res = call(daliMethods, "daliMethods", msg, MethodType::Method); + std::string a, b; + if (eldbus_message_error_get_impl(res, a, b)) throw error{} << "call to " << path << " " << interface << " " << name << " failed: " << a << ": " << b; + std::tuple tmp; + Decode(res, tmp); + return tmp; + } + template T fromTestGet(const std::string &path, const std::string &interface, const std::string &name) { + auto msg = newMessage(path, interface, name, false); + auto res = call(daliMethods, "daliMethods", msg, MethodType::Getter); + std::string a, b; + if (eldbus_message_error_get_impl(res, a, b)) throw error{} << "call to " << path << " " << interface << " " << name << " failed: " << a << ": " << b; + std::tuple tmp; + Decode(res, tmp); + return std::move(std::get<0>(tmp)); + } + template std::tuple fromTestSet(const std::string &path, const std::string &interface, const std::string &name, const T &arg) { + auto msg = newMessage(path, interface, name, false); + Encode(msg, TestDBusWrapper::Variant{ arg }); + auto res = call(daliMethods, "daliMethods", msg, MethodType::Setter); + std::string a, b; + if (eldbus_message_error_get_impl(res, a, b)) throw error{} << "call to " << path << " " << interface << " " << name << " failed: " << a << ": " << b; + std::tuple tmp; + Decode(res, tmp); + return tmp; + } + + TestDBusWrapper(); + ~TestDBusWrapper(); + + class error : public std::exception { + std::shared_ptr temp = std::make_shared(); + mutable std::string text; + public: + error() = default; + + template error &operator << (T &&t) { + *temp << std::forward(t); + return *this; + } + const char *what() const noexcept override { + text = temp->str(); + return text.c_str(); + } + }; + #define DEFINE_TYPE(name) struct name ## Impl; static name ## Impl *get(const name ## Ptr &); + DEFINE_TYPE(Connection) + DEFINE_TYPE(Proxy) + DEFINE_TYPE(Object) + DEFINE_TYPE(Message) + DEFINE_TYPE(MessageIter) + #undef DEFINE_TYPE + + class Element; + using ElementList = std::list; + using ElementMap = std::map; + using ElementTuple = std::tuple< + uint8_t, uint16_t, uint32_t, uint64_t, int16_t, int32_t, int64_t, double, bool, std::string, ObjectPath, + ElementList + >; + + class Element { + ElementTuple data; + char signature_ = 0, end_ = 0, index_ = 0; + template void set(T &&t, char signature = detail::DBusSig::value) { + signature_ = signature; + end_ = detail::DBusSig::end; + index_ = static_cast(detail::IndexFromTypeTuple::value); + get() = std::forward(t); + } + public: + template Element(T &&t, typename std::enable_if::value != 0>::type* = nullptr) { set(std::forward(t)); } + Element(ElementList t, int signature) { set(std::move(t), static_cast(signature)); } + + char signature() const { return signature_; } + char end() const { return end_; } + char index() const { return index_; } + bool isContainer() const { return index_ == detail::IndexFromTypeTuple::value; } + template ::value != 0>::type> + bool is() const { return index_ == detail::IndexFromTypeTuple::value; } + template ::value != 0>::type> + const T &get() const { if (!is()) throw error{}; return std::get::value>(data); } + template ::value != 0>::type> + T &get() { if (!is()) throw error{}; return std::get::value>(data); } + }; + + ConnectionPtr eldbus_address_connection_get_impl(const std::string &addr) override; + +#define eldbus_message_iter_arguments_append_impl_basic_impl(type_set, type_get, sig) \ + void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type_set src) override; \ + bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type_get &dst) override; +#define eldbus_message_iter_arguments_append_impl_basic(type, sig) \ + eldbus_message_iter_arguments_append_impl_basic_impl(type, type, sig) + + eldbus_message_iter_arguments_append_impl_basic(uint8_t, y) + eldbus_message_iter_arguments_append_impl_basic(uint16_t, q) + eldbus_message_iter_arguments_append_impl_basic(uint32_t, u) + eldbus_message_iter_arguments_append_impl_basic(uint64_t, t) + eldbus_message_iter_arguments_append_impl_basic(int16_t, n) + eldbus_message_iter_arguments_append_impl_basic(int32_t, i) + eldbus_message_iter_arguments_append_impl_basic(int64_t, x) + eldbus_message_iter_arguments_append_impl_basic(double, d) + eldbus_message_iter_arguments_append_impl_basic(bool, b) + eldbus_message_iter_arguments_append_impl_basic_impl(const std::string &, std::string, s) + eldbus_message_iter_arguments_append_impl_basic_impl(const ObjectPath &, ObjectPath, o) + +#undef eldbus_message_iter_arguments_append_impl_basic +#undef eldbus_message_iter_arguments_append_impl_basic_impl + + MessageIterPtr eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) override; + MessageIterPtr eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) override; + MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr &it, bool write) override; + MessagePtr eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) override; + MessagePtr eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) override; + bool eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) override; + std::string eldbus_message_signature_get_impl(const MessagePtr &msg) override; + PendingPtr eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) override; + std::string eldbus_proxy_interface_get_impl(const ProxyPtr &) override; + void eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function &cb) override; + std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) override; + MessagePtr eldbus_message_method_return_new_impl( const MessagePtr &msg) override; + MessagePtr eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) override; + PendingPtr eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) override; + MessagePtr eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) override; + MessagePtr eldbus_message_ref_impl(const MessagePtr &msg) override; + ConnectionPtr eldbus_connection_get_impl(ConnectionType type) override; + std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) override; + ObjectPtr eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) override; + ProxyPtr eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) override; + ProxyPtr eldbus_proxy_copy_impl( const ProxyPtr &ptr) override; + void add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const _Eina_Value * ) > cb) override; + void add_interface_impl( bool fallback, const std::string& pathName, + const ConnectionPtr &connection, + std::vector> &destructors, + const std::string& interfaceName, + std::vector< MethodInfo >& dscrMethods, + std::vector< PropertyInfo >& dscrProperties, + std::vector< SignalInfo >& dscrSignals ) override; + static bool completed(const MessageIterPtr &iter); +private: + MessagePtr call(std::unordered_map, std::function> &mp, const std::string &name, const MessagePtr &msg, MethodType type); +}; + +namespace detail { + template <> struct DBusSigImpl { enum { value = 'y', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'q', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'u', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 't', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'n', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'i', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'x', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'd', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'b', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 's', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'o', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = '(', end = ')' }; }; + template <> struct DBusSigImpl { enum { value = '{', end = '}' }; }; + + template struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const T &src) { + w.eldbus_message_iter_arguments_append_impl(tgt, src); + } + static void decode(TestDBusWrapper &w, T &tgt, const TestDBusWrapper::MessageIterPtr &src) { + if (!w.eldbus_message_iter_get_and_next_impl(src, tgt)) throw TestDBusWrapper::error{}; + } + }; + template struct Encoder::value>::type> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const T &src) { + Encoder::type>::encode(w, tgt, static_cast::type>(src)); + } + static void decode(TestDBusWrapper &w, T &tgt, const TestDBusWrapper::MessageIterPtr &src) { + typename std::underlying_type::type v = 0; + Encoder::type>::decode(w, v, src); + tgt = static_cast(v); + } + }; + template struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const T &src) { + Encoder::encode(w, tgt, src); + } + static void decode(TestDBusWrapper &w, T &tgt, const TestDBusWrapper::MessageIterPtr &src) { + Encoder::decode(w, tgt, src); + } + }; + template struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const T &src) { + Encoder::encode(w, tgt, src); + } + static void decode(TestDBusWrapper &w, T &tgt, const TestDBusWrapper::MessageIterPtr &src) { + Encoder::decode(w, tgt, src); + } + }; + template struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const T &src) { + Encoder::encode(w, tgt, src); + } + static void decode(TestDBusWrapper &w, T &tgt, const TestDBusWrapper::MessageIterPtr &src) { + Encoder::decode(w, tgt, src); + } + }; + template struct EncoderTuple { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::tuple &src) { + Encoder>::type>::encode(w, tgt, std::get(src)); + EncoderTuple::encode(w, tgt, src); + } + static void decode(TestDBusWrapper &w, std::tuple &tgt, const TestDBusWrapper::MessageIterPtr &src) { + Encoder>::type>::decode(w, std::get(tgt), src); + EncoderTuple::decode(w, tgt, src); + } + }; + template struct EncoderTuple { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::tuple &src) { } + static void decode(TestDBusWrapper &w, std::tuple &tgt, const TestDBusWrapper::MessageIterPtr &src) { } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::tuple &src) { + auto var = w.eldbus_message_iter_container_new_impl( tgt, 'r', ""); + EncoderTuple<0, sizeof...(ARGS), ARGS...>::encode(w, var, src); + } + static void decode(TestDBusWrapper &w, std::tuple &tgt, const TestDBusWrapper::MessageIterPtr &src) { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, 'r' ); + if( !s ) throw TestDBusWrapper::error{}; + EncoderTuple<0, sizeof...(ARGS), ARGS...>::decode(w, tgt, s); + } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::pair &src, char type = 'r') { + auto var = w.eldbus_message_iter_container_new_impl( tgt, type, ""); + Encoder::encode(w, var, src.first); + Encoder::encode(w, var, src.second); + } + static void decode(TestDBusWrapper &w, std::pair &tgt, const TestDBusWrapper::MessageIterPtr &src, char type = 'r') { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, type ); + if( !s ) throw TestDBusWrapper::error{}; + Encoder::decode(w, tgt.first, s); + Encoder::decode(w, tgt.second, s); + } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const TestDBusWrapper::Variant &src) { + //w.eldbus_message_iter_arguments_append_impl(tgt, src); + auto var = w.eldbus_message_iter_container_new_impl( tgt, 'v', ""); + Encoder::encode(w, var, src.value); + } + static void decode(TestDBusWrapper &w, TestDBusWrapper::Variant &tgt, const TestDBusWrapper::MessageIterPtr &src) { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, 'v' ); + if( !s ) throw TestDBusWrapper::error{}; + Encoder::decode(w, tgt.value, s); + } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::vector &src) { + auto var = w.eldbus_message_iter_container_new_impl( tgt, 'a', ""); + for(auto &q : src) + Encoder::encode(w, var, q); + } + static void decode(TestDBusWrapper &w, std::vector &tgt, const TestDBusWrapper::MessageIterPtr &src) { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, 'a' ); + if( !s ) throw TestDBusWrapper::error{}; + while(!TestDBusWrapper::completed(s)) { + tgt.push_back({}); + Encoder::decode(w, tgt.back(), s); + } + } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::unordered_map &src) { + auto var = w.eldbus_message_iter_container_new_impl( tgt, 'a', ""); + for(auto &q : src){ + Encoder::value_type>::encode(w, var, q, 'e'); + } + } + static void decode(TestDBusWrapper &w, std::unordered_map &tgt, const TestDBusWrapper::MessageIterPtr &src) { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, 'a' ); + if( !s ) throw TestDBusWrapper::error{}; + while(!TestDBusWrapper::completed(s)) { + std::pair tmp; + Encoder>::decode(w, tmp, s, 'e'); + tgt.insert(std::move(tmp)); + } + } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::array &src) { + auto var = w.eldbus_message_iter_container_new_impl( tgt, 'a', ""); + for(auto &q : src) + Encoder::encode(w, var, q); + } + static void decode(TestDBusWrapper &w, std::array &tgt, const TestDBusWrapper::MessageIterPtr &src) { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, 'a' ); + if( !s ) throw TestDBusWrapper::error{}; + size_t i = 0; + while(!TestDBusWrapper::completed(s)) { + if(i >= tgt.size()) throw TestDBusWrapper::error{}; + Encoder::decode(w, tgt[i], s); + ++i; + } + if( i!=tgt.size()) throw TestDBusWrapper::error{}; + } + }; + template <> struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const Dali::Accessibility::Address &src) { + Encoder>::encode(w, tgt,std::tuple { + src.GetBus(), ObjectPath{ "/org/a11y/atspi/accessible/" + src.GetPath() } } + ); + } + static void decode(TestDBusWrapper &w, Dali::Accessibility::Address &tgt, const TestDBusWrapper::MessageIterPtr &src) { + std::tuple tmp; + Encoder>::decode(w, tmp, src); + static const size_t prefixSize = std::string{ "/org/a11y/atspi/accessible/" }.size(); + tgt = { std::move(std::get<0>(tmp)), std::get<1>(tmp).value.substr(prefixSize) }; + } + }; + template <> struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const char *src) { + Encoder::encode(w, tgt, src); + } + }; +} +/// \endcond + +#define DBUS_DEBUG( ... ) \ + do \ + { \ + DBus::debugPrint( __FILE__, __LINE__, __VA_ARGS__ ); \ + } while( 0 ) + +#define DBUS_W DBusWrapper::Installed() + +/** + * @brief Template based, single file, wrapper library around eldbus for DBUS based communication. + * + * Main motivation was missing asynchronous calls in AT-SPI library and difficulties, + * when using eldbus from C++. + * + * The library: + * - takes care of marshalling arguments to and from DBUS calls. + * - allows synchronous and asynchronous calls. + * - allows synchronous and asynchronous listeners on signals. + * - manages all involved objects' lifetimes. + * - errors are passed as optional-alike objects, no exceptions are used. + * - allows setting additional debug-print function for more details about + * what's going on + * + * DBUS's method signatures (and expected return values) are specified as template argument, + * using functor syntax. For example: + * \code{.cpp} + * auto dbus = DBusClient{ ... }; + * auto v = dbus.method(float, float, std::string)>("foo").call(1.0f, 2.0f, "qwe"); + * \endcode + * means (synchronous) call on dbus object, which takes three arguments (thus making call signature \b dds) + * of types float, float and string (float will be automatically converted to double). + * Expected return value is std::tuple, which gives signature (id) - std::tuple acts + * as struct container. Returned value v will be of type ValueOrError>.\n + * Slightly different (asynchronous) example: + * \code{.cpp} + * auto dbus = DBusClient{ ... }; + * std::function)> callback; + * dbus.method(float, float, std::string)>("foo").asyncCall(callback, 1.0f, 2.0f, "qwe"); + * \endcode + * Now the call takes the same arguments and has the same signature. But expected values are different - + * now the signature is simply \b id. ValueOrError acts in this case as placeholder for list of values, + * which DBUS allows as return data. The call itself is asynchronous - instead of expecting reply + * you need to pass a callback, which will be called either with received data and error message. + * + * Library is not thread-safe, the same object shouldn't be called from different threads without + * synchronization. There's no guarantee, that callbacks will be executed on the same thread. + */ +namespace DBus +{ +/// \cond +class DBusServer; +class DBusClient; +class DBusInterfaceDescription; + +/** + * @brief Formats debug message and calls debug printer (if any) with it + */ +void debugPrint( const char* file, size_t line, const char* format, ... ); + +/** + * @brief Sets debug printer callback, which will be called with debug messages + * + * Callback will be called in various moments of DBus activity. First value passed to callback + * is pointer to text, second it's length. Text is ended with 0 (not counted towards it's size), + * user can safely printf it. + */ +void setDebugPrinter( std::function< void( const char*, size_t ) > ); + +struct Error +{ + std::string message; + + Error() = default; + Error( std::string msg ) : message( std::move( msg ) ) + { + assert( !message.empty() ); + } +}; + +struct Success +{ +}; +/// \endcond + +/** + * @brief Value representing data, that came from DBUS or error message + * + * Object of this class either helds series of values (of types ARGS...) + * or error message. This object will be true in boolean context, if has data + * and false, if an error occured. + * It's valid to create ValueOrError object with empty argument list or void: + * \code{.cpp} + * ValueOrError<> v1; + * ValueOrError v2; + * \endcode + * Both mean the same - ValueOrError containing no real data and being a marker, + * wherever operation successed or failed and containing possible error message. + */ +template < typename... ARGS > +class ValueOrError +{ +public: + /** + * @brief Empty constructor. Valid only, if all ARGS types are default constructible. + */ + ValueOrError() = default; + + /** + * @brief Value constructor. + * + * This will be initialized as success with passed in values. + */ + ValueOrError( ARGS... t ) : value( std::move( t )... ) {} + + /** + * @brief Alternative Value constructor. + * + * This will be initialized as success with passed in values. + */ + ValueOrError( std::tuple< ARGS... > t ) : value( std::move( t ) ) {} + + /** + * @brief Error constructor. This will be initialized as failure with given error message. + */ + ValueOrError( Error e ) : error( std::move( e ) ) + { + assert( !error.message.empty() ); + } + + /** + * @brief bool operator. + * + * Returns true, if operation was successful (getValues member is callable), or false + * when operation failed (getError is callable). + */ + explicit operator bool() const + { + return error.message.empty(); + } + + /** + * @brief Returns error message object. + * + * Returns object containing error message associated with the failed operation. + * Only callable, if operation actually failed, otherwise will assert. + */ + const Error& getError() const + { + return error; + } + + /** + * @brief Returns modifiable tuple of held data. + * + * Returns reference to the internal tuple containing held data. + * User can modify (or move) data safely. + * Only callable, if operation actually successed, otherwise will assert. + */ + std::tuple< ARGS... >& getValues() + { + assert( *this ); + return value; + } + + /** + * @brief Returns const tuple of held data. + * + * Returns const reference to the internal tuple containing held data. + * Only callable, if operation actually successed, otherwise will assert. + */ + const std::tuple< ARGS... >& getValues() const + { + assert( *this ); + return value; + } + +protected: + /// \cond + std::tuple< ARGS... > value; + Error error; + /// \endcond +}; + +/// \cond +template <> +class ValueOrError<> +{ +public: + ValueOrError() = default; + ValueOrError( std::tuple<> t ) {} + ValueOrError( Error e ) : error( std::move( e ) ) + { + assert( !error.message.empty() ); + } + + explicit operator bool() const + { + return error.message.empty(); + } + const Error& getError() const + { + return error; + } + std::tuple<>& getValues() + { + assert( *this ); + static std::tuple<> t; + return t; + } + std::tuple<> getValues() const + { + assert( *this ); + return {}; + } + +protected: + Error error; +}; + +template <> +class ValueOrError< void > +{ +public: + ValueOrError() = default; + ValueOrError( Success ) {} + ValueOrError( Error e ) : error( std::move( e ) ) + { + assert( !error.message.empty() ); + } + + explicit operator bool() const + { + return error.message.empty(); + } + const Error& getError() const + { + return error; + } + std::tuple<>& getValues() + { + assert( *this ); + static std::tuple<> t; + return t; + } + std::tuple<> getValues() const + { + assert( *this ); + return {}; + } + +protected: + Error error; +}; + +using ObjectPath = ObjectPath; + +/// \endcond + +/** + * @brief Class used to marshall DBUS's variant type + * + * Minimalistic class, that allows user to specify DBUS variant type + * as argument or return value. You need to pass real type hidden under variant as + * template type \b A. At this point library doesn't allow to expected one of few classes + * as return data in variant. So for example user can't specify method call, which on return + * expects DBUS variant holding either string or int. + */ +template < typename A > +struct EldbusVariant +{ + A value; +}; + +/** + * @brief Namespace for private, internal functions and classes + */ +namespace detail +{ +/// \cond +template < typename T, typename = void > +struct signature; +template < typename... ARGS > +struct signature< std::tuple< ARGS... > >; +template < typename A, typename B > +struct signature< std::pair< A, B > >; +template < typename A > +struct signature< std::vector< A > >; +template < typename A, size_t N > +struct signature< std::array< A, N > >; +template < typename A, typename B > +struct signature< std::unordered_map< A, B > >; +template < typename A, typename B > +struct signature< std::map< A, B > >; +/// \endcond + +/** + * @brief Signature class for marshalling uint8 type. + */ +template <> +struct signature< uint8_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "uint8_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "y"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, uint8_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, uint8_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling uint16 type. + */ +template <> +struct signature< uint16_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "uint16_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "q"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, uint16_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, uint16_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling uint32 type. + */ +template <> +struct signature< uint32_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "uint32_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "u"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, uint32_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, uint32_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling uint64 type. + */ +template <> +struct signature< uint64_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "uint64_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "t"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, uint64_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, uint64_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling int16 type. + */ +template <> +struct signature< int16_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "int16_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "n"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, int16_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, int16_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling int32 type. + */ +template <> +struct signature< int32_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "int32_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "i"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, int32_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, int32_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling int64 type. + */ +template <> +struct signature< int64_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "int64_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "x"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, int64_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, int64_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling double type. + */ +template <> +struct signature< double > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "double"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "d"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, double v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, double& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, float& v2 ) + { + double v = 0; + auto r = DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + v2 = static_cast< float >( v ); + return r; + } +}; + +/** + * @brief Signature class for marshalling float type. + */ +template <> +struct signature< float > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "float"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "d"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, float v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, double& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, float& v2 ) + { + double v = 0; + auto r = DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + v2 = static_cast< float >( v ); + return r; + } +}; + +/** + * @brief Signature class for marshalling boolean type. + */ +template <> +struct signature< bool > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "bool"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "b"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, bool v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, bool& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +template < typename T > +struct signature< T, typename std::enable_if< std::is_enum< T >::value, void >::type > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "enum"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature::type>::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, T v ) + { + signature::type>::set(iter, static_cast< int64_t >( v )); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, T& v ) + { + typename std::underlying_type::type q = 0; + if (!signature::type>::get(iter, q)) + return false; + + v = static_cast< T >( q ); + return true; + } +}; + +/** + * @brief Signature class for marshalling string type. + * + * Both (const) char * and std::string types are accepted as value to send. + * Only std::string is accepted as value to receive. + */ +template <> +struct signature< std::string > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "string"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "s"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::string& v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + +// /** +// * @brief Marshals value v as marshalled type into message +// */ +// static void set( const DBusWrapper::MessageIterPtr &iter, const char* v ) +// { +// DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); +// } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::string& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +template <> +struct signature< ObjectPath > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "path"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "o"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::string& v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, ObjectPath{ v }); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const ObjectPath& v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const char* v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, ObjectPath{ v }); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, ObjectPath& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::string& v ) + { + ObjectPath q; + if (!DBUS_W->eldbus_message_iter_get_and_next_impl(iter, q)) return false; + v = std::move(q.value); + return true; + } +}; + +/** + * @brief Signature class for marshalling (const) char * type. + * + * Both (const) char * and std::string types are accepted as value to send. + * You can't use (const) char * variable type to receive value. + */ +template <> +struct signature< char* > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "string"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "s"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::string& v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const char* v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, std::string{ v }); + } +}; +/// \cond + +template < size_t INDEX, typename A, typename... ARGS > +struct signature_tuple_element_type_helper +{ + using type = typename signature_tuple_element_type_helper< INDEX - 1, ARGS... >::type; +}; + +template < typename A, typename... ARGS > +struct signature_tuple_element_type_helper< 0, A, ARGS... > +{ + using type = A; +}; +/// \endcond + +/** + * @brief Helper class to marshall tuples + * + * This class marshals all elements of the tuple value starting at the index INDEX + * and incrementing. This class recursively calls itself with increasing INDEX value + * until INDEX is equal to SIZE, where recursive calling ends. + */ +template < size_t INDEX, size_t SIZE, typename... ARGS > +struct signature_tuple_helper +{ + using current_type = typename signature_tuple_element_type_helper< INDEX, ARGS... >::type; + + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + if( INDEX + 1 >= SIZE ) + return signature< current_type >::name(); + return signature< current_type >::name() + ", " + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::name(); + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature< current_type >::sig() + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::tuple< ARGS... >& args ) + { + signature< current_type >::set( iter, std::get< INDEX >( args ) ); + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::set( iter, args ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::tuple< ARGS... >& args ) + { + return signature< current_type >::get( iter, std::get< INDEX >( args ) ) && + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::get( iter, args ); + } +}; + +/** + * @brief Helper class to marshall tuples + * + * This class marks end of the tuple marshalling. Members of this class are called + * when INDEX value is equal to SIZE. + */ +template < size_t SIZE, typename... ARGS > +struct signature_tuple_helper< SIZE, SIZE, ARGS... > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return ""; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return ""; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::tuple< ARGS... >& args ) + { + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::tuple< ARGS... >& args ) + { + return true; + } +}; + +/** + * @brief Signature class for marshalling tuple of values + * + * This class marshalls tuple of values. This represents + * DBUS struct typle, encoded with character 'r' + */ +template < typename... ARGS > +struct signature< std::tuple< ARGS... > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "tuple<" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "(" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::sig() + ")"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::tuple< ARGS... >& args ) + { + auto entry = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'r', ""); + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::set( entry, args ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::tuple< ARGS... >& args ) + { + auto entry = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'r' ); + if (!entry) return false; + return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::get( entry, args ); + } +}; + +/** + * @brief Signature class for marshalling ValueOrError template type + * + * ValueOrError template type is used to marshall list of values passed to + * DBUS (or received from) at the "top" level. For example ss(s) is represented as + * \code{.cpp} ValueOrError> \endcode + * While (ss(s)) is represented as + * \code{.cpp} std::tuple> \endcode + * or + * \code{.cpp} ValueOrError>> \endcode + */ +template < typename... ARGS > +struct signature< ValueOrError< ARGS... > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "ValueOrError<" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const ValueOrError< ARGS... >& args ) + { + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::set( iter, args.getValues() ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, ValueOrError< ARGS... >& args ) + { + return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::get( iter, args.getValues() ); + } +}; + +/** + * @brief Signature class for marshalling ValueOrError type + */ +template <> +struct signature< ValueOrError< void > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "ValueOrError"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return ""; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const ValueOrError< void >& args ) + { + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, ValueOrError< void >& args ) + { + return true; + } +}; + +/** + * @brief Signature class for marshalling ValueOrError<> type + */ +template <> +struct signature< ValueOrError<> > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "ValueOrError<>"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return ""; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const ValueOrError<>& args ) + { + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, ValueOrError<>& args ) + { + return true; + } +}; + +/** + * @brief Signature class for marshalling pair of types + */ +template < typename A, typename B > +struct signature< std::pair< A, B > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "pair<" + signature_tuple_helper< 0, 2, A, B >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "(" + signature_tuple_helper< 0, 2, A, B >::sig() + ")"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::pair< A, B >& ab, bool dictionary = false ) + { + auto entry = DBUS_W->eldbus_message_iter_container_new_impl( iter, dictionary ? 'e' : 'r', ""); + signature_tuple_helper< 0, 2, A, B >::set( entry, ab ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::pair< A, B >& ab ) + { + auto entry = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'r' ); + if (!entry) { + entry = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, '{' ); + if (!entry) return false; + } + + std::tuple< A, B > ab_tmp; + auto z = signature_tuple_helper< 0, 2, A, B >::get( entry, ab_tmp ); + if( z ) + { + ab.first = std::move( std::get< 0 >( ab_tmp ) ); + ab.second = std::move( std::get< 1 >( ab_tmp ) ); + } + return z; + } +}; + +/** + * @brief Signature class for marshalling std::vector template type + * + * This marshals container's content as DBUS a ascii character type code. + */ +template < typename A > +struct signature< std::vector< A > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "vector<" + signature< A >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "a" + signature< A >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::vector< A >& v ) + { + auto lst = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'a', signature< A >::sig()); + assert( lst ); + for( auto& a : v ) + { + signature< A >::set( lst, a ); + } + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::vector< A >& v ) + { + auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'a' ); + if (!s) return false; + v.clear(); + A a; + while( signature< A >::get( s, a ) ) + v.push_back( std::move( a ) ); + + return true; + } +}; + +/** + * @brief Signature class for marshalling std::array template type + * + * This marshals container's content as DBUS a ascii character type code. + */ +template < typename A, size_t N > +struct signature< std::array< A, N > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "array<" + signature< A >::name() + ", " + std::to_string( N ) + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "a" + signature< A >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::array< A, N >& v ) + { + auto lst = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'a', signature< A >::sig()); + assert( lst ); + for( auto& a : v ) + { + signature< A >::set( lst, a ); + } + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::array< A, N >& v ) + { + auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'a' ); + if ( !s ) + return false; + for( auto& a : v ) + { + if( !signature< A >::get( s, a ) ) + return false; + } + return true; + } +}; + +/** + * @brief Signature class for marshalling EldbusVariant type + * + * This marshals variant's content as DBUS v ascii character type code. + */ +template < typename A > +struct signature< EldbusVariant< A > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "variant<" + signature< A >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "v"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const EldbusVariant< A >& v ) + { + set( iter, v.value ); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const A& v ) + { + auto var = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'v', signature< A >::sig()); + signature< A >::set( var, v ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, EldbusVariant< A >& v ) + { + auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'v' ); + if( !s ) + return false; + return signature< A >::get( s, v.value ); + } +}; + +/** + * @brief Signature class for marshalling std::unordered_map template type + * + * This marshals container's content as DBUS {} ascii character type code. + * Note, that library doesnt check, if the key is basic type, as DBUS + * specification mandates. + * User can always exchange std::unordered_map for std::map and the reverse. + * User can receive such values as std::vector of std::pair values. + * Order of such values is unspecified. + */ +template < typename A, typename B > +struct signature< std::unordered_map< A, B > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "unordered_map<" + signature< A >::name() + ", " + signature< B >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "a{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::unordered_map< A, B >& v ) + { + auto sig = "{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}"; + auto lst = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'a', sig); + assert( lst ); + for( auto& a : v ) + { + signature< std::pair< A, B > >::set( lst, a, true ); + } + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::unordered_map< A, B >& v ) + { + auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'a' ); + v.clear(); + if( !s ) + return false; + std::pair< A, B > a; + while( signature< std::pair< A, B > >::get( s, a ) ) + v.insert( std::move( a ) ); + return true; + } +}; + +/** + * @brief Signature class for marshalling std::unordered_map template type + * + * This marshals container's content as DBUS {} ascii character type code. + * Note, that library doesnt check, if the key is basic type, as DBUS + * specification mandates. + * User can always exchange std::unordered_map for std::map and the reverse. + * User can receive such values as std::vector of std::pair values. + * Order of such values is unspecified. + */ +template < typename A, typename B > +struct signature< std::map< A, B > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "map<" + signature< A >::name() + ", " + signature< B >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "a{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::map< A, B >& v ) + { + auto sig = "{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}"; + auto lst = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'a', sig); + assert( lst ); + for( auto& a : v ) + { + signature< std::pair< A, B > >::set( lst, a, true ); + } + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::map< A, B >& v ) + { + auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'a' ); + if( !s ) + return false; + std::pair< A, B > a; + while( signature< std::pair< A, B > >::get( s, a ) ) + v.insert( std::move( a ) ); + return true; + } +}; + +/** + * @brief Signature helper class for marshalling const reference types + */ +template < typename A > +struct signature< const A& > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "const " + signature< A >::name() + "&"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature< A >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const A& v ) + { + signature< A >::set( iter, v ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static void get( const DBusWrapper::MessageIterPtr &iter, A& v ) + { + signature< A >::get( iter, v ); + } +}; + +/** + * @brief Signature helper class for marshalling reference types + */ +template < typename A > +struct signature< A& > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return signature< A >::name() + "&"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature< A >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const A& v ) + { + signature< A >::set( iter, v ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static void get( const DBusWrapper::MessageIterPtr &iter, A& v ) + { + signature< A >::get( iter, v ); + } +}; + +/** + * @brief Signature helper class for marshalling const types + */ +template < typename A > +struct signature< const A > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "const " + signature< A >::name(); + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature< A >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const A& v ) + { + signature< A >::set( iter, v ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static void get( const DBusWrapper::MessageIterPtr &iter, A& v ) + { + signature< A >::get( iter, v ); + } +}; + +/// \cond +using CallId = DBusWrapper::CallId; + +template < typename ValueType > +ValueType unpackValues( CallId callId, const DBusWrapper::MessagePtr &msg ) +{ + auto iter = DBUS_W->eldbus_message_iter_get_impl( msg, false ); + ValueType r; + + if( iter ) + { + if( !signature< ValueType >::get( iter, r ) ) + { + DBUS_DEBUG( "ValueType is %s", signature< ValueType >::name().c_str() ); + r = Error{"call " + std::to_string( callId.id ) + ": failed to unpack values, got signature '" + + DBUS_W->eldbus_message_signature_get_impl( msg ) + "', expected '" + signature< ValueType >::sig() + "'"}; + } + } + else + { + r = Error{"call " + std::to_string( callId.id ) + ": failed to get iterator"}; + } + return r; +} + +inline void packValues_helper( const DBusWrapper::MessageIterPtr& ) {} + +template < typename A, typename... ARGS > +void packValues_helper( const DBusWrapper::MessageIterPtr &iter, A&& a, ARGS&&... r ) +{ + signature< A >::set( iter, std::forward< A >( a ) ); + packValues_helper( iter, std::forward< ARGS >( r )... ); +} + +template < typename... ARGS > +void packValues( CallId callId, const DBusWrapper::MessagePtr &msg, ARGS&&... r ) +{ + auto iter = DBUS_W->eldbus_message_iter_get_impl( msg, true ); + packValues_helper( iter, std::forward< ARGS >( r )... ); +} + +template < typename > +struct ReturnType; +template < typename R, typename... ARGS > +struct ReturnType< R( ARGS... ) > +{ + using type = R; +}; + +template < typename R, typename... ARGS > +struct ReturnType< std::function< R( ARGS... ) > > +{ + using type = R; +}; + +template < int... > +struct sequence +{ +}; + +template < int N, int... S > +struct sequence_gen : sequence_gen< N - 1, N - 1, S... > +{ +}; + +template < int... S > +struct sequence_gen< 0, S... > +{ + typedef sequence< S... > type; +}; + +template < typename C, typename... ARGS > +struct apply_helper +{ + const std::function< C >& c; + const std::tuple< ARGS... >& args; + + template < int... S > + auto apply_2( sequence< S... > ) const -> decltype( c( std::get< S >( args )... ) ) + { + return c( std::get< S >( args )... ); + } + auto apply_1() const -> decltype( apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ) ) + { + return apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ); + } +}; + +template < typename C, typename A, typename... ARGS > +struct apply_helper_2 +{ + const std::function< C >& c; + const A& a; + const std::tuple< ARGS... >& args; + + template < int... S > + auto apply_2( sequence< S... > ) const -> decltype( c( a, std::get< S >( args )... ) ) + { + return c( a, std::get< S >( args )... ); + } + auto apply_1() const -> decltype( apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ) ) + { + return apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ); + } +}; + +template < typename C, typename... ARGS > +auto apply( const std::function< C >& c, const std::tuple< ARGS... >& args ) -> typename ReturnType< C >::type +{ + apply_helper< C, ARGS... > ah{c, args}; + return ah.apply_1(); +} + +template < typename C, typename D, typename... ARGS > +auto apply( const std::function< C >& c, const D& d, const std::tuple< ARGS... >& args ) -> typename ReturnType< C >::type +{ + apply_helper_2< C, D, ARGS... > ah{c, d, args}; + return ah.apply_1(); +} + +struct ConnectionState +{ + DBusWrapper::ConnectionPtr connection; + DBusWrapper::ObjectPtr object; + DBusWrapper::ProxyPtr proxy, propertiesProxy; +}; + +template < typename RETTYPE, typename... ARGS > +RETTYPE call( CallId callId, const ConnectionState& connectionState, bool property, const std::string& funcName, const ARGS&... args ) +{ + const auto &proxy = property ? connectionState.propertiesProxy : connectionState.proxy; + if( !proxy ) + { + DBUS_DEBUG( "call %d: not initialized", callId.id ); + return Error{"not initialized"}; + } + + DBUS_DEBUG( "call %d: calling '%s'", callId.id, funcName.c_str() ); + auto msg = DBUS_W->eldbus_proxy_method_call_new_impl(proxy, funcName); + if( !msg ) + { + DBUS_DEBUG( "call %d: failed", callId.id ); + return Error{"failed to create message"}; + } + + detail::packValues( callId, msg, args... ); + auto reply = DBUS_W->eldbus_proxy_send_and_block_impl( proxy, msg ); + DBUS_DEBUG( "call %d: calling '%s' done", callId.id, funcName.c_str() ); + if( !reply ) + { + DBUS_DEBUG( "call %d: failed", callId.id ); + return Error{"eldbus returned null as reply"}; + } + std::string errname, errmsg; + if( DBUS_W->eldbus_message_error_get_impl( reply, errname, errmsg ) ) + { + DBUS_DEBUG( "call %d: %s: %s", callId.id, errname.c_str(), errmsg.c_str() ); + return Error{errname + ": " + errmsg}; + } + DBUS_DEBUG( "call %d: got reply with signature '%s'", callId.id, + DBUS_W->eldbus_message_signature_get_impl( reply ).c_str() ); + return detail::unpackValues< RETTYPE >( callId, reply ); +} + +template < typename RETTYPE, typename... ARGS > +void asyncCall( CallId callId, const ConnectionState &connectionState, + bool property, const std::string& funcName, + std::function< void( RETTYPE ) > callback, const ARGS&... args ) +{ + const auto &proxy = property ? connectionState.propertiesProxy : connectionState.proxy; + if( !proxy ) + { + DBUS_DEBUG( "call %d: not initialized", callId.id ); + callback( Error{"not initialized"} ); + return; + } + + auto msg = DBUS_W->eldbus_proxy_method_call_new_impl( proxy, funcName ); + if( !msg ) + { + DBUS_DEBUG( "call %d: failed", callId.id ); + callback( Error{"failed to create message"} ); + return; + } + + detail::packValues( callId, msg, args... ); + auto pending = DBUS_W->eldbus_proxy_send_impl( proxy, msg, [callback, callId, proxy]( const DBusWrapper::MessagePtr &reply ) { + DBUS_DEBUG( "call %d: calling done", callId.id ); + if( !reply ) + { + DBUS_DEBUG( "call %d: failed", callId.id ); + callback( Error{"eldbus returned null as reply"} ); + } + else + { + std::string errname, errmsg; + if( DBUS_W->eldbus_message_error_get_impl( reply, errname, errmsg ) ) + { + DBUS_DEBUG( "call %d: %s: %s", callId.id, errname.c_str(), errmsg.c_str() ); + callback( Error{errname + ": " + errmsg} ); + } + else + { + DBUS_DEBUG( "call %d: got reply with signature '%s'", callId.id, + DBUS_W->eldbus_message_signature_get_impl( reply ).c_str() ); + callback( detail::unpackValues< RETTYPE >( callId, reply ) ); + } + } + } + ); + if( pending ) + { + DBUS_DEBUG( "call %d: call sent", callId.id ); + } + else + { + DBUS_DEBUG( "call %d: failed to send call", callId.id ); + callback( Error{"failed to send call"} ); + } +} + +inline void displayDebugCallInfo( CallId callId, const std::string& funcName, const std::string& info, const std::string& interfaceName ) +{ + DBUS_DEBUG( "call %d: %s iname = %s fname = %s", callId.id, info.c_str(), interfaceName.c_str(), funcName.c_str() ); +} + +inline void displayDebugCallInfoSignal( CallId callId, const std::string& funcName, const std::string& info, const std::string& interfaceName ) +{ + DBUS_DEBUG( "call %d: %s signal iname = %s fname = %s", callId.id, info.c_str(), interfaceName.c_str(), funcName.c_str() ); +} + +inline void displayDebugCallInfoProperty( CallId callId, const std::string& funcName, std::string info, const std::string& interfaceName, + const std::string& propertyName ) +{ + DBUS_DEBUG( "call %d: %s iname = %s pname = %s", callId.id, info.c_str(), interfaceName.c_str(), propertyName.c_str() ); +} + +using StringStorage = DBusWrapper::StringStorage; + +template < typename A, typename... ARGS > +struct EldbusArgGenerator_Helper +{ + static void add( std::vector< std::pair >& r ) + { + auto s = r.size(); + auto sig = signature< A >::sig(); + assert( !sig.empty() ); + auto name = "p" + std::to_string( s + 1 ); + r.push_back({ std::move(sig), std::move(name) }); + EldbusArgGenerator_Helper::add( r ); + } +}; + +template <> +struct EldbusArgGenerator_Helper< void > +{ + static void add( std::vector< std::pair >& ) + { + } +}; + +template <> +struct EldbusArgGenerator_Helper< ValueOrError< void >, void > +{ + static void add( std::vector< std::pair >& ) + { + } +}; +template <> +struct EldbusArgGenerator_Helper< ValueOrError<>, void > +{ + static void add( std::vector< std::pair >& ) + { + } +}; + +template < typename... ARGS > +struct EldbusArgGenerator_Helper< std::tuple< ARGS... > > +{ + static void add( std::vector< std::pair >& r ) + { + EldbusArgGenerator_Helper< ARGS..., void >::add( r ); + } +}; + +template < typename RetType > +struct dbus_interface_return_type_traits +{ + using type = ValueOrError< RetType >; +}; + +template < typename... ARGS > +struct dbus_interface_return_type_traits< ValueOrError< ARGS... > > +{ + using type = ValueOrError< ARGS... >; +}; + +template < typename T > +struct dbus_interface_traits; +template < typename RetType, typename... ARGS > +struct dbus_interface_traits< RetType( ARGS... ) > +{ + using Ret = typename dbus_interface_return_type_traits< RetType >::type; + using SyncCB = std::function< Ret( ARGS... ) >; + using AsyncCB = std::function< void( std::function< void( Ret ) >, ARGS... ) >; + using VEArgs = ValueOrError< ARGS... >; +}; + +template < typename T > +struct EldbusArgGenerator_Args; +template < typename RetType, typename... ARGS > +struct EldbusArgGenerator_Args< RetType( ARGS... ) > +{ + static std::string name() + { + return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name(); + } + static std::vector< std::pair > get() + { + std::vector< std::pair > tmp; + EldbusArgGenerator_Helper< ARGS..., void >::add( tmp ); + return tmp; + } +}; + +template < typename T > +struct EldbusArgGenerator_ReturnType; +template < typename RetType, typename... ARGS > +struct EldbusArgGenerator_ReturnType< RetType( ARGS... ) > +{ + static std::string name() + { + return signature< RetType >::name(); + } + static std::vector< std::pair > get( ) + { + std::vector< std::pair > tmp; + EldbusArgGenerator_Helper< RetType, void >::add( tmp ); + return tmp; + } +}; + +template < typename T > +struct EldbusArgGenerator_ReturnType; +template < typename... ARGS > +struct EldbusArgGenerator_ReturnType< void( ARGS... ) > +{ + static std::string name() + { + return ""; + } + static std::vector< std::pair > get( ) + { + return {}; + } +}; +/// \endcond +} + +using ConnectionType = DBusWrapper::ConnectionType; + +/** + * @brief Class representing client's end of DBUS connection + * + * Allows calling (synchronous and asynchronos) methods on selected interface + * Allows (synchronous and asynchronos) setting / getting properties. + * Allows registering signals. + */ +class DBusClient +{ + /// \cond + struct ConnectionInfo + { + std::string interfaceName, busName, pathName; + }; + /// \endcond +public: + /** + * @brief Default constructor, creates non-connected object. + */ + DBusClient() = default; + + /** + * @brief Connects to dbus choosen by tp, using given arguments + * + * @param bus_name name of the bus to connect to + * @param path_name object's path + * @param interface_name interface name + */ + DBusClient( std::string busName_, std::string pathName_, std::string interfaceName_, + ConnectionType tp ); + + /** + * @brief Connects to dbus using connection conn + * + * @param bus_name name of the bus to connect to + * @param path_name object's path + * @param interface_name interface name + * @param conn connection object from getDBusConnectionByType call + */ + DBusClient( std::string busName_, std::string pathName_, std::string interfaceName_, + const DBusWrapper::ConnectionPtr &conn = {} ); + + /** + * @brief Destructor object. + * + * All signals added will be disconnected. + * All asynchronous calls will be cancelled, their callback's will be called + * with failure message. + */ + ~DBusClient() = default; + DBusClient( const DBusClient& ) = delete; + DBusClient( DBusClient&& ) = default; + + DBusClient& operator=( DBusClient&& ) = default; + DBusClient& operator=( const DBusClient& ) = delete; + + /** + * @brief bool operator + * + * Returns true, if object is connected to DBUS + */ + explicit operator bool() const + { + return bool( connectionState->proxy ); + } + + /** + * @brief Helper class for calling a method + * + * Template type T defines both arguments sent to the method + * and expected values. Receiving different values will be reported as + * error. For example: + * \code{.cpp} Method \endcode + * defines method, which takes two arguments (two floats) and return + * single value of type int. + */ + template < typename T > + struct Method + { + /// \cond + using RetType = typename detail::dbus_interface_traits< T >::Ret; + const detail::ConnectionState &connectionState; + std::string funcName; + std::string info; + std::shared_ptr< ConnectionInfo > connectionInfo; + /// \endcond + + /** + * @brief Executes synchronous call on DBUS's method + * + * The function returns ValueOrError<...> object, which + * contains either received values or error message. + * + * @param args arguments to pass to the method + */ + template < typename... ARGS > + RetType call( const ARGS&... args ) + { + detail::CallId callId; + detail::displayDebugCallInfo( callId, funcName, info, connectionInfo->interfaceName ); + return detail::call< RetType >( callId, connectionState, false, funcName, args... ); + } + + /** + * @brief Executes asynchronous call on DBUS's method + * + * The function calls callback with either received values or error message. + * + * @param callback callback functor, which will be called with return value(s) or error message + * @param args arguments to pass to the method + */ + template < typename... ARGS > + void asyncCall( std::function< void( RetType ) > callback, const ARGS&... args ) + { + detail::CallId callId; + detail::displayDebugCallInfo( callId, funcName, info, connectionInfo->interfaceName ); + detail::asyncCall< RetType >( callId, connectionState, false, funcName, std::move( callback ), args... ); + } + }; + + /** + * @brief Helper class for calling a property + * + * Template type T defines type of the value hidden under property. + * Note, that library automatically wraps both sent and received value into + * DBUS's wrapper type. + */ + template < typename T > + struct Property + { + /// \cond + using RetType = typename detail::dbus_interface_return_type_traits< T >::type; + using VariantRetType = typename detail::dbus_interface_return_type_traits< EldbusVariant< T > >::type; + const detail::ConnectionState &connectionState; + std::string propName; + std::string info; + std::shared_ptr< ConnectionInfo > connectionInfo; + /// \endcond + + /** + * @brief executes synchronous get on property + * + * The function returns ValueOrError<...> object, which + * contains either received values or error message. + */ + RetType get() + { + detail::CallId callId; + detail::displayDebugCallInfoProperty( callId, "Get", info, connectionInfo->interfaceName, propName ); + auto z = detail::call< VariantRetType >( callId, connectionState, true, "Get", connectionInfo->interfaceName, propName ); + if( !z ) + return z.getError(); + return {std::get< 0 >( z.getValues() ).value}; + } + + /** + * @brief executes asynchronous get on property + * + * The function calls callback with either received values or error message. + * + * @param callback callback functor, which will be called with return value(s) or error message + */ + void asyncGet( std::function< void( RetType ) > callback ) + { + detail::CallId callId; + detail::displayDebugCallInfoProperty( callId, "Get", info, connectionInfo->interfaceName, propName ); + auto cc = [callback]( VariantRetType reply ) { + if( reply ) + callback( std::move( std::get< 0 >( reply.getValues() ).value ) ); + else + callback( reply.getError() ); + }; + detail::asyncCall< VariantRetType >( callId, connectionState, true, "Get", std::move( cc ), connectionInfo->interfaceName, propName ); + } + + /** + * @brief executes synchronous set on property + * + * The function returns ValueOrError object, with + * possible error message. + */ + ValueOrError< void > set( const T& r ) + { + detail::CallId callId; + detail::displayDebugCallInfoProperty( callId, "Set", info, connectionInfo->interfaceName, propName ); + EldbusVariant< T > variantValue{std::move( r )}; + return detail::call< ValueOrError< void > >( callId, connectionState, true, "Set", connectionInfo->interfaceName, propName, variantValue ); + } + + /** + * @brief executes asynchronous get on property + * + * The function calls callback with either received values or error message. + * + * @param callback callback functor, which will be called with return value(s) or error message + */ + void asyncSet( std::function< void( ValueOrError< void > ) > callback, const T& r ) + { + detail::CallId callId; + detail::displayDebugCallInfoProperty( callId, "Set", info, connectionInfo->interfaceName, propName ); + EldbusVariant< T > variantValue{std::move( r )}; + detail::asyncCall< ValueOrError< void > >( callId, connectionState, true, "Set", std::move( callback ), connectionInfo->interfaceName, propName, variantValue ); + } + }; + + /** + * @brief Constructs Property<...> object for calling properties + * + * The function constructs and returns proxy object for calling property. + * + * @param propName property name to set and / or query + */ + template < typename PropertyType > + Property< PropertyType > property( std::string propName ) + { + return Property< PropertyType >{*connectionState, std::move( propName ), info, connectionInfo}; + } + + /** + * @brief Constructs Method<...> object for calling methods + * + * The function constructs and returns proxy object for calling method. + * + * @param funcName function name to call + */ + template < typename MethodType > + Method< MethodType > method( std::string funcName ) + { + return Method< MethodType >{*connectionState, std::move( funcName ), info, connectionInfo}; + } + + /** + * @brief Registers notification callback, when property has changed + * + * The callback will be called with new value, when property's value has changed. + * Note, that template type V must match expected type, otherwise undefined behavior will occur, + * there's no check for this. + */ + template < typename V > + void addPropertyChangedEvent( std::string propertyName, std::function< void( V ) > callback ) + { + detail::CallId callId; + detail::displayDebugCallInfoSignal( callId, propertyName, info, connectionInfo->interfaceName ); + DBUS_DEBUG( "call %d: adding property", callId.id ); + auto &cI = this->connectionInfo; + DBUS_W->add_property_changed_event_listener_impl(connectionState->proxy, cI->interfaceName, propertyName, + [callback]( const _Eina_Value *newValue ) { + V val = 0; + if( !getFromEinaValue( newValue, &val ) ) + { + DBUS_DEBUG( "unable to get property's value" ); + return; + } + callback( val ); + }); + } + + /** + * @brief Registers callback on the DBUS' signal + * + * The function registers callback signalName. When signal comes, callback will be called. + * Callback object will exists as long as signal is registered. You can unregister signal + * by destroying DBusClient object. + * + * @param signalName name of the signal to register + * @param callback callback to call + */ + template < typename SignalType > + void addSignal( std::string signalName, std::function< SignalType > callback ) + { + detail::CallId callId; + detail::displayDebugCallInfoSignal( callId, signalName, info, connectionInfo->interfaceName ); + DBUS_W->eldbus_proxy_signal_handler_add_impl( connectionState->proxy, signalName, + [callId, callback, signalName]( const DBusWrapper::MessagePtr &msg ) -> void { + std::string errname, aux; + if( DBUS_W->eldbus_message_error_get_impl( msg, errname, aux ) ) + { + DBUS_DEBUG( "call %d: Eldbus error: %s %s", callId.id, errname.c_str(), aux.c_str() ); + return; + } + DBUS_DEBUG( "call %d: received signal with signature '%s'", callId.id, DBUS_W->eldbus_message_signature_get_impl( msg ).c_str() ); + using ParamsType = typename detail::dbus_interface_traits< SignalType >::VEArgs; + auto params = detail::unpackValues< ParamsType >( callId, msg ); + if( !params ) + { + DBUS_DEBUG( "call %d: failed: %s", callId.id, params.getError().message.c_str() ); + return; + } + try + { + detail::apply( callback, params.getValues() ); + } + catch( ... ) + { + DBUS_DEBUG( "unhandled exception" ); + assert( 0 ); + } + }); + } + +private: + /// \cond + std::unique_ptr connectionState{ new detail::ConnectionState }; + std::string info; + std::shared_ptr< ConnectionInfo > connectionInfo; + + static bool getFromEinaValue(const _Eina_Value *v, void *dst); + /// \endcond +}; + +/** + * @brief Helper class describing DBUS's server interface + * + */ +class DBusInterfaceDescription +{ + friend class DBusServer; + +public: + /// \cond + using MethodInfo = DBusWrapper::MethodInfo; + using SignalInfo = DBusWrapper::SignalInfo; + using PropertyInfo = DBusWrapper::PropertyInfo; + using SignalId = DBusWrapper::SignalId; + /// \endcond + + /** + * @brief Creates empty interface description with given name + * + * @param interfaceName name of the interface + */ + DBusInterfaceDescription( std::string interfaceName ); + + /** + * @brief adds new, synchronous method to the interface + * + * When method memberName is called on DBUS, callback functor will be called + * with values received from DBUS. callback won't be called, if method was + * called with invalid signature. Value returned from functor (or error message) + * will be marshalled back to the caller. + * + * Template type T defines both arguments sent to the method + * and expected values. Receiving different values will be reported as + * error. For example: + * \code{.cpp} Method \endcode + * defines method, which takes two arguments (two floats) and return + * single value of type int. + * + * @param memberName name of the method + * @param callback functor, which will be called + */ + template < typename T > + void addMethod( const std::string& memberName, typename detail::dbus_interface_traits< T >::SyncCB callback ) + { + detail::CallId callId; + MethodInfo mi; + methods.push_back( std::move( mi ) ); + auto& z = methods.back(); + z.in = detail::EldbusArgGenerator_Args< T >::get( ); + z.out = detail::EldbusArgGenerator_ReturnType< T >::get( ); + z.memberName = memberName; + DBUS_DEBUG( "call %d: method %s, in %s, out %s", callId.id, memberName.c_str(), + detail::EldbusArgGenerator_Args< T >::name().c_str(), + detail::EldbusArgGenerator_ReturnType< T >::name().c_str() ); + z.callback = construct< T >( callId, callback ); + z.id = callId; + } + + /** + * @brief adds new, synchronous property to the interface + * + * When property memberName is called on DBUS, respective callback functor will be called + * with values received from DBUS. callback won't be called, if method was + * called with invalid signature. Value returned from functor (or error message) + * will be marshalled back to the caller. + * + * Template type T defines type of the value hidden under property. + * Note, that library automatically wraps both sent and received value into + * DBUS's wrapper type. + * + * @param memberName name of the method + * @param getter functor, which will be called when property is being read + * @param setter functor, which will be called when property is being set + */ + template < typename T > + void addProperty( const std::string& memberName, std::function< ValueOrError< T >() > getter, std::function< ValueOrError< void >( T ) > setter ) + { + properties.push_back( {} ); + auto& z = properties.back(); + z.memberName = memberName; + z.typeSignature = detail::signature< T >::sig(); + if( getter ) + { + detail::CallId getterId; + z.getterId = getterId; + DBUS_DEBUG( "call %d: property %s (get) type %s", getterId.id, memberName.c_str(), detail::signature< T >::name().c_str() ); + z.getCallback = [=]( const DBusWrapper::MessagePtr &src, const DBusWrapper::MessageIterPtr &dst ) -> std::string { + try + { + auto v = detail::apply( getter, std::tuple<>{} ); + if( v ) + { + detail::signature< T >::set( dst, std::get< 0 >( v.getValues() ) ); + DBUS_DEBUG( "call %d: success", getterId.id ); + return ""; + } + DBUS_DEBUG( "call %d: failed: %s", getterId.id, v.getError().message.c_str() ); + return v.getError().message; + } + catch( std::exception& e ) + { + return std::string( "unhandled exception (" ) + e.what() + ")"; + } + catch( ... ) + { + return "unhandled exception"; + } + }; + } + if( setter ) + { + detail::CallId setterId; + z.setterId = setterId; + DBUS_DEBUG( "call %d: property %s (set) type %s", setterId.id, memberName.c_str(), detail::signature< T >::name().c_str() ); + z.setCallback = [=]( const DBusWrapper::MessagePtr &src, const DBusWrapper::MessageIterPtr &src_iter ) -> std::string { + std::tuple< T > value; + auto src_signature = DBUS_W->eldbus_message_iter_signature_get_impl( src_iter ); + if( detail::signature< T >::get( src_iter, std::get< 0 >( value ) ) ) + { + try + { + auto v = detail::apply( setter, std::move( value ) ); + if( v ) + { + DBUS_DEBUG( "call %d: success", setterId.id ); + return ""; + } + DBUS_DEBUG( "call %d: failed: %s", setterId.id, v.getError().message.c_str() ); + return v.getError().message; + } + catch( std::exception& e ) + { + return std::string( "unhandled exception (" ) + e.what() + ")"; + } + catch( ... ) + { + return "unhandled exception"; + } + } + DBUS_DEBUG( "call %d: failed to unpack values, got signature '%s', expected '%s'", setterId.id, + src_signature.c_str(), detail::signature< T >::sig().c_str() ); + return "call " + std::to_string( setterId.id ) + ": failed to unpack values, got signature '" + + src_signature + "', expected '" + detail::signature< T >::sig() + "'"; + }; + } + } + + /** + * @brief adds new signal to the interface + * + * Template types ARGS defines values, which will be emited with the signal + * + * @param memberName name of the method + */ + template < typename... ARGS > + SignalId addSignal( const std::string& memberName ) + { + detail::CallId callId; + signals.push_back( {} ); + auto& z = signals.back(); + z.memberName = memberName; + z.args = detail::EldbusArgGenerator_Args< void( ARGS... ) >::get( DBUS_W->Strings ); + z.id = callId; + DBUS_DEBUG( "call %d: signal %s", callId.id, memberName.c_str() ); + return SignalId{callId}; + } + +private: + /// \cond + std::vector< MethodInfo > methods; + std::vector< PropertyInfo > properties; + std::vector< SignalInfo > signals; + std::string interfaceName; + + template < typename T > + std::function< DBusWrapper::MessagePtr( const DBusWrapper::MessagePtr &msg ) > construct( detail::CallId callId, + typename detail::dbus_interface_traits< T >::SyncCB callback ) + { + using VEArgs = typename detail::dbus_interface_traits< T >::VEArgs; + return [=]( const DBusWrapper::MessagePtr &msg ) -> DBusWrapper::MessagePtr { + DBUS_DEBUG( "call %d: entering", callId.id ); + DBusWrapper::MessagePtr ret = {}; + auto args = detail::unpackValues< VEArgs >( callId, msg ); + if( args ) + { + try + { + auto v = detail::apply( callback, std::move( args.getValues() ) ); + if( v ) + { + DBUS_DEBUG( "call %d: success", callId.id ); + ret = DBUS_W->eldbus_message_method_return_new_impl( msg ); + detail::packValues( callId, ret, v ); + } + else + { + DBUS_DEBUG( "call %d: failed: %s", callId.id, v.getError().message.c_str() ); + ret = DBUS_W->eldbus_message_error_new_impl( msg, "org.freedesktop.DBus.Error.Failed", v.getError().message ); + } + } + catch( std::exception& e ) + { + auto txt = std::string( "unhandled exception (" ) + e.what() + ")"; + DBUS_DEBUG( "call %d: failed: %s", callId.id, txt.c_str() ); + ret = DBUS_W->eldbus_message_error_new_impl( msg, "org.freedesktop.DBus.Error.Failed", txt ); + } + catch( ... ) + { + DBUS_DEBUG( "call %d: failed: %s", callId.id, "unhandled exception" ); + ret = DBUS_W->eldbus_message_error_new_impl( msg, "org.freedesktop.DBus.Error.Failed", "unhandled exception" ); + } + } + else + { + std::ostringstream err; + err << "expected signature '" << detail::signature< VEArgs >::sig() << "', got '" << DBUS_W->eldbus_message_signature_get_impl( msg ) << "'"; + auto str = err.str(); + DBUS_DEBUG( "call %d: failed: %s", callId.id, str.c_str() ); + ret = DBUS_W->eldbus_message_error_new_impl( msg, "org.freedesktop.DBus.Error.InvalidArgs", str ); + } + return ret; + }; + } + /// \endcond +}; + +/** + * @brief Class representing server's end of DBUS connection + * + * Allows listening (synchronously and asynchronosly) on methods on selected interface + * Allows listening (synchronously and asynchronosly) on setting / getting properties. + * Allows emiting signals. + */ +class DBusServer +{ +public: + /** + * @brief Constructs non-connected dbus server. + */ + DBusServer() = default; + + /** + * @brief Constructs dbus server on either system or user dbus connection. + */ + DBusServer( ConnectionType tp ); + + /** + * @brief Constructs dbus server on connection from getDBusConnectionByType + */ + DBusServer( const DBusWrapper::ConnectionPtr &conn ); + + /** + * @brief Destructor + * + * Destructor will properly destroy everything. Destructor will cancel + * pending replies. + */ + ~DBusServer() = default; + + DBusServer( const DBusServer& ) = delete; + DBusServer( DBusServer&& ) = default; + + DBusServer& operator=( DBusServer&& ) = default; + DBusServer& operator=( const DBusServer& ) = delete; + + /** + * @brief Registers interface on given path name + * + * @param pathName path object to register interface on. + * @param dscr + * @param fallback + */ + void addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback = false ); + + /** + * @brief Gets bus name of the current connection (must be connected) + */ + std::string getBusName() const; + + /** + * @brief Returns connection object for this dbus server object + * + * @return connection object + */ + DBusWrapper::ConnectionPtr getConnection(); + + /** + * @brief Emits signal + * + * Emits signal based only on data passed to the function + * + * @param signal identifier of the signal + * @param args values to emit + */ + template < typename... ARGS > + void emit2( const std::string& path, const std::string& interfaceName, + const std::string& signalName, const ARGS&... args ) + { + auto msg = DBUS_W->eldbus_message_signal_new_impl( path, interfaceName, signalName ); + detail::CallId id; + detail::packValues( id, msg, args... ); + DBUS_W->eldbus_connection_send_impl( connection, msg ); + } + + /** + * @brief Returns current object path, when handling call to property / method + * + * User can call this function from inside callback used to handle property / method calls. + * It will retrieve object's path used in the call. Note, that in asynchronous handling + * of those calls user need to retrieve and store the current object / current connection + * as the value will change at the moment user's callback handling will exit. For example: + * \code{.cpp} + * DBusInterfaceDescription interface{"name"}; + * auto handler_later = [](std::function done_cb) { + * // process something later on + * DBusServer::getCurrentObjectPath(); // this will return empty string + * }; + * interface.addAsyncMethod("m", [=](std::function done_cb) { + * DBusServer::getCurrentObjectPath(); // this will current object's path + * + * // do some processing later on and call done_cb, when it's done + * register_to_call_sometime_later_on(std::move(done_cb)); + * }; + * \endcode + */ + static std::string getCurrentObjectPath() { return currentObjectPath; } + + /** + * @brief Returns current connection object, when handling call to property / method + * + * User can call this function from inside callback used to handle property / method calls. + * It will retrieve object's path used in the call. Note, that in asynchronous handling + * of those calls user need to retrieve and store the current object / current connection + * as the value will change at the moment user's callback handling will exit. For example: + * \code{.cpp} + * DBusInterfaceDescription interface{"name"}; + * auto handler_later = [](std::function done_cb) { + * // process something later on + * DBusServer::getCurrentObjectPath(); // this will return empty string + * }; + * interface.addAsyncMethod("m", [=](std::function done_cb) { + * DBusServer::getCurrentObjectPath(); // this will current object's path + * + * // do some processing later on and call done_cb, when it's done + * register_to_call_sometime_later_on(std::move(done_cb)); + * }; + * \endcode + */ + static const DBusWrapper::ConnectionPtr &getCurrentConnection() { return currentConnection; } + + /// \cond + class CurrentObjectSetter + { + public: + CurrentObjectSetter( DBusWrapper::ConnectionPtr con, std::string path ) + { + currentObjectPath = std::move(path); + currentConnection = std::move( con ); + } + ~CurrentObjectSetter() + { + currentObjectPath = ""; + currentConnection = {}; + } + CurrentObjectSetter( const CurrentObjectSetter& ) = delete; + CurrentObjectSetter( CurrentObjectSetter&& ) = delete; + void operator=( const CurrentObjectSetter& ) = delete; + void operator=( CurrentObjectSetter&& ) = delete; + }; + /// \endcond + +private: + /// \cond + DBusWrapper::ConnectionPtr connection; + struct DestructorObject { + std::vector> destructors; + ~DestructorObject() { + for(auto &a : destructors) a(); + } + }; + + std::unique_ptr destructorObject { new DestructorObject() }; + static thread_local std::string currentObjectPath; + static thread_local DBusWrapper::ConnectionPtr currentConnection; + + /// \endcond +}; + +/// \cond +DBusWrapper::ConnectionPtr getDBusConnectionByType( ConnectionType tp ); +DBusWrapper::ConnectionPtr getDBusConnectionByName( const std::string& name ); +std::string getConnectionName( const DBusWrapper::ConnectionPtr& ); +/// \endcond +} + +/// \cond +namespace std +{ +template < size_t INDEX, typename... ARGS > +inline auto get( DBus::ValueOrError< ARGS... >& v ) -> decltype( std::get< INDEX >( v.getValues() ) ) & +{ + return std::get< INDEX >( v.getValues() ); +} + +template < size_t INDEX, typename... ARGS > +inline auto get( const DBus::ValueOrError< ARGS... >& v ) -> decltype( std::get< INDEX >( v.getValues() ) ) +{ + return std::get< INDEX >( v.getValues() ); +} +} +/// \endcond + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_H diff --git a/dali/internal/accessibility/bridge/optional.h b/dali/internal/accessibility/bridge/optional.h new file mode 100644 index 0000000..dffc3a6 --- /dev/null +++ b/dali/internal/accessibility/bridge/optional.h @@ -0,0 +1,283 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_OPTIONAL_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_OPTIONAL_H + +/* + * Copyright 2019 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 +#include +#include +#include + +/** + * Minimalistic implementation of standard library std::optional (c++17) for c++11 compiler. + * + * After project conversion to C++17 standard, this template class will be deleted and + * Optional will point to std::optional. + * + * Allowed operations (note, to make code simplier, than original, value class must have accessible copy and move constructor): + * - constructing empty (valueless) object + * - copying Optional (with and without value) + * - moving Optional (with and without value) + * - querying, if Optional has value (via explicit operator bool), for example: + * Optional v = ...; + * if (v) ... // if v has value, then do something + * - accessing value (via operator *), for example: + * Optional v = ...; + * auto z = *v; // z now has the same int, as v (copied) + * auto &y = *v; // y now has REFERENCE to int inside v, so modifying y modifies v + */ + +template < typename A > +class Optional +{ + /// \cond + union + { + A place; + }; + bool hasValue = false; + /// \endcond + +public: + /** + * @brief Empty constructor. + * Creates empty Optional object, which will be false in boolean context. + * So: + * \code{.cpp} + * Optional o; + * if (o) printf("1\n"); + * \endcode + * won't print 1. + */ + Optional() {} + + /** + * @brief Single element constructor, when implicit convertion can be applied. + * + * This constructor will be selected, when type of given argument (U) is + * implicitly convertable to expected type A. In other words following + * code must be valid: + * \code{.cpp} + * A foo() { + * return U(); + * } + * \endcode + * + * @param a value held by Optional object will be initialized from a. + */ + template < typename U = A, typename std::enable_if< + std::is_convertible< U&&, A >::value && + std::is_constructible< A, U&& >::value && + !std::is_same< typename std::decay< U >::type, Optional< A > >::value, + int* >::type = nullptr > + constexpr Optional( U&& a ) + : place( std::forward< U >( a ) ), hasValue( true ) + { + } + + /** + * @brief Single element constructor, when only explicit convertion can be applied. + * + * This constructor will be selected, when type of given argument (U) is + * convertable to expected type A. + * + * @param a value held by Optional object will be initialized from a. + */ + template < typename U = A, typename std::enable_if< + !std::is_convertible< U&&, A >::value && + std::is_constructible< A, U&& >::value && + !std::is_same< typename std::decay< U >::type, Optional< A > >::value, + int* >::type = nullptr > + explicit constexpr Optional( U&& a ) + : place( std::forward< U >( a ) ), hasValue( true ) + { + } + + /** + * @brief Copy constructor. + * + * @param v Optional value to copy from. Will cause to copy data held by object v, + * if v has data. + */ + Optional( const Optional& v ) : hasValue( v.hasValue ) + { + if( hasValue ) + new( &place ) A( v.place ); + } + + /** + * @brief Move constructor. + * + * @param v Optional value to copy from. Will move data help by v, if any. + * After construction \code{.cpp} bool(v) \endcode will be false. + */ + Optional( Optional&& v ) : hasValue( v.hasValue ) + { + if( hasValue ) + new( &place ) A( std::move( v.place ) ); + } + + /** + * @brief Destructor. + */ + ~Optional() + { + if( hasValue ) + { + place.~A(); + } + } + + /** + * @brief Explicit bool operator + * + * Will return true if and only if object is helding data. + */ + explicit operator bool() const + { + return hasValue; + } + + /** + * @brief Accessor (*) operator + * + * Will return modifiable reference to held object. Will assert, if not object is held. + */ + A& operator*() + { + assert( hasValue ); + return place; + } + + /** + * @brief Accessor (*) const operator + * + * Will return const reference to held object. Will assert, if not object is held. + */ + const A& operator*() const + { + assert( hasValue ); + return place; + } + + /** + * @brief Accessor (->) operator + * + * Will return pointer to held object allowing access to the value's members. + * Will assert, if not object is held. + */ + A* operator->() + { + assert( hasValue ); + return &place; + } + + /** + * @brief Accessor (->) operator + * + * Will return pointer to (const) held object allowing access to the value's members. + * Will assert, if not object is held. + */ + const A* operator->() const + { + assert( hasValue ); + return &place; + } + + /** + * @brief Assignment operator + * + * Will copy held value from v, if any. + * + * @param v Value to copy from + */ + Optional& operator=( const Optional& v ) + { + if( this != &v ) + { + if( hasValue != v.hasValue ) + { + if( v.hasValue ) + new( &place ) A( v.place ); + else + place.~A(); + hasValue = v.hasValue; + } + else if( hasValue ) + { + place = v.place; + } + } + return *this; + } + + /** + * @brief Assignment move operator + * + * Will move held value from v, if any. In all cases v won't held a value + * after assignment is done. + * + * @param v Value to copy from + */ + Optional& operator=( Optional&& v ) + { + if( this != &v ) + { + if( hasValue != v.hasValue ) + { + if( v.hasValue ) + new( &place ) A( std::move( v.place ) ); + else + place.~A(); + hasValue = v.hasValue; + } + else if( hasValue ) + { + place = std::move( v.place ); + } + } + return *this; + } + + /** + * @brief Assignment operator from value of type held. + * + * Will initialize held value from given parameter a. + * Type of the parameter must be the same (barring cv convertions), + * as the type of the value held. + * + * @param a Value to copy from + */ + template < class U, class = typename std::enable_if< + std::is_same< typename std::remove_reference< U >::type, A >::value && + std::is_constructible< A, U >::value && + std::is_assignable< A&, U >::value >::type > + Optional& operator=( U&& a ) + { + if( hasValue ) + place = std::forward< U >( a ); + else + { + hasValue = true; + new( &place ) A( std::forward< U >( a ) ); + } + return *this; + } +}; + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_OPTIONAL_H diff --git a/dali/internal/accessibility/common/accessibility-adaptor-impl.cpp b/dali/internal/accessibility/common/accessibility-adaptor-impl.cpp deleted file mode 100644 index d3eb43b..0000000 --- a/dali/internal/accessibility/common/accessibility-adaptor-impl.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* - * Copyright (c) 2019 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 - -// EXTERNAL INCLUDES -#include -#include -#include -#include - -// INTERNAL INCLUDES -#include -#include - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -namespace // unnamed namespace -{ - -#if defined(DEBUG_ENABLED) -Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR"); -#endif - -} // unnamed namespace - -AccessibilityAdaptor::AccessibilityAdaptor() -: mReadPosition(), - mActionHandler( NULL ), - mIsEnabled( false ) -{ - mAccessibilityGestureDetector = new AccessibilityGestureDetector(); -} - -void AccessibilityAdaptor::EnableAccessibility() -{ - if(mIsEnabled == false) - { - mIsEnabled = true; - - if( mActionHandler ) - { - mActionHandler->ChangeAccessibilityStatus(); - } - } -} - -void AccessibilityAdaptor::DisableAccessibility() -{ - if(mIsEnabled == true) - { - mIsEnabled = false; - - if( mActionHandler ) - { - mActionHandler->ChangeAccessibilityStatus(); - } - - // Destroy the TtsPlayer if exists. - if ( Adaptor::IsAvailable() ) - { - Dali::Adaptor& adaptor = Dali::Adaptor::Get(); - Adaptor& adaptorImpl = Adaptor::GetImplementation( adaptor ); - adaptorImpl.DestroyTtsPlayer( Dali::TtsPlayer::SCREEN_READER ); - } - } -} - -bool AccessibilityAdaptor::IsEnabled() const -{ - return mIsEnabled; -} - -Vector2 AccessibilityAdaptor::GetReadPosition() const -{ - return mReadPosition; -} - -void AccessibilityAdaptor::SetActionHandler(AccessibilityActionHandler& handler) -{ - mActionHandler = &handler; -} - -void AccessibilityAdaptor::SetGestureHandler(AccessibilityGestureHandler& handler) -{ - if( mAccessibilityGestureDetector ) - { - mAccessibilityGestureDetector->SetGestureHandler(handler); - } -} - -bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionNext(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionActivateEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionActivate(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain) -{ - bool ret = false; - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y); - - mReadPosition.x = static_cast< float > (x); - mReadPosition.y = static_cast< float > (y); - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionRead( allowReadAgain ); - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - } - - return ret; -} - -bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionUpEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionUp(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionDownEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionDown(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionClearFocusEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->ClearAccessibilityFocus(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, uint32_t timeStamp) -{ - bool ret = false; - - // We always need to emit a scroll signal, whether it's only a hover or not, - // so always send the action to the action handler. - if( mActionHandler ) - { - Dali::TouchEvent event(timeStamp); - event.points.push_back(point); - ret = mActionHandler->AccessibilityActionScroll( event ); - } - - Integration::TouchEvent touchEvent; - Integration::HoverEvent hoverEvent; - Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent( Integration::Point( point ), timeStamp, touchEvent, hoverEvent ); - if( type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth ) // hover event is ignored - { - // Process the touch event in accessibility gesture detector - if( mAccessibilityGestureDetector ) - { - mAccessibilityGestureDetector->SendEvent( touchEvent ); - ret = true; - } - } - - return ret; -} - -bool AccessibilityAdaptor::HandleActionTouchEvent(const TouchPoint& point, uint32_t timeStamp) -{ - bool ret = false; - - Dali::TouchEvent touchEvent(timeStamp); - touchEvent.points.push_back(point); - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionTouch(touchEvent); - } - return ret; -} - -bool AccessibilityAdaptor::HandleActionBackEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionBack(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -void AccessibilityAdaptor::HandleActionEnableEvent() -{ - EnableAccessibility(); -} - -void AccessibilityAdaptor::HandleActionDisableEvent() -{ - DisableAccessibility(); -} - -bool AccessibilityAdaptor::HandleActionScrollUpEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionScrollUp(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - - -bool AccessibilityAdaptor::HandleActionScrollDownEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionScrollDown(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionPageLeftEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionPageLeft(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionPageRightEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionPageRight(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionPageUpEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionPageUp(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionPageDownEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionPageDown(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionMoveToFirstEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionMoveToFirst(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionMoveToLastEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionMoveToLast(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionReadFromTopEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadFromTop(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionReadFromNextEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadFromNext(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionZoomEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionZoom(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadPauseResume(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptor::HandleActionStartStopEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionStartStop(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -AccessibilityAdaptor::~AccessibilityAdaptor() -{ - // Do any platform specific clean-up in OnDestroy() - OnDestroy(); -} - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali diff --git a/dali/internal/accessibility/common/accessibility-adaptor-impl.h b/dali/internal/accessibility/common/accessibility-adaptor-impl.h deleted file mode 100644 index d59f69f..0000000 --- a/dali/internal/accessibility/common/accessibility-adaptor-impl.h +++ /dev/null @@ -1,294 +0,0 @@ -#ifndef DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H -#define DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H - -/* - * Copyright (c) 2019 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 - -#include -#include -#include -#include - -// INTERNAL INCLUDES -#include -#include -#include -#include - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -/** - * This class detects to accessibility action - */ -class AccessibilityAdaptor : public Dali::BaseObject -{ -public: - - /** - * Constructor. - */ - AccessibilityAdaptor(); - - /** - * @brief Get an instance of the AccessibilityAdaptor. - * - * @note This singleton-style getter can be reimplemented for different platforms. - * @return The instance of the AccessibilityAdaptor. - */ - static Dali::AccessibilityAdaptor Get(); - - /** - * Turn on accessibility action - * This method should be called by vconf callback - */ - void EnableAccessibility(); - - /** - * Turn off accessibility action - * This method should be called by vconf callback - */ - void DisableAccessibility(); - - /** - * @copydoc Dali::AccessibilityAdaptor::IsEnabled() - */ - bool IsEnabled() const; - - /** - * @copydoc Dali::AccessibilityAdaptor::GetReadPosition() const - */ - Vector2 GetReadPosition() const; - - /** - * @copydoc Dali::AccessibilityAdaptor::SetActionHandler() - */ - void SetActionHandler(AccessibilityActionHandler& handler); - - /** - * @copydoc Dali::AccessibilityAdaptor::SetGestureHandler() - */ - void SetGestureHandler(AccessibilityGestureHandler& handler); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionNextEvent() - */ - virtual bool HandleActionNextEvent( bool allowEndFeedback = true); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionPreviousEvent() - */ - virtual bool HandleActionPreviousEvent( bool allowEndFeedback = true); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionActivateEvent() - */ - virtual bool HandleActionActivateEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionReadEvent() - */ - virtual bool HandleActionReadEvent( unsigned int x, unsigned int y, bool allowReadAgain ); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionReadNextEvent() - */ - virtual bool HandleActionReadNextEvent( bool allowEndFeedback = true); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionReadPreviousEvent() - */ - virtual bool HandleActionReadPreviousEvent( bool allowEndFeedback = true); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionUpEvent() - */ - virtual bool HandleActionUpEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionDownEvent() - */ - virtual bool HandleActionDownEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionClearFocusEvent() - */ - bool HandleActionClearFocusEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollEvent() - */ - bool HandleActionScrollEvent(const TouchPoint& point, uint32_t timeStamp); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionTouchEvent() - */ - bool HandleActionTouchEvent(const TouchPoint& point, uint32_t timeStamp); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionBackEvent() - */ - bool HandleActionBackEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionEnableEvent() - */ - void HandleActionEnableEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionDisableEvent() - */ - void HandleActionDisableEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollUpEvent() - */ - bool HandleActionScrollUpEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollDownEvent() - */ - bool HandleActionScrollDownEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionPageLeftEvent() - */ - bool HandleActionPageLeftEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionPageRightEvent() - */ - bool HandleActionPageRightEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionPageUpEvent() - */ - bool HandleActionPageUpEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionPageDownEvent() - */ - bool HandleActionPageDownEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionMoveToFirstEvent() - */ - bool HandleActionMoveToFirstEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionMoveToLastEvent() - */ - bool HandleActionMoveToLastEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionReadFromTopEvent() - */ - bool HandleActionReadFromTopEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionReadFromNextEvent() - */ - bool HandleActionReadFromNextEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionZoomEvent() - */ - bool HandleActionZoomEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionReadPauseResumeEvent() - */ - bool HandleActionReadPauseResumeEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionStartStopEvent() - */ - bool HandleActionStartStopEvent(); - -protected: - - /** - * Destructor. - */ - virtual ~AccessibilityAdaptor(); - -private: - - /** - * @brief Called when the singleton is destroyed. - * - * @note This can be reimplemented for different platforms. - * @return The instance of the AccessibilityAdaptor. - */ - static void OnDestroy(); - - // Undefined - AccessibilityAdaptor( const AccessibilityAdaptor& ); - AccessibilityAdaptor& operator=( AccessibilityAdaptor& ); - -protected: - - Dali::Integration::TouchEventCombiner mCombiner; ///< Combines multi-touch events. - - Vector2 mReadPosition; ///< ActionRead position - - AccessibilityActionHandler* mActionHandler; ///< The pointer of accessibility action handler - - AccessibilityGestureDetectorPtr mAccessibilityGestureDetector; ///< The accessibility gesture detector - - bool mIsEnabled : 1; ///< enable/disable the accessibility action - -public: - - // Helpers for public-api forwarding methods - - inline static Internal::Adaptor::AccessibilityAdaptor& GetImplementation(Dali::AccessibilityAdaptor& adaptor) - { - DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptor handle is empty" ); - - BaseObject& handle = adaptor.GetBaseObject(); - - return static_cast(handle); - } - - inline static const Internal::Adaptor::AccessibilityAdaptor& GetImplementation(const Dali::AccessibilityAdaptor& adaptor) - { - DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptor handle is empty" ); - - const BaseObject& handle = adaptor.GetBaseObject(); - - return static_cast(handle); - } - -}; - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali - -#endif // DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H diff --git a/dali/internal/accessibility/common/accessibility-gesture-detector.cpp b/dali/internal/accessibility/common/accessibility-gesture-detector.cpp deleted file mode 100644 index b872077..0000000 --- a/dali/internal/accessibility/common/accessibility-gesture-detector.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (c) 2019 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 - -// EXTERNAL INCLUDES -#include - -#include - -#include - - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -namespace -{ - const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN( 15.0f ); - const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_BEFORE_PAN ); - const float MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO( 2.0f / 3.0f ); - const unsigned long MAXIMUM_TIME_DIFF_ALLOWED( 500 ); - const unsigned long MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS( 100 ); - const unsigned int MINIMUM_MOTION_EVENTS_BEFORE_PAN(2); - const unsigned int MINIMUM_TOUCHES_BEFORE_PAN(1); - const unsigned int MAXIMUM_TOUCHES_BEFORE_PAN(1); -} // unnamed namespace - - -AccessibilityGestureDetector::AccessibilityGestureDetector() -: mState( Clear ), - mScene(nullptr), - mGestureHandler(nullptr), - mPanning(false), - mThresholdAdjustmentsRemaining( 0 ), - mThresholdTotalAdjustments( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO ), - mPrimaryTouchDownTime( 0 ), - mMinimumTouchesRequired( MINIMUM_TOUCHES_BEFORE_PAN ), - mMaximumTouchesRequired( MAXIMUM_TOUCHES_BEFORE_PAN ), - mMinimumDistanceSquared( MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED ), - mMinimumMotionEvents( MINIMUM_MOTION_EVENTS_BEFORE_PAN ), - mMotionEvents( 0 ) -{ -} - -AccessibilityGestureDetector::~AccessibilityGestureDetector() -{ -} - -void AccessibilityGestureDetector::SetGestureHandler(AccessibilityGestureHandler& handler) -{ - mGestureHandler = &handler; -} - -void AccessibilityGestureDetector::EmitPan(const AccessibilityGestureEvent gesture) -{ - if( mGestureHandler ) - { - if(gesture.state == AccessibilityGestureEvent::Started) - { - mPanning = true; - } - - if( mPanning ) - { - mGestureHandler->HandlePanGesture(gesture); - - if( (gesture.state == AccessibilityGestureEvent::Finished) || - (gesture.state == AccessibilityGestureEvent::Cancelled) ) - { - mPanning = false; - } - } - } -} - -void AccessibilityGestureDetector::SendEvent(const Integration::TouchEvent& event) -{ - PointState::Type primaryPointState(event.points[0].GetState()); - - if (primaryPointState == PointState::INTERRUPTED) - { - if ( ( mState == Started ) || ( mState == Possible ) ) - { - // If our pan had started and we are interrupted, then tell Core that pan is cancelled. - mTouchEvents.push_back(event); - SendPan(AccessibilityGestureEvent::Cancelled, event); - } - mState = Clear; // We should change our state to Clear. - mTouchEvents.clear(); - } - else - { - switch (mState) - { - case Clear: - { - if ( ( primaryPointState == PointState::DOWN ) || ( primaryPointState == PointState::STATIONARY ) ) - { - mPrimaryTouchDownLocation = event.points[0].GetScreenPosition(); - mPrimaryTouchDownTime = event.time; - mMotionEvents = 0; - if (event.GetPointCount() == mMinimumTouchesRequired) - { - // We have satisfied the minimum touches required for a pan, tell core that a gesture may be possible and change our state accordingly. - mState = Possible; - SendPan(AccessibilityGestureEvent::Possible, event); - } - - mTouchEvents.push_back(event); - } - break; - } - - case Possible: - { - unsigned int pointCount(event.GetPointCount()); - if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) ) - { - if (primaryPointState == PointState::MOTION) - { - mTouchEvents.push_back(event); - mMotionEvents++; - - Vector2 delta(event.points[0].GetScreenPosition() - mPrimaryTouchDownLocation); - - if ( ( mMotionEvents >= mMinimumMotionEvents ) && - ( delta.LengthSquared() >= static_cast( mMinimumDistanceSquared ) ) ) - { - // If the touch point(s) have moved enough distance to be considered a pan, then tell Core that the pan gesture has started and change our state accordingly. - mState = Started; - SendPan(AccessibilityGestureEvent::Started, event); - } - } - else if (primaryPointState == PointState::UP) - { - Vector2 delta(event.points[0].GetScreenPosition() - mPrimaryTouchDownLocation); - if (delta.LengthSquared() >= static_cast( mMinimumDistanceSquared ) ) - { - SendPan(AccessibilityGestureEvent::Started, event); - mTouchEvents.push_back(event); - SendPan(AccessibilityGestureEvent::Finished, event); - } - else - { - // If we have lifted the primary touch point then tell core the pan is cancelled and change our state to Clear. - SendPan(AccessibilityGestureEvent::Cancelled, event); - } - mState = Clear; - mTouchEvents.clear(); - } - } - else - { - // We do not satisfy pan conditions, tell Core our Gesture has been cancelled. - SendPan(AccessibilityGestureEvent::Cancelled, event); - - if (pointCount == 1 && primaryPointState == PointState::UP) - { - // If we have lifted the primary touch point, then change our state to Clear... - mState = Clear; - mTouchEvents.clear(); - } - else - { - // ...otherwise change it to Failed. - mState = Failed; - } - } - break; - } - - case Started: - { - mTouchEvents.push_back(event); - - unsigned int pointCount(event.GetPointCount()); - if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) ) - { - switch (primaryPointState) - { - case PointState::MOTION: - // Pan is continuing, tell Core. - SendPan(AccessibilityGestureEvent::Continuing, event); - break; - - case PointState::UP: - // Pan is finally finished when our primary point is lifted, tell Core and change our state to Clear. - SendPan(AccessibilityGestureEvent::Finished, event); - mState = Clear; - mTouchEvents.clear(); - break; - - case PointState::STATIONARY: - if (pointCount == mMinimumTouchesRequired) - { - Integration::PointContainerConstIterator iter = event.points.begin() + 1; // We already know the state of the first point - for(; iter != event.points.end(); ++iter) - { - if(iter->GetState() == PointState::UP) - { - // The number of touch points will be less than the minimum required. Inform core and change our state to Finished. - SendPan(AccessibilityGestureEvent::Finished, event); - mState = Finished; - break; - } - } - } - break; - - default: - break; - } - } - else - { - // We have gone outside of the pan requirements, inform Core that the gesture is finished. - SendPan(AccessibilityGestureEvent::Finished, event); - - if (pointCount == 1 && primaryPointState == PointState::UP) - { - // If this was the primary point being released, then we change our state back to Clear... - mState = Clear; - mTouchEvents.clear(); - } - else - { - // ...otherwise we change it to Finished. - mState = Finished; - } - } - break; - } - - case Finished: - case Failed: - { - if (primaryPointState == PointState::UP) - { - // Change our state back to clear when the primary touch point is released. - mState = Clear; - mTouchEvents.clear(); - } - break; - } - } - } -} - -void AccessibilityGestureDetector::SendPan(AccessibilityGestureEvent::State state, const Integration::TouchEvent& currentEvent) -{ - AccessibilityGestureEvent gesture(state); - gesture.currentPosition = currentEvent.points[0].GetScreenPosition(); - gesture.numberOfTouches = currentEvent.GetPointCount(); - - if ( mTouchEvents.size() > 1 ) - { - // Get the second last event in the queue, the last one is the current event - const Integration::TouchEvent& previousEvent( *( mTouchEvents.rbegin() + 1 ) ); - - Vector2 previousPosition( mPreviousPosition ); - uint32_t previousTime( previousEvent.time ); - - // If we've just started then we want to remove the threshold from Core calculations. - if ( state == AccessibilityGestureEvent::Started ) - { - previousPosition = mPrimaryTouchDownLocation; - previousTime = mPrimaryTouchDownTime; - - // If it's a slow pan, we do not want to phase in the threshold over the first few pan-events - // A slow pan is defined as one that starts the specified number of milliseconds after the down-event - if ( ( currentEvent.time - previousTime ) > MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS ) - { - mThresholdAdjustmentsRemaining = mThresholdTotalAdjustments; - mThresholdAdjustmentPerFrame = ( gesture.currentPosition - previousPosition ) / static_cast( mThresholdTotalAdjustments ); - } - else - { - mThresholdAdjustmentsRemaining = 0; - mThresholdAdjustmentPerFrame = Vector2::ZERO; - } - } - - gesture.previousPosition = previousPosition; - gesture.timeDelta = currentEvent.time - previousTime; - - // Apply the threshold with a phased approach - if ( mThresholdAdjustmentsRemaining > 0 ) - { - --mThresholdAdjustmentsRemaining; - gesture.currentPosition -= mThresholdAdjustmentPerFrame * static_cast( mThresholdAdjustmentsRemaining ); - } - - mPreviousPosition = gesture.currentPosition; - } - else - { - gesture.previousPosition = gesture.currentPosition; - gesture.timeDelta = 0; - } - - gesture.time = currentEvent.time; - - EmitPan(gesture); -} - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali diff --git a/dali/internal/accessibility/common/accessibility-gesture-detector.h b/dali/internal/accessibility/common/accessibility-gesture-detector.h deleted file mode 100644 index 616d76e..0000000 --- a/dali/internal/accessibility/common/accessibility-gesture-detector.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef DALI_INTERNAL_ACCESSIBILITY_GESTURE_DETECTOR_H -#define DALI_INTERNAL_ACCESSIBILITY_GESTURE_DETECTOR_H - -/* - * Copyright (c) 2019 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 - -// INTERNAL INCLUDES -#include -#include -#include -#include - -namespace Dali -{ - -namespace Integration -{ -struct TouchEvent; -} - -namespace Internal -{ - -namespace Adaptor -{ - -/** - * Detects an accessibility pan gesture and sends it to the gesture handler. - */ -class AccessibilityGestureDetector : public RefObject -{ -public: - - /** - * Constructor - */ - AccessibilityGestureDetector(); - - /** - * Virtual destructor. - */ - virtual ~AccessibilityGestureDetector(); - - /** - * Set the handler to handle accessibility gestures. - * @param[in] handler The Accessibility gesture handler. - * @note Handlers should remove themselves when they are destroyed. - */ - void SetGestureHandler(AccessibilityGestureHandler& handler); - - void SendEvent(const Integration::TouchEvent& event); - - void SendEvent(Integration::Scene& scene, const Integration::TouchEvent& event) - { - mScene = &scene; - SendEvent(event); - } - -private: - - /** - * Emits the pan gesture event (performs some smoothing operation). - * @param[in] state The state of the pan. - * @param[in] currentEvent The latest touch event. - */ - void SendPan(AccessibilityGestureEvent::State state, const Integration::TouchEvent& currentEvent); - - /** - * Emits the pan gesture event to the gesture handler. - * @param[in] gesture The pan gesture event. - */ - void EmitPan(const AccessibilityGestureEvent gesture); - -private: - - /** - * Internal state machine. - */ - enum State - { - Clear, ///< No gesture detected. - Possible, ///< The current touch event data suggests that a gesture is possible. - Started, ///< A gesture has been detected. - Finished, ///< A previously started pan gesture has finished. - Failed, ///< Current touch event data suggests a pan gesture is not possible. - }; - - State mState; ///< The current state of the detector. - - Integration::Scene* mScene; - AccessibilityGestureHandler* mGestureHandler; ///< The pointer of accessibility gesture handler - bool mPanning; ///< Keep track of panning state, when panning is occuring, this is true. - - std::vector mTouchEvents; ///< A container of all touch events after an initial down event. - - Vector2 mPrimaryTouchDownLocation; ///< The initial touch down point. - Vector2 mThresholdAdjustmentPerFrame; ///< The adjustment per frame at the start of a slow pan. - Vector2 mPreviousPosition; ///< The previous position. - - unsigned int mThresholdAdjustmentsRemaining; ///< No. of threshold adjustments still to apply (for a slow-pan). - unsigned int mThresholdTotalAdjustments; ///< The total number of adjustments required. - - uint32_t mPrimaryTouchDownTime; ///< The initial touch down time. - unsigned int mMinimumTouchesRequired; ///< The minimum touches required before a pan should be emitted. - unsigned int mMaximumTouchesRequired; ///< The maximum touches after which a pan should not be emitted. - unsigned int mMinimumDistanceSquared; ///< The minimum distance squared before pan should start. - unsigned int mMinimumMotionEvents; ///< The minimum motion events before pan should start. - unsigned int mMotionEvents; ///< The motion events received so far (before pan is emitted). -}; - -using AccessibilityGestureDetectorPtr = Dali::IntrusivePtr; - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali - -#endif // DALI_INTERNAL_ACCESSIBILITY_GESTURE_DETECTOR_H diff --git a/dali/internal/accessibility/file.list b/dali/internal/accessibility/file.list index 00bd528..1c91f1b 100644 --- a/dali/internal/accessibility/file.list +++ b/dali/internal/accessibility/file.list @@ -2,36 +2,28 @@ # module: accessibility, backend: common adaptor_accessibility_common_src_files=\ + ${adaptor_accessibility_dir}/accessibility-impl.cpp \ ${adaptor_accessibility_dir}/common/tts-player-factory.cpp \ ${adaptor_accessibility_dir}/common/tts-player-impl.cpp \ - ${adaptor_accessibility_dir}/common/accessibility-adaptor-impl.cpp \ - ${adaptor_accessibility_dir}/common/accessibility-gesture-detector.cpp + $(adaptor_accessibility_dir)/bridge/accessible.cpp \ + $(adaptor_accessibility_dir)/bridge/component.cpp \ + $(adaptor_accessibility_dir)/bridge/bridge-accessible.cpp \ + $(adaptor_accessibility_dir)/bridge/bridge-collection.cpp \ + $(adaptor_accessibility_dir)/bridge/bridge-base.cpp \ + $(adaptor_accessibility_dir)/bridge/bridge-component.cpp \ + $(adaptor_accessibility_dir)/bridge/bridge-action.cpp \ + $(adaptor_accessibility_dir)/bridge/bridge-value.cpp \ + $(adaptor_accessibility_dir)/bridge/bridge-object.cpp \ + $(adaptor_accessibility_dir)/bridge/bridge-impl.cpp \ + $(adaptor_accessibility_dir)/bridge/dbus.cpp \ + $(adaptor_accessibility_dir)/bridge/bridge-text.cpp \ + $(adaptor_accessibility_dir)/bridge/bridge-editable-text.cpp # module: accessibility, backend: tizen-wayland adaptor_accessibility_tizen_wayland_src_files=\ ${adaptor_accessibility_dir}/tizen-wayland/tts-player-factory-tizen.cpp \ ${adaptor_accessibility_dir}/tizen-wayland/tts-player-impl-tizen.cpp -# module: accessibility, backend: tizen-common profile -adaptor_accessibility_tizen_common_src_files=\ - ${adaptor_accessibility_dir}/tizen-wayland/tizen-common/accessibility-adaptor-impl-tizen.cpp - -# module: accessibility, backend: tizen-ivi profile -adaptor_accessibility_tizen_ivi_src_files=\ - ${adaptor_accessibility_dir}/tizen-wayland/tizen-ivi/accessibility-adaptor-impl-ivi.cpp - -# module: accessibility, backend: tizen-mobile profile -adaptor_accessibility_tizen_mobile_src_files=\ - ${adaptor_accessibility_dir}/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.cpp - -# module: accessibility, backend: tizen-tv profile -adaptor_accessibility_tizen_tv_src_files=\ - ${adaptor_accessibility_dir}/tizen-wayland/tizen-tv/accessibility-adaptor-impl-tv.cpp - -# module: accessibility, backend: tizen-wearable profile -adaptor_accessibility_tizen_wearable_src_files=\ - ${adaptor_accessibility_dir}/tizen-wayland/tizen-wearable/accessibility-adaptor-impl-wearable.cpp - # module: accessibility, backend: generic adaptor_accessibility_ubuntu_src_files=\ ${adaptor_accessibility_dir}/generic/accessibility-adaptor-impl-generic.cpp \ diff --git a/dali/internal/accessibility/generic/accessibility-adaptor-impl-generic.cpp b/dali/internal/accessibility/generic/accessibility-adaptor-impl-generic.cpp deleted file mode 100644 index 05dda37..0000000 --- a/dali/internal/accessibility/generic/accessibility-adaptor-impl-generic.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2019 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 - -// EXTERNAL INCLUDES -#include - -// INTERNAL INCLUDES -#include - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -Dali::AccessibilityAdaptor AccessibilityAdaptor::Get() -{ - Dali::AccessibilityAdaptor adaptor; - - Dali::SingletonService service( SingletonService::Get() ); - if ( service ) - { - // Check whether the singleton is already created - Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) ); - if(handle) - { - // If so, downcast the handle - adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) ); - } - else - { - adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptor() ); - service.Register( typeid( adaptor ), adaptor ); - } - } - - return adaptor; -} - -void AccessibilityAdaptor::OnDestroy() -{ - // Nothing to do here -} - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali diff --git a/dali/internal/accessibility/tizen-wayland/tizen-common/accessibility-adaptor-impl-tizen.cpp b/dali/internal/accessibility/tizen-wayland/tizen-common/accessibility-adaptor-impl-tizen.cpp deleted file mode 100644 index 18d57df..0000000 --- a/dali/internal/accessibility/tizen-wayland/tizen-common/accessibility-adaptor-impl-tizen.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2018 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 - -// EXTERNAL INCLUDES -#include - -#include -#include - -// INTERNAL INCLUDES -#include -#include - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -namespace -{ - -const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi"; - -// Disabled Accessibility temporarily in Tizen platform -bool GetEnabledVConf() -{ - int isEnabled = 0; - //vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled ); - - if( isEnabled == 0 ) - { - //vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled ); - } - - return static_cast(isEnabled); -} - -#if defined(DEBUG_ENABLED) -Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR" ); -#endif - -void AccessibilityOnOffNotification(keynode_t* node, void* data) -{ - AccessibilityAdaptor* adaptor = static_cast( data ); - - bool isEnabled = GetEnabledVConf(); - - DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" ); - - if( isEnabled ) - { - adaptor->EnableAccessibility(); - } - else - { - adaptor->DisableAccessibility(); - } -} - -} // unnamed namespace - -Dali::AccessibilityAdaptor AccessibilityAdaptor::Get() -{ - Dali::AccessibilityAdaptor adaptor; - - Dali::SingletonService service( SingletonService::Get() ); - if ( service ) - { - // Check whether the singleton is already created - Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) ); - if(handle) - { - // If so, downcast the handle - adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) ); - } - else - { - adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptor() ); - AccessibilityAdaptor& adaptorImpl = AccessibilityAdaptor::GetImplementation( adaptor ); - - bool isEnabled = GetEnabledVConf(); - - if( isEnabled ) - { - adaptorImpl.EnableAccessibility(); - } - DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" ); - - vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, &adaptorImpl ); - vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, &adaptorImpl ); - - service.Register( typeid( adaptor ), adaptor ); - } - } - - return adaptor; -} - -void AccessibilityAdaptor::OnDestroy() -{ - vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification ); - vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification ); -} - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali diff --git a/dali/internal/accessibility/tizen-wayland/tizen-ivi/accessibility-adaptor-impl-ivi.cpp b/dali/internal/accessibility/tizen-wayland/tizen-ivi/accessibility-adaptor-impl-ivi.cpp deleted file mode 100644 index f75eff9..0000000 --- a/dali/internal/accessibility/tizen-wayland/tizen-ivi/accessibility-adaptor-impl-ivi.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2019 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 - -// EXTERNAL INCLUDES -#include - -#ifndef WAYLAND -#include -#include -#endif - -#include - -#include -#include -#include - -// INTERNAL INCLUDES -#include -#include - -#ifndef WAYLAND -#define MSG_DOMAIN_CONTROL_ACCESS static_cast< int >( ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL ) -#endif - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -namespace // unnamed namespace -{ - -#if defined(DEBUG_ENABLED) -Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR"); -#endif - -const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi"; - -bool GetEnabledVConf() -{ - int isEnabled = 0; - vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled ); - - if( isEnabled == 0 ) - { - vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled ); - } - - return bool( isEnabled ); -} - - -void AccessibilityOnOffNotification(keynode_t* node, void* data) -{ - AccessibilityAdaptor* adaptor = static_cast( data ); - - bool isEnabled = GetEnabledVConf(); - - DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" ); - - if( isEnabled ) - { - adaptor->EnableAccessibility(); - } - else - { - adaptor->DisableAccessibility(); - } -} - -} // unnamed namespace - -Dali::AccessibilityAdaptor AccessibilityAdaptor::Get() -{ - Dali::AccessibilityAdaptor adaptor; - - Dali::SingletonService service( SingletonService::Get() ); - if ( service ) - { - // Check whether the singleton is already created - Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) ); - if(handle) - { - // If so, downcast the handle - adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) ); - } - else - { - adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptorMobile() ); - AccessibilityAdaptorMobile& adaptorImpl = AccessibilityAdaptorMobile::GetImplementation( adaptor ); - - bool isEnabled = GetEnabledVConf(); - - if( isEnabled ) - { - adaptorImpl.EnableAccessibility(); - } - DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" ); - - vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, &adaptorImpl ); - vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, &adaptorImpl ); - - service.Register( typeid( adaptor ), adaptor ); - } - } - - return adaptor; -} - -void AccessibilityAdaptor::OnDestroy() -{ - vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification ); - vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification ); -} - -AccessibilityAdaptorMobile::AccessibilityAdaptorMobile() -{ -} - -bool AccessibilityAdaptorMobile::HandleActionNextEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionNext(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionPreviousEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionActivateEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionActivate(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain) -{ - bool ret = false; - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y); - - mReadPosition.x = x; - mReadPosition.y = y; - - if( mActionHandler ) - { - // The accessibility actions should be handled by the registered accessibility action handler (e.g. focus manager) - ret = mActionHandler->AccessibilityActionRead(allowReadAgain); - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - } - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionReadNextEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionReadPreviousEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionUpEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionUp(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionDownEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionDown(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -AccessibilityAdaptorMobile::~AccessibilityAdaptorMobile() -{ -} - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali diff --git a/dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.cpp b/dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.cpp deleted file mode 100644 index f75eff9..0000000 --- a/dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2019 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 - -// EXTERNAL INCLUDES -#include - -#ifndef WAYLAND -#include -#include -#endif - -#include - -#include -#include -#include - -// INTERNAL INCLUDES -#include -#include - -#ifndef WAYLAND -#define MSG_DOMAIN_CONTROL_ACCESS static_cast< int >( ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL ) -#endif - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -namespace // unnamed namespace -{ - -#if defined(DEBUG_ENABLED) -Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR"); -#endif - -const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi"; - -bool GetEnabledVConf() -{ - int isEnabled = 0; - vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled ); - - if( isEnabled == 0 ) - { - vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled ); - } - - return bool( isEnabled ); -} - - -void AccessibilityOnOffNotification(keynode_t* node, void* data) -{ - AccessibilityAdaptor* adaptor = static_cast( data ); - - bool isEnabled = GetEnabledVConf(); - - DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" ); - - if( isEnabled ) - { - adaptor->EnableAccessibility(); - } - else - { - adaptor->DisableAccessibility(); - } -} - -} // unnamed namespace - -Dali::AccessibilityAdaptor AccessibilityAdaptor::Get() -{ - Dali::AccessibilityAdaptor adaptor; - - Dali::SingletonService service( SingletonService::Get() ); - if ( service ) - { - // Check whether the singleton is already created - Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) ); - if(handle) - { - // If so, downcast the handle - adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) ); - } - else - { - adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptorMobile() ); - AccessibilityAdaptorMobile& adaptorImpl = AccessibilityAdaptorMobile::GetImplementation( adaptor ); - - bool isEnabled = GetEnabledVConf(); - - if( isEnabled ) - { - adaptorImpl.EnableAccessibility(); - } - DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" ); - - vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, &adaptorImpl ); - vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, &adaptorImpl ); - - service.Register( typeid( adaptor ), adaptor ); - } - } - - return adaptor; -} - -void AccessibilityAdaptor::OnDestroy() -{ - vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification ); - vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification ); -} - -AccessibilityAdaptorMobile::AccessibilityAdaptorMobile() -{ -} - -bool AccessibilityAdaptorMobile::HandleActionNextEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionNext(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionPreviousEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionActivateEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionActivate(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain) -{ - bool ret = false; - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y); - - mReadPosition.x = x; - mReadPosition.y = y; - - if( mActionHandler ) - { - // The accessibility actions should be handled by the registered accessibility action handler (e.g. focus manager) - ret = mActionHandler->AccessibilityActionRead(allowReadAgain); - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - } - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionReadNextEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionReadPreviousEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionUpEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionUp(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionDownEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionDown(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -AccessibilityAdaptorMobile::~AccessibilityAdaptorMobile() -{ -} - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali diff --git a/dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.h b/dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.h deleted file mode 100644 index fd2939e..0000000 --- a/dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_MOBILE_H -#define DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_MOBILE_H - -/* - * Copyright (c) 2019 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. - * - */ - -// INTERNAL INCLUDES -#include -#include -#include -#include -#include - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -/** - * This mobile version is different since it forwards events to the indicator. - */ -class AccessibilityAdaptorMobile : public AccessibilityAdaptor -{ -public: - - /** - * Constructor. - */ - AccessibilityAdaptorMobile(); - - // From AccessibilityAdaptor base class - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionNextEvent() - */ - virtual bool HandleActionNextEvent( bool allowEndFeedback ); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionPreviousEvent() - */ - virtual bool HandleActionPreviousEvent( bool allowEndFeedback ); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionActivateEvent() - */ - virtual bool HandleActionActivateEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionReadEvent() - */ - virtual bool HandleActionReadEvent( unsigned int x, unsigned int y, bool allowReadAgain ); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionReadNextEvent() - */ - virtual bool HandleActionReadNextEvent( bool allowEndFeedback ); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionReadPreviousEvent() - */ - virtual bool HandleActionReadPreviousEvent( bool allowEndFeedback ); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionUpEvent() - */ - virtual bool HandleActionUpEvent(); - - /** - * @copydoc Dali::AccessibilityAdaptor::HandleActionDownEvent() - */ - virtual bool HandleActionDownEvent(); - -private: - - /** - * Destructor. - */ - virtual ~AccessibilityAdaptorMobile(); - - // Undefined - AccessibilityAdaptorMobile( const AccessibilityAdaptorMobile& ); - AccessibilityAdaptorMobile& operator=( AccessibilityAdaptorMobile& ); - -public: - - // Helpers for public-api forwarding methods - - inline static Internal::Adaptor::AccessibilityAdaptorMobile& GetImplementation(Dali::AccessibilityAdaptor& adaptor) - { - DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptorMobile handle is empty" ); - - BaseObject& handle = adaptor.GetBaseObject(); - - return static_cast(handle); - } - - inline static const Internal::Adaptor::AccessibilityAdaptorMobile& GetImplementation(const Dali::AccessibilityAdaptor& adaptor) - { - DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptorMobile handle is empty" ); - - const BaseObject& handle = adaptor.GetBaseObject(); - - return static_cast(handle); - } - -}; - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali - -#endif // DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_MOBILE_H diff --git a/dali/internal/accessibility/tizen-wayland/tizen-tv/accessibility-adaptor-impl-tv.cpp b/dali/internal/accessibility/tizen-wayland/tizen-tv/accessibility-adaptor-impl-tv.cpp deleted file mode 100644 index 18d57df..0000000 --- a/dali/internal/accessibility/tizen-wayland/tizen-tv/accessibility-adaptor-impl-tv.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2018 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 - -// EXTERNAL INCLUDES -#include - -#include -#include - -// INTERNAL INCLUDES -#include -#include - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -namespace -{ - -const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi"; - -// Disabled Accessibility temporarily in Tizen platform -bool GetEnabledVConf() -{ - int isEnabled = 0; - //vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled ); - - if( isEnabled == 0 ) - { - //vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled ); - } - - return static_cast(isEnabled); -} - -#if defined(DEBUG_ENABLED) -Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR" ); -#endif - -void AccessibilityOnOffNotification(keynode_t* node, void* data) -{ - AccessibilityAdaptor* adaptor = static_cast( data ); - - bool isEnabled = GetEnabledVConf(); - - DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" ); - - if( isEnabled ) - { - adaptor->EnableAccessibility(); - } - else - { - adaptor->DisableAccessibility(); - } -} - -} // unnamed namespace - -Dali::AccessibilityAdaptor AccessibilityAdaptor::Get() -{ - Dali::AccessibilityAdaptor adaptor; - - Dali::SingletonService service( SingletonService::Get() ); - if ( service ) - { - // Check whether the singleton is already created - Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) ); - if(handle) - { - // If so, downcast the handle - adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) ); - } - else - { - adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptor() ); - AccessibilityAdaptor& adaptorImpl = AccessibilityAdaptor::GetImplementation( adaptor ); - - bool isEnabled = GetEnabledVConf(); - - if( isEnabled ) - { - adaptorImpl.EnableAccessibility(); - } - DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" ); - - vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, &adaptorImpl ); - vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, &adaptorImpl ); - - service.Register( typeid( adaptor ), adaptor ); - } - } - - return adaptor; -} - -void AccessibilityAdaptor::OnDestroy() -{ - vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification ); - vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification ); -} - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali diff --git a/dali/internal/accessibility/tizen-wayland/tizen-wearable/accessibility-adaptor-impl-wearable.cpp b/dali/internal/accessibility/tizen-wayland/tizen-wearable/accessibility-adaptor-impl-wearable.cpp deleted file mode 100644 index d382759..0000000 --- a/dali/internal/accessibility/tizen-wayland/tizen-wearable/accessibility-adaptor-impl-wearable.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2019 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 - -// EXTERNAL INCLUDES -#include - -#ifndef WAYLAND -#include -#include -#endif - -#include - -#include -#include -#include - -// INTERNAL INCLUDES -#include -#include - -#ifndef WAYLAND -#define MSG_DOMAIN_CONTROL_ACCESS static_cast< int >( ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL ) -#endif - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -namespace // unnamed namespace -{ - -#if defined(DEBUG_ENABLED) -Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR"); -#endif - -const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi"; - -bool GetEnabledVConf() -{ - int isEnabled = 0; - vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled ); - - if( isEnabled == 0 ) - { - vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled ); - } - - return bool( isEnabled ); -} - - -void AccessibilityOnOffNotification(keynode_t* node, void* data) -{ - AccessibilityAdaptor* adaptor = static_cast( data ); - - bool isEnabled = GetEnabledVConf(); - - DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" ); - - if( isEnabled ) - { - adaptor->EnableAccessibility(); - } - else - { - adaptor->DisableAccessibility(); - } -} - -} // unnamed namespace - -Dali::AccessibilityAdaptor AccessibilityAdaptor::Get() -{ - Dali::AccessibilityAdaptor adaptor; - - Dali::SingletonService service( SingletonService::Get() ); - if ( service ) - { - // Check whether the singleton is already created - Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) ); - if(handle) - { - // If so, downcast the handle - adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) ); - } - else - { - adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptorMobile() ); - AccessibilityAdaptorMobile& adaptorImpl = AccessibilityAdaptorMobile::GetImplementation( adaptor ); - - bool isEnabled = GetEnabledVConf(); - - if( isEnabled ) - { - adaptorImpl.EnableAccessibility(); - } - DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" ); - - vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, &adaptorImpl ); - vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, &adaptorImpl ); - - service.Register( typeid( adaptor ), adaptor ); - } - } - - return adaptor; -} - -void AccessibilityAdaptor::OnDestroy() -{ - vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification ); - vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification ); -} - -AccessibilityAdaptorMobile::AccessibilityAdaptorMobile() -{ -} - -bool AccessibilityAdaptorMobile::HandleActionNextEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionNext(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionPreviousEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionActivateEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionActivate(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain) -{ - bool ret = false; - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y); - - mReadPosition.x = x; - mReadPosition.y = y; - - if( mActionHandler) - { - // The accessibility actions should be handled by the registered accessibility action handler (e.g. focus manager) - ret = mActionHandler->AccessibilityActionRead(allowReadAgain); - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - } - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionReadNextEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionReadPreviousEvent(bool allowEndFeedback) -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionUpEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionUp(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -bool AccessibilityAdaptorMobile::HandleActionDownEvent() -{ - bool ret = false; - - if( mActionHandler ) - { - ret = mActionHandler->AccessibilityActionDown(); - } - - DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - - return ret; -} - -AccessibilityAdaptorMobile::~AccessibilityAdaptorMobile() -{ -} - -} // namespace Adaptor - -} // namespace Internal - -} // namespace Dali diff --git a/dali/internal/adaptor/common/adaptor-impl.cpp b/dali/internal/adaptor/common/adaptor-impl.cpp index bff490a..c9eeb03 100755 --- a/dali/internal/adaptor/common/adaptor-impl.cpp +++ b/dali/internal/adaptor/common/adaptor-impl.cpp @@ -49,7 +49,6 @@ #include #include -#include #include #include #include @@ -61,6 +60,7 @@ #include #include +#include #include #include @@ -322,10 +322,36 @@ void Adaptor::Initialize( GraphicsFactory& graphicsFactory, Dali::Configuration: DALI_LOG_ERROR( "Fail to open file : %s\n", ( systemCachePath + "gpu-environment.conf" ).c_str() ); } } + auto appName = GetApplicationPackageName(); + auto bridge = Accessibility::Bridge::GetCurrentBridge(); + bridge->SetApplicationName( appName ); + bridge->Initialize(); + Dali::Stage stage = Dali::Stage::GetCurrent(); + Dali::Stage::GetCurrent().KeyEventSignal().Connect( &accessibilityObserver, &AccessibilityObserver::OnAccessibleKeyEvent ); +} + +void Adaptor::AccessibilityObserver::OnAccessibleKeyEvent( const KeyEvent& event ) +{ + Accessibility::KeyEventType type; + if( event.state == KeyEvent::Down ) + { + type = Accessibility::KeyEventType::KEY_PRESSED; + } + else if( event.state == KeyEvent::Up ) + { + type = Accessibility::KeyEventType::KEY_RELEASED; + } + else + { + return; + } + Dali::Accessibility::Bridge::GetCurrentBridge()->Emit( type, event.keyCode, event.keyPressedName, event.time, !event.keyPressed.empty() ); } Adaptor::~Adaptor() { + Accessibility::Bridge::GetCurrentBridge()->Terminate(); + // Ensure stop status Stop(); @@ -918,6 +944,8 @@ void Adaptor::RequestProcessEventsOnIdle( bool forceProcess ) void Adaptor::OnWindowShown() { + Dali::Accessibility::Bridge::GetCurrentBridge()->ApplicationShown(); + if( PAUSED_WHILE_HIDDEN == mState ) { // Adaptor can now be resumed @@ -943,6 +971,8 @@ void Adaptor::OnWindowShown() void Adaptor::OnWindowHidden() { + Dali::Accessibility::Bridge::GetCurrentBridge()->ApplicationHidden(); + if( RUNNING == mState || READY == mState ) { bool allWindowsHidden = true; diff --git a/dali/internal/adaptor/common/adaptor-impl.h b/dali/internal/adaptor/common/adaptor-impl.h index 74f7ab3..1f65fb1 100755 --- a/dali/internal/adaptor/common/adaptor-impl.h +++ b/dali/internal/adaptor/common/adaptor-impl.h @@ -52,11 +52,16 @@ #include #include +#include namespace Dali { class RenderSurfaceInterface; +namespace Accessibility +{ +class Bridge; +} namespace Integration { @@ -180,6 +185,8 @@ public: */ void SceneCreated(); + static std::string GetApplicationPackageName(); + public: // AdaptorInternalServices implementation /** * @copydoc Dali::Adaptor::Start() @@ -685,6 +692,13 @@ private: // Data const bool mEnvironmentOptionsOwned:1; ///< Whether we own the EnvironmentOptions (and thus, need to delete it) bool mUseRemoteSurface; ///< whether the remoteSurface is used or not + class AccessibilityObserver : public ConnectionTracker + { + public: + void OnAccessibleKeyEvent( const KeyEvent& event ); + }; + AccessibilityObserver accessibilityObserver; + public: inline static Adaptor& GetImplementation(Dali::Adaptor& adaptor) { return *adaptor.mImpl; } }; diff --git a/dali/internal/adaptor/common/adaptor.cpp b/dali/internal/adaptor/common/adaptor.cpp index 195f936..59230bc 100755 --- a/dali/internal/adaptor/common/adaptor.cpp +++ b/dali/internal/adaptor/common/adaptor.cpp @@ -22,7 +22,6 @@ #include // INTERNAL INCLUDES -#include #include #include #include diff --git a/dali/internal/adaptor/common/application-impl.cpp b/dali/internal/adaptor/common/application-impl.cpp index 94196b7..40b16d9 100755 --- a/dali/internal/adaptor/common/application-impl.cpp +++ b/dali/internal/adaptor/common/application-impl.cpp @@ -22,6 +22,7 @@ #include // INTERNAL INCLUDES +#include #include #include #include @@ -219,6 +220,8 @@ void Application::Quit() void Application::QuitFromMainLoop() { + Accessibility::Bridge::GetCurrentBridge()->Terminate(); + mAdaptor->Stop(); mFramework->Quit(); diff --git a/dali/internal/adaptor/generic/adaptor-impl-generic.cpp b/dali/internal/adaptor/generic/adaptor-impl-generic.cpp index 1b05919..2a983ee 100644 --- a/dali/internal/adaptor/generic/adaptor-impl-generic.cpp +++ b/dali/internal/adaptor/generic/adaptor-impl-generic.cpp @@ -27,6 +27,11 @@ namespace Internal namespace Adaptor { +std::string Adaptor::GetApplicationPackageName() +{ + return ""; +} + void Adaptor::GetDataStoragePath( std::string& path) { path = ""; diff --git a/dali/internal/adaptor/tizen-wayland/adaptor-impl-tizen.cpp b/dali/internal/adaptor/tizen-wayland/adaptor-impl-tizen.cpp index 3e2865d..d1761bf 100644 --- a/dali/internal/adaptor/tizen-wayland/adaptor-impl-tizen.cpp +++ b/dali/internal/adaptor/tizen-wayland/adaptor-impl-tizen.cpp @@ -33,6 +33,9 @@ #endif +#include +#include + namespace Dali { @@ -66,6 +69,14 @@ static void OnSystemLanguageChanged( system_settings_key_e key, void* data ) } // namesapce +std::string Adaptor::GetApplicationPackageName() +{ + char appname[4096] = {0}; + int pid = getpid(); + aul_app_get_pkgname_bypid( pid, appname, sizeof( appname ) ); + return appname; +} + void Adaptor::GetDataStoragePath( std::string& path) { #ifdef USE_APPFW diff --git a/dali/internal/clipboard/tizen-wayland/clipboard-impl-ecore-wl.cpp b/dali/internal/clipboard/tizen-wayland/clipboard-impl-ecore-wl.cpp index 8721844..06851f2 100644 --- a/dali/internal/clipboard/tizen-wayland/clipboard-impl-ecore-wl.cpp +++ b/dali/internal/clipboard/tizen-wayland/clipboard-impl-ecore-wl.cpp @@ -63,6 +63,7 @@ struct Clipboard::Impl Impl() { Eldbus_Object *eldbus_obj; + eldbus_init(); cbhm_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION); eldbus_obj = eldbus_object_get(cbhm_conn, CBHM_DBUS_INTERFACE, CBHM_DBUS_OBJPATH); eldbus_proxy = eldbus_proxy_get(eldbus_obj, CBHM_DBUS_INTERFACE); @@ -76,6 +77,7 @@ struct Clipboard::Impl { if (cbhm_conn) eldbus_connection_unref(cbhm_conn); + eldbus_shutdown(); } Eldbus_Proxy* cbhm_proxy_get() diff --git a/dali/internal/imaging/common/image-operations.cpp b/dali/internal/imaging/common/image-operations.cpp index b44a024..46ab713 100755 --- a/dali/internal/imaging/common/image-operations.cpp +++ b/dali/internal/imaging/common/image-operations.cpp @@ -1726,7 +1726,7 @@ void PointSample( const unsigned char * inPixels, } else { - DALI_ASSERT_DEBUG( 0 == "Inner branch conditions don't match outer branch." ); + DALI_ASSERT_DEBUG( false && "Inner branch conditions don't match outer branch." ); } } else @@ -2135,7 +2135,7 @@ void LinearSample( const unsigned char * __restrict__ inPixels, } else { - DALI_ASSERT_DEBUG( 0 == "Inner branch conditions don't match outer branch." ); + DALI_ASSERT_DEBUG( false && "Inner branch conditions don't match outer branch." ); } } else diff --git a/dali/internal/system/common/object-profiler.cpp b/dali/internal/system/common/object-profiler.cpp index 6ddc44b..ff83c38 100644 --- a/dali/internal/system/common/object-profiler.cpp +++ b/dali/internal/system/common/object-profiler.cpp @@ -139,7 +139,7 @@ std::size_t ObjectProfiler::GetMemorySize( const std::string& name, uint32_t cou struct MemoryMemorySize { std::string name; - std::size_t memorySize; + decltype(ANIMATION_MEMORY_SIZE) memorySize; }; MemoryMemorySize memoryMemorySizes[] = { @@ -161,7 +161,7 @@ std::size_t ObjectProfiler::GetMemorySize( const std::string& name, uint32_t cou { if( memoryMemorySizes[i].name.compare(name) == 0 ) { - return count * memoryMemorySizes[i].memorySize; + return count * static_cast( memoryMemorySizes[i].memorySize ); } } return 0; diff --git a/dali/internal/window-system/common/event-handler.cpp b/dali/internal/window-system/common/event-handler.cpp index 99f1796..f8c8fc0 100755 --- a/dali/internal/window-system/common/event-handler.cpp +++ b/dali/internal/window-system/common/event-handler.cpp @@ -52,7 +52,7 @@ Integration::Log::Filter* gSelectionEventLogFilter = Integration::Log::Filter::N } // unnamed namespace #endif -#ifdef DALI_ELDBUS_AVAILABLE +#if 0 and defined DALI_ELDBUS_AVAILABLE namespace { @@ -98,7 +98,6 @@ static uint32_t GetCurrentMilliSeconds(void) EventHandler::EventHandler( WindowRenderSurface* surface, DamageObserver& damageObserver ) : mStyleMonitor( StyleMonitor::Get() ), mDamageObserver( damageObserver ), - mAccessibilityAdaptor( AccessibilityAdaptor::Get() ), mClipboardEventNotifier( ClipboardEventNotifier::Get() ), mClipboard( Clipboard::Get() ), mPaused( false ) @@ -117,7 +116,6 @@ EventHandler::EventHandler( WindowRenderSurface* surface, DamageObserver& damage windowBase->SelectionDataSendSignal().Connect( this, &EventHandler::OnSelectionDataSend ); windowBase->SelectionDataReceivedSignal().Connect( this, &EventHandler::OnSelectionDataReceived ); windowBase->StyleChangedSignal().Connect( this, &EventHandler::OnStyleChanged ); - windowBase->AccessibilitySignal().Connect( this, &EventHandler::OnAccessibilityNotification ); } } @@ -246,260 +244,6 @@ void EventHandler::OnStyleChanged( StyleChange::Type styleChange ) SendEvent( styleChange ); } -void EventHandler::OnAccessibilityNotification( const WindowBase::AccessibilityInfo& info ) -{ -#ifdef DALI_ELDBUS_AVAILABLE - if( mPaused ) - { - return; - } - - if( !mAccessibilityAdaptor ) - { - DALI_LOG_ERROR( "Invalid accessibility adaptor\n" ); - return; - } - - AccessibilityAdaptor* accessibilityAdaptor( &AccessibilityAdaptor::GetImplementation( mAccessibilityAdaptor ) ); - if( !accessibilityAdaptor ) - { - DALI_LOG_ERROR( "Cannot access accessibility adaptor\n" ); - return; - } - - // Create a touch point object. - TouchPoint::State touchPointState( TouchPoint::Down ); - if( info.state == 0 ) - { - touchPointState = TouchPoint::Down; // Mouse down. - } - else if( info.state == 1 ) - { - touchPointState = TouchPoint::Motion; // Mouse move. - } - else if( info.state == 2 ) - { - touchPointState = TouchPoint::Up; // Mouse up. - } - else - { - touchPointState = TouchPoint::Interrupted; // Error. - } - - // Send touch event to accessibility adaptor. - TouchPoint point( 0, touchPointState, static_cast< float >( info.startX ), static_cast< float >( info.startY ) ); - - // Perform actions based on received gestures. - // Note: This is seperated from the reading so we can have other input readers without changing the below code. - switch( info.gestureValue ) - { - case 0: // OneFingerHover - { - // Focus, read out. - accessibilityAdaptor->HandleActionReadEvent( static_cast< unsigned int >( info.startX ), static_cast< unsigned int >( info.startY ), true /* allow read again */ ); - break; - } - case 1: // TwoFingersHover - { - // In accessibility mode, scroll action should be handled when the currently focused actor is contained in scrollable control - accessibilityAdaptor->HandleActionScrollEvent( point, GetCurrentMilliSeconds() ); - break; - } - case 2: // ThreeFingersHover - { - // Read from top item on screen continuously. - accessibilityAdaptor->HandleActionReadFromTopEvent(); - break; - } - case 3: // OneFingerFlickLeft - { - // Move to previous item. - accessibilityAdaptor->HandleActionReadPreviousEvent(); - break; - } - case 4: // OneFingerFlickRight - { - // Move to next item. - accessibilityAdaptor->HandleActionReadNextEvent(); - break; - } - case 5: // OneFingerFlickUp - { - // Move to previous item. - accessibilityAdaptor->HandleActionPreviousEvent(); - break; - } - case 6: // OneFingerFlickDown - { - // Move to next item. - accessibilityAdaptor->HandleActionNextEvent(); - break; - } - case 7: // TwoFingersFlickUp - { - // Scroll up the list. - accessibilityAdaptor->HandleActionScrollUpEvent(); - break; - } - case 8: // TwoFingersFlickDown - { - // Scroll down the list. - accessibilityAdaptor->HandleActionScrollDownEvent(); - break; - } - case 9: // TwoFingersFlickLeft - { - // Scroll left to the previous page - accessibilityAdaptor->HandleActionPageLeftEvent(); - break; - } - case 10: // TwoFingersFlickRight - { - // Scroll right to the next page - accessibilityAdaptor->HandleActionPageRightEvent(); - break; - } - case 11: // ThreeFingersFlickLeft - { - // Not exist yet - break; - } - case 12: // ThreeFingersFlickRight - { - // Not exist yet - break; - } - case 13: // ThreeFingersFlickUp - { - // Not exist yet - break; - } - case 14: // ThreeFingersFlickDown - { - // Not exist yet - break; - } - case 15: // OneFingerSingleTap - { - // Focus, read out. - accessibilityAdaptor->HandleActionReadEvent( static_cast< unsigned int >( info.startX ), static_cast< unsigned int >( info.startY ), true /* allow read again */ ); - break; - } - case 16: // OneFingerDoubleTap - { - // Activate selected item / active edit mode. - accessibilityAdaptor->HandleActionActivateEvent(); - break; - } - case 17: // OneFingerTripleTap - { - // Zoom - accessibilityAdaptor->HandleActionZoomEvent(); - break; - } - case 18: // TwoFingersSingleTap - { - // Pause/Resume current speech - accessibilityAdaptor->HandleActionReadPauseResumeEvent(); - break; - } - case 19: // TwoFingersDoubleTap - { - // Start/Stop current action - accessibilityAdaptor->HandleActionStartStopEvent(); - break; - } - case 20: // TwoFingersTripleTap - { - // Read information from indicator - // Not supported - break; - } - case 21: // ThreeFingersSingleTap - { - // Read from top item on screen continuously. - accessibilityAdaptor->HandleActionReadFromTopEvent(); - break; - } - case 22: // ThreeFingersDoubleTap - { - // Read from next item continuously. - accessibilityAdaptor->HandleActionReadFromNextEvent(); - break; - } - case 23: // ThreeFingersTripleTap - { - // Not exist yet - break; - } - case 24: // OneFingerFlickLeftReturn - { - // Scroll up to the previous page - accessibilityAdaptor->HandleActionPageUpEvent(); - break; - } - case 25: // OneFingerFlickRightReturn - { - // Scroll down to the next page - accessibilityAdaptor->HandleActionPageDownEvent(); - break; - } - case 26: // OneFingerFlickUpReturn - { - // Move to the first item on screen - accessibilityAdaptor->HandleActionMoveToFirstEvent(); - break; - } - case 27: // OneFingerFlickDownReturn - { - // Move to the last item on screen - accessibilityAdaptor->HandleActionMoveToLastEvent(); - break; - } - case 28: // TwoFingersFlickLeftReturn - { - // Not exist yet - break; - } - case 29: // TwoFingersFlickRightReturn - { - // Not exist yet - break; - } - case 30: // TwoFingersFlickUpReturn - { - // Not exist yet - break; - } - case 31: // TwoFingersFlickDownReturn - { - // Not exist yet - break; - } - case 32: // ThreeFingersFlickLeftReturn - { - // Not exist yet - break; - } - case 33: // ThreeFingersFlickRightReturn - { - // Not exist yet - break; - } - case 34: // ThreeFingersFlickUpReturn - { - // Not exist yet - break; - } - case 35: // ThreeFingersFlickDownReturn - { - // Not exist yet - break; - } - } -#endif -} - void EventHandler::AddObserver( Observer& observer ) { ObserverContainer::iterator match ( find(mObservers.begin(), mObservers.end(), &observer) ); diff --git a/dali/internal/window-system/common/event-handler.h b/dali/internal/window-system/common/event-handler.h index 795a919..96d6283 100755 --- a/dali/internal/window-system/common/event-handler.h +++ b/dali/internal/window-system/common/event-handler.h @@ -22,14 +22,20 @@ #include // uint32_t #include +#include +#include +#include +#include #include #include +#include // INTERNAL INCLUDES -#include +#include #include #include #include +#include namespace Dali { @@ -204,11 +210,6 @@ private: */ void OnStyleChanged( StyleChange::Type styleChange ); - /** - * Called when Ecore ElDBus accessibility event is received. - */ - void OnAccessibilityNotification( const WindowBase::AccessibilityInfo& info ); - private: // Undefined @@ -222,7 +223,6 @@ private: Dali::StyleMonitor mStyleMonitor; ///< Handle to the style monitor, set on construction, to send font size and font change events to. DamageObserver& mDamageObserver; ///< Reference to the DamageObserver, set on construction, to sent damage events to. - Dali::AccessibilityAdaptor mAccessibilityAdaptor; ///< Pointer to the accessibility adaptor Dali::ClipboardEventNotifier mClipboardEventNotifier; ///< Pointer to the clipboard event notifier Dali::Clipboard mClipboard;///< Pointer to the clipboard diff --git a/dali/internal/window-system/common/window-impl.cpp b/dali/internal/window-system/common/window-impl.cpp index fdb01bd..2ef0962 100644 --- a/dali/internal/window-system/common/window-impl.cpp +++ b/dali/internal/window-system/common/window-impl.cpp @@ -43,6 +43,7 @@ #include #include #include +#include namespace Dali { @@ -92,6 +93,17 @@ Window::Window() Window::~Window() { + if ( mAdaptor ) + { + auto bridge = Accessibility::Bridge::GetCurrentBridge(); + auto accessible2 = mScene.GetRootLayer(); + auto accessible = Accessibility::Accessible::Get( accessible2 ); + bridge->RemoveTopLevelWindow( accessible ); + + mAdaptor->RemoveWindow( this ); + mAdaptor = NULL; + } + if ( mEventHandler ) { mEventHandler->RemoveObserver( *this ); @@ -133,6 +145,14 @@ void Window::OnAdaptorSet(Dali::Adaptor& adaptor) { mEventHandler = EventHandlerPtr(new EventHandler( mWindowSurface, *mAdaptor ) ); mEventHandler->AddObserver( *this ); + + auto bridge = Accessibility::Bridge::GetCurrentBridge(); + auto v = mScene.GetRootLayer(); + auto accessible = Accessibility::Accessible::Get( v, true ); + bridge->AddTopLevelWindow( accessible ); + + //FIXME: line below is temporary solution for missing "activate" signal and should be removed + Show(); } void Window::OnSurfaceSet( Dali::RenderSurfaceInterface* surface ) @@ -598,6 +618,18 @@ void Window::OnFocusChanged( bool focusIn ) Dali::Window handle( this ); mFocusChangedSignal.Emit( focusIn ); mFocusChangeSignal.Emit( handle, focusIn ); + + if (auto b = Dali::Accessibility::Bridge::GetCurrentBridge()) + { + if (focusIn) + { + b->ApplicationShown(); + } + else + { + b->ApplicationHidden(); + } + } } void Window::OnOutputTransformed() diff --git a/dali/public-api/adaptor-framework/accessibility.cpp b/dali/public-api/adaptor-framework/accessibility.cpp new file mode 100644 index 0000000..beb5c4e --- /dev/null +++ b/dali/public-api/adaptor-framework/accessibility.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 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 +#include +#include +#include +#include + +#include +#include + +void Dali::Accessibility::PauseResume( bool pause ) +{ + if( auto b = Bridge::GetCurrentBridge() ) + { + b->PauseResume( pause ); + } +} + +void Dali::Accessibility::Say( const std::string &text, bool discardable, std::function callback ) +{ + if( auto b = Bridge::GetCurrentBridge() ) + { + b->Say( text, discardable, callback ); + } +} + + diff --git a/dali/public-api/adaptor-framework/accessibility.h b/dali/public-api/adaptor-framework/accessibility.h new file mode 100644 index 0000000..b373cc7 --- /dev/null +++ b/dali/public-api/adaptor-framework/accessibility.h @@ -0,0 +1,811 @@ +#ifndef DALI_ACCESSIBILITY_H +#define DALI_ACCESSIBILITY_H + +/* + * Copyright (c) 2019 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ +/** + * @addtogroup dali_adaptor_framework + * @{ + */ +class Actor; + +namespace Accessibility +{ + +/** + * @brief Enumeration describing a relation between accessible objects + * + * 1 to 0..N relation model is supported. By default relation is not symmetrical. + * Symmetry must be explicitly maintained. + */ +enum class RelationType : uint32_t +{ + NULL_, + LABEL_FOR, + LABELLED_BY, + CONTROLLER_FOR, + CONTROLLED_BY, + MEMBER_OF, + TOOLTIP_FOR, + NODE_CHILD_OF, + NODE_PARENT_OF, + EXTENDED, + FLOWS_TO, + FLOWS_FROM, + SUBWINDOW_OF, + EMBEDS, + EMBEDDED_BY, + POPUP_FOR, + PARENT_WINDOW_OF, + DESCRIPTION_FOR, + DESCRIBED_BY, + DETAILS, + DETAILS_FOR, + ERROR_MESSAGE, + ERROR_FOR, + LAST_DEFINED +}; + +/** + * @brief Enumeration describing if coordinates are relative to screen or window + * + * @see Accessibility::Component::GetExtents + * @see Accessibility::Component::Contains + */ +enum class CoordType +{ + SCREEN, + WINDOW +}; + +/** + * @brief Enumeration indicating relative stacking order + * + * ComponentLayer allows to describe visibility of all parts of UI + * basing on the concrete stacking order + * + * @see Accessibility::Component::GetLayer + * + * @note currently only ComponentLayer::Window is supported + */ +enum class ComponentLayer +{ + INVALID, + BACKGROUND, + CANVAS, + WIDGET, + MDI, + POPUP, + OVERLAY, + WINDOW, + LAST_DEFINED, +}; + +/** + * @brief Enumeration describing role of the Accessibility object + * + * Object can be described by only one role. + * + * @see Accessibility::Accessible::GetRole + */ +enum class Role : uint32_t +{ + INVALID, + ACCELERATOR_LABEL, + ALERT, + ANIMATION, + ARROW, + CALENDAR, + CANVAS, + CHECK_BOX, + CHECK_MENU_ITEM, + COLOR_CHOOSER, + COLUMN_HEADER, + COMBO_BOX, + DATE_EDITOR, + DESKTOP_ICON, + DESKTOP_FRAME, + DIAL, + DIALOG, + DIRECTORY_PANE, + DRAWING_AREA, + FILE_CHOOSER, + FILLER, + FOCUS_TRAVERSABLE, + FONT_CHOOSER, + FRAME, + GLASS_PANE, + HTML_CONTAINER, + ICON, + IMAGE, + INTERNAL_FRAME, + LABEL, + LAYERED_PANE, + LIST, + LIST_ITEM, + MENU, + MENU_BAR, + MENU_ITEM, + OPTION_PANE, + PAGE_TAB, + PAGE_TAB_LIST, + PANEL, + PASSWORD_TEXT, + POPUP_MENU, + PROGRESS_BAR, + PUSH_BUTTON, + RADIO_BUTTON, + RADIO_MENU_ITEM, + ROOT_PANE, + ROW_HEADER, + SCROLL_BAR, + SCROLL_PANE, + SEPARATOR, + SLIDER, + SPIN_BUTTON, + SPLIT_PANE, + STATUS_BAR, + TABLE, + TABLE_CELL, + TABLE_COLUMN_HEADER, + TABLE_ROW_HEADER, + TEAROFF_MENU_ITEM, + TERMINAL, + TEXT, + TOGGLE_BUTTON, + TOOL_BAR, + TOOL_TIP, + TREE, + TREE_TABLE, + UNKNOWN, + VIEWPORT, + WINDOW, + EXTENDED, + HEADER, + FOOTER, + PARAGRAPH, + RULER, + APPLICATION, + AUTOCOMPLETE, + EDITBAR, + EMBEDDED, + ENTRY, + CHART, + CAPTION, + DOCUMENT_FRAME, + HEADING, + PAGE, + SECTION, + REDUNDANT_OBJECT, + FORM, + LINK, + INPUT_METHOD_WINDOW, + TABLE_ROW, + TREE_ITEM, + DOCUMENT_SPREADSHEET, + DOCUMENT_PRESENTATION, + DOCUMENT_TEXT, + DOCUMENT_WEB, + DOCUMENT_EMAIL, + COMMENT, + LIST_BOX, + GROUPING, + IMAGE_MAP, + NOTIFICATION, + INFO_BAR, + LEVEL_BAR, + TITLE_BAR, + BLOCK_QUOTE, + AUDIO, + VIDEO, + DEFINITION, + ARTICLE, + LANDMARK, + LOG, + MARQUEE, + MATH, + RATING, + TIMER, + STATIC, + MATH_FRACTION, + MATH_ROOT, + SUBSCRIPT, + SUPERSCRIPT, + _COUNT, +}; + +/** + * @brief Enumeration describing states of the Accessibility object + * + * Object can be in many states at the same time. + * + * @see Accessibility::Accessible::GetStates + */ +enum class State : uint32_t +{ + INVALID, + ACTIVE, + ARMED, + BUSY, + CHECKED, + COLLAPSED, + DEFUNCT, + EDITABLE, + ENABLED, + EXPANDABLE, + EXPANDED, + FOCUSABLE, + FOCUSED, + HAS_TOOLTIP, + HORIZONTAL, + ICONIFIED, + MODAL, + MULTI_LINE, + MULTI_SELECTABLE, + OPAQUE, + PRESSED, + RESIZEABLE, + SELECTABLE, + SELECTED, + SENSITIVE, + SHOWING, + SINGLE_LINE, + STALE, + TRANSIENT, + VERTICAL, + VISIBLE, + MANAGES_DESCENDANTS, + INDETERMINATE, + REQUIRED, + TRUNCATED, + ANIMATED, + INVALID_ENTRY, + SUPPORTS_AUTOCOMPLETION, + SELECTABLE_TEXT, + IS_DEFAULT, + VISITED, + CHECKABLE, + HAS_POPUP, + READ_ONLY, + HIGHLIGHTED, + HIGHLIGHTABLE, + _COUNT +}; + +/** + * @brief Enumeration describing change of text object + */ +enum class TextChangedState : uint32_t +{ + INSERT, + DELETE, + _COUNT +}; + +enum class ObjectPropertyChangeEvent { + NAME, + DESCRIPTION, + VALUE, + ROLE, + PARENT, +}; + +/** + * @brief Enumeration describing change of window object + * + * @see Accessibility::Accessible::Emit + */ +enum class WindowEvent +{ + PROPERTY_CHANGE, + MINIMIZE, + MAXIMIZE, + RESTORE, + CLOSE, + CREATE, + REPARENT, + DESKTOP_CREATE, + DESKTOP_DESTROY, + DESTROY, + ACTIVATE, + DEACTIVATE, + RAISE, + LOWER, + MOVE, + RESIZE, + SHADE, + UU_SHADE, + RESTYLE, +}; + +/** + * @brief Enumeration used to acquire bounded text from accessible object having textual content. + * + * @see Accessibility::Text::GetTextAtOffset + * + * @note Currently only TextBoundary::Character is supported + */ +enum class TextBoundary : uint32_t +{ + /** + * Only one character is acquired. + */ + CHARACTER, + + /** + * Not supported. + */ + WORD, + + /** + * Not supported. + */ + SENTENCE, + + /** + * Not supported. + */ + LINE, + + /** + * Not supported. + */ + PARAGRAPH, + _COUNT +}; + +/** + * @brief Enumeration describing type of gesture + * + * @see Accessibility::Accessible::DoGesture + */ +enum class Gesture : int32_t +{ + ONE_FINGER_HOVER, + TWO_FINGER_HOVER, + THREE_FINGER_HOVER, + ONE_FINGER_FLICK_LEFT, + ONE_FINGER_FLICK_RIGHT, + ONE_FINGER_FLICK_UP, + ONE_FINGER_FLICK_DOWN, + TWO_FINGERS_FLICK_LEFT, + TWO_FINGERS_FLICK_RIGHT, + TWO_FINGERS_FLICK_UP, + TWO_FINGERS_FLICK_DOWN, + THREE_FINGERS_FLICK_LEFT, + THREE_FINGERS_FLICK_RIGHT, + THREE_FINGERS_FLICK_UP, + THREE_FINGERS_FLICK_DOWN, + ONE_FINGER_SINGLE_TAP, + ONE_FINGER_DOUBLE_TAP, + ONE_FINGER_TRIPLE_TAP, + TWO_FINGERS_SINGLE_TAP, + TWO_FINGERS_DOUBLE_TAP, + TWO_FINGERS_TRIPLE_TAP, + THREE_FINGERS_SINGLE_TAP, + THREE_FINGERS_DOUBLE_TAP, + THREE_FINGERS_TRIPLE_TAP, + ONE_FINGER_FLICK_LEFT_RETURN, + ONE_FINGER_FLICK_RIGHT_RETURN, + ONE_FINGER_FLICK_UP_RETURN, + ONE_FINGER_FLICK_DOWN_RETURN, + TWO_FINGERS_FLICK_LEFT_RETURN, + TWO_FINGERS_FLICK_RIGHT_RETURN, + TWO_FINGERS_FLICK_UP_RETURN, + TWO_FINGERS_FLICK_DOWN_RETURN, + THREE_FINGERS_FLICK_LEFT_RETURN, + THREE_FINGERS_FLICK_RIGHT_RETURN, + THREE_FINGERS_FLICK_UP_RETURN, + THREE_FINGERS_FLICK_DOWN_RETURN, + ONE_FINGER_DOUBLE_TAP_N_HOLD, + TWO_FINGERS_DOUBLE_TAP_N_HOLD, + THREE_FINGERS_DOUBLE_TAP_N_HOLD, + _COUNT +}; + +/** + * @brief Enumeration indicating current state of gesture + * + * @see Dali::Accessibility::GestureInfo + */ +enum class GestureState : int32_t +{ + BEGIN, + ONGOING, + ENDED, + ABORTED +}; + +enum class ReadingInfoType +{ + NAME, + ROLE, + DESCRIPTION, + STATE +}; + +/** + * @brief Helper class for storing values treated as bit sets + * + * This class provides all bitset-like methods for bitset size larger, than long long int + * + * @see Dali::Accessibility::Accessible::GetStates + * @see Dali::Accessibility::Accessible::GetRoles + */ +template < size_t I, typename S > +class BitSets +{ + std::array< uint32_t, I > data; + + void _set() { } + static constexpr bool _accepts() { return true; } + template < typename T > static constexpr bool _accepts() + { + return std::is_enum< T >::value; + } + template < typename T, typename T2, typename ... ARGS > static constexpr bool _accepts() + { + return std::is_enum< T >::value && _accepts< T2, ARGS... >(); + } + template < typename T, typename ... ARGS > void _set( T t, ARGS ... args ) + { + ( *this )[ t ] = true; + _set( args... ); + } +public: + BitSets() + { + for( auto& u : data ) + u = 0; + } + BitSets( const BitSets & ) = default; + BitSets( BitSets&& ) = default; + template < typename T, typename ... ARGS, typename std::enable_if< _accepts< T, ARGS... >() >::type* = nullptr >BitSets(T t, ARGS ... args) { + for(auto& u : data) + u = 0; + _set(t, args...); + } + explicit BitSets( std::array< uint32_t, I > d ) { + for( auto i = 0u; i < I; ++i ) + data[ i ] = d[ i ]; + } + explicit BitSets( std::array< int32_t, I > d ) { + for( auto i = 0u; i < I; ++i ) + data[ i ] = static_cast< uint32_t >( d[ i ]); + } + BitSets &operator = ( const BitSets& ) = default; + BitSets &operator = ( BitSets&& ) = default; + + struct reference + { + std::array< uint32_t, I >& data; + size_t pos; + reference &operator=( reference r ) + { + ( *this ) = static_cast< bool >( r ); + return *this; + } + reference &operator=( bool v ) + { + if( v ) + data[ pos / 32 ] |= 1 << ( pos & 31 ); + else + data[ pos / 32 ] &= ~( 1 << ( pos & 31 ) ); + return *this; + } + operator bool() const + { + auto i = static_cast< size_t >( pos ); + return ( data[i / 32] & ( 1 << ( i & 31 ) ) ) != 0; + } + }; + reference operator[]( S index ) { return {data, static_cast< size_t >( index )}; } + bool operator[]( S index ) const + { + auto i = static_cast< size_t >( index ); + return ( data[i / 32] & ( 1 << ( i & 31 ) ) ) != 0; + } + std::array< uint32_t, I > GetRawData() const { return data; } + + BitSets operator|( BitSets b ) const + { + BitSets r; + for( auto i = 0u; i < I; ++i ) + r.data[i] = data[i] | b.data[i]; + return r; + } + BitSets operator^( BitSets b ) const + { + BitSets r; + for( auto i = 0u; i < I; ++i ) + r.data[i] = data[i] ^ b.data[i]; + return r; + } + BitSets operator&( BitSets b ) const + { + BitSets r; + for( auto i = 0u; i < I; ++i ) + r.data[i] = data[i] & b.data[i]; + return r; + } + bool operator==( BitSets b ) const + { + for( auto i = 0u; i < I; ++i ) + if( data[i] != b.data[i] ) + return false; + return true; + } + bool operator!=( BitSets b ) const + { + return !((*this) == b); + } + explicit operator bool() const + { + for( auto& u : data ) + if( u ) + return true; + return false; + } + size_t size() const { return I; } +}; + +using ReadingInfoTypes = BitSets<1, ReadingInfoType>; +using States = BitSets< 2, State >; +using Attributes = std::unordered_map< std::string, std::string >; + +/** + * @brief Class representing unique object address on accessibility bus + * + * @see Dali::Accessibility::Accessible::GetAddress + */ +class DALI_ADAPTOR_API Address +{ +public: + Address() = default; + Address( std::string bus, std::string path ) : bus( std::move( bus ) ), path( std::move( path ) ) {} + + explicit operator bool() const { return !path.empty(); } + std::string ToString() const + { + return *this ? bus + ":" + path : "::null"; + } + const std::string& GetBus() const; + const std::string& GetPath() const { return path; } + + bool operator == (const Address &a) const { + return bus == a.bus && path == a.path; + } + bool operator != (const Address &a) const { + return !(*this == a); + } +private: + mutable std::string bus, path; +}; + +/** + * @brief Enumeration describing type of key event + * + * @see Adaptor::AccessibilityObserver::OnAccessibleKeyEvent + */ +enum class KeyEventType +{ + KEY_PRESSED, + KEY_RELEASED, +}; + +/** + * @brief Enumeration with human readable values describing state of event + * + * @see Dali::Accessibility::Bridge::Emit + */ +enum class Consumed +{ + NO, + YES +}; + +/** + * @brief Helper class representing two dimensional point with integer coordinates + */ +struct DALI_ADAPTOR_API Point +{ + int x = 0; + int y = 0; + + Point() = default; + Point( int x, int y ) : x( x ), y( y ) {} + + bool operator==( Point p ) const + { + return x == p.x && y == p.y; + } + bool operator!=( Point p ) const + { + return !( *this == p ); + } +}; + +/** + * @brief Helper class representing size of rectangle object with usage of two integer values + */ +struct DALI_ADAPTOR_API Size +{ + int width = 0; + int height = 0; + + Size() = default; + Size( int w, int h ) : width( w ), height( h ) {} + + bool operator==( Size p ) const + { + return width == p.width && height == p.height; + } + bool operator!=( Size p ) const + { + return !( *this == p ); + } +}; + +/** + * @brief Helper class used to store data related with Accessibility::Text interface + * + * @see Dali::Accessibility::Text::GetTextAtOffset + * @see Dali::Accessibility::Text::GetSelection + */ +struct DALI_ADAPTOR_API Range +{ + int startOffset = 0; + int endOffset = 0; + std::string content; + + Range() = default; + Range( size_t start, size_t end ) : startOffset( start ), endOffset( end ) + { + } + Range( size_t start, size_t end, std::string content ) : startOffset( start ), endOffset( end ), content( content ) + { + } +}; + +/** + * @brief Structure containing all values needed to invoke Accessible::DoGesture + * + * type + * enumerated gesture type + * xBeg, yBeg + * point where gesture begins + * xEnd, yEnd + * point where gesture ends + * state + * enumerated state of gesture + * eventTime + * time when event occured + * + * @see Dali::Accessibility::Accessible::DoGesture + */ +struct DALI_ADAPTOR_API GestureInfo +{ + GestureInfo() = default; + GestureInfo(Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, GestureState state, uint32_t eventTime) + : type(type), xBeg(xBeg), xEnd(xEnd), yBeg(yBeg), yEnd(yEnd), state(state), eventTime(eventTime) + {} + + Gesture type{}; + int32_t xBeg{}; + int32_t xEnd{}; + int32_t yBeg{}; + int32_t yEnd{}; + GestureState state{}; + uint32_t eventTime{}; +}; + +class Accessible; + +/** + * @brief Class representing accessibility relations + * + * Class connecting one source object with multiple target objects with usage + * of specific relation type. + * + * @note std::string representing source and targets are string values of Accessibility::Address + * + * @see Dali::Accessibility::Accessible::Address + * @see Dali::Accessibility::Accessible::RelationType + */ +struct DALI_ADAPTOR_API Relation +{ + Relation(RelationType relationType, std::vector
targets) + : relationType(relationType), targets(targets) + {} + RelationType relationType; + std::vector
targets; +}; + +/** + * @brief Reads given text by screen reader + * + * @param text The text to read + * @param discardable If TRUE, reading can be discarded by subsequent reading requests, + * if FALSE the reading must finish before next reading request can be started + * @param callback the callback function that is called on reading signals emitted + * during processing of this reading request. + * Callback can be one of the following signals: + * “ReadingCancelled” + * “ReadingStopped” + * “ReadingSkipped” + */ +DALI_ADAPTOR_API void Say( const std::string &text, bool discardable, std::function callback ); + +/** + * @brief Force accessibility client to pause / resume. + * + * @param[in] pause true if you want to pause, false if you want to resume + */ +DALI_ADAPTOR_API void PauseResume( bool pause ); + +/// \endcond +} // namespace Accessibility +/** + * @} + */ +} // namespace Dali + +namespace std +{ +template <> +struct hash< Dali::Accessibility::Point > +{ + size_t operator()( Dali::Accessibility::Point p ) + { + return static_cast< size_t >( p.x ) ^ ( static_cast< size_t >( p.y ) * 11 ); + } +}; +template <> +struct hash< Dali::Accessibility::Size > +{ + size_t operator()( Dali::Accessibility::Size p ) + { + return static_cast< size_t >( p.width ) ^ ( static_cast< size_t >( p.height ) * 11 ); + } +}; +} + +#endif // DALI_ACCESSIBILITY_H diff --git a/dali/public-api/adaptor-framework/tts-player.h b/dali/public-api/adaptor-framework/tts-player.h index 55cef69..2251026 100755 --- a/dali/public-api/adaptor-framework/tts-player.h +++ b/dali/public-api/adaptor-framework/tts-player.h @@ -42,6 +42,7 @@ class TtsPlayer; /** * @brief The Text-to-speech (TTS) Player. + * @deprecated Instead of this class use Dali::Accessibility::Say() method * @SINCE_1_0.0 */ class DALI_ADAPTOR_API TtsPlayer : public BaseHandle diff --git a/dali/public-api/file.list b/dali/public-api/file.list index cf91bee..a1c361f 100755 --- a/dali/public-api/file.list +++ b/dali/public-api/file.list @@ -1,4 +1,5 @@ adaptor_public_api_src_files = \ + $(adaptor_public_api_dir)/adaptor-framework/accessibility.cpp \ $(adaptor_public_api_dir)/adaptor-framework/application.cpp \ $(adaptor_public_api_dir)/adaptor-framework/key.cpp \ $(adaptor_public_api_dir)/adaptor-framework/window.cpp \ @@ -22,6 +23,7 @@ public_api_adaptor_framework_header_files = \ $(adaptor_public_api_dir)/adaptor-framework/device-status.h \ $(adaptor_public_api_dir)/adaptor-framework/input-method.h \ $(adaptor_public_api_dir)/adaptor-framework/key.h \ + $(adaptor_public_api_dir)/adaptor-framework/accessibility.h \ $(adaptor_public_api_dir)/adaptor-framework/key-grab.h \ $(adaptor_public_api_dir)/adaptor-framework/style-change.h \ $(adaptor_public_api_dir)/adaptor-framework/timer.h \ diff --git a/packaging/dali-adaptor.spec b/packaging/dali-adaptor.spec index 49e5b8c..ad8a7ee 100644 --- a/packaging/dali-adaptor.spec +++ b/packaging/dali-adaptor.spec @@ -99,6 +99,8 @@ BuildRequires: pkgconfig(capi-system-system-settings) # for autofill %if 0%{?tizen_version_major} >= 5 && 0%{?tizen_version_minor} >= 5 BuildRequires: pkgconfig(capi-ui-autofill) +# for ATSPI (Accessibility) support +BuildRequires: pkgconfig(eldbus) %endif # for feedback plugin