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