From 3aa4e1b0e077b43bde211f424b1419be6c99ea2b Mon Sep 17 00:00:00 2001 From: suhyung Eom Date: Wed, 3 Aug 2016 10:24:48 +0900 Subject: [PATCH] Implement wayland clipboard Signed-off-by: suhyung Eom Change-Id: I5fb6dcec69ecf65a346b31d8002530e7745a9bc6 --- adaptors/common/clipboard-impl.h | 49 +++-- adaptors/devel-api/adaptor-framework/clipboard.cpp | 12 +- adaptors/devel-api/adaptor-framework/clipboard.h | 16 +- adaptors/ecore/wayland/clipboard-impl-ecore-wl.cpp | 224 ++++++++++++++++++--- adaptors/ecore/wayland/event-handler-ecore-wl.cpp | 63 +++++- adaptors/wayland/clipboard/clipboard-impl-wl.cpp | 16 +- adaptors/x11/clipboard-impl-x.cpp | 33 ++- 7 files changed, 336 insertions(+), 77 deletions(-) diff --git a/adaptors/common/clipboard-impl.h b/adaptors/common/clipboard-impl.h index da164a9..75f70e9 100644 --- a/adaptors/common/clipboard-impl.h +++ b/adaptors/common/clipboard-impl.h @@ -66,9 +66,9 @@ public: bool SetItem(const std::string &itemData); /** - * @copydoc Dali::Clipboard::GetItem() + * @copydoc Dali::Clipboard::RequestItem() */ - std::string GetItem( unsigned int index ); + void RequestItem(); /** * @copydoc Dali::Clipboard::NumberOfClipboardItems() @@ -83,7 +83,21 @@ public: /** * @copydoc Dali::Clipboard::HideClipboard() */ - void HideClipboard(); + void HideClipboard(bool skipFirstHide); + + /** + * @copydoc Dali::Clipboard::IsVisible() + */ + bool IsVisible() const; + + /** + * @brief exchange either sending or receiving buffered data + * + * @param[in] type true for send buffered data, false for receive data to buffer + * @param[in] event information pointer + * @return The buffer pointer for send or receive data + */ + char* ExcuteBuffered( bool type, void *event ); private: @@ -95,26 +109,27 @@ private: Impl* mImpl; -}; // class clipboard +public: +}; // class clipboard } // namespace Adaptor } // namespace Internal - inline static Internal::Adaptor::Clipboard& GetImplementation(Dali::Clipboard& clipboard) - { - DALI_ASSERT_ALWAYS( clipboard && "Clipboard handle is empty" ); - BaseObject& handle = clipboard.GetBaseObject(); - return static_cast(handle); - } - - inline static const Internal::Adaptor::Clipboard& GetImplementation(const Dali::Clipboard& clipboard) - { - DALI_ASSERT_ALWAYS( clipboard && "Clipboard handle is empty" ); - const BaseObject& handle = clipboard.GetBaseObject(); - return static_cast(handle); - } +inline static Internal::Adaptor::Clipboard& GetImplementation(Dali::Clipboard& clipboard) +{ + DALI_ASSERT_ALWAYS( clipboard && "Clipboard handle is empty" ); + BaseObject& handle = clipboard.GetBaseObject(); + return static_cast(handle); +} + +inline static const Internal::Adaptor::Clipboard& GetImplementation(const Dali::Clipboard& clipboard) +{ + DALI_ASSERT_ALWAYS( clipboard && "Clipboard handle is empty" ); + const BaseObject& handle = clipboard.GetBaseObject(); + return static_cast(handle); +} } // namespace Dali diff --git a/adaptors/devel-api/adaptor-framework/clipboard.cpp b/adaptors/devel-api/adaptor-framework/clipboard.cpp index 95f1b52..38264a5 100644 --- a/adaptors/devel-api/adaptor-framework/clipboard.cpp +++ b/adaptors/devel-api/adaptor-framework/clipboard.cpp @@ -39,14 +39,15 @@ Clipboard Clipboard::Get() { return Internal::Adaptor::Clipboard::Get(); } + bool Clipboard::SetItem( const std::string &itemData) { return GetImplementation(*this).SetItem( itemData ); } -std::string Clipboard::GetItem( unsigned int index ) +void Clipboard::RequestItem() { - return GetImplementation(*this).GetItem( index ); + GetImplementation(*this).RequestItem(); } unsigned int Clipboard::NumberOfItems() @@ -61,7 +62,12 @@ void Clipboard::ShowClipboard() void Clipboard::HideClipboard() { - GetImplementation(*this).HideClipboard(); + GetImplementation(*this).HideClipboard(false); +} + +bool Clipboard::IsVisible() const +{ + return GetImplementation(*this).IsVisible(); } } // namespace Dali diff --git a/adaptors/devel-api/adaptor-framework/clipboard.h b/adaptors/devel-api/adaptor-framework/clipboard.h index 9b5a54a..5d84c8f 100644 --- a/adaptors/devel-api/adaptor-framework/clipboard.h +++ b/adaptors/devel-api/adaptor-framework/clipboard.h @@ -2,7 +2,7 @@ #define __DALI_CLIPBOARD_H__ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 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. @@ -82,12 +82,12 @@ public: bool SetItem( const std::string& itemData ); /** - * @brief Retreive the string at the given index in the clipboard. + * @brief Request clipboard service to retrieve an item * - * @param[in] index item in clipboard list to retrieve - * @return string the text item at the current index. + * Calling this method will trigger a signal from the clipboard event notifier. + * @see Dali::ClipboardEventNotifier::ContentSelectedSignal() */ - std::string GetItem( unsigned int index ); + void RequestItem(); /** * @brief Returns the number of item currently in the clipboard. @@ -106,6 +106,12 @@ public: */ void HideClipboard(); + /** + * @brief Retrieves the clipboard's visibility + * @return bool true if the clipboard is visible. + */ + bool IsVisible() const; + }; } // namespace Dali diff --git a/adaptors/ecore/wayland/clipboard-impl-ecore-wl.cpp b/adaptors/ecore/wayland/clipboard-impl-ecore-wl.cpp index cea687c..1744b2d 100644 --- a/adaptors/ecore/wayland/clipboard-impl-ecore-wl.cpp +++ b/adaptors/ecore/wayland/clipboard-impl-ecore-wl.cpp @@ -24,21 +24,22 @@ #include #include #include +#include + +#ifdef DALI_ELDBUS_AVAILABLE +#include +#endif // DALI_ELDBUS_AVAILABLE // INTERNAL INCLUDES #include -namespace //unnamed namespace -{ -const char* const CBHM_WINDOW = "CBHM_XWIN"; -const char* const CBHM_MSG = "CBHM_MSG"; -const char* const CBHM_ITEM = "CBHM_ITEM"; -const char* const CBHM_cCOUNT = "CBHM_cCOUNT"; -const char* const CBHM_ERROR = "CBHM_ERROR"; -const char* const SET_ITEM = "SET_ITEM"; -const char* const SHOW = "show0"; -const char* const HIDE = "cbhm_hide"; -} +#define CBHM_DBUS_OBJPATH "/org/tizen/cbhm/dbus" +#ifndef CBHM_DBUS_INTERFACE +#define CBHM_DBUS_INTERFACE "org.tizen.cbhm.dbus" +#endif /* CBHM_DBUS_INTERFACE */ + +#define CLIPBOARD_STR "CLIPBOARD_STR" +#define CLIPBOARD_BUFFER_SIZE 512 /////////////////////////////////////////////////////////////////////////////////////////////////// // Clipboard @@ -55,7 +56,168 @@ namespace Adaptor struct Clipboard::Impl { - // Put implementation here. + Impl() + { + Eldbus_Object *eldbus_obj; + 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); + eldbus_name_owner_changed_callback_add(cbhm_conn, CBHM_DBUS_INTERFACE, NULL, cbhm_conn, EINA_TRUE); + eldbus_proxy_signal_handler_add(eldbus_proxy, "ItemClicked", _on_item_clicked, this); + mVisible = false; + mIsFirstTimeHidden = true; + } + + ~Impl() + { + if (cbhm_conn) + eldbus_connection_unref(cbhm_conn); + } + + Eldbus_Proxy* cbhm_proxy_get() + { + return eldbus_proxy; + } + + Eldbus_Connection* cbhm_connection_get() + { + return cbhm_conn; + } + + void SetItem( const std::string &itemData ) + { + const char *data = itemData.c_str(); + const char *types[10] = {0, }; + int i = -1; + + if (data == NULL) + { + return; + } + strcpy(mSendBuf, data); + + // ELM_SEL_TYPE_CLIPBOARD - To distinguish clipboard selection in cbhm + types[++i] = "CLIPBOARD_BEGIN"; + + types[++i] = "application/x-elementary-markup"; + types[++i] = "text/plain"; + types[++i] = "text/plain;charset=utf-8"; + + // ELM_SEL_TYPE_CLIPBOARD - To distinguish clipboard selection in cbhm + types[++i] = "CLIPBOARD_END"; + ecore_wl_dnd_selection_set(ecore_wl_input_get(), types); + } + + void RequestItem() + { + const char *types[10] = {0, }; + int i = -1; + + types[++i] = "application/x-elementary-markup"; + types[++i] = "text/plain"; + types[++i] = "text/plain;charset=utf-8"; + ecore_wl_dnd_selection_get(ecore_wl_input_get(), *types); + } + + char *ExcuteSend( void *event ) + { + Ecore_Wl_Event_Data_Source_Send *ev = (Ecore_Wl_Event_Data_Source_Send *)event; + int len_buf = strlen(mSendBuf); + int len_remained = len_buf; + int len_written = 0, ret; + char *buf = mSendBuf; + + while (len_written < len_buf) + { + ret = write(ev->fd, buf, len_remained); + if (ret == -1) break; + buf += ret; + len_written += ret; + len_remained -= ret; + } + close(ev->fd); + return (char *)mSendBuf; + } + + char *ExcuteReceive( void *event ) + { + Ecore_Wl_Event_Selection_Data_Ready *ev = (Ecore_Wl_Event_Selection_Data_Ready *)event; + + strncpy(mReceiveBuf, (char *)ev->data, ev->len); + mReceiveBuf[ev->len] = '\0'; + return (char *)mReceiveBuf; + } + + int GetCount() + { + Eldbus_Message *reply, *req; + const char *errname = NULL, *errmsg = NULL; + int count = -1; + + if (!(req = eldbus_proxy_method_call_new(eldbus_proxy, "CbhmGetCount"))) + { + DALI_LOG_ERROR("Failed to create method call on org.freedesktop.DBus.Properties.Get"); + return -1; + } + + eldbus_message_ref(req); + reply = eldbus_proxy_send_and_block(eldbus_proxy, req, 100); + if (!reply || eldbus_message_error_get(reply, &errname, &errmsg)) + { + DALI_LOG_ERROR("Unable to call method org.freedesktop.DBus.Properties.Get: %s %s", + errname, errmsg); + eldbus_message_unref(req); + return -1; + } + + if (!eldbus_message_arguments_get(reply, "i", &count)) + { + DALI_LOG_ERROR("Cannot get arguments from eldbus"); + eldbus_message_unref(req); + return -1; + } + + eldbus_message_unref(req); + DALI_LOG_ERROR("cbhm item count(%d)", count); + return count; + } + + void ShowClipboard() + { + eldbus_proxy_call(cbhm_proxy_get(), "CbhmShow", NULL, NULL, -1, "s", "0"); + mIsFirstTimeHidden = true; + mVisible = true; + } + + void HideClipboard( bool skipFirstHide ) + { + if ( skipFirstHide && mIsFirstTimeHidden ) + { + mIsFirstTimeHidden = false; + return; + } + eldbus_proxy_call(cbhm_proxy_get(), "CbhmHide", NULL, NULL, -1, ""); + mIsFirstTimeHidden = false; + mVisible = false; + } + + bool IsVisible() const + { + return mVisible; + } + + static void _on_item_clicked(void *data, const Eldbus_Message *msg EINA_UNUSED) + { + static_cast(data)->RequestItem(); + } + + Eldbus_Proxy *eldbus_proxy; + Eldbus_Connection *cbhm_conn; + + char mSendBuf[CLIPBOARD_BUFFER_SIZE]; + char mReceiveBuf[CLIPBOARD_BUFFER_SIZE]; + bool mVisible; + bool mIsFirstTimeHidden; }; Clipboard::Clipboard(Impl* impl) @@ -94,24 +256,16 @@ Dali::Clipboard Clipboard::Get() bool Clipboard::SetItem(const std::string &itemData ) { + mImpl->SetItem( itemData ); return true; } /* - * Get string at given index of clipboard + * Request clipboard service to give an item */ -std::string Clipboard::GetItem( unsigned int index ) // change string to a Dali::Text object. +void Clipboard::RequestItem() { - if ( index >= NumberOfItems() ) - { - return ""; - } - - std::string emptyString( "" ); - char sendBuf[20]; - - snprintf( sendBuf, 20, "%s%d", CBHM_ITEM, index ); - return emptyString; + mImpl->RequestItem(); } /* @@ -119,24 +273,28 @@ std::string Clipboard::GetItem( unsigned int index ) // change string to a Dali */ unsigned int Clipboard::NumberOfItems() { - int count = -1; - - return count; + return mImpl->GetCount(); } -/** - * Show clipboard window - * Function to send message to show the Clipboard (cbhm) as no direct API available - * Reference elementary/src/modules/ctxpopup_copypasteUI/cbhm_helper.c - */ void Clipboard::ShowClipboard() { + mImpl->ShowClipboard(); } -void Clipboard::HideClipboard() +void Clipboard::HideClipboard(bool skipFirstHide) { + mImpl->HideClipboard(skipFirstHide); } +bool Clipboard::IsVisible() const +{ + return mImpl->IsVisible(); +} + +char* Clipboard::ExcuteBuffered( bool type, void *event ) +{ + return (type ? mImpl->ExcuteSend( event ) : mImpl->ExcuteReceive( event )); +} } // namespace Adaptor diff --git a/adaptors/ecore/wayland/event-handler-ecore-wl.cpp b/adaptors/ecore/wayland/event-handler-ecore-wl.cpp index 84a8aa2..6d29d80 100644 --- a/adaptors/ecore/wayland/event-handler-ecore-wl.cpp +++ b/adaptors/ecore/wayland/event-handler-ecore-wl.cpp @@ -193,8 +193,13 @@ struct EventHandler::Impl mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_KEY_DOWN, EcoreEventKeyDown, handler ) ); mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_KEY_UP, EcoreEventKeyUp, handler ) ); + // Register Selection event - clipboard selection + mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_WL_EVENT_DATA_SOURCE_SEND, EcoreEventDataSend, handler ) ); + mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_WL_EVENT_SELECTION_DATA_READY, EcoreEventDataReceive, handler ) ); + // Register Detent event mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_DETENT_ROTATE, EcoreEventDetent, handler) ); + #ifndef DALI_PROFILE_UBUNTU // Register Vconf notify - font name and size vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontNameChanged, handler ); @@ -502,7 +507,8 @@ struct EventHandler::Impl } } } - // No need to connect callbacks as KeyboardStatusChanged will be called. + Dali::Clipboard clipboard = Clipboard::Get(); + clipboard.HideClipboard(); } return ECORE_CALLBACK_PASS_ON; @@ -534,9 +540,13 @@ struct EventHandler::Impl } } - // Clipboard don't support that whether clipboard is shown or not. Hide clipboard. + // Hiding clipboard event will be ignored once because window focus out event is always received on showing clipboard Dali::Clipboard clipboard = Clipboard::Get(); - clipboard.HideClipboard(); + if ( clipboard ) + { + Clipboard& clipBoardImpl( GetImplementation( clipboard ) ); + clipBoardImpl.HideClipboard(true); + } } return ECORE_CALLBACK_PASS_ON; @@ -652,8 +662,51 @@ struct EventHandler::Impl } /** - * Called when detent event is recevied - */ + * Called when the source window notifies us the content in clipboard is selected. + */ + static Eina_Bool EcoreEventDataSend( void* data, int type, void* event ) + { + DALI_LOG_INFO(gSelectionEventLogFilter, Debug::Concise, "EcoreEventDataSend\n" ); + + Dali::Clipboard clipboard = Clipboard::Get(); + if ( clipboard ) + { + Clipboard& clipBoardImpl( GetImplementation( clipboard ) ); + clipBoardImpl.ExcuteBuffered( true, event ); + } + return ECORE_CALLBACK_PASS_ON; + } + + /** + * Called when the source window sends us about the selected content. + * For example, when item is selected in the clipboard. + */ + static Eina_Bool EcoreEventDataReceive( void* data, int type, void* event ) + { + DALI_LOG_INFO(gSelectionEventLogFilter, Debug::Concise, "EcoreEventDataReceive\n" ); + + EventHandler* handler( (EventHandler*)data ); + Dali::Clipboard clipboard = Clipboard::Get(); + char *selectionData = NULL; + if ( clipboard ) + { + Clipboard& clipBoardImpl( GetImplementation( clipboard ) ); + selectionData = clipBoardImpl.ExcuteBuffered( false, event ); + } + if ( selectionData && handler->mClipboardEventNotifier ) + { + ClipboardEventNotifier& clipboardEventNotifier( ClipboardEventNotifier::GetImplementation( handler->mClipboardEventNotifier ) ); + std::string content( selectionData, strlen(selectionData) ); + + clipboardEventNotifier.SetContent( content ); + clipboardEventNotifier.EmitContentSelectedSignal(); + } + return ECORE_CALLBACK_PASS_ON; + } + + /* + * Called when detent event is recevied + */ static Eina_Bool EcoreEventDetent( void* data, int type, void* event ) { DALI_LOG_INFO(gSelectionEventLogFilter, Debug::Concise, "EcoreEventDetent\n" ); diff --git a/adaptors/wayland/clipboard/clipboard-impl-wl.cpp b/adaptors/wayland/clipboard/clipboard-impl-wl.cpp index e207e6f..611ddf3 100644 --- a/adaptors/wayland/clipboard/clipboard-impl-wl.cpp +++ b/adaptors/wayland/clipboard/clipboard-impl-wl.cpp @@ -87,11 +87,10 @@ bool Clipboard::SetItem(const std::string &itemData ) } /* - * Get string at given index of clipboard + * Request clipboard service to retrieve an item */ -std::string Clipboard::GetItem( unsigned int index ) // change string to a Dali::Text object. +void Clipboard::RequestItem() { - return "not supported"; } /* @@ -111,10 +110,19 @@ void Clipboard::ShowClipboard() { } -void Clipboard::HideClipboard() +void Clipboard::HideClipboard(bool skipFirstHide) { } +bool Clipboard::IsVisible() const +{ + return false; +} + +char* Clipboard::ExcuteBuffered( bool type, void *event ) +{ + return NULL; +} } // namespace Adaptor diff --git a/adaptors/x11/clipboard-impl-x.cpp b/adaptors/x11/clipboard-impl-x.cpp index 1982b5e..de8c98d 100644 --- a/adaptors/x11/clipboard-impl-x.cpp +++ b/adaptors/x11/clipboard-impl-x.cpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace //unnamed namespace { @@ -127,15 +128,11 @@ bool Clipboard::SetItem(const std::string &itemData ) } /* - * Get string at given index of clipboard + * Request clipboard service to retrieve an item */ -std::string Clipboard::GetItem( unsigned int index ) // change string to a Dali::Text object. +void Clipboard::RequestItem() { - if ( index >= NumberOfItems() ) - { - return ""; - } - + int index = 0; char sendBuf[20]; snprintf( sendBuf, 20, "%s%d", CBHM_ITEM, index ); Ecore_X_Atom xAtomCbhmItem = ecore_x_atom_get( sendBuf ); @@ -150,10 +147,17 @@ std::string Clipboard::GetItem( unsigned int index ) // change string to a Dali Ecore_X_Atom xAtomCbhmError = ecore_x_atom_get( CBHM_ERROR ); if ( xAtomItemType != xAtomCbhmError ) { - return clipboardString; + // Call ClipboardEventNotifier to notify event observe of retrieved string + Dali::ClipboardEventNotifier clipboardEventNotifier(ClipboardEventNotifier::Get()); + if ( clipboardEventNotifier ) + { + ClipboardEventNotifier& notifierImpl( ClipboardEventNotifier::GetImplementation( clipboardEventNotifier ) ); + + notifierImpl.SetContent( clipboardString ); + notifierImpl.EmitContentSelectedSignal(); + } } } - return ""; } /* @@ -190,7 +194,7 @@ void Clipboard::ShowClipboard() ECore::WindowInterface::SendXEvent( ecore_x_display_get(), cbhmWin, False, NoEventMask, atomCbhmMsg, 8, SHOW ); } -void Clipboard::HideClipboard() +void Clipboard::HideClipboard(bool skipFirstHide) { Ecore_X_Window cbhmWin = ECore::WindowInterface::GetWindow(); // Launch the clipboard window @@ -201,6 +205,15 @@ void Clipboard::HideClipboard() ecore_x_selection_secondary_clear(); } +bool Clipboard::IsVisible() const +{ + return false; +} + +char* Clipboard::ExcuteBuffered( bool type, void *event ) +{ + return NULL; +} } // namespace Adaptor -- 2.7.4