|
1 /* vim:set st=2 sts=2 ts=2 et cin: */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nsIObserverService.h" |
|
7 #include "mozilla/Services.h" |
|
8 #include "nsISupportsPrimitives.h" |
|
9 #include "nsIStringEnumerator.h" |
|
10 |
|
11 #include "nsXPCOMCID.h" |
|
12 |
|
13 #include "nsCategoryCache.h" |
|
14 |
|
15 nsCategoryObserver::nsCategoryObserver(const char* aCategory) |
|
16 : mCategory(aCategory) |
|
17 , mObserversRemoved(false) |
|
18 { |
|
19 // First, enumerate the currently existing entries |
|
20 nsCOMPtr<nsICategoryManager> catMan = |
|
21 do_GetService(NS_CATEGORYMANAGER_CONTRACTID); |
|
22 if (!catMan) |
|
23 return; |
|
24 |
|
25 nsCOMPtr<nsISimpleEnumerator> enumerator; |
|
26 nsresult rv = catMan->EnumerateCategory(aCategory, |
|
27 getter_AddRefs(enumerator)); |
|
28 if (NS_FAILED(rv)) |
|
29 return; |
|
30 |
|
31 nsCOMPtr<nsIUTF8StringEnumerator> strings = do_QueryInterface(enumerator); |
|
32 MOZ_ASSERT(strings); |
|
33 |
|
34 bool more; |
|
35 while (NS_SUCCEEDED(strings->HasMore(&more)) && more) { |
|
36 nsAutoCString entryName; |
|
37 strings->GetNext(entryName); |
|
38 |
|
39 nsCString entryValue; |
|
40 rv = catMan->GetCategoryEntry(aCategory, |
|
41 entryName.get(), |
|
42 getter_Copies(entryValue)); |
|
43 if (NS_SUCCEEDED(rv)) { |
|
44 nsCOMPtr<nsISupports> service = do_GetService(entryValue.get()); |
|
45 if (service) { |
|
46 mHash.Put(entryName, service); |
|
47 } |
|
48 } |
|
49 } |
|
50 |
|
51 // Now, listen for changes |
|
52 nsCOMPtr<nsIObserverService> serv = |
|
53 mozilla::services::GetObserverService(); |
|
54 if (serv) { |
|
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); |
|
59 } |
|
60 } |
|
61 |
|
62 nsCategoryObserver::~nsCategoryObserver() { |
|
63 } |
|
64 |
|
65 NS_IMPL_ISUPPORTS(nsCategoryObserver, nsIObserver) |
|
66 |
|
67 void |
|
68 nsCategoryObserver::ListenerDied() { |
|
69 RemoveObservers(); |
|
70 } |
|
71 |
|
72 void |
|
73 nsCategoryObserver::RemoveObservers() { |
|
74 if (mObserversRemoved) |
|
75 return; |
|
76 |
|
77 mObserversRemoved = true; |
|
78 nsCOMPtr<nsIObserverService> obsSvc = |
|
79 mozilla::services::GetObserverService(); |
|
80 if (obsSvc) { |
|
81 obsSvc->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); |
|
82 obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID); |
|
83 obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID); |
|
84 obsSvc->RemoveObserver(this, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID); |
|
85 } |
|
86 } |
|
87 |
|
88 NS_IMETHODIMP |
|
89 nsCategoryObserver::Observe(nsISupports* aSubject, const char* aTopic, |
|
90 const char16_t* aData) { |
|
91 if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { |
|
92 mHash.Clear(); |
|
93 RemoveObservers(); |
|
94 |
|
95 return NS_OK; |
|
96 } |
|
97 |
|
98 if (!aData || |
|
99 !nsDependentString(aData).Equals(NS_ConvertASCIItoUTF16(mCategory))) |
|
100 return NS_OK; |
|
101 |
|
102 nsAutoCString str; |
|
103 nsCOMPtr<nsISupportsCString> strWrapper(do_QueryInterface(aSubject)); |
|
104 if (strWrapper) |
|
105 strWrapper->GetData(str); |
|
106 |
|
107 if (strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID) == 0) { |
|
108 // We may get an add notification even when we already have an entry. This |
|
109 // is due to the notification happening asynchronously, so if the entry gets |
|
110 // added and an nsCategoryObserver gets instantiated before events get |
|
111 // processed, we'd get the notification for an existing entry. |
|
112 // Do nothing in that case. |
|
113 if (mHash.GetWeak(str)) |
|
114 return NS_OK; |
|
115 |
|
116 nsCOMPtr<nsICategoryManager> catMan = |
|
117 do_GetService(NS_CATEGORYMANAGER_CONTRACTID); |
|
118 if (!catMan) |
|
119 return NS_OK; |
|
120 |
|
121 nsCString entryValue; |
|
122 catMan->GetCategoryEntry(mCategory.get(), |
|
123 str.get(), |
|
124 getter_Copies(entryValue)); |
|
125 |
|
126 nsCOMPtr<nsISupports> service = do_GetService(entryValue.get()); |
|
127 |
|
128 if (service) { |
|
129 mHash.Put(str, service); |
|
130 } |
|
131 } else if (strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID) == 0) { |
|
132 mHash.Remove(str); |
|
133 } else if (strcmp(aTopic, NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID) == 0) { |
|
134 mHash.Clear(); |
|
135 } |
|
136 return NS_OK; |
|
137 } |