From 88fb0c68d719bc461791e0fc2025aa2eae0d2abd Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Wed, 26 Jul 2023 11:22:21 +0000 Subject: [PATCH] Fix #779: Remove `src/unix/ibus/selection_monitor.cc` selection_monitor.cc has been a fallback for features built on top of surrounding text APIs to continue working even when IbusEngineWrapper::GetSurroundingText() doesn't return correct anchor_pos. The way how selection_monitor.cc worked around was to keep monitoring clipboards via by X11 APIs. However I believe it's time to remove this workaround. My rationales are: * Having a runtime dependency on xcb from ibus_mozc is getting more and more questionable, especially when the industry is heading to Wayland. There was actually an issue in Ubuntu 21.10 [1] because of this dependency. * If an IME API doesn't work well, ideally such an issue should be addressed in the right component, rather than trying to work around it in each IME. [1]: https://bugs.launchpad.net/ubuntu/+source/mozc/+bug/1946969 #codehealth PiperOrigin-RevId: 551164079 --- .github/workflows/linux.yaml | 4 +- docker/ubuntu20.04/Dockerfile | 2 +- src/unix/ibus/BUILD.bazel | 30 -- src/unix/ibus/ibus.gyp | 56 --- src/unix/ibus/mozc_engine.cc | 26 +- src/unix/ibus/mozc_engine.h | 2 - src/unix/ibus/selection_monitor.cc | 576 ----------------------------- src/unix/ibus/selection_monitor.h | 73 ---- 8 files changed, 5 insertions(+), 764 deletions(-) delete mode 100644 src/unix/ibus/selection_monitor.cc delete mode 100644 src/unix/ibus/selection_monitor.h diff --git a/.github/workflows/linux.yaml b/.github/workflows/linux.yaml index 1d1b90b36..1ab931c82 100644 --- a/.github/workflows/linux.yaml +++ b/.github/workflows/linux.yaml @@ -26,7 +26,7 @@ jobs: - name: Setup run: | sudo apt-get update - sudo apt-get install -y libibus-1.0-dev qtbase5-dev libgtk2.0-dev libxcb-xfixes0-dev + sudo apt-get install -y libibus-1.0-dev qtbase5-dev libgtk2.0-dev echo "CC=clang-12" >> $GITHUB_ENV echo "CXX=clang++-12" >> $GITHUB_ENV # @@ -59,7 +59,7 @@ jobs: - name: Setup run: | sudo apt-get update - sudo apt-get install -y libibus-1.0-dev qtbase5-dev libgtk2.0-dev libxcb-xfixes0-dev + sudo apt-get install -y libibus-1.0-dev qtbase5-dev libgtk2.0-dev echo "CC=clang-14" >> $GITHUB_ENV echo "CXX=clang++-14" >> $GITHUB_ENV # diff --git a/docker/ubuntu20.04/Dockerfile b/docker/ubuntu20.04/Dockerfile index f11f0137b..0e932a533 100644 --- a/docker/ubuntu20.04/Dockerfile +++ b/docker/ubuntu20.04/Dockerfile @@ -40,7 +40,7 @@ RUN apt upgrade -y ## Common packages for linux build environment RUN apt-get install -y clang libc++-dev libc++abi-dev python3 pkg-config git curl bzip2 unzip make ninja-build ## Packages for linux desktop version -RUN apt-get install -y libibus-1.0-dev libglib2.0-dev qtbase5-dev libgtk2.0-dev libxcb-xfixes0-dev +RUN apt-get install -y libibus-1.0-dev libglib2.0-dev qtbase5-dev libgtk2.0-dev ## Packages for misc tools RUN apt-get install -y nano diff --git a/src/unix/ibus/BUILD.bazel b/src/unix/ibus/BUILD.bazel index d1b0e29ae..bb065f2e2 100644 --- a/src/unix/ibus/BUILD.bazel +++ b/src/unix/ibus/BUILD.bazel @@ -194,7 +194,6 @@ mozc_cc_library( ), defines = [ "ENABLE_QT_RENDERER", - "MOZC_ENABLE_X11_SELECTION_MONITOR", ], deps = [ ":candidate_window_handler", @@ -203,7 +202,6 @@ mozc_cc_library( ":ibus_property_handler", ":ibus_utils", ":ibus_wrapper", - ":x11_selection_monitor", "//base:clock", "//base:const", "//base:file_util", @@ -369,31 +367,3 @@ mozc_cc_test( "//testing:gunit_main", ], ) - -mozc_cc_library( - name = "x11_selection_monitor", - srcs = mozc_select(linux = ["selection_monitor.cc"]), - hdrs = mozc_select(linux = ["selection_monitor.h"]), - defines = ["MOZC_ENABLE_X11_SELECTION_MONITOR"], - linkopts = mozc_select( - oss_linux = [ - "-lxcb", - "-lxcb-xfixes", - ], - ), - deps = [ - "//base:logging", - "//base:port", - "//base:thread2", - "//base:util", - "@com_google_absl//absl/synchronization", - "@com_google_absl//absl/time", - ] + mozc_select( - linux = [ - "//third_party/libxcb", - "//third_party/libxcb:includes", - "//third_party/libxcb:libxcb-xfixes", - ], - oss_linux = [], - ), -) diff --git a/src/unix/ibus/ibus.gyp b/src/unix/ibus/ibus.gyp index 6166ef118..affd3881e 100644 --- a/src/unix/ibus/ibus.gyp +++ b/src/unix/ibus/ibus.gyp @@ -33,9 +33,6 @@ 'gen_out_dir': '<(SHARED_INTERMEDIATE_DIR)/<(relative_dir)', 'ibus_mozc_icon_path%': '/usr/share/ibus-mozc/product_icon.png', 'ibus_mozc_path%': '/usr/lib/ibus-mozc/ibus-engine-mozc', - # enable_x11_selection_monitor represents if ibus_mozc uses X11 selection - # monitor or not. - 'enable_x11_selection_monitor%': 1, }, 'targets': [ { @@ -187,13 +184,6 @@ 'message_translator', 'path_util', ], - 'conditions': [ - ['enable_x11_selection_monitor==1', { - 'dependencies': [ - 'selection_monitor', - ], - }], - ], }, { 'target_name': 'gen_ibus_mozc_files', @@ -277,52 +267,6 @@ }], ], }, - { - # Meta target to set up build environment for ibus. Required 'cflags' - # and 'link_settings' will be automatically injected into any target - # which directly or indirectly depends on this target. - 'target_name': 'xcb_build_environment', - 'type': 'none', - 'variables': { - 'target_libs': [ - 'xcb', - 'xcb-xfixes', - ], - }, - 'all_dependent_settings': { - 'cflags': [ - 'CheckCapabilities(IBUS_CAP_SURROUNDING_TEXT))) { VLOG(1) << "Give up CONVERT_REVERSE due to client_capabilities: " @@ -122,18 +120,6 @@ bool GetSurroundingText(IbusEngineWrapper *engine, const absl::string_view surrounding_text = engine->GetSurroundingText(&cursor_pos, &anchor_pos); -#ifdef MOZC_ENABLE_X11_SELECTION_MONITOR - if (cursor_pos == anchor_pos && selection_monitor != nullptr) { - const SelectionInfo &info = selection_monitor->GetSelectionInfo(); - uint new_anchor_pos = 0; - if (SurroundingTextUtil::GetAnchorPosFromSelection( - surrounding_text, info.selected_text, cursor_pos, - &new_anchor_pos)) { - anchor_pos = new_anchor_pos; - } - } -#endif // MOZC_ENABLE_X11_SELECTION_MONITOR - if (!SurroundingTextUtil::GetSafeDelta(cursor_pos, anchor_pos, &info->relative_selected_length)) { LOG(ERROR) << "Too long text selection."; @@ -218,16 +204,10 @@ MozcEngine::MozcEngine() : last_sync_time_(Clock::GetTime()), key_event_handler_(new KeyEventHandler), client_(CreateAndConfigureClient()), -#ifdef MOZC_ENABLE_X11_SELECTION_MONITOR - selection_monitor_(SelectionMonitorFactory::Create(1024)), -#endif // MOZC_ENABLE_X11_SELECTION_MONITOR preedit_handler_(new PreeditHandler()), use_mozc_candidate_window_(UseMozcCandidateWindow()), mozc_candidate_window_handler_(new renderer::RendererClient()), preedit_method_(config::Config::ROMAN) { - if (selection_monitor_ != nullptr) { - selection_monitor_->StartMonitoring(); - } if (use_mozc_candidate_window_) { mozc_candidate_window_handler_.RegisterGSettingsObserver(); } @@ -389,8 +369,7 @@ bool MozcEngine::ProcessKeyEvent(IbusEngineWrapper *engine, uint keyval, commands::Context context; SurroundingTextInfo surrounding_text_info; - if (GetSurroundingText(engine, selection_monitor_.get(), - &surrounding_text_info)) { + if (GetSurroundingText(engine, &surrounding_text_info)) { context.set_preceding_text(surrounding_text_info.preceding_text); context.set_following_text(surrounding_text_info.following_text); } @@ -591,8 +570,7 @@ bool MozcEngine::ExecuteCallback(IbusEngineWrapper *engine, } break; case commands::SessionCommand::CONVERT_REVERSE: { - if (!GetSurroundingText(engine, selection_monitor_.get(), - &surrounding_text_info)) { + if (!GetSurroundingText(engine, &surrounding_text_info)) { return false; } session_command.set_text(surrounding_text_info.selection_text); diff --git a/src/unix/ibus/mozc_engine.h b/src/unix/ibus/mozc_engine.h index 884875b3a..2a81026d2 100644 --- a/src/unix/ibus/mozc_engine.h +++ b/src/unix/ibus/mozc_engine.h @@ -58,7 +58,6 @@ namespace ibus { class CandidateWindowHandlerInterface; class KeyEventHandler; class LaunchToolTest; -class SelectionMonitorInterface; // Implements EngineInterface and handles signals from IBus daemon. // This class mainly does the two things: @@ -137,7 +136,6 @@ class MozcEngine : public EngineInterface { uint64_t last_sync_time_; std::unique_ptr key_event_handler_; std::unique_ptr client_; - std::unique_ptr selection_monitor_; std::unique_ptr property_handler_; std::unique_ptr preedit_handler_; diff --git a/src/unix/ibus/selection_monitor.cc b/src/unix/ibus/selection_monitor.cc deleted file mode 100644 index 4f5e4384a..000000000 --- a/src/unix/ibus/selection_monitor.cc +++ /dev/null @@ -1,576 +0,0 @@ -// Copyright 2010-2021, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "unix/ibus/selection_monitor.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include "base/logging.h" -#include "base/port.h" -#include "base/thread2.h" -#include "base/util.h" -#include "absl/synchronization/mutex.h" -#include "absl/synchronization/notification.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" - -namespace mozc { -namespace ibus { -namespace { - -class ScopedXcbGenericError { - public: - ScopedXcbGenericError() : error_(nullptr) {} - ~ScopedXcbGenericError() { - free(error_); - error_ = nullptr; - } - const xcb_generic_error_t *get() const { return error_; } - xcb_generic_error_t **mutable_get() { return &error_; } - - private: - xcb_generic_error_t *error_; -}; - -template -struct FreeDeleter { - void operator()(T *ptr) const { free(ptr); } -}; - -// TODO(yukawa): Use template aliases when GCC 4.6 is retired. -typedef std::unique_ptr> - ScopedXcbGetPropertyReply; -typedef std::unique_ptr> - ScopedXcbGetAtomNameReply; -typedef std::unique_ptr> - ScopedXcbInternAtomReply; -typedef std::unique_ptr> - ScopedXcbXFixesQueqyVersionReply; - -struct XcbAtoms { - xcb_atom_t mozc_selection_monitor; - xcb_atom_t net_wm_name; - xcb_atom_t net_wm_pid; - xcb_atom_t utf8_string; - xcb_atom_t wm_client_machine; - XcbAtoms() - : mozc_selection_monitor(XCB_NONE), - net_wm_name(XCB_NONE), - net_wm_pid(XCB_NONE), - utf8_string(XCB_NONE), - wm_client_machine(XCB_NONE) {} -}; - -class SelectionMonitorServer { - public: - SelectionMonitorServer() - : connection_(nullptr), - requestor_window_(0), - root_window_(0), - xfixes_first_event_(0), - xcb_maximum_request_len_(0) {} - - SelectionMonitorServer(const SelectionMonitorServer &) = delete; - SelectionMonitorServer &operator=(const SelectionMonitorServer &) = delete; - - ~SelectionMonitorServer() { Release(); } - - bool Init() { - connection_ = ::xcb_connect(nullptr, nullptr); - if (connection_ == nullptr) { - return false; - } - - if (!InitXFixes()) { - Release(); - return false; - } - - if (!InitAtoms()) { - Release(); - return false; - } - - const xcb_screen_t *screen = - ::xcb_setup_roots_iterator(::xcb_get_setup(connection_)).data; - - requestor_window_ = ::xcb_generate_id(connection_); - const uint32_t mask = XCB_CW_EVENT_MASK; - const uint32_t values[] = {XCB_EVENT_MASK_PROPERTY_CHANGE}; - root_window_ = screen->root; - ::xcb_create_window(connection_, screen->root_depth, requestor_window_, - root_window_, 0, 0, 1, 1, 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, - mask, values); - const uint32_t xfixes_mask = - XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | - XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY | - XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE; - ::xcb_xfixes_select_selection_input_checked(connection_, requestor_window_, - XCB_ATOM_PRIMARY, xfixes_mask); - ::xcb_flush(connection_); - return true; - } - - bool checkConnection() { - if (!connection_) { - return false; - } - if (::xcb_connection_has_error(connection_)) { - LOG(ERROR) << "XCB connection has error."; - connection_ = nullptr; - return false; - } - return true; - } - - bool WaitForNextSelectionEvent(size_t max_bytes, SelectionInfo *next_info) { - DCHECK(next_info); - if (!connection_) { - return false; - } - - ::xcb_flush(connection_); - std::unique_ptr event( - ::xcb_wait_for_event(connection_), &std::free); - - if (event.get() == nullptr) { - LOG(ERROR) << "nullptr event returned."; - return false; - } - - const uint32_t response_type = (event->response_type & ~0x80); - - if (response_type == (xfixes_first_event_ + XCB_XFIXES_SELECTION_NOTIFY)) { - return OnXFixesSelectionNotify(event.get(), max_bytes, next_info); - } - - if (response_type != XCB_SELECTION_NOTIFY) { - VLOG(2) << "Ignored a message. response_type: " << response_type; - return false; - } - - return OnSelectionNotify(event.get(), max_bytes, next_info); - } - - // Sends a harmless message to the |requestor_window_|. You can call this - // method to awake a message pump thread which is waiting for the next - // X11 message for |requestor_window_|. - void SendNoopEventMessage() { - if (!connection_ || !requestor_window_) { - return; - } - - // Send a dummy event so that the event pump can wake up. - xcb_client_message_event_t event = {}; - event.response_type = XCB_CLIENT_MESSAGE; - event.window = requestor_window_; - event.format = 32; - event.type = XCB_NONE; - ::xcb_send_event(connection_, false, requestor_window_, - XCB_EVENT_MASK_NO_EVENT, - reinterpret_cast(&event)); - ::xcb_flush(connection_); - } - - private: - void Release() { - if (connection_) { - ::xcb_disconnect(connection_); - connection_ = nullptr; - } - } - - bool CreateAtom(const std::string &name, xcb_atom_t *atom) const { - DCHECK(atom); - *atom = XCB_NONE; - xcb_intern_atom_cookie_t cookie = - ::xcb_intern_atom(connection_, false, name.size(), name.c_str()); - ScopedXcbInternAtomReply reply( - ::xcb_intern_atom_reply(connection_, cookie, 0)); - if (reply.get() == nullptr) { - LOG(ERROR) << "xcb_intern_atom_reply returned nullptr reply."; - return false; - } - if (reply->atom == XCB_NONE) { - return false; - } - *atom = reply->atom; - return true; - } - - bool InitAtoms() { - return CreateAtom("MOZC_SEL_MON", &atoms_.mozc_selection_monitor) && - CreateAtom("UTF8_STRING", &atoms_.utf8_string) && - CreateAtom("_NET_WM_NAME", &atoms_.net_wm_name) && - CreateAtom("_NET_WM_PID", &atoms_.net_wm_pid) && - CreateAtom("WM_CLIENT_MACHINE", &atoms_.wm_client_machine); - } - - bool InitXFixes() { - const xcb_query_extension_reply_t *ext_reply = - ::xcb_get_extension_data(connection_, &xcb_xfixes_id); - if (ext_reply == nullptr) { - LOG(ERROR) << "xcb_get_extension_data returns nullptr."; - return false; - } - - const xcb_xfixes_query_version_cookie_t xfixes_query_cookie = - xcb_xfixes_query_version(connection_, XCB_XFIXES_MAJOR_VERSION, - XCB_XFIXES_MINOR_VERSION); - ScopedXcbGenericError xcb_error; - ScopedXcbXFixesQueqyVersionReply xfixes_query( - ::xcb_xfixes_query_version_reply(connection_, xfixes_query_cookie, - xcb_error.mutable_get())); - if (xcb_error.get() != nullptr) { - LOG(ERROR) << "xcb_xfixes_query_version_reply failed. error_code: " - << static_cast(xcb_error.get()->error_code); - return false; - } - if (xfixes_query.get() == nullptr) { - return false; - } - - xfixes_first_event_ = ext_reply->first_event; - LOG(INFO) << "XFixes ver: " << xfixes_query->major_version << "." - << xfixes_query->major_version - << ", first_event: " << xfixes_first_event_; - - xcb_maximum_request_len_ = ::xcb_get_maximum_request_length(connection_); - if (xcb_maximum_request_len_ <= 0) { - LOG(ERROR) << "Unexpected xcb maximum request length: " - << xcb_maximum_request_len_; - return false; - } - - return true; - } - - std::string GetAtomName(xcb_atom_t atom) const { - const xcb_get_atom_name_cookie_t cookie = - ::xcb_get_atom_name(connection_, atom); - ScopedXcbGenericError xcb_error; - ScopedXcbGetAtomNameReply reply(::xcb_get_atom_name_reply( - connection_, cookie, xcb_error.mutable_get())); - if (xcb_error.get() != nullptr) { - LOG(ERROR) << "xcb_get_atom_name_reply failed. error_code: " - << static_cast(xcb_error.get()->error_code); - return ""; - } - if (reply.get() == nullptr) { - VLOG(2) << "reply is nullptr"; - return ""; - } - - const char *ptr = ::xcb_get_atom_name_name(reply.get()); - const size_t len = ::xcb_get_atom_name_name_length(reply.get()); - return std::string(ptr, len); - } - - bool GetByteArrayProperty(xcb_window_t window, xcb_atom_t property_atom, - xcb_atom_t property_type_atom, size_t max_bytes, - std::string *retval) const { - DCHECK(retval); - retval->clear(); - size_t bytes_after = 0; - int element_bit_size = 0; - { - const xcb_get_property_cookie_t cookie = ::xcb_get_property( - connection_, false, window, property_atom, property_type_atom, 0, 0); - ScopedXcbGetPropertyReply reply( - ::xcb_get_property_reply(connection_, cookie, 0)); - if (reply.get() == nullptr) { - VLOG(2) << "reply is nullptr"; - return false; - } - if (reply->type == XCB_NONE) { - LOG(ERROR) << "reply type is XCB_NONE"; - return false; - } - if (reply->type != property_type_atom) { - LOG(ERROR) << "unexpected atom type: " << GetAtomName(reply->type); - return false; - } - bytes_after = reply->bytes_after; - element_bit_size = reply->format; - } - - if (max_bytes < bytes_after) { - LOG(WARNING) << "Exceeds size limit. Returns an empty string." - << " max_bytes: " << max_bytes - << ", bytes_after: " << bytes_after; - *retval = ""; - return true; - } - - if (element_bit_size == 0) { - VLOG(1) << "element_bit_size is 0. Assuming byte-size data."; - element_bit_size = 8; - } - - if (element_bit_size != 8) { - LOG(ERROR) << "Unsupported bit size: " << element_bit_size; - return false; - } - - int byte_offset = 0; - - while (bytes_after > 0) { - const xcb_get_property_cookie_t cookie = - ::xcb_get_property(connection_, false, window, property_atom, - property_type_atom, byte_offset, max_bytes); - ScopedXcbGetPropertyReply reply( - ::xcb_get_property_reply(connection_, cookie, 0)); - if (reply.get() == nullptr) { - VLOG(2) << "reply is nullptr"; - return false; - } - if (reply->format != element_bit_size) { - LOG(ERROR) << "bit size changed: " << reply->format; - return false; - } - bytes_after = reply->bytes_after; - const char *data = - reinterpret_cast(::xcb_get_property_value(reply.get())); - const int length = ::xcb_get_property_value_length(reply.get()); - *retval += std::string(data, length); - byte_offset += length; - } - return true; - } - - template - bool GetCardinalProperty(xcb_window_t window, xcb_atom_t property_atom, - T *retval) const { - *retval = 0; - const xcb_get_property_cookie_t cookie = - ::xcb_get_property(connection_, false, window, property_atom, - XCB_ATOM_CARDINAL, 0, sizeof(T) * 8); - ScopedXcbGetPropertyReply reply( - ::xcb_get_property_reply(connection_, cookie, 0)); - if (reply.get() == nullptr) { - VLOG(2) << "reply is nullptr"; - return false; - } - - if (reply->type != XCB_ATOM_CARDINAL) { - LOG(ERROR) << "unexpected type: " << GetAtomName(reply->type); - return false; - } - - // All data should be read. - if (reply->bytes_after != 0) { - LOG(ERROR) << "unexpectedly " << reply->bytes_after - << " bytes data remain."; - return false; - } - if (reply->format != 0 && (reply->format != sizeof(T) * 8)) { - LOG(ERROR) << "unexpected bit size: " << reply->format; - return false; - } - - *retval = - *reinterpret_cast(::xcb_get_property_value(reply.get())); - return true; - } - - bool OnXFixesSelectionNotify(const xcb_generic_event_t *event, - size_t max_bytes, SelectionInfo *next_info) { - const xcb_xfixes_selection_notify_event_t *event_notify = - reinterpret_cast(event); - if (event_notify->selection != XCB_ATOM_PRIMARY) { - VLOG(2) << "Ignored :" << GetAtomName(event_notify->selection); - return false; - } - - // Send request message for selection info. - ::xcb_convert_selection(connection_, requestor_window_, XCB_ATOM_PRIMARY, - atoms_.utf8_string, atoms_.mozc_selection_monitor, - XCB_CURRENT_TIME); - - last_request_info_.timestamp = event_notify->selection_timestamp; - - uint32_t net_wm_pid = 0; - if (GetCardinalProperty(event_notify->owner, atoms_.net_wm_pid, - &net_wm_pid)) { - last_request_info_.process_id = net_wm_pid; - } - - std::string net_wm_name; - if (GetByteArrayProperty(event_notify->owner, atoms_.net_wm_name, - atoms_.utf8_string, max_bytes, &net_wm_name)) { - last_request_info_.window_title = net_wm_name; - } - - std::string wm_client_machine; - if (GetByteArrayProperty(event_notify->owner, atoms_.wm_client_machine, - XCB_ATOM_STRING, max_bytes, &wm_client_machine)) { - last_request_info_.machine_name = wm_client_machine; - } - - *next_info = last_request_info_; - return true; - } - - bool OnSelectionNotify(const xcb_generic_event_t *event, size_t max_bytes, - SelectionInfo *next_info) { - const xcb_selection_notify_event_t *event_notify = - reinterpret_cast(event); - if (event_notify->selection != XCB_ATOM_PRIMARY) { - VLOG(2) << "Ignored a message. selection type:" - << event_notify->selection; - return false; - } - - if (event_notify->property == XCB_NONE) { - VLOG(2) << "Ignored a message whose property type is XCB_NONE"; - return false; - } - - std::string selected_text; - if (!GetByteArrayProperty(event_notify->requestor, event_notify->property, - atoms_.utf8_string, max_bytes, &selected_text)) { - LOG(ERROR) << "Failed to retrieve selection text."; - return false; - } - - // Update the result. - *next_info = last_request_info_; - next_info->selected_text = selected_text; - return true; - } - - xcb_connection_t *connection_; - xcb_window_t requestor_window_; - xcb_window_t root_window_; - uint32_t xfixes_first_event_; - uint32_t xcb_maximum_request_len_; - SelectionInfo last_request_info_; - XcbAtoms atoms_; -}; - -class SelectionMonitorImpl : public SelectionMonitorInterface { - public: - SelectionMonitorImpl(SelectionMonitorServer *server, size_t max_text_bytes) - : server_(server), max_text_bytes_(max_text_bytes) {} - - SelectionMonitorImpl(const SelectionMonitorImpl &) = delete; - SelectionMonitorImpl &operator=(const SelectionMonitorImpl &) = delete; - - ~SelectionMonitorImpl() override { - if (thread_.has_value()) { - QueryQuit(); - thread_->Join(); - } - } - - // Implements SelectionMonitorInterface::StartMonitoring. - void StartMonitoring() override { - if (thread_.has_value()) { - QueryQuit(); - thread_->Join(); - } - thread_ = mozc::Thread2([this] { - while (!quit_.HasBeenNotified()) { - if (!server_->checkConnection()) { - absl::MutexLock l(&mutex_); - last_selection_info_ = SelectionInfo(); - quit_.Notify(); - break; - } - - SelectionInfo next_info; - // Note that this is a blocking call and will not return until the next - // X11 message is received. In order to interrupt, you can call - // SendNoopEventMessage() from other threads. - if (server_->WaitForNextSelectionEvent(max_text_bytes_, &next_info)) { - absl::MutexLock l(&mutex_); - last_selection_info_ = next_info; - } - } - }); - } - - // Implements SelectionMonitorInterface::QueryQuit. - void QueryQuit() override { - if (!quit_.HasBeenNotified()) { - quit_.Notify(); - // Awake the message pump thread so that it can see the updated - // |quit_| immediately. - server_->SendNoopEventMessage(); - } - } - - // Implements SelectionMonitorInterface::GetSelectionInfo. - SelectionInfo GetSelectionInfo() override { - SelectionInfo info; - { - absl::MutexLock l(&mutex_); - info = last_selection_info_; - } - return info; - } - - private: - absl::Notification quit_; - std::optional thread_; - std::unique_ptr server_; - const size_t max_text_bytes_; - absl::Mutex mutex_; - SelectionInfo last_selection_info_; -}; - -} // namespace - -SelectionMonitorInterface::~SelectionMonitorInterface() {} - -SelectionInfo::SelectionInfo() : timestamp(0), process_id(0) {} - -SelectionMonitorInterface *SelectionMonitorFactory::Create( - size_t max_text_bytes) { - std::unique_ptr server(new SelectionMonitorServer()); - if (!server->Init()) { - return nullptr; - } - return new SelectionMonitorImpl(server.release(), max_text_bytes); -} - -} // namespace ibus -} // namespace mozc diff --git a/src/unix/ibus/selection_monitor.h b/src/unix/ibus/selection_monitor.h deleted file mode 100644 index a0aa1a9ae..000000000 --- a/src/unix/ibus/selection_monitor.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2010-2021, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef MOZC_UNIX_IBUS_SELECTION_MONITOR_H_ -#define MOZC_UNIX_IBUS_SELECTION_MONITOR_H_ - -#include -#include - -#include "base/port.h" - -namespace mozc { -namespace ibus { - -struct SelectionInfo { - uint64_t timestamp; - uint32_t process_id; - std::string machine_name; - std::string window_title; - std::string selected_text; - SelectionInfo(); -}; - -class SelectionMonitorInterface { - public: - virtual ~SelectionMonitorInterface(); - virtual SelectionInfo GetSelectionInfo() = 0; - virtual void StartMonitoring() = 0; - virtual void QueryQuit() = 0; -}; - -class SelectionMonitorFactory { - public: - SelectionMonitorFactory() = delete; - SelectionMonitorFactory(const SelectionMonitorFactory&) = delete; - SelectionMonitorFactory& operator=(const SelectionMonitorFactory&) = delete; - // Returns an instance of SelectionMonitorInterface implementation. - // Caller must take the ownership of returned object. - // |max_text_bytes| represents the maximum string size in bytes which - // limits each string field in SelectionInfo structure. - static SelectionMonitorInterface *Create(size_t max_text_bytes); -}; - -} // namespace ibus -} // namespace mozc - -#endif // MOZC_UNIX_IBUS_SELECTION_MONITOR_H_