PopupQueue.cpp (2692B)
1 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */ 2 /* vim: set sw=2 ts=8 et tw=80 : */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "PopupQueue.h" 8 9 #include "mozilla/StaticPtr.h" 10 #include "mozilla/dom/Element.h" 11 #include "nsThreadUtils.h" 12 13 using namespace mozilla; 14 15 void PopupQueue::Enqueue(Element* aPopup, 16 MoveOnlyFunction<void(Element*)>&& aCallback) { 17 if (!aCallback) { 18 return; 19 } 20 21 if (Store(aPopup, false, std::move(aCallback)) && !mShowing) { 22 MaybeShowNext(); 23 } 24 } 25 26 void PopupQueue::Show(Element* aPopup, 27 MoveOnlyFunction<void(Element*)>&& aCallback) { 28 if (!aCallback) { 29 return; 30 } 31 32 MoveOnlyFunction<void(Element*)> callback = std::move(aCallback); 33 34 if (Store(aPopup, true, nullptr)) { 35 ++mShowing; 36 callback(aPopup); 37 } 38 } 39 40 bool PopupQueue::Store(Element* aPopup, bool aShown, 41 MoveOnlyFunction<void(Element*)>&& aCallback) { 42 // Let's avoid the same popup shown multiple time, if it's already on screen. 43 if (!aShown) { 44 for (const PendingPopup& popup : mQueue) { 45 if (popup.mPopup == aPopup) { 46 return false; 47 } 48 } 49 } 50 51 mQueue.AppendElement(PendingPopup{aPopup, 52 /* if not shown, it's qeueable */ !aShown, 53 aShown, std::move(aCallback)}); 54 return true; 55 } 56 57 void PopupQueue::NotifyDismissed(Element* aPopup, bool aRemoveAll) { 58 if (mQueue.IsEmpty()) { 59 return; 60 } 61 62 for (uint32_t i = 0; i < mQueue.Length();) { 63 if (mQueue[i].mPopup == aPopup) { 64 if (mShowing && mQueue[i].mShown) { 65 --mShowing; 66 } 67 68 mQueue.RemoveElementAt(i); 69 70 if (!aRemoveAll) { 71 break; 72 } 73 74 continue; 75 } 76 77 ++i; 78 } 79 80 if (!mQueue.IsEmpty() && !mShowing) { 81 NS_DispatchToMainThread(NewRunnableMethod("PopupQueue::MaybeShowNext", this, 82 &PopupQueue::MaybeShowNext)); 83 } 84 } 85 86 void PopupQueue::MaybeShowNext() { 87 if (mQueue.IsEmpty() || mShowing) { 88 return; 89 } 90 91 PendingPopup& popup = mQueue[0]; 92 93 ++mShowing; 94 MOZ_ASSERT(!popup.mShown); 95 popup.mShown = true; 96 97 MoveOnlyFunction<void(Element*)> callback = std::move(popup.mCallback); 98 MOZ_ASSERT(!popup.mCallback); 99 100 callback(mQueue[0].mPopup); 101 } 102 103 PopupQueue::Element* PopupQueue::RetrieveQueueableShownPopup() const { 104 for (auto& popup : mQueue) { 105 if (popup.mQueueable && popup.mShown) { 106 return popup.mPopup; 107 } 108 } 109 110 return nullptr; 111 }