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_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