Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(424)

Side by Side Diff: chromeos/dbus/ibus/ibus_engine_service.cc

Issue 10806006: Implement IBusEngineService (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fix wrong usage of Message Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chromeos/dbus/ibus/ibus_constants.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chromeos/dbus/ibus/ibus_engine_service.h" 5 #include "chromeos/dbus/ibus/ibus_engine_service.h"
6 6
7 #include <string>
7 #include "base/bind.h" 8 #include "base/bind.h"
8 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "chromeos/dbus/ibus/ibus_constants.h"
9 #include "chromeos/dbus/ibus/ibus_lookup_table.h" 11 #include "chromeos/dbus/ibus/ibus_lookup_table.h"
10 #include "chromeos/dbus/ibus/ibus_property.h" 12 #include "chromeos/dbus/ibus/ibus_property.h"
11 #include "chromeos/dbus/ibus/ibus_text.h" 13 #include "chromeos/dbus/ibus/ibus_text.h"
12 #include "dbus/bus.h" 14 #include "dbus/bus.h"
13 #include "dbus/exported_object.h" 15 #include "dbus/exported_object.h"
14 #include "dbus/message.h" 16 #include "dbus/message.h"
15 #include "dbus/object_path.h" 17 #include "dbus/object_path.h"
16 #include "dbus/object_proxy.h" 18 #include "dbus/object_proxy.h"
17 19
18 namespace chromeos { 20 namespace chromeos {
19 21
20 class IBusEngineServiceImpl : public IBusEngineService { 22 class IBusEngineServiceImpl : public IBusEngineService {
21 public: 23 public:
22 IBusEngineServiceImpl(dbus::Bus* bus, 24 IBusEngineServiceImpl(dbus::Bus* bus,
23 const dbus::ObjectPath& object_path) 25 const dbus::ObjectPath& object_path)
24 : bus_(bus), 26 : bus_(bus),
25 object_path_(object_path), 27 object_path_(object_path),
26 weak_ptr_factory_(this) { 28 weak_ptr_factory_(this) {
27 exported_object_ = bus->GetExportedObject(object_path_); 29 exported_object_ = bus->GetExportedObject(object_path_);
28 // TODO(nona): Export methods here. 30
31 exported_object_->ExportMethod(
32 ibus::engine::kServiceInterface,
33 ibus::engine::kFocusInMethod,
34 base::Bind(&IBusEngineServiceImpl::FocusIn,
35 weak_ptr_factory_.GetWeakPtr()),
36 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
37 weak_ptr_factory_.GetWeakPtr()));
38
39 exported_object_->ExportMethod(
40 ibus::engine::kServiceInterface,
41 ibus::engine::kFocusOutMethod,
42 base::Bind(&IBusEngineServiceImpl::FocusOut,
43 weak_ptr_factory_.GetWeakPtr()),
44 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
45 weak_ptr_factory_.GetWeakPtr()));
46
47 exported_object_->ExportMethod(
48 ibus::engine::kServiceInterface,
49 ibus::engine::kEnableMethod,
50 base::Bind(&IBusEngineServiceImpl::Enable,
51 weak_ptr_factory_.GetWeakPtr()),
52 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
53 weak_ptr_factory_.GetWeakPtr()));
54
55 exported_object_->ExportMethod(
56 ibus::engine::kServiceInterface,
57 ibus::engine::kDisableMethod,
58 base::Bind(&IBusEngineServiceImpl::Disable,
59 weak_ptr_factory_.GetWeakPtr()),
60 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
61 weak_ptr_factory_.GetWeakPtr()));
62
63 exported_object_->ExportMethod(
64 ibus::engine::kServiceInterface,
65 ibus::engine::kPropertyActivateMethod,
66 base::Bind(&IBusEngineServiceImpl::PropertyActivate,
67 weak_ptr_factory_.GetWeakPtr()),
68 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
69 weak_ptr_factory_.GetWeakPtr()));
70
71 exported_object_->ExportMethod(
72 ibus::engine::kServiceInterface,
73 ibus::engine::kPropertyShowMethod,
74 base::Bind(&IBusEngineServiceImpl::PropertyShow,
75 weak_ptr_factory_.GetWeakPtr()),
76 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
77 weak_ptr_factory_.GetWeakPtr()));
78
79 exported_object_->ExportMethod(
80 ibus::engine::kServiceInterface,
81 ibus::engine::kPropertyHideMethod,
82 base::Bind(&IBusEngineServiceImpl::PropertyHide,
83 weak_ptr_factory_.GetWeakPtr()),
84 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
85 weak_ptr_factory_.GetWeakPtr()));
86
87 exported_object_->ExportMethod(
88 ibus::engine::kServiceInterface,
89 ibus::engine::kSetCapabilityMethod,
90 base::Bind(&IBusEngineServiceImpl::SetCapability,
91 weak_ptr_factory_.GetWeakPtr()),
92 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
93 weak_ptr_factory_.GetWeakPtr()));
94
95 exported_object_->ExportMethod(
96 ibus::engine::kServiceInterface,
97 ibus::engine::kResetMethod,
98 base::Bind(&IBusEngineServiceImpl::Reset,
99 weak_ptr_factory_.GetWeakPtr()),
100 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
101 weak_ptr_factory_.GetWeakPtr()));
102
103 exported_object_->ExportMethod(
104 ibus::engine::kServiceInterface,
105 ibus::engine::kProcessKeyEventMethod,
106 base::Bind(&IBusEngineServiceImpl::ProcessKeyEvent,
107 weak_ptr_factory_.GetWeakPtr()),
108 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
109 weak_ptr_factory_.GetWeakPtr()));
110
111 exported_object_->ExportMethod(
112 ibus::engine::kServiceInterface,
113 ibus::engine::kCandidateClickedMethod,
114 base::Bind(&IBusEngineServiceImpl::CandidateClicked,
115 weak_ptr_factory_.GetWeakPtr()),
116 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
117 weak_ptr_factory_.GetWeakPtr()));
118
119 exported_object_->ExportMethod(
120 ibus::engine::kServiceInterface,
121 ibus::engine::kSetSurroundingTextMethod,
122 base::Bind(&IBusEngineServiceImpl::SetSurroundingText,
123 weak_ptr_factory_.GetWeakPtr()),
124 base::Bind(&IBusEngineServiceImpl::OnMethodExported,
125 weak_ptr_factory_.GetWeakPtr()));
29 } 126 }
30 127
31 virtual ~IBusEngineServiceImpl() { 128 virtual ~IBusEngineServiceImpl() {
32 bus_->UnregisterExportedObject(object_path_); 129 bus_->UnregisterExportedObject(object_path_);
33 } 130 }
34 131
35 // IBusEngineService override. 132 // IBusEngineService override.
36 virtual void Initialize(IBusEngineHandlerInterface* handler) OVERRIDE { 133 virtual void Initialize(IBusEngineHandlerInterface* handler) OVERRIDE {
37 if (engine_handler_.get() == NULL) { 134 if (engine_handler_.get() == NULL) {
38 engine_handler_.reset(handler); 135 engine_handler_.reset(handler);
39 } else { 136 } else {
40 LOG(ERROR) << "Already initialized."; 137 LOG(ERROR) << "Already initialized.";
41 } 138 }
42 } 139 }
43 140
44 // IBusEngineService override. 141 // IBusEngineService override.
45 virtual void RegisterProperties( 142 virtual void RegisterProperties(
46 const ibus::IBusPropertyList& property_list) OVERRIDE { 143 const ibus::IBusPropertyList& property_list) OVERRIDE {
47 // TODO(nona): Implement this. 144 dbus::Signal signal(ibus::engine::kServiceInterface,
48 NOTIMPLEMENTED(); 145 ibus::engine::kRegisterPropertiesSignal);
146 dbus::MessageWriter writer(&signal);
147 AppendIBusPropertyList(property_list, &writer);
148 exported_object_->SendSignal(&signal);
49 } 149 }
50 150
51 // IBusEngineService override. 151 // IBusEngineService override.
52 virtual void UpdatePreedit(const ibus::IBusText& ibus_text, 152 virtual void UpdatePreedit(const ibus::IBusText& ibus_text,
53 uint32 cursor_pos, 153 uint32 cursor_pos,
54 bool is_visible, 154 bool is_visible,
55 IBusEnginePreeditFocusOutMode mode) OVERRIDE { 155 IBusEnginePreeditFocusOutMode mode) OVERRIDE {
56 // TODO(nona): Implement this. 156 dbus::Signal signal(ibus::engine::kServiceInterface,
57 NOTIMPLEMENTED(); 157 ibus::engine::kUpdatePreeditSignal);
158 dbus::MessageWriter writer(&signal);
159 AppendIBusText(ibus_text, &writer);
160 writer.AppendUint32(cursor_pos);
161 writer.AppendBool(is_visible);
162 writer.AppendUint32(static_cast<uint32>(mode));
163 exported_object_->SendSignal(&signal);
58 } 164 }
59 165
60 // IBusEngineService override. 166 // IBusEngineService override.
61 virtual void UpdateAuxiliaryText(const ibus::IBusText& ibus_text, 167 virtual void UpdateAuxiliaryText(const ibus::IBusText& ibus_text,
62 bool is_visible) OVERRIDE { 168 bool is_visible) OVERRIDE {
63 // TODO(nona): Implement this. 169 dbus::Signal signal(ibus::engine::kServiceInterface,
64 NOTIMPLEMENTED(); 170 ibus::engine::kUpdateAuxiliaryTextSignal);
171 dbus::MessageWriter writer(&signal);
172 AppendIBusText(ibus_text, &writer);
173 writer.AppendBool(is_visible);
174 exported_object_->SendSignal(&signal);
65 } 175 }
66 176
67 // IBusEngineService override. 177 // IBusEngineService override.
68 virtual void UpdateLookupTable(const ibus::IBusLookupTable& lookup_table, 178 virtual void UpdateLookupTable(const ibus::IBusLookupTable& lookup_table,
69 bool is_visible) OVERRIDE { 179 bool is_visible) OVERRIDE {
70 // TODO(nona): Implement this. 180 dbus::Signal signal(ibus::engine::kServiceInterface,
71 NOTIMPLEMENTED(); 181 ibus::engine::kUpdateLookupTableSignal);
182 dbus::MessageWriter writer(&signal);
183 AppendIBusLookupTable(lookup_table, &writer);
184 writer.AppendBool(is_visible);
185 exported_object_->SendSignal(&signal);
72 } 186 }
73 187
74 // IBusEngineService override. 188 // IBusEngineService override.
75 virtual void UpdateProperty(const ibus::IBusProperty& property) OVERRIDE { 189 virtual void UpdateProperty(const ibus::IBusProperty& property) OVERRIDE {
76 // TODO(nona): Implement this. 190 dbus::Signal signal(ibus::engine::kServiceInterface,
77 NOTIMPLEMENTED(); 191 ibus::engine::kUpdatePropertySignal);
192 dbus::MessageWriter writer(&signal);
193 AppendIBusProperty(property, &writer);
194 exported_object_->SendSignal(&signal);
78 } 195 }
79 196
80 // IBusEngineService override. 197 // IBusEngineService override.
81 virtual void ForwardKeyEvent(uint32 keyval, uint32 keycode, 198 virtual void ForwardKeyEvent(uint32 keyval, uint32 keycode,
82 uint32 state) OVERRIDE { 199 uint32 state) OVERRIDE {
83 // TODO(nona): Implement this. 200 dbus::Signal signal(ibus::engine::kServiceInterface,
84 NOTIMPLEMENTED(); 201 ibus::engine::kForwardKeyEventSignal);
202 dbus::MessageWriter writer(&signal);
203 writer.AppendUint32(keyval);
204 writer.AppendUint32(keycode);
205 writer.AppendUint32(state);
206 exported_object_->SendSignal(&signal);
85 } 207 }
86 208
87 // IBusEngineService override. 209 // IBusEngineService override.
88 virtual void RequireSurroundingText() OVERRIDE { 210 virtual void RequireSurroundingText() OVERRIDE {
89 // TODO(nona): Implement this. 211 dbus::Signal signal(ibus::engine::kServiceInterface,
90 NOTIMPLEMENTED(); 212 ibus::engine::kRequireSurroundingTextSignal);
213 exported_object_->SendSignal(&signal);
91 } 214 }
92 215
93 private: 216 private:
217 // Handles FocusIn method call from ibus-daemon.
218 void FocusIn(dbus::MethodCall* method_call,
219 dbus::ExportedObject::ResponseSender response_sender) {
220 DCHECK(engine_handler_.get());
221 engine_handler_->FocusIn();
222 scoped_ptr<dbus::Response> response(
223 dbus::Response::FromMethodCall(method_call));
224 response_sender.Run(response.get());
225 }
226
227 // Handles FocusOut method call from ibus-daemon.
228 void FocusOut(dbus::MethodCall* method_call,
229 dbus::ExportedObject::ResponseSender response_sender) {
230 DCHECK(engine_handler_.get());
231 engine_handler_->FocusOut();
232 scoped_ptr<dbus::Response> response(
233 dbus::Response::FromMethodCall(method_call));
234 response_sender.Run(response.get());
235 }
236
237 // Handles Enable method call from ibus-daemon.
238 void Enable(dbus::MethodCall* method_call,
239 dbus::ExportedObject::ResponseSender response_sender) {
240 DCHECK(engine_handler_.get());
241 engine_handler_->Enable();
242 scoped_ptr<dbus::Response> response(
243 dbus::Response::FromMethodCall(method_call));
244 response_sender.Run(response.get());
245 }
246
247 // Handles Disable method call from ibus-daemon.
248 void Disable(dbus::MethodCall* method_call,
249 dbus::ExportedObject::ResponseSender response_sender) {
250 DCHECK(engine_handler_.get());
251 engine_handler_->Disable();
252 scoped_ptr<dbus::Response> response(
253 dbus::Response::FromMethodCall(method_call));
254 response_sender.Run(response.get());
255 }
256
257 // Handles PropertyActivate method call from ibus-daemon.
258 void PropertyActivate(dbus::MethodCall* method_call,
259 dbus::ExportedObject::ResponseSender response_sender) {
260 dbus::MessageReader reader(method_call);
261 std::string property_name;
262 if (!reader.PopString(&property_name)) {
263 LOG(WARNING) << "PropertyActivate called with incorrect parameters: "
264 << method_call->ToString();
265 return;
266 }
267 uint32 property_state = 0;
268 if (!reader.PopUint32(&property_state)) {
269 LOG(WARNING) << "PropertyActivate called with incorrect parameters: "
270 << method_call->ToString();
271 return;
272 }
273 DCHECK(engine_handler_.get());
274 engine_handler_->PropertyActivate(
275 property_name,
276 static_cast<IBusEngineHandlerInterface::IBusPropertyState>(
277 property_state));
278 scoped_ptr<dbus::Response> response(
279 dbus::Response::FromMethodCall(method_call));
280 response_sender.Run(response.get());
281 }
282
283 // Handles PropertyShow method call from ibus-daemon.
284 void PropertyShow(dbus::MethodCall* method_call,
285 dbus::ExportedObject::ResponseSender response_sender) {
286 dbus::MessageReader reader(method_call);
287 std::string property_name;
288 if (!reader.PopString(&property_name)) {
289 LOG(WARNING) << "PropertyShow called with incorrect parameters: "
290 << method_call->ToString();
291 return;
292 }
293 DCHECK(engine_handler_.get());
294 engine_handler_->PropertyShow(property_name);
295 scoped_ptr<dbus::Response> response(
296 dbus::Response::FromMethodCall(method_call));
297 response_sender.Run(response.get());
298 }
299
300 // Handles PropertyHide method call from ibus-daemon.
301 void PropertyHide(dbus::MethodCall* method_call,
302 dbus::ExportedObject::ResponseSender response_sender) {
303 dbus::MessageReader reader(method_call);
304 std::string property_name;
305 if (!reader.PopString(&property_name)) {
306 LOG(WARNING) << "PropertyHide called with incorrect parameters: "
307 << method_call->ToString();
308 return;
309 }
310 DCHECK(engine_handler_.get());
311 engine_handler_->PropertyHide(property_name);
312 scoped_ptr<dbus::Response> response(
313 dbus::Response::FromMethodCall(method_call));
314 response_sender.Run(response.get());
315 }
316
317 // Handles SetCapability method call from ibus-daemon.
318 void SetCapability(dbus::MethodCall* method_call,
319 dbus::ExportedObject::ResponseSender response_sender) {
320 dbus::MessageReader reader(method_call);
321 uint32 capability = 0;
322 if (!reader.PopUint32(&capability)) {
323 LOG(WARNING) << "SetCapability called with incorrect parameters: "
324 << method_call->ToString();
325 return;
326 }
327 DCHECK(engine_handler_.get());
328 engine_handler_->SetCapability(
329 static_cast<IBusEngineHandlerInterface::IBusCapability>(capability));
330 scoped_ptr<dbus::Response> response(
331 dbus::Response::FromMethodCall(method_call));
332 response_sender.Run(response.get());
333 }
334
335 void Reset(dbus::MethodCall* method_call,
336 dbus::ExportedObject::ResponseSender response_sender) {
337 DCHECK(engine_handler_.get());
338 engine_handler_->Reset();
339 scoped_ptr<dbus::Response> response(
340 dbus::Response::FromMethodCall(method_call));
341 response_sender.Run(response.get());
342 }
343
344 // Handles ProcessKeyEvent method call from ibus-daemon.
345 void ProcessKeyEvent(dbus::MethodCall* method_call,
346 dbus::ExportedObject::ResponseSender response_sender) {
347 dbus::MessageReader reader(method_call);
348 uint32 keysym = 0;
349 if (!reader.PopUint32(&keysym)) {
350 LOG(WARNING) << "ProcessKeyEvent called with incorrect parameters: "
351 << method_call->ToString();
352 return;
353 }
354 uint32 keycode = 0;
355 if (!reader.PopUint32(&keycode)) {
356 LOG(WARNING) << "ProcessKeyEvent called with incorrect parameters: "
357 << method_call->ToString();
358 return;
359 }
360 uint32 state = 0;
361 if (!reader.PopUint32(&state)) {
362 LOG(WARNING) << "ProcessKeyEvent called with incorrect parameters: "
363 << method_call->ToString();
364 return;
365 }
366 DCHECK(engine_handler_.get());
367 bool consume = engine_handler_->ProcessKeyEvent(keysym, keycode, state);
368 scoped_ptr<dbus::Response> response(
369 dbus::Response::FromMethodCall(method_call));
370 dbus::MessageWriter writer(response.get());
371 writer.AppendBool(consume);
372 response_sender.Run(response.get());
373 }
374
375 // Handles CandidateClicked method call from ibus-daemon.
376 void CandidateClicked(dbus::MethodCall* method_call,
377 dbus::ExportedObject::ResponseSender response_sender) {
378 dbus::MessageReader reader(method_call);
379 uint32 index = 0;
380 if (!reader.PopUint32(&index)) {
381 LOG(WARNING) << "CandidateClicked called with incorrect parameters: "
382 << method_call->ToString();
383 return;
384 }
385 uint32 button = 0;
386 if (!reader.PopUint32(&button)) {
387 LOG(WARNING) << "CandidateClicked called with incorrect parameters: "
388 << method_call->ToString();
389 return;
390 }
391 uint32 state = 0;
392 if (!reader.PopUint32(&state)) {
393 LOG(WARNING) << "CandidateClicked called with incorrect parameters: "
394 << method_call->ToString();
395 return;
396 }
397 DCHECK(engine_handler_.get());
398 engine_handler_->CandidateClicked(
399 index,
400 static_cast<IBusEngineHandlerInterface::IBusMouseButton>(button),
401 state);
402 scoped_ptr<dbus::Response> response(
403 dbus::Response::FromMethodCall(method_call));
404 response_sender.Run(response.get());
405 }
406
407 // Handles SetSurroundingText method call from ibus-daemon.
408 void SetSurroundingText(
409 dbus::MethodCall* method_call,
410 dbus::ExportedObject::ResponseSender response_sender) {
411 dbus::MessageReader reader(method_call);
412 std::string text;
413 if (!reader.PopString(&text)) {
414 LOG(WARNING) << "SetSurroundingText called with incorrect parameters: "
415 << method_call->ToString();
416 return;
417 }
418 uint32 cursor_pos = 0;
419 if (!reader.PopUint32(&cursor_pos)) {
420 LOG(WARNING) << "CandidateClicked called with incorrect parameters: "
421 << method_call->ToString();
422 return;
423 }
424 uint32 anchor_pos = 0;
425 if (!reader.PopUint32(&anchor_pos)) {
426 LOG(WARNING) << "CandidateClicked called with incorrect parameters: "
427 << method_call->ToString();
428 return;
429 }
430
431 DCHECK(engine_handler_.get());
432 engine_handler_->SetSurroundingText(text, cursor_pos, anchor_pos);
433 scoped_ptr<dbus::Response> response(
434 dbus::Response::FromMethodCall(method_call));
435 response_sender.Run(response.get());
436 }
437
438 // Called when the method call is exported.
439 void OnMethodExported(const std::string& interface_name,
440 const std::string& method_name,
441 bool success) {
442 LOG_IF(WARNING, !success) << "Failed to export "
443 << interface_name << "." << method_name;
444 }
445
94 // D-Bus bus object used for unregistering exported methods in dtor. 446 // D-Bus bus object used for unregistering exported methods in dtor.
95 dbus::Bus* bus_; 447 dbus::Bus* bus_;
96 448
97 // All incoming method calls are passed on to the |engine_handler_|. 449 // All incoming method calls are passed on to the |engine_handler_|.
98 scoped_ptr<IBusEngineHandlerInterface> engine_handler_; 450 scoped_ptr<IBusEngineHandlerInterface> engine_handler_;
99 451
100 dbus::ObjectPath object_path_; 452 dbus::ObjectPath object_path_;
101 scoped_refptr<dbus::ExportedObject> exported_object_; 453 scoped_refptr<dbus::ExportedObject> exported_object_;
102 base::WeakPtrFactory<IBusEngineServiceImpl> weak_ptr_factory_; 454 base::WeakPtrFactory<IBusEngineServiceImpl> weak_ptr_factory_;
103 455
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 DBusClientImplementationType type, 491 DBusClientImplementationType type,
140 dbus::Bus* bus, 492 dbus::Bus* bus,
141 const dbus::ObjectPath& object_path) { 493 const dbus::ObjectPath& object_path) {
142 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) 494 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
143 return new IBusEngineServiceImpl(bus, object_path); 495 return new IBusEngineServiceImpl(bus, object_path);
144 else 496 else
145 return new IBusEngineServiceStubImpl(); 497 return new IBusEngineServiceStubImpl();
146 } 498 }
147 499
148 } // namespace chromeos 500 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/dbus/ibus/ibus_constants.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698