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 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 34 CFWL_NoteDriver::~CFWL_NoteDriver() { 35 ClearEventTargets(true); 36 } 37 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 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 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 74 void CFWL_NoteDriver::PushNoteLoop(CFWL_NoteLoop* pNoteLoop) { 75 m_NoteLoopQueue.push_back(pNoteLoop); 76 } 77 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 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 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 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 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 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 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 174 void CFWL_NoteDriver::QueueMessage(std::unique_ptr<CFWL_Message> pMessage) { 175 m_NoteQueue.push_back(std::move(pMessage)); 176 } 177 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 190 CFWL_NoteLoop* CFWL_NoteDriver::GetTopLoop() const { 191 return !m_NoteLoopQueue.empty() ? m_NoteLoopQueue.back() : nullptr; 192 } 193 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 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 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 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 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 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 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 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 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 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 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 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