Home | History | Annotate | Download | only in fwl
      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 
     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 
     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 
     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 
     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 
     68 void CFWL_NoteDriver::PushNoteLoop(CFWL_NoteLoop* pNoteLoop) {
     69   m_NoteLoopQueue.push_back(pNoteLoop);
     70 }
     71 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    167 void CFWL_NoteDriver::QueueMessage(std::unique_ptr<CFWL_Message> pMessage) {
    168   m_NoteQueue.push_back(std::move(pMessage));
    169 }
    170 
    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 
    183 CFWL_NoteLoop* CFWL_NoteDriver::GetTopLoop() const {
    184   return !m_NoteLoopQueue.empty() ? m_NoteLoopQueue.back() : nullptr;
    185 }
    186 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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