Implement wayland clipboard 24/82324/17
authorsuhyung Eom <suhyung.eom@samsung.com>
Wed, 3 Aug 2016 01:24:48 +0000 (10:24 +0900)
committersuhyung Eom <suhyung.eom@samsung.com>
Wed, 24 Aug 2016 08:33:35 +0000 (17:33 +0900)
Signed-off-by: suhyung Eom <suhyung.eom@samsung.com>
Change-Id: I5fb6dcec69ecf65a346b31d8002530e7745a9bc6

adaptors/common/clipboard-impl.h
adaptors/devel-api/adaptor-framework/clipboard.cpp
adaptors/devel-api/adaptor-framework/clipboard.h
adaptors/ecore/wayland/clipboard-impl-ecore-wl.cpp
adaptors/ecore/wayland/event-handler-ecore-wl.cpp
adaptors/wayland/clipboard/clipboard-impl-wl.cpp
adaptors/x11/clipboard-impl-x.cpp

index da164a9..75f70e9 100644 (file)
@@ -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<Internal::Adaptor::Clipboard&>(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<const Internal::Adaptor::Clipboard&>(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<Internal::Adaptor::Clipboard&>(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<const Internal::Adaptor::Clipboard&>(handle);
+}
 
 } // namespace Dali
 
index 95f1b52..38264a5 100644 (file)
@@ -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
index 9b5a54a..5d84c8f 100644 (file)
@@ -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
 
index cea687c..1744b2d 100644 (file)
 #include <dali/public-api/object/any.h>
 #include <dali/public-api/object/type-registry.h>
 #include <dali/integration-api/debug.h>
+#include <unistd.h>
+
+#ifdef DALI_ELDBUS_AVAILABLE
+#include <Eldbus.h>
+#endif // DALI_ELDBUS_AVAILABLE
 
 // INTERNAL INCLUDES
 #include <singleton-service-impl.h>
 
-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<Clipboard::Impl*>(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
 
index 84a8aa2..6d29d80 100644 (file)
@@ -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" );
index e207e6f..611ddf3 100644 (file)
@@ -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
 
index 1982b5e..de8c98d 100644 (file)
@@ -28,6 +28,7 @@
 #include <adaptor-impl.h>
 #include <ecore-x-window-interface.h>
 #include <singleton-service-impl.h>
+#include <clipboard-event-notifier-impl.h>
 
 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