ecore_win32: add clipboard management 60/85460/1
authorVincent Torri <vincent dot torri at gmail dot com>
Thu, 15 Oct 2015 21:11:28 +0000 (23:11 +0200)
committerThiep Ha <thiep.ha@samsung.com>
Thu, 25 Aug 2016 07:02:22 +0000 (16:02 +0900)
@feature

Change-Id: If9577dcb75efeaa7579df440224285ec5ce60049
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
src/Makefile_Ecore_Win32.am
src/lib/ecore_win32/Ecore_Win32.h
src/lib/ecore_win32/ecore_win32.c
src/lib/ecore_win32/ecore_win32_clipboard.c [new file with mode: 0644]
src/lib/ecore_win32/ecore_win32_event.c
src/lib/ecore_win32/ecore_win32_private.h

index dbdaec5..0f564f6 100644 (file)
@@ -10,6 +10,7 @@ lib/ecore_win32/Ecore_Win32.h
 
 lib_ecore_win32_libecore_win32_la_SOURCES = \
 lib/ecore_win32/ecore_win32.c \
+lib/ecore_win32/ecore_win32_clipboard.c \
 lib/ecore_win32/ecore_win32_cursor.c \
 lib/ecore_win32/ecore_win32_dnd.c \
 lib/ecore_win32/ecore_win32_dnd_enumformatetc.cpp \
index b829a7b..95fecc0 100644 (file)
@@ -129,6 +129,21 @@ typedef enum
 } Ecore_Win32_DnD_State;
 
 /**
+ * @typedef Ecore_Win32_Selection
+ * Type of the selection.
+ *
+ * @since 1.16
+ */
+typedef enum
+{
+   ECORE_WIN32_SELECTION_PRIMARY,
+   ECORE_WIN32_SELECTION_SECONDARY,
+   ECORE_WIN32_SELECTION_DND,
+   ECORE_WIN32_SELECTION_CLIPBOARD,
+   ECORE_WIN32_SELECTION_OTHER
+} Ecore_Win32_Selection;
+
+/**
  * @typedef Ecore_Win32_Window
  * Abstract type for a window.
  */
@@ -214,6 +229,22 @@ typedef struct _Ecore_Win32_Event_Window_Resize         Ecore_Win32_Event_Window
 typedef struct _Ecore_Win32_Event_Window_Delete_Request Ecore_Win32_Event_Window_Delete_Request;
 
 /**
+ * @typedef Ecore_Win32_Event_Selection_Clear
+ * Event sent when the content of the clipboard has been removed.
+ *
+ * @since 1.16
+ */
+typedef struct _Ecore_Win32_Event_Selection_Clear Ecore_Win32_Event_Selection_Clear;
+
+/**
+ * @typedef Ecore_Win32_Event_Selection_Notify
+ * Event sent when the content of the clipboard has been added.
+ *
+ * @since 1.16
+ */
+typedef struct _Ecore_Win32_Event_Selection_Notify Ecore_Win32_Event_Selection_Notify;
+
+/**
  * @struct _Ecore_Win32_Event_Mouse_In
  * Event sent when the mouse enters the window.
  */
@@ -351,6 +382,33 @@ struct _Ecore_Win32_Event_Window_Delete_Request
 };
 
 /**
+ * @struct _Ecore_Win32_Event_Selection_Clear
+ * Event sent when the content of the clipboard has been removed.
+ *
+ * @since 1.16
+ */
+struct _Ecore_Win32_Event_Selection_Clear
+{
+   Ecore_Win32_Window   *window; /**< The window that received the event */
+   unsigned long         timestamp; /**< The time the event occurred */
+   Ecore_Win32_Selection selection; /**< The type of the selection */
+};
+
+/**
+ * @struct _Ecore_Win32_Event_Selection_Notify
+ * Event sent when the content of the clipboard has been added.
+ *
+ * @since 1.16
+ */
+struct _Ecore_Win32_Event_Selection_Notify
+{
+   Ecore_Win32_Window   *window; /**< The window that received the event */
+   unsigned long         timestamp; /**< The time the event occurred */
+   Ecore_Win32_Selection selection; /**< The type of the selection */
+   void                 *data; /**< The data of the selection */
+};
+
+/**
  * @typedef Ecore_Win32_Dnd_DropTarget_Callback
  * Callback type for Drop operations. See ecore_win32_dnd_register_drop_target().
  */
@@ -368,6 +426,8 @@ EAPI extern int ECORE_WIN32_EVENT_WINDOW_SHOW; /**< Ecore_Event for the Ecore_Wi
 EAPI extern int ECORE_WIN32_EVENT_WINDOW_CONFIGURE; /**< Ecore_Event for the Ecore_Win32_Event_Configure event */
 EAPI extern int ECORE_WIN32_EVENT_WINDOW_RESIZE; /**< Ecore_Event for the Ecore_Win32_Event_Resize event */
 EAPI extern int ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST; /**< Ecore_Event for the #Ecore_Win32_Event_Window_Delete_Request event */
+EAPI extern int ECORE_WIN32_EVENT_SELECTION_CLEAR; /**< Ecore_Event for the #Ecore_Win32_Event_Selection_Clear event @since 1.16 */
+EAPI extern int ECORE_WIN32_EVENT_SELECTION_NOTIFY; /**< Ecore_Event for the #Ecore_Win32_Event_Selection_Notify event @since 1.16 */
 
 
 /* Core */
@@ -520,6 +580,60 @@ EAPI Eina_Bool ecore_win32_dnd_register_drop_target(Ecore_Win32_Window
                                                     Ecore_Win32_Dnd_DropTarget_Callback callback);
 EAPI void      ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window);
 
+/* Clipboard */
+
+/**
+ * @brief Set data to the clipboard.
+ *
+ * @param[in] window The window that owns the clipboard.
+ * @param[in] data The data to set.
+ * @param[in] size The size of the data.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function sets @p data of size @p size in the clipboard owned by
+ * @p window. This function returns #EINA_TRUE on success, and
+ * #EINA_FALSE otherwise. If @p window or @p data are @c NULL, or @p size
+ * is less than or equal to 0, this function returns #EINA_FALSE.
+ *
+ * @since 1.16
+ */
+EAPI Eina_Bool ecore_win32_clipboard_set(const Ecore_Win32_Window *window,
+                                         const void *data,
+                                         int size);
+
+/**
+ * @brief Get data from the clipboard.
+ *
+ * @param[in] window The window that owns the clipboard.
+ * @param[out] data The retrieved data.
+ * @param[out] size The size of the data.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function gets @p data of size @p size from the clipboard owned by
+ * @p window. This function returns #EINA_TRUE on success, and
+ * #EINA_FALSE otherwise. If @p window is @c NULL, this function returns
+ * #EINA_FALSE. @p data and @p size must be valid buffers.
+ *
+ * @since 1.16
+ */
+EAPI Eina_Bool ecore_win32_clipboard_get(const Ecore_Win32_Window *window,
+                                         void **data,
+                                         int *size);
+
+/**
+ * @brief Cleat the clipboard.
+ *
+ * @param[in] window The window that owns the clipboard.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function clears the clipboard owned by @p window. This
+ * function returns #EINA_TRUE on success, and #EINA_FALSE otherwise.
+ * If @p window is @c NULL, this function returns #EINA_FALSE.
+ *
+ * @since 1.16
+ */
+EAPI Eina_Bool ecore_win32_clipboard_clear(const Ecore_Win32_Window *window);
+
 /**
  * @}
  */
index cb54190..9a9bf9c 100644 (file)
  * @cond LOCAL
  */
 
+/* FIXME: uncomment when mingw-w64 will be updated in win-builds */
+
+/* #if _WIN32_WINNT >= 0x0600 */
+/* # ifndef WM_CLIPBOARDUPDATE */
+#  define WM_CLIPBOARDUPDATE 0x031D
+/* # endif */
+/* #endif */
+
 /* OLE IID for Drag'n Drop */
 
-# define INITGUID
-# include <basetyps.h>
+#define INITGUID
+#include <basetyps.h>
 DEFINE_OLEGUID(IID_IEnumFORMATETC, 0x00000103L, 0, 0);
 DEFINE_OLEGUID(IID_IDataObject,    0x0000010EL, 0, 0);
 DEFINE_OLEGUID(IID_IDropSource,    0x00000121L, 0, 0);
@@ -36,7 +44,10 @@ DEFINE_OLEGUID(IID_IUnknown,       0x00000000L, 0, 0);
 
 #define IDI_ICON 101
 
-static int       _ecore_win32_init_count = 0;
+typedef BOOL WINAPI (*efl_AddClipboardFormatListener)(_In_ HWND hwnd);
+typedef BOOL WINAPI (*efl_RemoveClipboardFormatListener)(_In_ HWND hwnd);
+
+static int _ecore_win32_init_count = 0;
 
 LRESULT CALLBACK
 _ecore_win32_window_procedure(HWND   window,
@@ -194,13 +205,33 @@ _ecore_win32_window_procedure(HWND   window,
        return 0;
        /* Window notifications */
      case WM_CREATE:
-       INF("create window message");
+       {
+          efl_AddClipboardFormatListener acfl;
+
+          INF("create window message");
+          acfl = (efl_AddClipboardFormatListener)GetProcAddress(GetModuleHandle("user32.dll"),
+                                                                "AddClipboardFormatListener");
+          if (acfl)
+            {
+               if (!acfl(window))
+                 INF("can not create clipboard format listener; no clipboard notification will be sent");
+            }
        _ecore_win32_event_handle_create_notify(data);
        return 0;
+       }
      case WM_DESTROY:
-       INF("destroy window message");
-       _ecore_win32_event_handle_destroy_notify(data);
-       return 0;
+       {
+          efl_RemoveClipboardFormatListener rcfl;
+
+          INF("destroy window message");
+          _ecore_win32_event_handle_destroy_notify(data);
+
+          rcfl = (efl_RemoveClipboardFormatListener)GetProcAddress(GetModuleHandle("user32.dll"),
+                                                                   "RemoveClipboardFormatListener");
+          if (rcfl)
+            rcfl(window);
+          return 0;
+       }
      case WM_SHOWWINDOW:
        INF("show window message");
        if ((data->data_param == SW_OTHERUNZOOM) ||
@@ -299,6 +330,10 @@ _ecore_win32_window_procedure(HWND   window,
            return 0;
          }
        return DefWindowProc(window, message, window_param, data_param);
+      case WM_CLIPBOARDUPDATE:
+       INF("clipboard data updated");
+       _ecore_win32_event_handle_selection_notify(data);
+       return 0;
        /* GDI notifications */
      case WM_PAINT:
        {
@@ -358,6 +393,8 @@ int ECORE_WIN32_EVENT_WINDOW_HIDE           = 0;
 int ECORE_WIN32_EVENT_WINDOW_CONFIGURE      = 0;
 int ECORE_WIN32_EVENT_WINDOW_RESIZE         = 0;
 int ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST = 0;
+int ECORE_WIN32_EVENT_SELECTION_CLEAR       = 0;
+int ECORE_WIN32_EVENT_SELECTION_NOTIFY      = 0;
 
 /*============================================================================*
  *                                   API                                      *
@@ -504,6 +541,8 @@ ecore_win32_init()
         ECORE_WIN32_EVENT_WINDOW_CONFIGURE      = ecore_event_type_new();
         ECORE_WIN32_EVENT_WINDOW_RESIZE         = ecore_event_type_new();
         ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new();
+        ECORE_WIN32_EVENT_SELECTION_CLEAR       = ecore_event_type_new();
+        ECORE_WIN32_EVENT_SELECTION_NOTIFY      = ecore_event_type_new();
      }
 
    return _ecore_win32_init_count;
diff --git a/src/lib/ecore_win32/ecore_win32_clipboard.c b/src/lib/ecore_win32/ecore_win32_clipboard.c
new file mode 100644 (file)
index 0000000..a20be68
--- /dev/null
@@ -0,0 +1,188 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <Eina.h>
+
+#include "Ecore_Win32.h"
+#include "ecore_win32_private.h"
+
+/*============================================================================*
+ *                                  Local                                     *
+ *============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ *                                 Global                                     *
+ *============================================================================*/
+
+
+/*============================================================================*
+ *                                   API                                      *
+ *============================================================================*/
+
+
+EAPI Eina_Bool
+ecore_win32_clipboard_set(const Ecore_Win32_Window *window,
+                          const void *data,
+                          int size)
+{
+   HGLOBAL global;
+   char *d;
+
+   /*
+    * See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms649016%28v=vs.85%29.aspx#_win32_Copying_Information_to_the_Clipboard
+    * 1. Open the clipboard
+    * 2. Empty the clipboard
+    * 3. Set the data
+    * 4. Close the clipboard
+    */
+
+   INF("setting data to the clipboard");
+
+   if (!window || !data || (size <= 0))
+     return EINA_FALSE;
+
+   if (!OpenClipboard(window->window))
+     return EINA_FALSE;
+
+   if (!EmptyClipboard())
+     goto close_clipboard;
+
+   global = GlobalAlloc(GMEM_MOVEABLE, size + 1);
+   if (!global)
+     goto close_clipboard;
+
+   d = (char *)GlobalLock(global);
+   if (!d)
+     goto unlock_global;
+
+   memcpy(d, data, size);
+   d[size] = '\0';
+   GlobalUnlock(global);
+   SetClipboardData(CF_TEXT, global);
+   CloseClipboard();
+
+   return EINA_TRUE;
+
+ unlock_global:
+   GlobalUnlock(global);
+ close_clipboard:
+   CloseClipboard();
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_win32_clipboard_get(const Ecore_Win32_Window *window,
+                          void **data,
+                          int *size)
+{
+   HGLOBAL global;
+   void *d;
+   void *p;
+
+   /*
+    * See https://msdn.microsoft.com/en-us/library/windows/desktop/ms649016%28v=vs.85%29.aspx#_win32_Pasting_Information_from_the_Clipboard
+    * 1. Open Clipboard
+    * 2. Determine format
+    * 3. Retrieve data
+    * 4. Manage data
+    * 5. Close clipboard
+    */
+
+   INF("getting data from the clipboard");
+
+   if (!window)
+     return EINA_FALSE;
+
+   if (!IsClipboardFormatAvailable(CF_TEXT))
+     return EINA_FALSE;
+
+   if (!OpenClipboard(window->window))
+     goto set_val;
+
+   /* { */
+   /*   UINT fmt = 0; */
+
+   /*   while (1) */
+   /*     { */
+   /*       fmt = EnumClipboardFormats(fmt); */
+   /*       printf(" $ Format : %x\n", fmt); */
+   /*       if (!fmt) */
+   /*         break; */
+   /*     } */
+   /* } */
+
+   global = GetClipboardData(CF_TEXT);
+   if (!global)
+     goto close_clipboard;
+
+   d = GlobalLock(global);
+   if (!d)
+     goto unlock_global;
+
+   *size = strlen(d);
+   p = malloc(*size);
+   if (!p)
+     goto unlock_global;
+
+   memcpy(p, d, *size);
+   *data = p;
+   GlobalUnlock(global);
+   CloseClipboard();
+
+   return EINA_TRUE;
+
+ unlock_global:
+   GlobalUnlock(global);
+ close_clipboard:
+   CloseClipboard();
+ set_val:
+   *data = NULL;
+   *size = 0;
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+ecore_win32_clipboard_clear(const Ecore_Win32_Window *window)
+{
+   INF("clearing the clipboard");
+
+   if (!window)
+     return EINA_FALSE;
+
+   if (!OpenClipboard(window->window))
+     return EINA_FALSE;
+
+   if (!EmptyClipboard())
+     goto close_clipboard;
+
+   CloseClipboard();
+
+   return EINA_TRUE;
+
+ close_clipboard:
+   CloseClipboard();
+
+   return EINA_FALSE;
+}
+
+/**
+ * @}
+ */
index 99ad2d4..b5f0d60 100644 (file)
@@ -40,6 +40,7 @@ static int                  _ecore_win32_mouse_down_did_triple = 0;
 static int                  _ecore_win32_mouse_up_count = 0;
 static Ecore_Win32_Key_Mask _ecore_win32_key_mask = 0;
 static Eina_Bool            _ecore_win32_ctrl_fake = EINA_FALSE;
+static Eina_Bool            _ecore_win32_clipboard_has_data = EINA_FALSE;
 
 static unsigned int
 _ecore_win32_modifiers_get(void)
@@ -1895,3 +1896,72 @@ _ecore_win32_event_handle_delete_request(Ecore_Win32_Callback_Data *msg)
 
    ecore_event_add(ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL);
 }
+
+void
+_ecore_win32_event_handle_selection_notify(Ecore_Win32_Callback_Data *msg)
+{
+   Ecore_Win32_Event_Selection_Notify *e;
+   HGLOBAL global;
+   char *str;
+
+   INF("selection_notify");
+
+   /*
+    * we have text data in clipboard but no data before,
+    * so text data has just been added
+    */
+   if (IsClipboardFormatAvailable(CF_TEXT) && !_ecore_win32_clipboard_has_data)
+     {
+        e = calloc(1, sizeof(Ecore_Win32_Event_Selection_Notify));
+        if (!e) return;
+
+        e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+        e->timestamp = _ecore_win32_event_last_time;
+        e->selection = ECORE_WIN32_SELECTION_CLIPBOARD;
+
+        if (!OpenClipboard(msg->window))
+          goto free_e;
+
+        global = GetClipboardData(CF_TEXT);
+        if (!global)
+          goto close_clipboard;
+
+        str = GlobalLock(global);
+        if (str)
+          {
+             e->data = strdup(str);
+             GlobalUnlock(global);
+          }
+
+        CloseClipboard();
+
+        ecore_event_add(ECORE_WIN32_EVENT_SELECTION_NOTIFY, e, NULL, NULL);
+
+        _ecore_win32_clipboard_has_data = EINA_TRUE;
+     }
+
+   /*
+    * we have no more text data in clipboard and data before,
+    * so text data has just been removed
+    */
+   if (!IsClipboardFormatAvailable(CF_TEXT) && _ecore_win32_clipboard_has_data)
+     {
+        e = calloc(1, sizeof(Ecore_Win32_Event_Selection_Clear));
+        if (!e) return;
+
+        e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA);
+        e->timestamp = _ecore_win32_event_last_time;
+        e->selection = ECORE_WIN32_SELECTION_CLIPBOARD;
+
+        ecore_event_add(ECORE_WIN32_EVENT_SELECTION_CLEAR, e, NULL, NULL);
+
+        _ecore_win32_clipboard_has_data = EINA_FALSE;
+     }
+
+   return;
+
+ close_clipboard:
+   CloseClipboard();
+ free_e:
+   free(e);
+}
index 1e2bb1b..23af65a 100644 (file)
@@ -164,6 +164,7 @@ void  _ecore_win32_event_handle_unmap_notify(Ecore_Win32_Callback_Data *msg);
 void  _ecore_win32_event_handle_configure_notify(Ecore_Win32_Callback_Data *msg);
 void  _ecore_win32_event_handle_resize(Ecore_Win32_Callback_Data *msg);
 void  _ecore_win32_event_handle_delete_request(Ecore_Win32_Callback_Data *msg);
+void  _ecore_win32_event_handle_selection_notify(Ecore_Win32_Callback_Data *msg);
 
 void *_ecore_win32_dnd_data_object_new(void *fmtetc, void *stgmeds, int count);
 void _ecore_win32_dnd_data_object_free(void *data_object);