Codebase list mozc / 12cc99c unix / ibus / client.cc
12cc99c

Tree @12cc99c (Download .tar.gz)

client.cc @12cc99craw · history · blame

// Copyright 2010-2011, 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/client.h"

#include "base/base.h"
#include "base/singleton.h"
#include "session/commands.pb.h"
#include "session/session_handler.h"

namespace mozc {
namespace ibus {

// Session Handler must be singleton per user.
class StandaloneSessionHandler {
 public:
  StandaloneSessionHandler()
    : handler_(new SessionHandler) {}

  bool EvalCommand(commands::Command *command) {
    // SessionHandler::EvalCommand is not thread safe.
    // When IBusMozc creates multiple Session instances and
    // calls EvalCommand simultaneously, EvalCommand will crashes.
    // To prevent such situation, do a giant lock on EvalCommand
    // just in case. Seems that IBusMozc will never create
    // multiple instances.
    scoped_lock l(&mutex_);
    return handler_->EvalCommand(command);
  }

  void SetSessionFactory(session::SessionFactoryInterface *new_factory) {
    scoped_lock l(&mutex_);
    handler_->SetSessionFactory(new_factory);
  }

 private:
  Mutex mutex_;
  scoped_ptr<SessionHandler> handler_;
};

Client::Client()
    : id_(0),
      handler_(Singleton<StandaloneSessionHandler>::get()) {
}

Client::~Client() {
  DeleteSession();
}

bool Client::IsValidRunLevel() const {
  return true;
}

bool Client::EnsureSession() {
  if (id_ != 0) {
    VLOG(1) << "session has been already created.";
    return true;
  }
  return CreateSession();
}

bool Client::EnsureConnection() {
  return true;
}

bool Client::SendKey(const commands::KeyEvent &key,
                      commands::Output *output) {
  commands::Input input;
  input.set_type(commands::Input::SEND_KEY);
  input.mutable_key()->CopyFrom(key);
  return EnsureCallCommand(&input, output);
}

bool Client::TestSendKey(const commands::KeyEvent &key,
                          commands::Output *output) {
  commands::Input input;
  input.set_type(commands::Input::TEST_SEND_KEY);
  input.mutable_key()->CopyFrom(key);
  return EnsureCallCommand(&input, output);
}

bool Client::SendCommand(const commands::SessionCommand &command,
                          commands::Output *output) {
  commands::Input input;
  input.set_type(commands::Input::SEND_COMMAND);
  input.mutable_command()->CopyFrom(command);
  return EnsureCallCommand(&input, output);
}

bool Client::CheckVersionOrRestartServer() {
  return true;
}

bool Client::EnsureCallCommand(commands::Input *input,
                                commands::Output *output) {
  if (!EnsureSession()) {
    LOG(ERROR) << "EnsureSession failed";
    return false;
  }

  input->set_id(id_);
  output->set_id(0);
  return Call(*input, output);
}

void Client::EnableCascadingWindow(bool enable) {
  // TODO(mazda): implement this
}

void Client::set_timeout(int timeout) {
}

void Client::set_restricted(bool restricted) {
}

void Client::set_server_program(const string &program_path) {
}

void Client::set_client_capability(const commands::Capability &capability) {
  client_capability_.CopyFrom(capability);
}

bool Client::LaunchTool(const string &mode,
                         const string &extra_arg) {
  return true;
}

bool Client::LaunchToolWithProtoBuf(const commands::Output &output) {
  return true;
}

bool Client::OpenBrowser(const string &url) {
  return true;
}

bool Client::CreateSession() {
  if (id_ != 0) {
    VLOG(1) << "session has been already created.";
    return true;
  }

  commands::Command command;
  command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
  command.mutable_input()->mutable_capability()->CopyFrom(client_capability_);
  if (!handler_->EvalCommand(&command)) {
    LOG(ERROR) << "EvalCommand failed";
    return false;
  }
  id_ = command.output().id();
  return true;
}

bool Client::DeleteSession() {
  // No need to delete session
  if (id_ == 0) {
    VLOG(1) << "session has been already deleted.";
    return true;
  }

  commands::Command command;
  command.mutable_input()->set_id(id_);
  command.mutable_input()->set_type(commands::Input::DELETE_SESSION);
  bool result = handler_->EvalCommand(&command);
  id_ = 0;
  return result;
}

bool Client::GetConfig(config::Config *config) {
  commands::Input input;
  input.set_id(id_);
  input.set_type(commands::Input::GET_CONFIG);

  commands::Output output;
  if (!Call(input, &output)) {
    return false;
  }

  if (!output.has_config()) {
    return false;
  }

  config->Clear();
  config->CopyFrom(output.config());
  return true;
}

bool Client::SetConfig(const config::Config &config) {
  commands::Input input;
  input.set_id(id_);
  input.set_type(commands::Input::SET_CONFIG);
  input.mutable_config()->CopyFrom(config);

  commands::Output output;
  if (!Call(input, &output)) {
    return false;
  }

  return true;
}

bool Client::ClearUserHistory() {
  return CallCommand(commands::Input::CLEAR_USER_HISTORY);
}

bool Client::ClearUserPrediction() {
  return CallCommand(commands::Input::CLEAR_USER_PREDICTION);
}

bool Client::ClearUnusedUserPrediction() {
  return CallCommand(commands::Input::CLEAR_UNUSED_USER_PREDICTION);
}

bool Client::Shutdown() {
  CallCommand(commands::Input::SHUTDOWN);
  return true;
}

bool Client::SyncData() {
  return CallCommand(commands::Input::SYNC_DATA);
}

bool Client::Reload() {
  return CallCommand(commands::Input::RELOAD);
}

bool Client::Cleanup() {
  return CallCommand(commands::Input::CLEANUP);
}

bool Client::NoOperation() {
  return CallCommand(commands::Input::NO_OPERATION);
}

bool Client::PingServer() const {
  return true;
}


bool Client::CallCommand(commands::Input::CommandType type) {
  commands::Input input;
  input.set_id(id_);
  input.set_type(type);
  commands::Output output;
  return Call(input, &output);
}

bool Client::Call(const commands::Input &input,
                   commands::Output *output) {
  DCHECK(output) << "output is null";

  commands::Command command;
  command.mutable_input()->CopyFrom(input);
  if (!handler_->EvalCommand(&command)) {
    LOG(ERROR) << "EvalCommand failed.";
    return false;
  }
  output->CopyFrom(command.output());
  return true;
}

void Client::Reset() {
}

void Client::SetSessionFactory(
    session::SessionFactoryInterface *new_factory) {
  Singleton<StandaloneSessionHandler>::get()->SetSessionFactory(new_factory);
}

void Client::SetIPCClientFactory(IPCClientFactoryInterface *interface) {
  // Do nothing because ChromeOS does not adopt multi-process architecture.
}

void Client::SetServerLauncher(client::ServerLauncherInterface *interface) {
  // Do nothing because ChromeOS does not adopt multi-process architecture.
}

}  // namespace ibus
}  // namespace mozc