1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/fwl/cfwl_notedriver.h"
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "core/fxcrt/fx_extension.h"
13 #include "third_party/base/ptr_util.h"
14 #include "third_party/base/stl_util.h"
15 #include "xfa/fwl/cfwl_app.h"
16 #include "xfa/fwl/cfwl_eventtarget.h"
17 #include "xfa/fwl/cfwl_form.h"
18 #include "xfa/fwl/cfwl_messagekey.h"
19 #include "xfa/fwl/cfwl_messagekillfocus.h"
20 #include "xfa/fwl/cfwl_messagemouse.h"
21 #include "xfa/fwl/cfwl_messagemousewheel.h"
22 #include "xfa/fwl/cfwl_messagesetfocus.h"
23 #include "xfa/fwl/cfwl_noteloop.h"
24 #include "xfa/fwl/cfwl_widgetmgr.h"
25
CFWL_NoteDriver()26 CFWL_NoteDriver::CFWL_NoteDriver()
27 : m_pHover(nullptr),
28 m_pFocus(nullptr),
29 m_pGrab(nullptr),
30 m_pNoteLoop(pdfium::MakeUnique<CFWL_NoteLoop>()) {
31 PushNoteLoop(m_pNoteLoop.get());
32 }
33
~CFWL_NoteDriver()34 CFWL_NoteDriver::~CFWL_NoteDriver() {}
35
SendEvent(CFWL_Event * pNote)36 void CFWL_NoteDriver::SendEvent(CFWL_Event* pNote) {
37 for (const auto& pair : m_eventTargets) {
38 if (pair.second->IsValid())
39 pair.second->ProcessEvent(pNote);
40 }
41 }
42
RegisterEventTarget(CFWL_Widget * pListener,CFWL_Widget * pEventSource)43 void CFWL_NoteDriver::RegisterEventTarget(CFWL_Widget* pListener,
44 CFWL_Widget* pEventSource) {
45 uint32_t key = pListener->GetEventKey();
46 if (key == 0) {
47 do {
48 key = rand();
49 } while (key == 0 || pdfium::ContainsKey(m_eventTargets, key));
50 pListener->SetEventKey(key);
51 }
52 if (!m_eventTargets[key])
53 m_eventTargets[key] = pdfium::MakeUnique<CFWL_EventTarget>(pListener);
54
55 m_eventTargets[key]->SetEventSource(pEventSource);
56 }
57
UnregisterEventTarget(CFWL_Widget * pListener)58 void CFWL_NoteDriver::UnregisterEventTarget(CFWL_Widget* pListener) {
59 uint32_t key = pListener->GetEventKey();
60 if (key == 0)
61 return;
62
63 auto it = m_eventTargets.find(key);
64 if (it != m_eventTargets.end())
65 it->second->FlagInvalid();
66 }
67
PushNoteLoop(CFWL_NoteLoop * pNoteLoop)68 void CFWL_NoteDriver::PushNoteLoop(CFWL_NoteLoop* pNoteLoop) {
69 m_NoteLoopQueue.push_back(pNoteLoop);
70 }
71
PopNoteLoop()72 CFWL_NoteLoop* CFWL_NoteDriver::PopNoteLoop() {
73 if (m_NoteLoopQueue.empty())
74 return nullptr;
75
76 CFWL_NoteLoop* p = m_NoteLoopQueue.back();
77 m_NoteLoopQueue.pop_back();
78 return p;
79 }
80
SetFocus(CFWL_Widget * pFocus)81 bool CFWL_NoteDriver::SetFocus(CFWL_Widget* pFocus) {
82 if (m_pFocus == pFocus)
83 return true;
84
85 CFWL_Widget* pPrev = m_pFocus;
86 m_pFocus = pFocus;
87 if (pPrev) {
88 if (IFWL_WidgetDelegate* pDelegate = pPrev->GetDelegate()) {
89 CFWL_MessageKillFocus ms(pPrev, pPrev);
90 pDelegate->OnProcessMessage(&ms);
91 }
92 }
93 if (pFocus) {
94 CFWL_Widget* pWidget =
95 pFocus->GetOwnerApp()->GetWidgetMgr()->GetSystemFormWidget(pFocus);
96 CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
97 if (pForm)
98 pForm->SetSubFocus(pFocus);
99
100 if (IFWL_WidgetDelegate* pDelegate = pFocus->GetDelegate()) {
101 CFWL_MessageSetFocus ms(nullptr, pFocus);
102 pDelegate->OnProcessMessage(&ms);
103 }
104 }
105 return true;
106 }
107
Run()108 void CFWL_NoteDriver::Run() {
109 #if _FX_OS_ == _FX_OS_LINUX_ || _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
110 for (;;) {
111 CFWL_NoteLoop* pTopLoop = GetTopLoop();
112 if (!pTopLoop || !pTopLoop->ContinueModal())
113 break;
114 UnqueueMessageAndProcess(pTopLoop);
115 }
116 #endif // _FX_OS_ == _FX_OS_LINUX_ || _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
117 }
118
NotifyTargetHide(CFWL_Widget * pNoteTarget)119 void CFWL_NoteDriver::NotifyTargetHide(CFWL_Widget* pNoteTarget) {
120 if (m_pFocus == pNoteTarget)
121 m_pFocus = nullptr;
122 if (m_pHover == pNoteTarget)
123 m_pHover = nullptr;
124 if (m_pGrab == pNoteTarget)
125 m_pGrab = nullptr;
126 }
127
NotifyTargetDestroy(CFWL_Widget * pNoteTarget)128 void CFWL_NoteDriver::NotifyTargetDestroy(CFWL_Widget* pNoteTarget) {
129 if (m_pFocus == pNoteTarget)
130 m_pFocus = nullptr;
131 if (m_pHover == pNoteTarget)
132 m_pHover = nullptr;
133 if (m_pGrab == pNoteTarget)
134 m_pGrab = nullptr;
135
136 UnregisterEventTarget(pNoteTarget);
137
138 for (CFWL_Widget* pWidget : m_Forms) {
139 CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
140 if (!pForm)
141 continue;
142
143 CFWL_Widget* pSubFocus = pForm->GetSubFocus();
144 if (!pSubFocus)
145 return;
146
147 if (pSubFocus == pNoteTarget)
148 pForm->SetSubFocus(nullptr);
149 }
150 }
151
RegisterForm(CFWL_Widget * pForm)152 void CFWL_NoteDriver::RegisterForm(CFWL_Widget* pForm) {
153 if (!pForm || pdfium::ContainsValue(m_Forms, pForm))
154 return;
155
156 m_Forms.push_back(pForm);
157 if (m_Forms.size() == 1 && !m_NoteLoopQueue.empty() && m_NoteLoopQueue[0])
158 m_NoteLoopQueue[0]->SetMainForm(pForm);
159 }
160
UnRegisterForm(CFWL_Widget * pForm)161 void CFWL_NoteDriver::UnRegisterForm(CFWL_Widget* pForm) {
162 auto iter = std::find(m_Forms.begin(), m_Forms.end(), pForm);
163 if (iter != m_Forms.end())
164 m_Forms.erase(iter);
165 }
166
QueueMessage(std::unique_ptr<CFWL_Message> pMessage)167 void CFWL_NoteDriver::QueueMessage(std::unique_ptr<CFWL_Message> pMessage) {
168 m_NoteQueue.push_back(std::move(pMessage));
169 }
170
UnqueueMessageAndProcess(CFWL_NoteLoop * pNoteLoop)171 void CFWL_NoteDriver::UnqueueMessageAndProcess(CFWL_NoteLoop* pNoteLoop) {
172 if (m_NoteQueue.empty())
173 return;
174
175 std::unique_ptr<CFWL_Message> pMessage = std::move(m_NoteQueue.front());
176 m_NoteQueue.pop_front();
177 if (!IsValidMessage(pMessage.get()))
178 return;
179
180 ProcessMessage(std::move(pMessage));
181 }
182
GetTopLoop() const183 CFWL_NoteLoop* CFWL_NoteDriver::GetTopLoop() const {
184 return !m_NoteLoopQueue.empty() ? m_NoteLoopQueue.back() : nullptr;
185 }
186
ProcessMessage(std::unique_ptr<CFWL_Message> pMessage)187 void CFWL_NoteDriver::ProcessMessage(std::unique_ptr<CFWL_Message> pMessage) {
188 CFWL_WidgetMgr* pWidgetMgr =
189 pMessage->m_pDstTarget->GetOwnerApp()->GetWidgetMgr();
190 CFWL_Widget* pMessageForm = pWidgetMgr->IsFormDisabled()
191 ? pMessage->m_pDstTarget
192 : GetMessageForm(pMessage->m_pDstTarget);
193 if (!pMessageForm)
194 return;
195
196 if (!DispatchMessage(pMessage.get(), pMessageForm))
197 return;
198
199 if (pMessage->GetType() == CFWL_Message::Type::Mouse)
200 MouseSecondary(pMessage.get());
201 }
202
DispatchMessage(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)203 bool CFWL_NoteDriver::DispatchMessage(CFWL_Message* pMessage,
204 CFWL_Widget* pMessageForm) {
205 switch (pMessage->GetType()) {
206 case CFWL_Message::Type::SetFocus: {
207 if (!DoSetFocus(pMessage, pMessageForm))
208 return false;
209 break;
210 }
211 case CFWL_Message::Type::KillFocus: {
212 if (!DoKillFocus(pMessage, pMessageForm))
213 return false;
214 break;
215 }
216 case CFWL_Message::Type::Key: {
217 if (!DoKey(pMessage, pMessageForm))
218 return false;
219 break;
220 }
221 case CFWL_Message::Type::Mouse: {
222 if (!DoMouse(pMessage, pMessageForm))
223 return false;
224 break;
225 }
226 case CFWL_Message::Type::MouseWheel: {
227 if (!DoWheel(pMessage, pMessageForm))
228 return false;
229 break;
230 }
231 default:
232 break;
233 }
234 if (IFWL_WidgetDelegate* pDelegate = pMessage->m_pDstTarget->GetDelegate())
235 pDelegate->OnProcessMessage(pMessage);
236
237 return true;
238 }
239
DoSetFocus(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)240 bool CFWL_NoteDriver::DoSetFocus(CFWL_Message* pMessage,
241 CFWL_Widget* pMessageForm) {
242 CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
243 if (pWidgetMgr->IsFormDisabled()) {
244 m_pFocus = pMessage->m_pDstTarget;
245 return true;
246 }
247
248 CFWL_Widget* pWidget = pMessage->m_pDstTarget;
249 if (!pWidget)
250 return false;
251
252 CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
253 CFWL_Widget* pSubFocus = pForm->GetSubFocus();
254 if (pSubFocus && ((pSubFocus->GetStates() & FWL_WGTSTATE_Focused) == 0)) {
255 pMessage->m_pDstTarget = pSubFocus;
256 if (m_pFocus != pMessage->m_pDstTarget) {
257 m_pFocus = pMessage->m_pDstTarget;
258 return true;
259 }
260 }
261 return false;
262 }
263
DoKillFocus(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)264 bool CFWL_NoteDriver::DoKillFocus(CFWL_Message* pMessage,
265 CFWL_Widget* pMessageForm) {
266 CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
267 if (pWidgetMgr->IsFormDisabled()) {
268 if (m_pFocus == pMessage->m_pDstTarget)
269 m_pFocus = nullptr;
270 return true;
271 }
272
273 CFWL_Form* pForm = static_cast<CFWL_Form*>(pMessage->m_pDstTarget);
274 if (!pForm)
275 return false;
276
277 CFWL_Widget* pSubFocus = pForm->GetSubFocus();
278 if (pSubFocus && (pSubFocus->GetStates() & FWL_WGTSTATE_Focused)) {
279 pMessage->m_pDstTarget = pSubFocus;
280 if (m_pFocus == pMessage->m_pDstTarget) {
281 m_pFocus = nullptr;
282 return true;
283 }
284 }
285 return false;
286 }
287
DoKey(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)288 bool CFWL_NoteDriver::DoKey(CFWL_Message* pMessage, CFWL_Widget* pMessageForm) {
289 CFWL_MessageKey* pMsg = static_cast<CFWL_MessageKey*>(pMessage);
290 #if (_FX_OS_ != _FX_OS_MACOSX_)
291 if (pMsg->m_dwCmd == FWL_KeyCommand::KeyDown &&
292 pMsg->m_dwKeyCode == FWL_VKEY_Tab) {
293 CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
294 CFWL_Widget* pForm = GetMessageForm(pMsg->m_pDstTarget);
295 CFWL_Widget* pFocus = m_pFocus;
296 if (m_pFocus && pWidgetMgr->GetSystemFormWidget(m_pFocus) != pForm)
297 pFocus = nullptr;
298
299 bool bFind = false;
300 CFWL_Widget* pNextTabStop = pWidgetMgr->NextTab(pForm, pFocus, bFind);
301 if (!pNextTabStop) {
302 bFind = false;
303 pNextTabStop = pWidgetMgr->NextTab(pForm, nullptr, bFind);
304 }
305 if (pNextTabStop == pFocus)
306 return true;
307 if (pNextTabStop)
308 SetFocus(pNextTabStop);
309 return true;
310 }
311 #endif
312
313 if (!m_pFocus) {
314 if (pMsg->m_dwCmd == FWL_KeyCommand::KeyDown &&
315 pMsg->m_dwKeyCode == FWL_VKEY_Return) {
316 CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
317 CFWL_Widget* defButton = pWidgetMgr->GetDefaultButton(pMessageForm);
318 if (defButton) {
319 pMsg->m_pDstTarget = defButton;
320 return true;
321 }
322 }
323 return false;
324 }
325 pMsg->m_pDstTarget = m_pFocus;
326 return true;
327 }
328
DoMouse(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)329 bool CFWL_NoteDriver::DoMouse(CFWL_Message* pMessage,
330 CFWL_Widget* pMessageForm) {
331 CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
332 if (pMsg->m_dwCmd == FWL_MouseCommand::Leave ||
333 pMsg->m_dwCmd == FWL_MouseCommand::Hover ||
334 pMsg->m_dwCmd == FWL_MouseCommand::Enter) {
335 return !!pMsg->m_pDstTarget;
336 }
337 if (pMsg->m_pDstTarget != pMessageForm)
338 pMsg->m_pos = pMsg->m_pDstTarget->TransformTo(pMessageForm, pMsg->m_pos);
339 if (!DoMouseEx(pMsg, pMessageForm))
340 pMsg->m_pDstTarget = pMessageForm;
341 return true;
342 }
343
DoWheel(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)344 bool CFWL_NoteDriver::DoWheel(CFWL_Message* pMessage,
345 CFWL_Widget* pMessageForm) {
346 CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
347 if (!pWidgetMgr)
348 return false;
349
350 CFWL_MessageMouseWheel* pMsg = static_cast<CFWL_MessageMouseWheel*>(pMessage);
351 CFWL_Widget* pDst = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_pos);
352 if (!pDst)
353 return false;
354
355 pMsg->m_pos = pMessageForm->TransformTo(pDst, pMsg->m_pos);
356 pMsg->m_pDstTarget = pDst;
357 return true;
358 }
359
DoMouseEx(CFWL_Message * pMessage,CFWL_Widget * pMessageForm)360 bool CFWL_NoteDriver::DoMouseEx(CFWL_Message* pMessage,
361 CFWL_Widget* pMessageForm) {
362 CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
363 if (!pWidgetMgr)
364 return false;
365 CFWL_Widget* pTarget = nullptr;
366 if (m_pGrab)
367 pTarget = m_pGrab;
368
369 CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
370 if (!pTarget)
371 pTarget = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_pos);
372 if (!pTarget)
373 return false;
374 if (pTarget && pMessageForm != pTarget)
375 pMsg->m_pos = pMessageForm->TransformTo(pTarget, pMsg->m_pos);
376
377 pMsg->m_pDstTarget = pTarget;
378 return true;
379 }
380
MouseSecondary(CFWL_Message * pMessage)381 void CFWL_NoteDriver::MouseSecondary(CFWL_Message* pMessage) {
382 CFWL_Widget* pTarget = pMessage->m_pDstTarget;
383 if (pTarget == m_pHover)
384 return;
385
386 CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
387 if (m_pHover) {
388 CFWL_MessageMouse msLeave(nullptr, m_pHover);
389 msLeave.m_pos = pTarget->TransformTo(m_pHover, pMsg->m_pos);
390 msLeave.m_dwFlags = 0;
391 msLeave.m_dwCmd = FWL_MouseCommand::Leave;
392 DispatchMessage(&msLeave, nullptr);
393 }
394 if (pTarget->GetClassID() == FWL_Type::Form) {
395 m_pHover = nullptr;
396 return;
397 }
398 m_pHover = pTarget;
399
400 CFWL_MessageMouse msHover(nullptr, pTarget);
401 msHover.m_pos = pMsg->m_pos;
402 msHover.m_dwFlags = 0;
403 msHover.m_dwCmd = FWL_MouseCommand::Hover;
404 DispatchMessage(&msHover, nullptr);
405 }
406
IsValidMessage(CFWL_Message * pMessage)407 bool CFWL_NoteDriver::IsValidMessage(CFWL_Message* pMessage) {
408 for (CFWL_NoteLoop* pNoteLoop : m_NoteLoopQueue) {
409 CFWL_Widget* pForm = pNoteLoop->GetForm();
410 if (pForm && pForm == pMessage->m_pDstTarget)
411 return true;
412 }
413 for (CFWL_Widget* pWidget : m_Forms) {
414 CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
415 if (pForm == pMessage->m_pDstTarget)
416 return true;
417 }
418 return false;
419 }
420
GetMessageForm(CFWL_Widget * pDstTarget)421 CFWL_Widget* CFWL_NoteDriver::GetMessageForm(CFWL_Widget* pDstTarget) {
422 if (m_NoteLoopQueue.empty())
423 return nullptr;
424
425 CFWL_Widget* pMessageForm = nullptr;
426 if (m_NoteLoopQueue.size() > 1)
427 pMessageForm = m_NoteLoopQueue.back()->GetForm();
428 else if (!pdfium::ContainsValue(m_Forms, pDstTarget))
429 pMessageForm = pDstTarget;
430
431 if (!pMessageForm && pDstTarget) {
432 CFWL_WidgetMgr* pWidgetMgr = pDstTarget->GetOwnerApp()->GetWidgetMgr();
433 if (!pWidgetMgr)
434 return nullptr;
435
436 pMessageForm = pWidgetMgr->GetSystemFormWidget(pDstTarget);
437 }
438 return pMessageForm;
439 }
440
ClearEventTargets()441 void CFWL_NoteDriver::ClearEventTargets() {
442 auto it = m_eventTargets.begin();
443 while (it != m_eventTargets.end()) {
444 auto old = it++;
445 if (!old->second->IsValid())
446 m_eventTargets.erase(old);
447 }
448 }
449