Get surrounding and selection text by fd 06/69606/5
authorLi Zhang <li2012.zhang@samsung.com>
Fri, 13 May 2016 14:18:35 +0000 (22:18 +0800)
committerLi Zhang <li2012.zhang@samsung.com>
Wed, 8 Jun 2016 05:43:06 +0000 (13:43 +0800)
Passing selection and surrounding text have limit of 4096 bytes if using string type argument
in wayland protocol, the wayland-client library will crash if over this limit. using fd type
argument does not have this constraint.

Change-Id: I07b4d7fc8f7024b2b8096ad2b37ab741b3613f7a

13 files changed:
configure.ac
ism/extras/wayland_immodule/wayland_imcontext.c
ism/modules/panelagent/ecoresocket/ecore_socket_panel_agent_module.cpp
ism/modules/panelagent/wayland/wayland_panel_agent_module.cpp
ism/src/isf_info_manager.cpp
ism/src/isf_info_manager.h
ism/src/isf_panel_agent_base.cpp
ism/src/isf_panel_agent_base.h
ism/src/isf_panel_agent_manager.cpp
ism/src/isf_panel_agent_manager.h
ism/src/scim_helper.cpp
ism/src/scim_socket.cpp
ism/src/scim_socket.h

index a2cc470..4f1efd6 100644 (file)
@@ -194,6 +194,8 @@ AC_SUBST(UINT16)
 AC_SUBST(UINT32)
 AC_SUBST(UINT64)
 
+AC_CHECK_MEMBERS([struct msghdr.msg_control],,, [#include <sys/socket.h>])
+
 # Checks for library functions.
 AC_FUNC_MALLOC
 AC_CHECK_FUNCS([gettimeofday memmove memset nl_langinfo setlocale daemon])
index 2aab5b0..e511774 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include "scim_private.h"
+#include <unistd.h>
 
 #include <Ecore.h>
 #include <Ecore_Evas.h>
@@ -950,55 +951,71 @@ text_input_input_panel_data(void                 *data,
     if (!imcontext || !imcontext->ctx) return;
 
     if (imcontext->input_panel_data)
-        free(imcontext->input_panel_data);
+        free (imcontext->input_panel_data);
 
-    imcontext->input_panel_data = calloc(1, length);
-    memcpy(imcontext->input_panel_data, input_panel_data, length);
+    imcontext->input_panel_data = calloc (1, length);
+    memcpy (imcontext->input_panel_data, input_panel_data, length);
     imcontext->input_panel_data_length = length;
 }
 
 static void
 text_input_get_selection_text (void                 *data,
-                              struct wl_text_input *text_input EINA_UNUSED,
-                              uint32_t              serial)
+                               struct wl_text_input *text_input EINA_UNUSED,
+                               int32_t              fd)
 {
     char *selection = NULL;
-    LOGD ("%d", serial);
+    LOGD ("%d", fd);
     WaylandIMContext *imcontext = (WaylandIMContext *)data;
     if (!imcontext || !imcontext->ctx) {
         LOGD ("");
+        close (fd);
         return;
     }
 
     ecore_imf_context_selection_get (imcontext->ctx, &selection);
     if (imcontext->text_input) {
         LOGD ("selection :%s", selection ? selection : "");
-        wl_text_input_set_selection_text (imcontext->text_input, serial, selection ? selection : "");
+        if (selection) {
+            char *_selection = selection;
+            size_t len = strlen (selection);
+            while (len) {
+                ssize_t ret = write (fd, _selection, len);
+                if (ret <= 0) {
+                    if (errno == EINTR)
+                        continue;
+                    LOGW ("write pipe failed, errno: %d", errno);
+                    break;
+                }
+                _selection += ret;
+                len -= ret;
+            }
+        }
     }
-
     if (selection)
         free (selection);
+    close (fd);
 }
 
 static void
 text_input_get_surrounding_text (void                 *data,
-                                struct wl_text_input *text_input EINA_UNUSED,
-                                uint32_t              serial,
-                                uint32_t              maxlen_before,
-                                uint32_t              maxlen_after)
+                                 struct wl_text_input *text_input EINA_UNUSED,
+                                 uint32_t              maxlen_before,
+                                 uint32_t              maxlen_after,
+                                 int32_t              fd)
 {
     int cursor_pos;
     char *surrounding = NULL;
-    LOGD ("serial: %d maxlen_before: %d maxlen_after: %d", serial, maxlen_before, maxlen_after);
+    LOGD("fd: %d maxlen_before: %d maxlen_after: %d", fd, maxlen_before, maxlen_after);
     WaylandIMContext *imcontext = (WaylandIMContext *)data;
     if (!imcontext || !imcontext->ctx) {
-        LOGD ("");
+        LOGD("");
+        close(fd);
         return;
     }
 
     /* cursor_pos is a byte index */
     if (ecore_imf_context_surrounding_get (imcontext->ctx, &surrounding, &cursor_pos)) {
-        LOGD ("surrounding :%s, cursor: %d", surrounding? surrounding : "", cursor_pos);
+        LOGD ("surrounding :%s, cursor: %d", surrounding ? surrounding : "", cursor_pos);
         if (imcontext->text_input) {
             Eina_Unicode *wide_surrounding = eina_unicode_utf8_to_unicode (surrounding, NULL);
             size_t wlen = eina_unicode_strlen (wide_surrounding);
@@ -1018,8 +1035,21 @@ text_input_get_surrounding_text (void                 *data,
 
             char *req_surrounding = eina_unicode_unicode_to_utf8_range (wide_surrounding + maxlen_before, maxlen_after - maxlen_before, NULL);
 
-            wl_text_input_set_surrounding_text (imcontext->text_input,
-                    serial, req_surrounding ? req_surrounding : "", cursor_pos);
+            if (req_surrounding) {
+                char *_surrounding = req_surrounding;
+                size_t len = strlen(req_surrounding);
+                while (len) {
+                    ssize_t ret = write(fd, _surrounding, len);
+                    if (ret <= 0) {
+                        if (errno == EINTR)
+                            continue;
+                        LOGW ("write pipe failed, errno: %d", errno);
+                        break;
+                    }
+                    _surrounding += ret;
+                    len -= ret;
+                }
+            }
 
             if (req_surrounding)
                 free (req_surrounding);
@@ -1031,6 +1061,7 @@ text_input_get_surrounding_text (void                 *data,
         if (surrounding)
             free (surrounding);
     }
+    close(fd);
 }
 //
 
index 2946af8..0c72da0 100644 (file)
@@ -1165,7 +1165,7 @@ private:
         unlock();
     }
 
-    void socket_helper_get_surrounding_text(int client, uint32 context_id, uint32 maxlen_before, uint32 maxlen_after) {
+    void socket_helper_get_surrounding_text(int client, uint32 context_id, uint32 maxlen_before, uint32 maxlen_after, const int fd) {
         SCIM_DEBUG_MAIN(4) << __FUNCTION__ << " (" << client << ")\n";
         LOGD ("client id:%d\n", client);
 
@@ -1197,7 +1197,7 @@ private:
         unlock();
     }
 
-    void socket_helper_get_selection(int client, uint32 context_id) {
+    void socket_helper_get_selection(int client, uint32 context_id, const int fd) {
         SCIM_DEBUG_MAIN(4) << __FUNCTION__ << " (" << client << ")\n";
         LOGD ("client id:%d\n", client);
 
@@ -2451,7 +2451,14 @@ private:
                     if (m_recv_trans.get_data(uuid) &&
                         m_recv_trans.get_data(maxlen_before) &&
                         m_recv_trans.get_data(maxlen_after)) {
-                        m_info_manager->socket_helper_get_surrounding_text(client_id, uuid, maxlen_before, maxlen_after);
+                        int fd;
+                        client.read_fd (&fd);
+                        if (fd == -1) {
+                            LOGW ("wrong format of transaction\n");
+                        } else {
+                            m_info_manager->socket_helper_get_surrounding_text(client_id, uuid, maxlen_before, maxlen_after, fd);
+                            close (fd);
+                        }
                     } else {
                         LOGW ("wrong format of transaction\n");
                     }
@@ -2468,7 +2475,14 @@ private:
                     String uuid;
 
                     if (m_recv_trans.get_data(uuid)) {
-                        m_info_manager->socket_helper_get_selection(client_id, uuid);
+                        int fd;
+                        client.read_fd (&fd);
+                        if (fd == -1) {
+                            LOGW ("wrong format of transaction\n");
+                        } else {
+                            m_info_manager->socket_helper_get_selection(client_id, uuid, fd);
+                            close (fd);
+                        }
                     } else {
                         LOGW ("wrong format of transaction\n");
                     }
index 8df93aa..209e030 100644 (file)
@@ -251,22 +251,6 @@ InfoManager* g_info_manager = NULL;
 /////////////////////////////////////////////////////////////////////////////
 // Implementation of Wayland Input Method functions.
 /////////////////////////////////////////////////////////////////////////////
-static void
-_wsc_im_ctx_surrounding_text(void *data, struct wl_input_method_context *im_ctx, uint32_t serial, const char *text, uint32_t cursor_position)
-{
-    LOGD ("");
-    WSCContextISF *wsc_ctx = (WSCContextISF*)data;
-    if (!wsc_ctx) return;
-
-    if (wsc_ctx->surrounding_text)
-        free (wsc_ctx->surrounding_text);
-
-    wsc_ctx->surrounding_text = strdup (text ? text : "");
-    wsc_ctx->surrounding_cursor = cursor_position;
-    g_info_manager->socket_update_surrounding_text (wsc_ctx->surrounding_text, wsc_ctx->surrounding_cursor);
-
-    LOGD ("text : '%s', cursor : %d\n", text, cursor_position);
-}
 
 static void
 _wsc_im_ctx_reset(void *data, struct wl_input_method_context *im_ctx)
@@ -409,17 +393,6 @@ _wsc_im_ctx_bidi_direction(void *data, struct wl_input_method_context *im_ctx, u
 }
 
 static void
-_wsc_im_ctx_selection_text(void *data, struct wl_input_method_context *im_ctx, uint32_t serial, const char *text)
-{
-    WSCContextISF *wsc_ctx = (WSCContextISF*)data;
-
-    LOGD ("im_context = %p selection text = %s\n", im_ctx, text);
-    if (!wsc_ctx) return;
-
-    g_info_manager->socket_update_selection (text);
-}
-
-static void
 _wsc_im_ctx_cursor_position(void *data, struct wl_input_method_context *im_ctx, uint32_t cursor_pos)
 {
     WSCContextISF *wsc_ctx = (WSCContextISF*)data;
@@ -431,7 +404,6 @@ _wsc_im_ctx_cursor_position(void *data, struct wl_input_method_context *im_ctx,
 }
 
 static const struct wl_input_method_context_listener wsc_im_context_listener = {
-     _wsc_im_ctx_surrounding_text,
      _wsc_im_ctx_reset,
      _wsc_im_ctx_content_type,
      _wsc_im_ctx_invoke_action,
@@ -441,8 +413,7 @@ static const struct wl_input_method_context_listener wsc_im_context_listener = {
      _wsc_im_ctx_return_key_disabled,
      _wsc_im_ctx_input_panel_data,
      _wsc_im_ctx_bidi_direction,
-     _wsc_im_ctx_selection_text,
-     _wsc_im_ctx_cursor_position,
+     _wsc_im_ctx_cursor_position
 };
 
 static void
@@ -2729,10 +2700,10 @@ public:
     }
 
     void
-    socket_helper_get_surrounding_text (int id, uint32 context_id, uint32 maxlen_before, uint32 maxlen_after) {
-        LOGD ("client id:%d", id);
+    socket_helper_get_surrounding_text (int id, uint32 context_id, uint32 maxlen_before, uint32 maxlen_after, const int fd) {
+        LOGD ("client id:%d, fd:%d", id, fd);
         WSCContextISF* ic = find_ic (context_id);
-        wl_input_method_context_get_surrounding_text(ic->im_ctx, ic->serial, maxlen_before, maxlen_after);
+        wl_input_method_context_get_surrounding_text(ic->im_ctx, maxlen_before, maxlen_after, fd);
     }
 
     void
@@ -2773,10 +2744,10 @@ public:
     }
 
     void
-    socket_helper_get_selection (int id, uint32 context_id) {
-        LOGD ("client id:%d", id);
+    socket_helper_get_selection (int id, uint32 context_id, const int fd) {
+        LOGD ("client id:%d, fd:%d", id, fd);
         WSCContextISF* ic = find_ic (context_id);
-        wl_input_method_context_get_selection_text (ic->im_ctx, ic->serial);
+        wl_input_method_context_get_selection_text (ic->im_ctx, fd);
     }
 };
 
index a935bff..909929f 100644 (file)
@@ -3130,7 +3130,7 @@ client context helpers: %d, helpers uuid count: %d",
         }
     }
     //SCIM_TRANS_CMD_GET_SURROUNDING_TEXT
-    void socket_helper_get_surrounding_text (int client, String uuid, uint32 maxlen_before, uint32 maxlen_after) {
+    void socket_helper_get_surrounding_text (int client, String uuid, uint32 maxlen_before, uint32 maxlen_after, const int fd) {
         SCIM_DEBUG_MAIN (4) << __FUNCTION__ << " (" << client << ")\n";
         LOGD ("");
         int     focused_client;
@@ -3139,7 +3139,7 @@ client context helpers: %d, helpers uuid count: %d",
         ClientInfo client_info = socket_get_client_info (focused_client);
 
         if (client_info.type == FRONTEND_CLIENT) {
-            m_panel_agent_manager.socket_helper_get_surrounding_text (focused_client, focused_context, maxlen_before, maxlen_after);
+            m_panel_agent_manager.socket_helper_get_surrounding_text (focused_client, focused_context, maxlen_before, maxlen_after, fd);
         }
     }
     //SCIM_TRANS_CMD_DELETE_SURROUNDING_TEXT
@@ -3156,7 +3156,7 @@ client context helpers: %d, helpers uuid count: %d",
         }
     }
     //SCIM_TRANS_CMD_GET_SELECTION
-    void socket_helper_get_selection (int client, String uuid) {
+    void socket_helper_get_selection (int client, String uuid, const int fd) {
         SCIM_DEBUG_MAIN (4) << __FUNCTION__ << " (" << client << ")\n";
         LOGD ("");
         int     focused_client;
@@ -3165,7 +3165,7 @@ client context helpers: %d, helpers uuid count: %d",
         ClientInfo client_info = socket_get_client_info (focused_client);
 
         if (client_info.type == FRONTEND_CLIENT) {
-            m_panel_agent_manager.socket_helper_get_selection (focused_client, focused_context);
+            m_panel_agent_manager.socket_helper_get_selection (focused_client, focused_context, fd);
         }
     }
     //SCIM_TRANS_CMD_SET_SELECTION
@@ -4581,9 +4581,9 @@ void InfoManager::socket_helper_commit_string (int client, uint32 target_ic, Str
 }
 
 //SCIM_TRANS_CMD_GET_SURROUNDING_TEXT
-void InfoManager::socket_helper_get_surrounding_text (int client, String uuid, uint32 maxlen_before, uint32 maxlen_after)
+void InfoManager::socket_helper_get_surrounding_text (int client, String uuid, uint32 maxlen_before, uint32 maxlen_after, const int fd)
 {
-    m_impl->socket_helper_get_surrounding_text (client, uuid, maxlen_before, maxlen_after);
+    m_impl->socket_helper_get_surrounding_text (client, uuid, maxlen_before, maxlen_after, fd);
 }
 
 //SCIM_TRANS_CMD_DELETE_SURROUNDING_TEXT
@@ -4593,9 +4593,9 @@ void InfoManager::socket_helper_delete_surrounding_text (int client, uint32 offs
 }
 
 //SCIM_TRANS_CMD_GET_SELECTION
-void InfoManager::socket_helper_get_selection (int client, String uuid)
+void InfoManager::socket_helper_get_selection (int client, String uuid, const int fd)
 {
-    m_impl->socket_helper_get_selection (client, uuid);
+    m_impl->socket_helper_get_selection (client, uuid, fd);
 }
 
 //SCIM_TRANS_CMD_SET_SELECTION
index f07d553..8019074 100644 (file)
@@ -883,13 +883,13 @@ public:
     void socket_helper_commit_string (int client, uint32 target_ic, String target_uuid, WideString wstr);
 
     //SCIM_TRANS_CMD_GET_SURROUNDING_TEXT
-    void socket_helper_get_surrounding_text (int client, String uuid, uint32 maxlen_before, uint32 maxlen_after);
+    void socket_helper_get_surrounding_text (int client, String uuid, uint32 maxlen_before, uint32 maxlen_after, const int fd);
 
     //SCIM_TRANS_CMD_DELETE_SURROUNDING_TEXT
     void socket_helper_delete_surrounding_text (int client, uint32 offset, uint32 len);
 
     //SCIM_TRANS_CMD_GET_SELECTION
-    void socket_helper_get_selection (int client, String uuid);
+    void socket_helper_get_selection (int client, String uuid, const int fd);
 
     //SCIM_TRANS_CMD_SET_SELECTION
     void socket_helper_set_selection (int client, uint32 start, uint32 end);
index 7a6f771..ed1b9b1 100644 (file)
@@ -398,7 +398,7 @@ void PanelAgentBase::socket_helper_key_event (int client, uint32 context, int cm
 
 //SCIM_TRANS_CMD_GET_SURROUNDING_TEXT
 //socket_helper_get_surrounding_text
-void PanelAgentBase::socket_helper_get_surrounding_text (int client, uint32 context, uint32 maxlen_before, uint32 maxlen_after)
+void PanelAgentBase::socket_helper_get_surrounding_text (int client, uint32 context, uint32 maxlen_before, uint32 maxlen_after, const int fd)
 {
     LOGW ("not implemented for %s", m_name.c_str ());
 }
@@ -409,7 +409,7 @@ void PanelAgentBase::socket_helper_delete_surrounding_text (int client, uint32 c
     LOGD ("not implemented ");
 }
 //SCIM_TRANS_CMD_GET_SELECTION
-void PanelAgentBase::socket_helper_get_selection (int client, uint32 context)
+void PanelAgentBase::socket_helper_get_selection (int client, uint32 context, const int fd)
 {
     LOGW ("not implemented for %s", m_name.c_str ());
 }
index ddf8501..4ff3a48 100644 (file)
@@ -644,7 +644,7 @@ public:
      *
      * @return none.
      */
-    virtual void socket_helper_get_surrounding_text (int client, uint32 context, uint32 maxlen_before, uint32 maxlen_after);
+    virtual void socket_helper_get_surrounding_text (int client, uint32 context, uint32 maxlen_before, uint32 maxlen_after, const int fd);
 
     /**
      * @brief socket_helper_delete_surrounding_text.
@@ -662,7 +662,7 @@ public:
      *
      * @return none.
      */
-    virtual void socket_helper_get_selection (int client, uint32 context);
+    virtual void socket_helper_get_selection (int client, uint32 context, const int fd);
 
     /**
      * @brief socket_helper_set_selection.
index a174c61..f33b009 100644 (file)
@@ -643,12 +643,12 @@ void PanelAgentManager::socket_helper_key_event (int id, uint32 context_id, int
         _p->socket_helper_key_event (id, context_id, cmd, key);
 }
 
-void PanelAgentManager::socket_helper_get_surrounding_text (int id, uint32 context_id, uint32 maxlen_before, uint32 maxlen_after)
+void PanelAgentManager::socket_helper_get_surrounding_text (int id, uint32 context_id, uint32 maxlen_before, uint32 maxlen_after, const int fd)
 {
     PanelAgentPointer _p = m_impl->get_panel_agent_by_id (id);
 
     if (!_p.null ())
-        _p->socket_helper_get_surrounding_text (id, context_id, maxlen_before, maxlen_after);
+        _p->socket_helper_get_surrounding_text (id, context_id, maxlen_before, maxlen_after, fd);
 }
 
 void PanelAgentManager::socket_helper_delete_surrounding_text (int id, uint32 context_id, uint32 offset, uint32 len)
@@ -659,12 +659,12 @@ void PanelAgentManager::socket_helper_delete_surrounding_text (int id, uint32 co
         _p->socket_helper_delete_surrounding_text (id, context_id, offset, len);
 }
 
-void PanelAgentManager::socket_helper_get_selection (int id, uint32 context_id)
+void PanelAgentManager::socket_helper_get_selection (int id, uint32 context_id, const int fd)
 {
     PanelAgentPointer _p = m_impl->get_panel_agent_by_id (id);
 
     if (!_p.null ())
-        _p->socket_helper_get_selection (id, context_id);
+        _p->socket_helper_get_selection (id, context_id, fd);
 }
 
 void PanelAgentManager::socket_helper_set_selection (int id, uint32 context_id, uint32 start, uint32 end)
index a91d219..5e3e981 100644 (file)
@@ -325,9 +325,9 @@ public:
     void helper_process_imengine_event (int client, uint32 context, const String& ic_uuid, const Transaction& nest_transaction);
     void process_helper_event (int client, uint32 context, String target_uuid, String active_uuid, Transaction& nest_trans);
     void socket_helper_key_event (int client, uint32 context, int cmd , KeyEvent& key);
-    void socket_helper_get_surrounding_text (int client, uint32 context_id, uint32 maxlen_before, uint32 maxlen_after);
+    void socket_helper_get_surrounding_text (int client, uint32 context_id, uint32 maxlen_before, uint32 maxlen_after, const int fd);
     void socket_helper_delete_surrounding_text (int client, uint32 context_id, uint32 offset, uint32 len);
-    void socket_helper_get_selection (int client, uint32 context_id);
+    void socket_helper_get_selection (int client, uint32 context_id, const int fd);
     void socket_helper_set_selection (int client, uint32 context_id, uint32 start, uint32 end);
     void update_ise_input_context (int    focused_client, uint32 focused_context, uint32 type, uint32 value);
     void send_private_command (int    focused_client, uint32 focused_context, String command);
index a7537fd..760b20a 100644 (file)
@@ -48,6 +48,7 @@
 
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "scim_private.h"
 #include "scim.h"
@@ -1955,10 +1956,6 @@ void
 HelperAgent::get_surrounding_text (int maxlen_before, int maxlen_after, String &text, int &cursor)
 {
     LOGD ("");
-    if (m_impl->surrounding_text) {
-        free (m_impl->surrounding_text);
-        m_impl->surrounding_text = NULL;
-    }
 
     if (!m_impl->socket_active.is_connected ())
         return;
@@ -1972,6 +1969,48 @@ HelperAgent::get_surrounding_text (int maxlen_before, int maxlen_after, String &
     m_impl->send.put_data (maxlen_after);
     m_impl->send.write_to_socket (m_impl->socket_active, m_impl->magic_active);
 
+#ifdef WAYLAND
+    int filedes[2];
+    if (pipe2(filedes,O_CLOEXEC|O_NONBLOCK) ==-1 ) {
+        LOGD ("create pipe failed");
+        return;
+    }
+    LOGD("%d,%d",filedes[0],filedes[1]);
+
+    m_impl->socket_active.write_fd (filedes[1]);
+    close (filedes[1]);
+
+    for (int i = 0; i < 3; i++) {
+        int fds[3];
+        fds[0] = m_impl->socket_active.get_id();
+        fds[1] = filedes[0];
+        fds[2] = 0;
+        if (!scim_wait_for_data (fds)) {
+            LOGE ("");
+            break;
+        }
+
+        if (fds[1]) {
+            char buff[512];
+            int len = read (fds[1], buff, sizeof(buff));
+            if (len <= 0)
+                break;
+            else {
+                buff[len] = '\0';
+                text.append (buff);
+            }
+        }
+        if (fds[0])
+            filter_event ();
+    }
+    close (filedes[0]);
+    cursor = m_impl->cursor_pos;
+#else
+    if (m_impl->surrounding_text) {
+        free (m_impl->surrounding_text);
+        m_impl->surrounding_text = NULL;
+    }
+
     for (int i = 0; i < 3; i++) {
         if (filter_event () && m_impl->surrounding_text) {
             text = m_impl->surrounding_text;
@@ -1984,6 +2023,7 @@ HelperAgent::get_surrounding_text (int maxlen_before, int maxlen_after, String &
         free (m_impl->surrounding_text);
         m_impl->surrounding_text = NULL;
     }
+#endif
 }
 
 /**
@@ -2038,10 +2078,6 @@ void
 HelperAgent::get_selection_text (String &text)
 {
     LOGD ("");
-    if (m_impl->selection_text) {
-        free (m_impl->selection_text);
-        m_impl->selection_text = NULL;
-    }
 
     if (!m_impl->socket_active.is_connected ())
         return;
@@ -2052,6 +2088,46 @@ HelperAgent::get_selection_text (String &text)
     m_impl->send.put_command (SCIM_TRANS_CMD_GET_SELECTION);
     m_impl->send.put_data ("");
     m_impl->send.write_to_socket (m_impl->socket_active, m_impl->magic_active);
+#ifdef WAYLAND
+    int filedes[2];
+    if (pipe2 (filedes,O_CLOEXEC|O_NONBLOCK) == -1 ) {
+        LOGD ("create pipe failed");
+        return;
+    }
+    LOGD("%d,%d", filedes[0], filedes[1]);
+
+    m_impl->socket_active.write_fd (filedes[1]);
+    close (filedes[1]);
+
+    for (int i = 0; i < 3; i++) {
+        int fds[3];
+        fds[0] = m_impl->socket_active.get_id();
+        fds[1] = filedes[0];
+        fds[2] = 0;
+        if (!scim_wait_for_data (fds)) {
+            LOGE ("");
+            break;
+        }
+
+        if (fds[1]) {
+            char buff[512];
+            int len = read (fds[1], buff, sizeof(buff));
+            if (len <= 0)
+                break;
+            else {
+                buff[len] = '\0';
+                text.append (buff);
+            }
+        }
+        if (fds[0])
+            filter_event ();
+    }
+    close (filedes[0]);
+#else
+    if (m_impl->selection_text) {
+        free (m_impl->selection_text);
+        m_impl->selection_text = NULL;
+    }
 
     for (int i = 0; i < 3; i++) {
         if (filter_event () && m_impl->selection_text) {
@@ -2059,11 +2135,11 @@ HelperAgent::get_selection_text (String &text)
             break;
         }
     }
-
     if (m_impl->selection_text) {
         free (m_impl->selection_text);
         m_impl->selection_text = NULL;
     }
+#endif
 }
 
 /**
index 45f3b16..9c2eb70 100644 (file)
@@ -373,6 +373,95 @@ public:
         return m_id >= 0;
     }
 
+    void write_fd (int fd) {
+        struct msghdr msg;
+        char buff[]={0};
+        struct iovec iov[1];
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+        union{
+            struct cmsghdr cm;
+            char control[CMSG_SPACE (sizeof (int))];
+        }control_un;
+        struct cmsghdr *cmptr;
+        msg.msg_control = control_un.control;
+        msg.msg_controllen = sizeof(control_un.control);
+        cmptr = CMSG_FIRSTHDR (&msg);
+        cmptr->cmsg_len = CMSG_LEN (sizeof(int));
+        cmptr->cmsg_level = SOL_SOCKET;
+        cmptr->cmsg_type = SCM_RIGHTS;
+        memcpy (CMSG_DATA (cmptr), &fd, sizeof(int));
+#else
+        msg.msg_accrights = (caddr_t)&fd;
+        msg.msg_accrightslen = sizeof (int);
+#endif
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+        iov[0].iov_base = buff;
+        iov[0].iov_len = sizeof (buff);
+        msg.msg_iov = iov;
+        msg.msg_iovlen = 1;
+        sendmsg (m_id, &msg, 0);
+    }
+
+    void read_fd (int *fd) {
+        struct msghdr msg;
+        char buff[]={0};
+        struct iovec iov[1];
+#ifndef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+        int newfd;
+#endif
+
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+        union{
+            struct cmsghdr cm;
+            char control[CMSG_SPACE (sizeof (int))];
+        }control_un;
+        struct cmsghdr *cmptr;
+        msg.msg_control = control_un.control;
+        msg.msg_controllen = sizeof (control_un.control);
+#else
+        msg.msg_accrights = (caddr_t) &newfd;
+        msg.msg_accrightslen = sizeof (int);
+#endif
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+        iov[0].iov_base = buff;
+        iov[0].iov_len = sizeof (buff);
+        msg.msg_iov = iov;
+        msg.msg_iovlen = 1;
+        while (true) {
+            if (recvmsg (m_id, &msg, 0) <= 0) {
+                if (errno ==  EAGAIN)
+                    continue;
+                *fd = -1;
+                LOGE ("%d", errno);
+                return;
+            }
+            break;
+        }
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+        cmptr = CMSG_FIRSTHDR (&msg);
+        if ((cmptr != NULL) && (cmptr->cmsg_len == CMSG_LEN (sizeof (int)))) {
+            if (cmptr->cmsg_level != SOL_SOCKET || cmptr->cmsg_type != SCM_RIGHTS) {
+                *fd = -1;
+                LOGE ("unknow message");
+                return;
+            }
+            memcpy (fd, CMSG_DATA (cmptr), sizeof(int));
+        }
+        else
+        {
+            *fd = -1;
+            LOGE ("unknow message format");
+        }
+#else
+        if (msg.msg_accrightslen == sizeof (int))
+            *fd = newfd;
+        else
+            *fd = -1;
+#endif
+    }
+
     int read (void *buf, size_t size) {
         if (!buf || !size) { m_err = EINVAL; return -1; }
         if (m_id < 0) { m_err = EBADF; return -1; }
@@ -872,6 +961,18 @@ Socket::set_nonblock_mode ()
     return m_impl->set_nonblock_mode ();
 }
 
+void
+Socket::write_fd (int fd) const
+{
+    m_impl->write_fd (fd);
+}
+
+void
+Socket::read_fd (int *fd) const
+{
+    m_impl->read_fd (fd);
+}
+
 bool
 Socket::create (SocketFamily family)
 {
@@ -1593,6 +1694,43 @@ scim_socket_accept_connection (uint32       &key,
     return String ("");
 }
 
+bool
+scim_wait_for_data (int *fds)
+{
+    fd_set _fd_set;
+    int max_fd;
+    int *_fds;
+    if (fds == NULL)
+        return false;
+    max_fd = *fds;
+    FD_ZERO (&_fd_set);
+    for (_fds = fds; *_fds; _fds++) {
+        FD_SET (*_fds, &_fd_set);
+        if (*_fds > max_fd)
+           max_fd = *_fds;
+    }
+    while (true) {
+        int ret = select (max_fd + 1, &_fd_set, NULL, NULL, NULL);
+        if (ret < 0) {
+            if (errno == EINTR)
+                continue;
+            LOGW ("%d", errno);
+            return false;
+        }
+        else if (ret == 0)
+            continue;
+        else
+            break;
+    }
+
+    for (_fds = fds; *_fds; _fds++) {
+        if (!FD_ISSET(*_fds, &_fd_set))
+            *_fds = 0;
+    }
+    return true;
+}
+
+
 } // namespace scim
 
 /*
index 3cb9250..7372109 100644 (file)
@@ -282,6 +282,10 @@ public:
      */
     int set_nonblock_mode ();
 
+    void write_fd (int fd) const;
+    void read_fd (int *fd) const;
+
+
 protected:
 
     /**
@@ -650,6 +654,8 @@ EXAPI String scim_socket_accept_connection (uint32       &key,
                                       const String &client_types,
                                       const Socket &socket,
                                       int           timeout = -1);
+
+EXAPI bool scim_wait_for_data (int *fds);
 /** @} */
 
 } // namespace scim