1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 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/. */
7 #include "nsIObserverService.h"
8 #include "mozilla/Services.h"
9 #include "mozilla/SimpleEnumerator.h"
11 #include "nsICategoryManager.h"
12 #include "nsISupportsPrimitives.h"
14 #include "nsXPCOMCID.h"
16 #include "nsCategoryCache.h"
18 using mozilla::SimpleEnumerator
;
20 nsCategoryObserver::nsCategoryObserver(const nsACString
& aCategory
)
21 : mCategory(aCategory
),
24 mObserversRemoved(false) {
25 MOZ_ASSERT(NS_IsMainThread());
26 // First, enumerate the currently existing entries
27 nsCOMPtr
<nsICategoryManager
> catMan
=
28 do_GetService(NS_CATEGORYMANAGER_CONTRACTID
);
33 nsCOMPtr
<nsISimpleEnumerator
> enumerator
;
35 catMan
->EnumerateCategory(aCategory
, getter_AddRefs(enumerator
));
40 for (auto& categoryEntry
: SimpleEnumerator
<nsICategoryEntry
>(enumerator
)) {
41 nsAutoCString entryValue
;
42 categoryEntry
->GetValue(entryValue
);
44 if (nsCOMPtr
<nsISupports
> service
= do_GetService(entryValue
.get())) {
45 nsAutoCString entryName
;
46 categoryEntry
->GetEntry(entryName
);
48 mHash
.InsertOrUpdate(entryName
, service
);
52 // Now, listen for changes
53 nsCOMPtr
<nsIObserverService
> serv
= mozilla::services::GetObserverService();
55 serv
->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, false);
56 serv
->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID
, false);
57 serv
->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID
, false);
58 serv
->AddObserver(this, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID
, false);
62 nsCategoryObserver::~nsCategoryObserver() = default;
64 NS_IMPL_ISUPPORTS(nsCategoryObserver
, nsIObserver
)
66 void nsCategoryObserver::ListenerDied() {
67 MOZ_ASSERT(NS_IsMainThread());
73 void nsCategoryObserver::SetListener(void(aCallback
)(void*), void* aClosure
) {
74 MOZ_ASSERT(NS_IsMainThread());
75 mCallback
= aCallback
;
79 void nsCategoryObserver::RemoveObservers() {
80 MOZ_ASSERT(NS_IsMainThread());
82 if (mObserversRemoved
) {
90 mObserversRemoved
= true;
91 nsCOMPtr
<nsIObserverService
> obsSvc
= mozilla::services::GetObserverService();
93 obsSvc
->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
);
94 obsSvc
->RemoveObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID
);
95 obsSvc
->RemoveObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID
);
96 obsSvc
->RemoveObserver(this, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID
);
101 nsCategoryObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
102 const char16_t
* aData
) {
103 MOZ_ASSERT(NS_IsMainThread());
105 if (strcmp(aTopic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
) == 0) {
113 !nsDependentString(aData
).Equals(NS_ConvertASCIItoUTF16(mCategory
))) {
118 nsCOMPtr
<nsISupportsCString
> strWrapper(do_QueryInterface(aSubject
));
120 strWrapper
->GetData(str
);
123 if (strcmp(aTopic
, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID
) == 0) {
124 // We may get an add notification even when we already have an entry. This
125 // is due to the notification happening asynchronously, so if the entry gets
126 // added and an nsCategoryObserver gets instantiated before events get
127 // processed, we'd get the notification for an existing entry.
128 // Do nothing in that case.
129 if (mHash
.GetWeak(str
)) {
133 nsCOMPtr
<nsICategoryManager
> catMan
=
134 do_GetService(NS_CATEGORYMANAGER_CONTRACTID
);
139 nsCString entryValue
;
140 catMan
->GetCategoryEntry(mCategory
, str
, entryValue
);
142 nsCOMPtr
<nsISupports
> service
= do_GetService(entryValue
.get());
145 mHash
.InsertOrUpdate(str
, service
);
150 } else if (strcmp(aTopic
, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID
) == 0) {
155 } else if (strcmp(aTopic
, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID
) == 0) {