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