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 26CFWL_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 34CFWL_NoteDriver::~CFWL_NoteDriver() {} 35 36void 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 43void 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 58void 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 68void CFWL_NoteDriver::PushNoteLoop(CFWL_NoteLoop* pNoteLoop) { 69 m_NoteLoopQueue.push_back(pNoteLoop); 70} 71 72CFWL_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 81bool 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 108void 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 119void 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 128void 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 152void 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 161void 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 167void CFWL_NoteDriver::QueueMessage(std::unique_ptr<CFWL_Message> pMessage) { 168 m_NoteQueue.push_back(std::move(pMessage)); 169} 170 171void 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 183CFWL_NoteLoop* CFWL_NoteDriver::GetTopLoop() const { 184 return !m_NoteLoopQueue.empty() ? m_NoteLoopQueue.back() : nullptr; 185} 186 187void 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 203bool 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 240bool 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 264bool 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 288bool 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 329bool 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 344bool 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 360bool 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 381void 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 407bool 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 421CFWL_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 441void 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