/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */ /* vim: set sw=2 ts=8 et tw=80 : */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "PopupQueue.h" #include "mozilla/StaticPtr.h" #include "mozilla/dom/Element.h" #include "nsThreadUtils.h" using namespace mozilla; void PopupQueue::Enqueue(Element* aPopup, MoveOnlyFunction&& aCallback) { if (!aCallback) { return; } if (Store(aPopup, false, std::move(aCallback)) && !mShowing) { MaybeShowNext(); } } void PopupQueue::Show(Element* aPopup, MoveOnlyFunction&& aCallback) { if (!aCallback) { return; } MoveOnlyFunction callback = std::move(aCallback); if (Store(aPopup, true, nullptr)) { ++mShowing; callback(aPopup); } } bool PopupQueue::Store(Element* aPopup, bool aShown, MoveOnlyFunction&& aCallback) { // Let's avoid the same popup shown multiple time, if it's already on screen. if (!aShown) { for (const PendingPopup& popup : mQueue) { if (popup.mPopup == aPopup) { return false; } } } mQueue.AppendElement(PendingPopup{aPopup, /* if not shown, it's qeueable */ !aShown, aShown, std::move(aCallback)}); return true; } void PopupQueue::NotifyDismissed(Element* aPopup, bool aRemoveAll) { if (mQueue.IsEmpty()) { return; } for (uint32_t i = 0; i < mQueue.Length();) { if (mQueue[i].mPopup == aPopup) { if (mShowing && mQueue[i].mShown) { --mShowing; } mQueue.RemoveElementAt(i); if (!aRemoveAll) { break; } continue; } ++i; } if (!mQueue.IsEmpty() && !mShowing) { NS_DispatchToMainThread(NewRunnableMethod("PopupQueue::MaybeShowNext", this, &PopupQueue::MaybeShowNext)); } } void PopupQueue::MaybeShowNext() { if (mQueue.IsEmpty() || mShowing) { return; } PendingPopup& popup = mQueue[0]; ++mShowing; MOZ_ASSERT(!popup.mShown); popup.mShown = true; MoveOnlyFunction callback = std::move(popup.mCallback); MOZ_ASSERT(!popup.mCallback); callback(mQueue[0].mPopup); } PopupQueue::Element* PopupQueue::RetrieveQueueableShownPopup() const { for (auto& popup : mQueue) { if (popup.mQueueable && popup.mShown) { return popup.mPopup; } } return nullptr; }