diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/presentation/PresentationDeviceManager.cpp | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/presentation/PresentationDeviceManager.cpp')
-rw-r--r-- | dom/presentation/PresentationDeviceManager.cpp | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/dom/presentation/PresentationDeviceManager.cpp b/dom/presentation/PresentationDeviceManager.cpp new file mode 100644 index 0000000000..185f541430 --- /dev/null +++ b/dom/presentation/PresentationDeviceManager.cpp @@ -0,0 +1,307 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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 "PresentationDeviceManager.h" + +#include "mozilla/Services.h" +#include "MainThreadUtils.h" +#include "nsArrayUtils.h" +#include "nsCategoryCache.h" +#include "nsCOMPtr.h" +#include "nsComponentManagerUtils.h" +#include "nsIMutableArray.h" +#include "nsIObserverService.h" +#include "nsISupportsPrimitives.h" +#include "nsThreadUtils.h" +#include "nsXULAppAPI.h" +#include "PresentationSessionRequest.h" +#include "PresentationTerminateRequest.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_ISUPPORTS(PresentationDeviceManager, nsIPresentationDeviceManager, + nsIPresentationDeviceListener, nsIObserver, + nsISupportsWeakReference) + +PresentationDeviceManager::PresentationDeviceManager() = default; + +PresentationDeviceManager::~PresentationDeviceManager() { + UnloadDeviceProviders(); + mDevices.Clear(); +} + +void PresentationDeviceManager::Init() { + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + if (obs) { + obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); + } + + LoadDeviceProviders(); +} + +void PresentationDeviceManager::Shutdown() { + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + if (obs) { + obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); + } + + UnloadDeviceProviders(); +} + +void PresentationDeviceManager::LoadDeviceProviders() { + MOZ_ASSERT(mProviders.IsEmpty()); + + nsCategoryCache<nsIPresentationDeviceProvider> providerCache( + PRESENTATION_DEVICE_PROVIDER_CATEGORY); + providerCache.GetEntries(mProviders); + + for (uint32_t i = 0; i < mProviders.Length(); ++i) { + mProviders[i]->SetListener(this); + } +} + +void PresentationDeviceManager::UnloadDeviceProviders() { + for (uint32_t i = 0; i < mProviders.Length(); ++i) { + mProviders[i]->SetListener(nullptr); + } + + mProviders.Clear(); +} + +void PresentationDeviceManager::NotifyDeviceChange( + nsIPresentationDevice* aDevice, const char16_t* aType) { + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); + if (obs) { + obs->NotifyObservers(aDevice, PRESENTATION_DEVICE_CHANGE_TOPIC, aType); + } +} + +// nsIPresentationDeviceManager +NS_IMETHODIMP +PresentationDeviceManager::ForceDiscovery() { + MOZ_ASSERT(NS_IsMainThread()); + + for (uint32_t i = 0; i < mProviders.Length(); ++i) { + mProviders[i]->ForceDiscovery(); + } + + return NS_OK; +} + +NS_IMETHODIMP +PresentationDeviceManager::AddDeviceProvider( + nsIPresentationDeviceProvider* aProvider) { + NS_ENSURE_ARG(aProvider); + MOZ_ASSERT(NS_IsMainThread()); + + if (NS_WARN_IF(mProviders.Contains(aProvider))) { + return NS_OK; + } + + mProviders.AppendElement(aProvider); + aProvider->SetListener(this); + + return NS_OK; +} + +NS_IMETHODIMP +PresentationDeviceManager::RemoveDeviceProvider( + nsIPresentationDeviceProvider* aProvider) { + NS_ENSURE_ARG(aProvider); + MOZ_ASSERT(NS_IsMainThread()); + + if (NS_WARN_IF(!mProviders.RemoveElement(aProvider))) { + return NS_ERROR_FAILURE; + } + + aProvider->SetListener(nullptr); + + return NS_OK; +} + +NS_IMETHODIMP +PresentationDeviceManager::GetDeviceAvailable(bool* aRetVal) { + NS_ENSURE_ARG_POINTER(aRetVal); + MOZ_ASSERT(NS_IsMainThread()); + + *aRetVal = !mDevices.IsEmpty(); + + return NS_OK; +} + +NS_IMETHODIMP +PresentationDeviceManager::GetAvailableDevices(nsIArray* aPresentationUrls, + nsIArray** aRetVal) { + NS_ENSURE_ARG_POINTER(aRetVal); + MOZ_ASSERT(NS_IsMainThread()); + + // Bug 1194049: some providers may discontinue discovery after timeout. + // Call |ForceDiscovery()| here to make sure device lists are updated. + NS_DispatchToMainThread( + NewRunnableMethod("dom::PresentationDeviceManager::ForceDiscovery", this, + &PresentationDeviceManager::ForceDiscovery)); + + nsTArray<nsString> presentationUrls; + if (aPresentationUrls) { + uint32_t length; + nsresult rv = aPresentationUrls->GetLength(&length); + if (NS_SUCCEEDED(rv)) { + for (uint32_t i = 0; i < length; ++i) { + nsCOMPtr<nsISupportsString> isupportStr = + do_QueryElementAt(aPresentationUrls, i); + + nsAutoString presentationUrl; + rv = isupportStr->GetData(presentationUrl); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + + presentationUrls.AppendElement(presentationUrl); + } + } + } + + nsCOMPtr<nsIMutableArray> devices = do_CreateInstance(NS_ARRAY_CONTRACTID); + for (uint32_t i = 0; i < mDevices.Length(); ++i) { + if (presentationUrls.IsEmpty()) { + devices->AppendElement(mDevices[i]); + continue; + } + + for (uint32_t j = 0; j < presentationUrls.Length(); ++j) { + bool isSupported; + if (NS_SUCCEEDED(mDevices[i]->IsRequestedUrlSupported(presentationUrls[j], + &isSupported)) && + isSupported) { + devices->AppendElement(mDevices[i]); + break; + } + } + } + + devices.forget(aRetVal); + + return NS_OK; +} + +// nsIPresentationDeviceListener +NS_IMETHODIMP +PresentationDeviceManager::AddDevice(nsIPresentationDevice* aDevice) { + NS_ENSURE_ARG(aDevice); + MOZ_ASSERT(NS_IsMainThread()); + + if (NS_WARN_IF(mDevices.Contains(aDevice))) { + return NS_ERROR_FAILURE; + } + + mDevices.AppendElement(aDevice); + + NotifyDeviceChange(aDevice, u"add"); + + return NS_OK; +} + +NS_IMETHODIMP +PresentationDeviceManager::RemoveDevice(nsIPresentationDevice* aDevice) { + NS_ENSURE_ARG(aDevice); + MOZ_ASSERT(NS_IsMainThread()); + + int32_t index = mDevices.IndexOf(aDevice); + if (NS_WARN_IF(index < 0)) { + return NS_ERROR_FAILURE; + } + + mDevices.RemoveElementAt(index); + + NotifyDeviceChange(aDevice, u"remove"); + + return NS_OK; +} + +NS_IMETHODIMP +PresentationDeviceManager::UpdateDevice(nsIPresentationDevice* aDevice) { + NS_ENSURE_ARG(aDevice); + MOZ_ASSERT(NS_IsMainThread()); + + if (NS_WARN_IF(!mDevices.Contains(aDevice))) { + return NS_ERROR_FAILURE; + } + + NotifyDeviceChange(aDevice, u"update"); + + return NS_OK; +} + +NS_IMETHODIMP +PresentationDeviceManager::OnSessionRequest( + nsIPresentationDevice* aDevice, const nsAString& aUrl, + const nsAString& aPresentationId, + nsIPresentationControlChannel* aControlChannel) { + NS_ENSURE_ARG(aDevice); + NS_ENSURE_ARG(aControlChannel); + + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); + NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); + + RefPtr<PresentationSessionRequest> request = new PresentationSessionRequest( + aDevice, aUrl, aPresentationId, aControlChannel); + obs->NotifyObservers(request, PRESENTATION_SESSION_REQUEST_TOPIC, nullptr); + + return NS_OK; +} + +NS_IMETHODIMP +PresentationDeviceManager::OnTerminateRequest( + nsIPresentationDevice* aDevice, const nsAString& aPresentationId, + nsIPresentationControlChannel* aControlChannel, bool aIsFromReceiver) { + NS_ENSURE_ARG(aDevice); + NS_ENSURE_ARG(aControlChannel); + + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); + NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); + + RefPtr<PresentationTerminateRequest> request = + new PresentationTerminateRequest(aDevice, aPresentationId, + aControlChannel, aIsFromReceiver); + obs->NotifyObservers(request, PRESENTATION_TERMINATE_REQUEST_TOPIC, nullptr); + + return NS_OK; +} + +NS_IMETHODIMP +PresentationDeviceManager::OnReconnectRequest( + nsIPresentationDevice* aDevice, const nsAString& aUrl, + const nsAString& aPresentationId, + nsIPresentationControlChannel* aControlChannel) { + NS_ENSURE_ARG(aDevice); + NS_ENSURE_ARG(aControlChannel); + + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); + NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); + + RefPtr<PresentationSessionRequest> request = new PresentationSessionRequest( + aDevice, aUrl, aPresentationId, aControlChannel); + obs->NotifyObservers(request, PRESENTATION_RECONNECT_REQUEST_TOPIC, nullptr); + + return NS_OK; +} + +// nsIObserver +NS_IMETHODIMP +PresentationDeviceManager::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) { + if (!strcmp(aTopic, "profile-after-change")) { + Init(); + } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { + Shutdown(); + } + + return NS_OK; +} + +} // namespace dom +} // namespace mozilla |