sbBaseMediacoreEventTarget.cpp
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2008 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25 */
26 
28 
29 #include <nsAutoLock.h>
30 #include <nsComponentManagerUtils.h>
31 
32 #include <sbIMediacore.h>
33 #include <sbIMediacoreError.h>
34 #include <sbIMediacoreEventListener.h>
35 
36 #include <sbMediacoreEvent.h>
38 
39 /* ctor / dtor */
41  : mTarget(aTarget),
42  mMonitor(nsAutoMonitor::NewMonitor("sbBaseMediacoreEventTarget::mMonitor"))
43 {
44 }
46 {
47  nsAutoMonitor::DestroyMonitor(mMonitor);
48 }
49 
50 
51 /* boolean dispatchEvent (in sbIMediacoreEvent aEvent, [optional] PRBool aAsync); */
52 nsresult
54  PRBool aAsync,
55  PRBool* _retval)
56 {
57  nsresult rv;
58 
59  // Note: in the async case, we need to make a new runnable, because
60  // DispatchEvent has an out param, and XPCOM proxies can't deal with that.
61  if (aAsync) {
62  nsRefPtr<AsyncDispatchHelper> dispatchHelper =
63  new AsyncDispatchHelper(static_cast<sbIMediacoreEventTarget*>(mTarget), aEvent);
64  NS_ENSURE_TRUE(dispatchHelper, NS_ERROR_OUT_OF_MEMORY);
65  rv = NS_DispatchToMainThread(dispatchHelper, NS_DISPATCH_NORMAL);
66  NS_ENSURE_SUCCESS(rv, rv);
67  return NS_OK;
68  }
69  if (!NS_IsMainThread()) {
70  // we need to proxy to the main thread
71  nsCOMPtr<sbIMediacoreEventTarget> proxiedSelf;
72  { /* scope the monitor */
73  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
74  nsAutoMonitor mon(mMonitor);
75  rv = do_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
76  NS_GET_IID(sbIMediacoreEventTarget),
77  mTarget,
78  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
79  getter_AddRefs(proxiedSelf));
80  NS_ENSURE_SUCCESS(rv, rv);
81  }
82  // don't have a return value if dispatching asynchronously
83  // (since the variable is likely to be dead by that point)
84  return proxiedSelf->DispatchEvent(aEvent, PR_FALSE, _retval);
85  }
86 
87  return DispatchEventInternal(aEvent, _retval);
88 }
89 
90 /* Dispatch an event, assuming we're already on the main thread */
91 nsresult
93  PRBool* _retval)
94 {
95  DispatchState state;
96  state.length = mListeners.Count();
97 
98  nsresult rv;
99 
100  // make sure the event has not already been dispatched
101  nsCOMPtr<sbMediacoreEvent> event = do_QueryInterface(aEvent, &rv);
102  NS_ENSURE_SUCCESS(rv, rv);
103  NS_ENSURE_FALSE(event->WasDispatched(), NS_ERROR_ALREADY_INITIALIZED);
104 
105  // set the event target
106  rv = event->SetTarget(mTarget);
107  NS_ENSURE_SUCCESS(rv, rv);
108 
109  // store the state into our state stack, so if any listener removes a
110  // listener we get updated
111  mStates.Push(&state);
112 
113  // note that the return value doesn't exist if we're an async proxy
114  if (_retval)
115  *_retval = PR_FALSE;
116 
117  for (state.index = 0; state.index < state.length; ++state.index) {
118  rv = mListeners[state.index]->OnMediacoreEvent(aEvent);
119  /* the return value is only checked on debug builds */
120  #if DEBUG
121  if (NS_FAILED(rv)) {
122  NS_WARNING("Mediacore event listener returned error");
123  }
124  #endif
125  if (_retval)
126  *_retval = PR_TRUE;
127  }
128 
129  // pop the stored state, to ensure we don't end up with a pointer to a stack
130  // variable dangling
131  mStates.Pop();
132 
133  return NS_OK;
134 }
135 
136  /* void addEventListener (in sbIMediacoreEventListener aListener); */
137 nsresult
139 {
140  nsresult rv;
141 
142  // we need to access the listeners from the main thread only
143  if (!NS_IsMainThread()) {
144  // we need to proxy to the main thread
145  // because we can't just use a monitor (that'll deadlock if we're in the
146  // middle of a listener, then got proxied onto a second thread)
147  nsCOMPtr<sbIMediacoreEventTarget> proxiedSelf;
148  { /* scope the monitor */
149  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
150  nsAutoMonitor mon(mMonitor);
151  rv = do_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
152  NS_GET_IID(sbIMediacoreEventTarget),
153  mTarget,
154  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
155  getter_AddRefs(proxiedSelf));
156  NS_ENSURE_SUCCESS(rv, rv);
157  }
158 
159  // XXX Mook: consider wrapping the listener in a proxy
160 
161  return proxiedSelf->AddListener(aListener);
162  }
163 
164  PRInt32 index = mListeners.IndexOf(aListener);
165  if (index >= 0) {
166  // the listener already exists, do not re-add
167  return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
168  }
169  PRBool succeeded = mListeners.AppendObject(aListener);
170  return succeeded ? NS_OK : NS_ERROR_FAILURE;
171 }
172 
173  /* void removeEventListener (in sbIMediacoreEventListener aListener); */
174 nsresult
176 {
177  nsresult rv;
178 
179  // we need to access the listeners from the main thread only
180  if (!NS_IsMainThread()) {
181  // we need to proxy to the main thread
182  nsCOMPtr<sbIMediacoreEventTarget> proxiedSelf;
183  { /* scope the monitor */
184  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
185  nsAutoMonitor mon(mMonitor);
186  rv = do_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
187  NS_GET_IID(sbIMediacoreEventTarget),
188  mTarget,
189  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
190  getter_AddRefs(proxiedSelf));
191  NS_ENSURE_SUCCESS(rv, rv);
192  }
193  return proxiedSelf->RemoveListener(aListener);
194  }
195 
196  // XXX Mook: if we wrapped listeners, watch for equality!
197  PRInt32 indexToRemove = mListeners.IndexOf(aListener);
198  if (indexToRemove < 0) {
199  // err, no such listener
200  return NS_OK;
201  }
202 
203  // remove the listener
204  PRBool succeeded = mListeners.RemoveObjectAt(indexToRemove);
205  NS_ENSURE_TRUE(succeeded, NS_ERROR_FAILURE);
206 
207  // fix up the stack to account for the removed listener
208  // (decrease the stored length of the listener array)
209  RemovalHelper helper(indexToRemove);
210  mStates.ForEach(helper);
211 
212  return NS_OK;
213 }
214 
215 NS_IMPL_THREADSAFE_ISUPPORTS1(sbBaseMediacoreEventTarget::AsyncDispatchHelper,
216  nsIRunnable);
sbBaseMediacoreEventTarget(sbIMediacoreEventTarget *aTarget)
return NS_OK
Songbird Mediacore Event Definition.
function succeeded(ch, cx, status, data)
virtual nsresult AddListener(sbIMediacoreEventListener *aListener)
var event
nsresult do_GetProxyForObject(nsIEventTarget *aTarget, REFNSIID aIID, nsISupports *aObj, PRInt32 aProxyType, void **aProxyObject)
Definition of the sbIMediacoreEvent interface.
virtual nsresult RemoveListener(sbIMediacoreEventListener *aListener)
NS_IMPL_THREADSAFE_ISUPPORTS1(sbBaseMediacoreEventTarget::AsyncDispatchHelper, nsIRunnable)
virtual nsresult DispatchEvent(sbIMediacoreEvent *aEvent, PRBool aAsync, PRBool *aDispatched)
nsresult DispatchEventInternal(sbIMediacoreEvent *aEvent, PRBool *_retval)