| // Copyright 2010-2015, 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 "renderer/win32/win32_server.h" |
| |
| #include <memory> |
| |
| #include "base/logging.h" |
| #include "base/port.h" |
| #include "base/run_level.h" |
| #include "base/util.h" |
| #include "renderer/renderer_command.pb.h" |
| #include "renderer/win32/window_manager.h" |
| |
| using std::unique_ptr; |
| |
| namespace mozc { |
| namespace renderer { |
| namespace { |
| |
| bool IsIMM32Message(const commands::RendererCommand &command) { |
| if (!command.has_application_info()) { |
| return false; |
| } |
| if (!command.application_info().has_input_framework()) { |
| return false; |
| } |
| return (command.application_info().input_framework() == |
| commands::RendererCommand::ApplicationInfo::IMM32); |
| } |
| |
| bool IsTSFMessage(const commands::RendererCommand &command) { |
| if (!command.has_application_info()) { |
| return false; |
| } |
| if (!command.application_info().has_input_framework()) { |
| return false; |
| } |
| return (command.application_info().input_framework() == |
| commands::RendererCommand::ApplicationInfo::TSF); |
| } |
| |
| } // namespace |
| |
| namespace win32 { |
| |
| Win32Server::Win32Server() |
| : event_(nullptr), |
| window_manager_(new WindowManager) { |
| // Manual reset event to notify we have a renderer command |
| // to be handled in the UI thread. |
| // The renderer command is serialized into "message_". |
| event_ = ::CreateEvent(nullptr, FALSE, FALSE, nullptr); |
| DCHECK_NE(nullptr, event_) |
| << "CreateEvent failed, Error = " << ::GetLastError(); |
| } |
| |
| Win32Server::~Win32Server() { |
| ::CloseHandle(event_); |
| } |
| |
| void Win32Server::AsyncHide() { |
| { |
| // Cancel the remaining event |
| scoped_lock l(&mutex_); |
| ::ResetEvent(event_); |
| } |
| window_manager_->AsyncHideAllWindows(); |
| } |
| |
| void Win32Server::AsyncQuit() { |
| { |
| // Cancel the remaining event |
| scoped_lock l(&mutex_); |
| ::ResetEvent(event_); |
| } |
| window_manager_->AsyncQuitAllWindows(); |
| } |
| |
| bool Win32Server::Activate() { |
| // TODO(yukawa): Implement this. |
| return true; |
| } |
| |
| bool Win32Server::IsAvailable() const { |
| // TODO(yukawa): Implement this. |
| return true; |
| } |
| |
| bool Win32Server::ExecCommand(const commands::RendererCommand &command) { |
| VLOG(2) << command.DebugString(); |
| |
| switch (command.type()) { |
| case commands::RendererCommand::NOOP: |
| break; |
| case commands::RendererCommand::SHUTDOWN: |
| // Do not destroy windows here. |
| window_manager_->HideAllWindows(); |
| break; |
| case commands::RendererCommand::UPDATE: |
| if (!command.visible()) { |
| window_manager_->HideAllWindows(); |
| } else if (IsIMM32Message(command)) { |
| window_manager_->UpdateLayoutIMM32(command); |
| } else if (IsTSFMessage(command)) { |
| window_manager_->UpdateLayoutTSF(command); |
| } else { |
| LOG(WARNING) << "output/left/bottom are not set"; |
| } |
| break; |
| default: |
| LOG(WARNING) << "Unknown command: " << command.type(); |
| break; |
| } |
| return true; |
| } |
| |
| void Win32Server::SetSendCommandInterface( |
| client::SendCommandInterface *send_command_interface) { |
| window_manager_->SetSendCommandInterface(send_command_interface); |
| } |
| |
| bool Win32Server::AsyncExecCommand(string *proto_message) { |
| // Take the ownership of |proto_message|. |
| unique_ptr<string> proto_message_owner(proto_message); |
| scoped_lock l(&mutex_); |
| if (message_ == *proto_message_owner.get()) { |
| // This is exactly the same to the previous message. Theoretically it is |
| // safe to do nothing here. |
| return true; |
| } |
| // Since mozc rendering protocol is state-less, we can always ignore the |
| // previous content of |message_|. |
| message_.swap(*proto_message_owner.get()); |
| // Set the event signaled to mark we have a message to render. |
| ::SetEvent(event_); |
| return true; |
| } |
| |
| int Win32Server::StartMessageLoop() { |
| window_manager_->Initialize(); |
| |
| int return_code = 0; |
| |
| while (true) { |
| // WindowManager::IsAvailable() returns false at least one window does not |
| // have a valid window handle. |
| // - WindowManager::Initialize() somehow failed. |
| // - A window is closed as a result of WM_CLOSE sent from an external |
| // process. This may happen if the shell or restart manager wants to shut |
| // down the renderer. |
| if (!window_manager_->IsAvailable()) { |
| // Mark this thread to quit. |
| ::PostQuitMessage(0); |
| break; // exit message pump. |
| } |
| |
| // Wait for the next window message or next rendering message. |
| const DWORD wait_result = |
| ::MsgWaitForMultipleObjects(1, &event_, FALSE, INFINITE, QS_ALLINPUT); |
| if (wait_result == WAIT_OBJECT_0) { |
| // "event_" is signaled so that we have to handle the renderer command |
| // stored in "message_" |
| string message; |
| { |
| scoped_lock l(&mutex_); |
| message.assign(message_); |
| ::ResetEvent(event_); |
| } |
| commands::RendererCommand command; |
| if (command.ParseFromString(message)) { |
| ExecCommandInternal(command); |
| if (command.type() == commands::RendererCommand::SHUTDOWN) { |
| break; // exit message pump. |
| } |
| } else { |
| LOG(ERROR) << "ParseFromString failed"; |
| } |
| } else if (wait_result == WAIT_OBJECT_0 + 1) { |
| // We have at least one window message. Let's handle them. |
| while (true) { |
| MSG msg = {}; |
| if (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) == 0) { |
| // No more message. |
| break; // exit message pump. |
| } |
| if (msg.message == WM_QUIT) { |
| return_code = msg.wParam; |
| VLOG(0) << "Reveiced WM_QUIT."; |
| break; // exit message pump. |
| } |
| window_manager_->PreTranslateMessage(msg); |
| ::TranslateMessage(&msg); |
| ::DispatchMessage(&msg); |
| } |
| } else if (wait_result == WAIT_ABANDONED_0) { |
| LOG(INFO) << "WAIT_ABANDONED_0"; |
| } else { |
| LOG(ERROR) << "MsgWaitForMultipleObjects returned unexpected result: " |
| << wait_result; |
| } |
| } |
| |
| // Ensure that IPC thread is terminated. |
| // TODO(yukawa): Update the IPC server so that we can set a timeout here. |
| Terminate(); |
| |
| // Make sure all the windows are closed. |
| // WindowManager::DestroyAllWindows supports multiple calls on the UI thread. |
| window_manager_->DestroyAllWindows(); |
| return return_code; |
| } |
| } // namespace win32 |
| } // namespace renderer |
| } // namespace mozc |