1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "renderer/win32/win32_server.h"
31 
32 #include <memory>
33 
34 #include "base/logging.h"
35 #include "base/port.h"
36 #include "base/run_level.h"
37 #include "base/util.h"
38 #include "protocol/renderer_command.pb.h"
39 #include "renderer/win32/window_manager.h"
40 
41 using std::unique_ptr;
42 
43 namespace mozc {
44 namespace renderer {
45 namespace {
46 
IsIMM32Message(const commands::RendererCommand & command)47 bool IsIMM32Message(const commands::RendererCommand &command) {
48   if (!command.has_application_info()) {
49     return false;
50   }
51   if (!command.application_info().has_input_framework()) {
52     return false;
53   }
54   return (command.application_info().input_framework() ==
55           commands::RendererCommand::ApplicationInfo::IMM32);
56 }
57 
IsTSFMessage(const commands::RendererCommand & command)58 bool IsTSFMessage(const commands::RendererCommand &command) {
59   if (!command.has_application_info()) {
60     return false;
61   }
62   if (!command.application_info().has_input_framework()) {
63     return false;
64   }
65   return (command.application_info().input_framework() ==
66           commands::RendererCommand::ApplicationInfo::TSF);
67 }
68 
69 }  // namespace
70 
71 namespace win32 {
72 
Win32Server()73 Win32Server::Win32Server()
74     : event_(nullptr),
75       window_manager_(new WindowManager) {
76   // Manual reset event to notify we have a renderer command
77   // to be handled in the UI thread.
78   // The renderer command is serialized into "message_".
79   event_ = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);
80   DCHECK_NE(nullptr, event_)
81       << "CreateEvent failed, Error = " << ::GetLastError();
82 }
83 
~Win32Server()84 Win32Server::~Win32Server() {
85   ::CloseHandle(event_);
86 }
87 
AsyncHide()88 void Win32Server::AsyncHide() {
89   {
90     // Cancel the remaining event
91     scoped_lock l(&mutex_);
92     ::ResetEvent(event_);
93   }
94   window_manager_->AsyncHideAllWindows();
95 }
96 
AsyncQuit()97 void Win32Server::AsyncQuit() {
98   {
99     // Cancel the remaining event
100     scoped_lock l(&mutex_);
101     ::ResetEvent(event_);
102   }
103   window_manager_->AsyncQuitAllWindows();
104 }
105 
Activate()106 bool Win32Server::Activate() {
107   // TODO(yukawa): Implement this.
108   return true;
109 }
110 
IsAvailable() const111 bool Win32Server::IsAvailable() const {
112   // TODO(yukawa): Implement this.
113   return true;
114 }
115 
ExecCommand(const commands::RendererCommand & command)116 bool Win32Server::ExecCommand(const commands::RendererCommand &command) {
117   VLOG(2) << command.DebugString();
118 
119   switch (command.type()) {
120     case commands::RendererCommand::NOOP:
121       break;
122     case commands::RendererCommand::SHUTDOWN:
123       // Do not destroy windows here.
124       window_manager_->HideAllWindows();
125       break;
126     case commands::RendererCommand::UPDATE:
127       if (!command.visible()) {
128         window_manager_->HideAllWindows();
129       } else if (IsIMM32Message(command)) {
130         window_manager_->UpdateLayoutIMM32(command);
131       } else if (IsTSFMessage(command)) {
132         window_manager_->UpdateLayoutTSF(command);
133       } else {
134         LOG(WARNING) << "output/left/bottom are not set";
135       }
136       break;
137     default:
138       LOG(WARNING) << "Unknown command: " << command.type();
139       break;
140   }
141   return true;
142 }
143 
SetSendCommandInterface(client::SendCommandInterface * send_command_interface)144 void Win32Server::SetSendCommandInterface(
145     client::SendCommandInterface *send_command_interface) {
146   window_manager_->SetSendCommandInterface(send_command_interface);
147 }
148 
AsyncExecCommand(string * proto_message)149 bool Win32Server::AsyncExecCommand(string *proto_message) {
150   // Take the ownership of |proto_message|.
151   std::unique_ptr<string> proto_message_owner(proto_message);
152   scoped_lock l(&mutex_);
153   if (message_ == *proto_message_owner.get()) {
154     // This is exactly the same to the previous message. Theoretically it is
155     // safe to do nothing here.
156     return true;
157   }
158   // Since mozc rendering protocol is state-less, we can always ignore the
159   // previous content of |message_|.
160   message_.swap(*proto_message_owner.get());
161   // Set the event signaled to mark we have a message to render.
162   ::SetEvent(event_);
163   return true;
164 }
165 
StartMessageLoop()166 int Win32Server::StartMessageLoop() {
167   window_manager_->Initialize();
168 
169   int return_code = 0;
170 
171   while (true) {
172     // WindowManager::IsAvailable() returns false at least one window does not
173     // have a valid window handle.
174     // - WindowManager::Initialize() somehow failed.
175     // - A window is closed as a result of WM_CLOSE sent from an external
176     //   process. This may happen if the shell or restart manager wants to shut
177     //   down the renderer.
178     if (!window_manager_->IsAvailable()) {
179       // Mark this thread to quit.
180       ::PostQuitMessage(0);
181       break;  // exit message pump.
182     }
183 
184     // Wait for the next window message or next rendering message.
185     const DWORD wait_result =
186       ::MsgWaitForMultipleObjects(1, &event_, FALSE, INFINITE, QS_ALLINPUT);
187     if (wait_result == WAIT_OBJECT_0) {
188       // "event_" is signaled so that we have to handle the renderer command
189       // stored in "message_"
190       string message;
191       {
192         scoped_lock l(&mutex_);
193         message.assign(message_);
194         ::ResetEvent(event_);
195       }
196       commands::RendererCommand command;
197       if (command.ParseFromString(message)) {
198         ExecCommandInternal(command);
199         if (command.type() == commands::RendererCommand::SHUTDOWN) {
200           break;  // exit message pump.
201         }
202       } else {
203         LOG(ERROR) << "ParseFromString failed";
204       }
205     } else if (wait_result == WAIT_OBJECT_0 + 1) {
206       // We have at least one window message. Let's handle them.
207       while (true) {
208         MSG msg = {};
209         if (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) == 0) {
210           // No more message.
211           break;  // exit message pump.
212         }
213         if (msg.message == WM_QUIT) {
214           return_code = msg.wParam;
215           VLOG(0) << "Reveiced WM_QUIT.";
216           break;  // exit message pump.
217         }
218         window_manager_->PreTranslateMessage(msg);
219         ::TranslateMessage(&msg);
220         ::DispatchMessage(&msg);
221       }
222     } else if (wait_result == WAIT_ABANDONED_0) {
223       LOG(INFO) << "WAIT_ABANDONED_0";
224     } else {
225       LOG(ERROR) << "MsgWaitForMultipleObjects returned unexpected result: "
226                  << wait_result;
227     }
228   }
229 
230   // Ensure that IPC thread is terminated.
231   // TODO(yukawa): Update the IPC server so that we can set a timeout here.
232   Terminate();
233 
234   // Make sure all the windows are closed.
235   // WindowManager::DestroyAllWindows supports multiple calls on the UI thread.
236   window_manager_->DestroyAllWindows();
237   return return_code;
238 }
239 }  // namespace win32
240 }  // namespace renderer
241 }  // namespace mozc
242