sbWindowWatcher.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4  *=BEGIN SONGBIRD GPL
5  *
6  * This file is part of the Songbird web player.
7  *
8  * Copyright(c) 2005-2009 POTI, Inc.
9  * http://www.songbirdnest.com
10  *
11  * This file may be licensed under the terms of of the
12  * GNU General Public License Version 2 (the ``GPL'').
13  *
14  * Software distributed under the License is distributed
15  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
16  * express or implied. See the GPL for the specific language
17  * governing rights and limitations.
18  *
19  * You should have received a copy of the GPL along with this
20  * program. If not, go to http://www.gnu.org/licenses/gpl.html
21  * or write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  *=END SONGBIRD GPL
25  */
26 
27 //------------------------------------------------------------------------------
28 //------------------------------------------------------------------------------
29 //
30 // Songbird window watcher.
31 //
32 //------------------------------------------------------------------------------
33 //------------------------------------------------------------------------------
34 
40 //------------------------------------------------------------------------------
41 //
42 // Songbird window watcher imported services.
43 //
44 //------------------------------------------------------------------------------
45 
46 // Self imports.
47 #include "sbWindowWatcher.h"
48 
49 // Songbird imports.
50 #include <sbThreadUtils.h>
51 
52 // Mozilla imports.
53 #include <nsAutoLock.h>
54 #include <nsIDOMDocument.h>
55 #include <nsIDOMElement.h>
56 #include <nsIDOMEvent.h>
57 #include <nsIProxyObjectManager.h>
58 #include <nsMemory.h>
59 #include <nsServiceManagerUtils.h>
60 #include <prlog.h>
61 
66 #ifdef PR_LOGGING
67 static PRLogModuleInfo* gWindowWatcherLog = nsnull;
68 #define TRACE(args) PR_LOG(gWindowWatcherLog, PR_LOG_DEBUG, args)
69 #define LOG(args) PR_LOG(gWindowWatcherLog, PR_LOG_WARN, args)
70 #else
71 #define TRACE(args) /* nothing */
72 #define LOG(args) /* nothing */
73 #endif
74 
75 //------------------------------------------------------------------------------
76 //
77 // Songbird window watcher preprocessor definitions.
78 //
79 //------------------------------------------------------------------------------
80 
81 //------------------------------------------------------------------------------
82 //
83 // Songbird window watcher nsISupports implementation.
84 //
85 //------------------------------------------------------------------------------
86 
91 
92 
93 //------------------------------------------------------------------------------
94 //
95 // Songbird window watcher sbIWindowWatcher implementation.
96 //
97 //------------------------------------------------------------------------------
98 
99 
115 NS_IMETHODIMP
116 sbWindowWatcher::CallWithWindow(const nsAString& aWindowType,
117  sbICallWithWindowCallback* aCallback,
118  PRBool aWait)
119 {
120  // Validate arguments.
121  NS_ENSURE_ARG_POINTER(aCallback);
122 
123  // Function variables.
124  nsresult rv;
125 
126  // If not on main thread, call back through a proxy.
127  if (!SB_IsMainThread(mThreadManager)) {
128  // Get a main thread proxy to this instance.
129  nsCOMPtr<sbIWindowWatcher> proxyWindowWatcher;
130  rv = GetProxiedWindowWatcher(getter_AddRefs(proxyWindowWatcher));
131  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
132 
133  // Call back through the proxy. Wait for window if specified to do so.
134  rv = NS_OK;
135  while (1) {
136  // Call the proxied window watcher. Exit loop on success or if not
137  // waiting.
138  rv = proxyWindowWatcher->CallWithWindow(aWindowType, aCallback, aWait);
139  if (NS_SUCCEEDED(rv) || !aWait)
140  break;
141  if (rv != NS_ERROR_NOT_AVAILABLE)
142  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
143 
144  // Wait for a window if none available.
145  rv = WaitForWindow(aWindowType);
146  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
147  }
148  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
149 
150  return NS_OK;
151  }
152 
153  // Operate within the monitor.
154  nsAutoMonitor autoMonitor(mMonitor);
155 
156  // Check if window is already available.
157  nsCOMPtr<nsIDOMWindow> window;
158  rv = GetWindow(aWindowType, getter_AddRefs(window));
159  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
160 
161  // If a window is available or this instance is shutting down, call the
162  // callback. Otherwise, place the call with window information on the call
163  // with window list.
164  if (window || mIsShuttingDown) {
165  aCallback->HandleWindowCallback(window);
166  } else {
167  // If specified to wait and the window is not available, return a not
168  // available error indication instead of enqueuing onto the call with window
169  // list.
170  if (aWait)
171  return NS_ERROR_NOT_AVAILABLE;
172 
173  // Place the call with window information on the call with window list.
174  CallWithWindowInfo callWithWindowInfo;
175  callWithWindowInfo.windowType = aWindowType;
176  callWithWindowInfo.callback = aCallback;
177  mCallWithWindowList.AppendElement(callWithWindowInfo);
178  }
179 
180  return NS_OK;
181 }
182 
183 
196 NS_IMETHODIMP
197 sbWindowWatcher::GetWindow(const nsAString& aWindowType,
198  nsIDOMWindow** _retval)
199 {
200  // Validate arguments.
201  NS_ENSURE_ARG_POINTER(_retval);
202 
203  // Function variables.
204  nsCOMPtr<nsIDOMWindow> retWindow;
205  PRBool success;
206  nsresult rv;
207 
208  // This method may only be called on the main thread.
209  NS_ENSURE_TRUE(SB_IsMainThread(mThreadManager), NS_ERROR_UNEXPECTED);
210 
211  // Operate within the monitor.
212  nsAutoMonitor autoMonitor(mMonitor);
213 
214  // Get an enumerator of all windows of the specified type, sorted from oldest
215  // to youngest.
216  nsCOMPtr<nsISimpleEnumerator> enumerator;
217  rv = mWindowMediator->GetEnumerator(aWindowType.BeginReading(),
218  getter_AddRefs(enumerator));
219  NS_ENSURE_SUCCESS(rv, rv);
220 
221  // Search for the most recently focused ready window of the specified type.
222  // The enumerator enumerates from oldest to youngest (least recently focused
223  // to most recently), so the last matching window is the most recently focused
224  // one.
225  PRBool hasMoreElements;
226  rv = enumerator->HasMoreElements(&hasMoreElements);
227  NS_ENSURE_SUCCESS(rv, rv);
228  while (hasMoreElements) {
229  // Get the window. Skip if not ready.
230  nsCOMPtr<nsISupports> _window;
231  nsCOMPtr<nsIDOMWindow> window;
232  rv = enumerator->GetNext(getter_AddRefs(_window));
233  NS_ENSURE_SUCCESS(rv, rv);
234  window = do_QueryInterface(_window, &rv);
235  NS_ENSURE_SUCCESS(rv, rv);
236  rv = enumerator->HasMoreElements(&hasMoreElements);
237  NS_ENSURE_SUCCESS(rv, rv);
238 
239  // Skip window if not ready.
240  WindowInfo* windowInfo;
241  success = mWindowInfoTable.Get(window, &windowInfo);
242  if (!success || !(windowInfo->isReady))
243  continue;
244 
245  // Get the window type.
246  nsAutoString windowType;
247  rv = GetWindowType(window, windowType);
248  if (NS_FAILED(rv))
249  continue;
250 
251  // Check for a match.
252  if (aWindowType.Equals(windowType)) {
253  retWindow = window;
254  }
255  }
256 
257  // Return results.
258  NS_IF_ADDREF(*_retval = retWindow);
259 
260  return NS_OK;
261 }
262 
263 
272 NS_IMETHODIMP
273 sbWindowWatcher::WaitForWindow(const nsAString& aWindowType)
274 {
275  nsresult rv;
276 
277  // This method may not be called on the main thread.
278  NS_ENSURE_TRUE(!SB_IsMainThread(mThreadManager), NS_ERROR_UNEXPECTED);
279 
280  // Don't wait if this instance is shutting down.
281  {
282  // Check is shutting down within the monitor.
283  nsAutoMonitor autoMonitor(mMonitor);
284  if (mIsShuttingDown)
285  return NS_OK;
286  }
287 
288  // Create a wait for window object.
289  nsRefPtr<sbWindowWatcherWaitForWindow> waitForWindow;
290  rv = sbWindowWatcherWaitForWindow::New(getter_AddRefs(waitForWindow));
291  NS_ENSURE_SUCCESS(rv, rv);
292 
293  // Wait for the window.
294  rv = waitForWindow->Wait(aWindowType);
295  NS_ENSURE_SUCCESS(rv, rv);
296 
297  return NS_OK;
298 }
299 
300 
301 //
302 // Getters/setters.
303 //
304 
310 NS_IMETHODIMP
311 sbWindowWatcher::GetIsShuttingDown(PRBool* aIsShuttingDown)
312 {
313  // Validate arguments.
314  NS_ENSURE_ARG_POINTER(aIsShuttingDown);
315 
316  // Operate within the monitor.
317  nsAutoMonitor autoMonitor(mMonitor);
318 
319  // Return results.
320  *aIsShuttingDown = mIsShuttingDown;
321 
322  return NS_OK;
323 }
324 
325 
326 //------------------------------------------------------------------------------
327 //
328 // Songbird window watcher nsIObserver implementation.
329 //
330 //------------------------------------------------------------------------------
331 
350 NS_IMETHODIMP
351 sbWindowWatcher::Observe(nsISupports* aSubject,
352  const char* aTopic,
353  const PRUnichar* aData)
354 {
355  nsresult rv;
356 
357  TRACE(("%s: observing %s", __FUNCTION__, aTopic));
358 
359  /* Dispatch processing of event. */
360  if (!strcmp(aTopic, "domwindowopened")) {
361  rv = OnDOMWindowOpened(aSubject, aData);
362  NS_ENSURE_SUCCESS(rv, rv);
363  } else if (!strcmp(aTopic, "domwindowclosed")) {
364  rv = OnDOMWindowClosed(aSubject, aData);
365  NS_ENSURE_SUCCESS(rv, rv);
366  } else if (!strcmp(aTopic, "quit-application-granted")) {
367  rv = OnQuitApplicationGranted();
368  NS_ENSURE_SUCCESS(rv, rv);
369  }
370 
371  return NS_OK;
372 }
373 
374 
382 nsresult
383 sbWindowWatcher::OnDOMWindowOpened(nsISupports* aSubject,
384  const PRUnichar* aData)
385 {
386  // Validate arguments and state.
387  NS_ASSERTION(aSubject, "aSubject is null");
388  NS_ASSERTION(SB_IsMainThread(mThreadManager), "not on main thread");
389 
390  // Function variables.
391  nsresult rv;
392 
393  // Get the event window.
394  nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(aSubject, &rv);
395  NS_ENSURE_SUCCESS(rv, rv);
396 
397  // Add the window.
398  rv = AddWindow(window);
399  NS_ENSURE_SUCCESS(rv, rv);
400 
401  return NS_OK;
402 }
403 
404 
412 nsresult
413 sbWindowWatcher::OnDOMWindowClosed(nsISupports* aSubject,
414  const PRUnichar* aData)
415 {
416  // Validate arguments and state.
417  NS_ASSERTION(aSubject, "aSubject is null");
418  NS_ASSERTION(SB_IsMainThread(mThreadManager), "not on main thread");
419 
420  // Function variables.
421  nsresult rv;
422 
423  // Get the event window.
424  nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(aSubject, &rv);
425  NS_ENSURE_SUCCESS(rv, rv);
426 
427  // Remove the window.
428  rv = RemoveWindow(window);
429  NS_ENSURE_SUCCESS(rv, rv);
430 
431  return NS_OK;
432 }
433 
434 
439 nsresult
440 sbWindowWatcher::OnQuitApplicationGranted()
441 {
442  // Validate state.
443  NS_ASSERTION(SB_IsMainThread(mThreadManager), "not on main thread");
444 
445  // Shutdown the Songbird window watcher services.
446  Shutdown();
447 
448  return NS_OK;
449 }
450 
451 
452 //------------------------------------------------------------------------------
453 //
454 // Songbird window watcher services.
455 //
456 //------------------------------------------------------------------------------
457 
463  mSentMainWinPresentedNotification(PR_FALSE),
464  mIsShuttingDown(PR_FALSE),
465  mServicingCallWithWindowList(PR_FALSE)
466 {
467  #if PR_LOGGING
468  if (!gWindowWatcherLog)
469  gWindowWatcherLog= PR_NewLogModule("sbWindowWatcher");
470  #endif /* PR_LOGGING */
471 }
472 
473 
479 {
480  // Finalize the window watcher.
481  Finalize();
482 }
483 
484 
489 nsresult
491 {
492  nsresult rv;
493 
494  // Get the window watcher service.
495  mWindowWatcher = do_GetService("@mozilla.org/embedcomp/window-watcher;1",
496  &rv);
497  NS_ENSURE_SUCCESS(rv, rv);
498 
499  // Get the window mediator service.
500  mWindowMediator = do_GetService("@mozilla.org/appshell/window-mediator;1",
501  &rv);
502  NS_ENSURE_SUCCESS(rv, rv);
503 
504  // Get the observer service.
505  mObserverService = do_GetService("@mozilla.org/observer-service;1", &rv);
506  NS_ENSURE_SUCCESS(rv, rv);
507 
508  // Get the thread manager. This is used so that main thread checks work
509  // during XPCOM shutdown.
510  mThreadManager = do_GetService("@mozilla.org/thread-manager;1", &rv);
511  NS_ENSURE_SUCCESS(rv, rv);
512 
513  // Create a monitor.
514  mMonitor = nsAutoMonitor::NewMonitor("sbWindowWatcher::mMonitor");
515  NS_ENSURE_TRUE(mMonitor, NS_ERROR_OUT_OF_MEMORY);
516 
517  // Initialize the window information table.
518  mWindowInfoTable.Init();
519 
520  // Add a window watcher observer.
521  rv = mWindowWatcher->RegisterNotification(this);
522  NS_ENSURE_SUCCESS(rv, rv);
523 
524  // Add quit-application-granted observer.
525  rv = mObserverService->AddObserver(this,
526  "quit-application-granted",
527  PR_FALSE);
528  NS_ENSURE_SUCCESS(rv, rv);
529 
530  return NS_OK;
531 }
532 
533 
538 void
540 {
541  TRACE(("%s", __FUNCTION__));
542  // Ensure this instance is shut down.
543  Shutdown();
544 
545  // Remove all windows.
546  RemoveAllWindows();
547 
548  // Dispose of monitor.
549  if (mMonitor)
550  nsAutoMonitor::DestroyMonitor(mMonitor);
551  mMonitor = nsnull;
552 
553  // Remove object references.
554  mWindowWatcher = nsnull;
555  mWindowMediator = nsnull;
556  mWindowList.Clear();
557  mWindowInfoTable.Clear();
558  mCallWithWindowList.Clear();
559 }
560 
561 
562 //------------------------------------------------------------------------------
563 //
564 // Internal Songbird window watcher services.
565 //
566 //------------------------------------------------------------------------------
567 
575 void
576 sbWindowWatcher::Shutdown()
577 {
578  // Validate state.
579  NS_ASSERTION(SB_IsMainThread(mThreadManager), "not on main thread");
580 
581  // Operate within the monitor.
582  {
583  nsAutoMonitor autoMonitor(mMonitor);
584 
585  // Do nothing if already shutting down.
586  if (mIsShuttingDown)
587  return;
588 
589  // Indicate that this instance is shutting down.
590  mIsShuttingDown = PR_TRUE;
591  }
592 
593  // Remove quit-application-granted observer.
594  mObserverService->RemoveObserver(this, "quit-application-granted");
595 
596  // Invoke all call with window callbacks.
597  InvokeCallWithWindowCallbacks(nsnull);
598 
599  // Remove window watcher observer.
600  if (mWindowWatcher)
601  mWindowWatcher->UnregisterNotification(this);
602 }
603 
604 
611 nsresult
612 sbWindowWatcher::AddWindow(nsIDOMWindow* aWindow)
613 {
614  // Validate arguments and state.
615  NS_ASSERTION(aWindow, "aWindow is null");
616 
617  // Function variables.
618  PRBool success;
619  nsresult rv;
620 
621  // Operate within the monitor.
622  nsAutoMonitor autoMonitor(mMonitor);
623 
624  // Create the window info object.
625  nsAutoPtr<WindowInfo> windowInfo;
626  windowInfo = new WindowInfo();
627  NS_ENSURE_TRUE(windowInfo, NS_ERROR_OUT_OF_MEMORY);
628  windowInfo->window = aWindow;
629 
630  // Get the window event target.
631  nsCOMPtr<nsIDOMWindow2> window2 = do_QueryInterface(aWindow, &rv);
632  NS_ENSURE_SUCCESS(rv, rv);
633  nsCOMPtr<nsIDOMEventTarget> windowEventTarget;
634  rv = window2->GetWindowRoot(getter_AddRefs(windowEventTarget));
635  NS_ENSURE_SUCCESS(rv, rv);
636  windowInfo->eventTarget = windowEventTarget;
637 
638  // Create a window event listener.
639  nsRefPtr<sbWindowWatcherEventListener> eventListener;
640  rv = sbWindowWatcherEventListener::New(getter_AddRefs(eventListener),
641  this,
642  aWindow);
643  NS_ENSURE_SUCCESS(rv, rv);
644  windowInfo->eventListener = eventListener;
645 
646  // Add the window info to the window info table.
647  success = mWindowInfoTable.Put(aWindow, windowInfo.forget());
648  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
649 
650  // Add the opened window to the window list.
651  success = mWindowList.AppendObject(aWindow);
652  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
653 
654  // Listen for when the window has opened completely.
655  // Due to annoying platform differences, we need to figure out when the
656  // _last_ of a combination of events to occur (but the first instance of each)
657  const char* DOM_WINDOW_READY_EVENT_TYPES[] = { "resize", "sb-overlay-load" };
658 
659  for (unsigned int i = 0; i < NS_ARRAY_LENGTH(DOM_WINDOW_READY_EVENT_TYPES); ++i) {
660  rv = eventListener->AddEventListener(DOM_WINDOW_READY_EVENT_TYPES[i]);
661  NS_ENSURE_SUCCESS(rv, rv);
662  }
663 
664  return NS_OK;
665 }
666 
667 
675 nsresult
676 sbWindowWatcher::RemoveWindow(nsIDOMWindow* aWindow)
677 {
678  // Validate arguments.
679  NS_ASSERTION(aWindow, "aWindow is null");
680 
681  // Function variables.
682  PRBool success;
683  nsresult rv;
684 
685  // Operate within the monitor.
686  nsAutoMonitor autoMonitor(mMonitor);
687 
688  // Get the removed window information.
689  WindowInfo* windowInfo;
690  success = mWindowInfoTable.Get(aWindow, &windowInfo);
691  if (!success)
692  windowInfo = nsnull;
693 
694  // Remove listener for the end of window overlay load events.
695  if (windowInfo) {
696  rv = windowInfo->eventListener->ClearEventListeners();
697  NS_ENSURE_SUCCESS(rv, rv);
698  }
699 
700  // Remove the closed window from the window information map.
701  mWindowInfoTable.Remove(aWindow);
702 
703  // Remove the closed window from the window list.
704  mWindowList.RemoveObject(aWindow);
705 
706  return NS_OK;
707 }
708 
709 
716 void
717 sbWindowWatcher::RemoveAllWindows()
718 {
719  // Operate within the monitor.
720  nsAutoMonitor autoMonitor(mMonitor);
721 
722  // Remove all of the windows.
723  PRInt32 windowCount = mWindowList.Count();
724  for (PRInt32 i = windowCount - 1; i >= 0; i--) {
725  RemoveWindow(mWindowList[i]);
726  }
727 }
728 
729 
736 void
737 sbWindowWatcher::OnWindowReady(nsIDOMWindow* aWindow)
738 {
739  // Validate arguments.
740  NS_ENSURE_TRUE(aWindow, /* void */);
741 
742  // Function variables.
743  PRBool success;
744  nsresult rv;
745 
746  // If window is the main Songbird window, notify observers.
747  if (!mSentMainWinPresentedNotification) {
748  nsAutoString windowType;
749  rv = GetWindowType(aWindow, windowType);
750  NS_ENSURE_SUCCESS(rv, /* void */);
751  if (windowType.EqualsLiteral("Songbird:Main")) {
752  rv = mObserverService->NotifyObservers(aWindow,
753  "songbird-main-window-presented",
754  nsnull);
755  NS_ENSURE_SUCCESS(rv, /* void */);
756  mSentMainWinPresentedNotification = PR_TRUE;
757  }
758  }
759 
760  // Operate within the monitor.
761  {
762  nsAutoMonitor autoMonitor(mMonitor);
763 
764  // Get the window information. Do nothing if not available.
765  WindowInfo* windowInfo;
766  success = mWindowInfoTable.Get(aWindow, &windowInfo);
767  NS_ENSURE_TRUE(success, /* void */);
768 
769  // Indicate that the window is ready.
770  windowInfo->isReady = PR_TRUE;
771  }
772 
773  // Invoke call with window callbacks.
774  InvokeCallWithWindowCallbacks(aWindow);
775 }
776 
777 
785 nsresult
786 sbWindowWatcher::GetWindowType(nsIDOMWindow* aWindow,
787  nsAString& aWindowType)
788 {
789  // Validate arguments.
790  NS_ASSERTION(aWindow, "aWindow is null.");
791 
792  // Function variables.
793  nsresult rv;
794 
795  // Get the window element. The window won't neccessariy have one.
796  nsCOMPtr<nsIDOMElement> element;
797  nsCOMPtr<nsIDOMDocument> document;
798  rv = aWindow->GetDocument(getter_AddRefs(document));
799  NS_ENSURE_SUCCESS(rv, rv);
800  if (!document)
801  return NS_ERROR_NOT_AVAILABLE;
802  rv = document->GetDocumentElement(getter_AddRefs(element));
803  NS_ENSURE_SUCCESS(rv, rv);
804  if (!element)
805  return NS_ERROR_NOT_AVAILABLE;
806 
807  // Get the window type attribute.
808  rv = element->GetAttribute(NS_LITERAL_STRING("windowtype"), aWindowType);
809  NS_ENSURE_SUCCESS(rv, rv);
810 
811  return NS_OK;
812 }
813 
814 
822 nsresult
823 sbWindowWatcher::InvokeCallWithWindowCallbacks(nsIDOMWindow* aWindow)
824 {
825  // Function variables.
826  nsresult rv;
827 
828  // Get the window type.
829  nsAutoString windowType;
830  if (aWindow) {
831  rv = GetWindowType(aWindow, windowType);
832  NS_ENSURE_SUCCESS(rv, rv);
833  }
834 
835  // Operate within the monitor.
836  nsAutoMonitor autoMonitor(mMonitor);
837 
838  // Do nothing if the call with window list is already being serviced.
839  if (mServicingCallWithWindowList)
840  return NS_OK;
841 
842  // Mark that the call with window list is being serviced
843  mServicingCallWithWindowList = PR_TRUE;
844 
845  // Call all of the matching callbacks.
846  for (PRUint32 i = 0; i < mCallWithWindowList.Length();) {
847  // Get the call with window info.
848  CallWithWindowInfo& callWithWindowInfo = mCallWithWindowList[i];
849 
850  // If the info matches, call callback and remove info from list. Otherwise,
851  // advance to the next info item in list.
852  if (!aWindow || windowType.Equals(callWithWindowInfo.windowType)) {
853  callWithWindowInfo.callback->HandleWindowCallback(aWindow);
854  mCallWithWindowList.RemoveElementAt(i);
855  } else {
856  i++;
857  }
858  }
859 
860  // Mark that the call with window list is no longer being serviced
861  mServicingCallWithWindowList = PR_FALSE;
862 
863  return NS_OK;
864 }
865 
866 
873 nsresult
874 sbWindowWatcher::GetProxiedWindowWatcher(sbIWindowWatcher** aWindowWatcher)
875 {
876  // Validate arguments.
877  NS_ASSERTION(aWindowWatcher, "aWindowWatcher is null");
878 
879  // Function variables.
880  nsresult rv;
881 
882  // Create a main thread proxy for the window watcher.
883  nsCOMPtr<nsIProxyObjectManager>
884  proxyObjectManager = do_GetService("@mozilla.org/xpcomproxy;1", &rv);
885  NS_ENSURE_SUCCESS(rv, rv);
886  rv = proxyObjectManager->GetProxyForObject
887  (NS_PROXY_TO_MAIN_THREAD,
888  NS_GET_IID(sbIWindowWatcher),
889  NS_ISUPPORTS_CAST(sbIWindowWatcher *, this),
890  nsIProxyObjectManager::INVOKE_SYNC |
891  nsIProxyObjectManager::FORCE_PROXY_CREATION,
892  (void**) aWindowWatcher);
893  NS_ENSURE_SUCCESS(rv, rv);
894 
895  return NS_OK;
896 }
897 
898 
899 //------------------------------------------------------------------------------
900 //------------------------------------------------------------------------------
901 //
902 // Songbird window watcher event listener class.
903 //
904 //------------------------------------------------------------------------------
905 //------------------------------------------------------------------------------
906 
907 //------------------------------------------------------------------------------
908 //
909 // Songbird window watcher event listener nsISupports implementation.
910 //
911 //------------------------------------------------------------------------------
912 
915 
916 
917 //------------------------------------------------------------------------------
918 //
919 // Songbird window watcher event listener nsIDOMEventListener implementation.
920 //
921 //------------------------------------------------------------------------------
922 
923 
933 NS_IMETHODIMP
935 {
936  // Validate arguments.
937  NS_ENSURE_ARG_POINTER(event);
938 
939  #if PR_LOGGING
940  {
941  nsString type;
942  nsresult rv = event->GetType(type);
943  if (NS_SUCCEEDED(rv)) {
944  TRACE(("%s: got event %s",
945  __FUNCTION__,
946  NS_ConvertUTF16toUTF8(type).get()));
947  }
948  }
949  #endif
950 
951  // Function variables.
952  nsresult rv;
953 
954  // Ensure the window watcher still exists.
955  nsCOMPtr<sbIWindowWatcher>
956  windowWatcher = do_QueryReferent(mWeakSBWindowWatcher, &rv);
957  NS_ENSURE_SUCCESS(rv, rv);
958 
959  // Get the event type.
960  nsAutoString eventType;
961  rv = event->GetType(eventType);
962  NS_ENSURE_SUCCESS(rv, rv);
963 
964  // Dispatch processing of event.
965  if (mOutstandingEvents.Contains(eventType)) {
966  nsCOMPtr<nsIDOMEventTarget> target;
967  rv = event->GetCurrentTarget(getter_AddRefs(target));
968  NS_ENSURE_SUCCESS(rv, rv);
969  rv = target->RemoveEventListener(eventType, this, PR_TRUE);
970  NS_ENSURE_SUCCESS(rv, rv);
971  mOutstandingEvents.RemoveElement(eventType);
972  TRACE(("%s: removed event %s listener %p from %p",
973  __FUNCTION__,
974  NS_ConvertUTF16toUTF8(eventType).get(),
975  this,
976  target.get()));
977  if (mOutstandingEvents.IsEmpty()) {
978  mSBWindowWatcher->OnWindowReady(mWindow);
979  }
980  }
981 
982  return NS_OK;
983 }
984 
985 
986 //------------------------------------------------------------------------------
987 //
988 // Songbird window watcher event listener implementation.
989 //
990 //------------------------------------------------------------------------------
991 
1003 /* static */
1004 nsresult
1007  sbWindowWatcher* aSBWindowWatcher,
1008  nsIDOMWindow* aWindow)
1009 {
1010  // Validate arguments.
1011  NS_ENSURE_ARG_POINTER(aListener);
1012 
1013  // Function variables.
1014  nsresult rv;
1015 
1016  // Create the listener object.
1017  nsRefPtr<sbWindowWatcherEventListener> listener;
1018  listener = new sbWindowWatcherEventListener(aSBWindowWatcher, aWindow);
1019  NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
1020 
1021  // Initialize the listener object.
1022  rv = listener->Initialize();
1023  NS_ENSURE_SUCCESS(rv, rv);
1024 
1025  // Return results.
1026  return CallQueryInterface(listener.get(), aListener);
1027 }
1028 
1029 
1030 //------------------------------------------------------------------------------
1031 //
1032 // Internal Songbird window watcher event listener implementation.
1033 //
1034 //------------------------------------------------------------------------------
1035 
1040 nsresult
1041 sbWindowWatcherEventListener::Initialize()
1042 {
1043  nsresult rv;
1044 
1045  // Get a weak reference to the window watcher object.
1046  nsCOMPtr<nsISupportsWeakReference>
1047  weakSBWindowWatcher =
1048  do_QueryInterface(NS_ISUPPORTS_CAST(sbIWindowWatcher*, mSBWindowWatcher),
1049  &rv);
1050  NS_ENSURE_SUCCESS(rv, rv);
1051  rv = weakSBWindowWatcher->GetWeakReference
1052  (getter_AddRefs(mWeakSBWindowWatcher));
1053  NS_ENSURE_SUCCESS(rv, rv);
1054 
1055  // Get the window event target.
1056  nsCOMPtr<nsIDOMWindow2> window2 = do_QueryInterface(mWindow, &rv);
1057  NS_ENSURE_SUCCESS(rv, rv);
1058  rv = window2->GetWindowRoot(getter_AddRefs(mEventTarget));
1059  NS_ENSURE_SUCCESS(rv, rv);
1060 
1061  return NS_OK;
1062 }
1063 
1064 
1069 nsresult
1071 {
1072  nsresult rv;
1073 
1074  NS_ENSURE_TRUE(mEventTarget, NS_ERROR_NOT_INITIALIZED);
1075 
1076  NS_ConvertASCIItoUTF16 eventName(aEventName);
1077 
1078  if (mOutstandingEvents.Contains(eventName)) {
1079  return NS_OK;
1080  }
1081 
1082  rv = mEventTarget->AddEventListener(eventName, this, PR_TRUE);
1083  NS_ENSURE_SUCCESS(rv, rv);
1084 
1085  mOutstandingEvents.AppendElement(eventName);
1086  TRACE(("%s: Added event %s listener %p to %p",
1087  __FUNCTION__,
1088  aEventName,
1089  this,
1090  mEventTarget.get()));
1091 
1092  return NS_OK;
1093 }
1094 
1099 nsresult
1101 {
1102  nsresult rv;
1103 
1104  TRACE(("%s: clearing %p from %p",
1105  __FUNCTION__,
1106  this,
1107  mEventTarget.get()));
1108 
1109  NS_ENSURE_TRUE(mEventTarget, NS_ERROR_NOT_INITIALIZED);
1110 
1111  for (PRUint32 i = mOutstandingEvents.Length() - 1; i != PRUint32(-1); --i) {
1112  TRACE(("%s: Removing event %s listener %p from %p",
1113  __FUNCTION__,
1114  NS_ConvertUTF16toUTF8(mOutstandingEvents[i]).get(),
1115  this,
1116  mEventTarget.get()));
1117  rv = mEventTarget->RemoveEventListener(mOutstandingEvents[i],
1118  this,
1119  PR_TRUE);
1120  NS_ENSURE_SUCCESS(rv, rv);
1121  mOutstandingEvents.RemoveElementAt(i);
1122  }
1123  NS_ASSERTION(mOutstandingEvents.IsEmpty(),
1124  "unexpected outstanding listeners!");
1125  return NS_OK;
1126 }
1127 
1128 //------------------------------------------------------------------------------
1129 //------------------------------------------------------------------------------
1130 //
1131 // Songbird window watcher wait for window class.
1132 //
1133 //------------------------------------------------------------------------------
1134 //------------------------------------------------------------------------------
1135 
1136 //------------------------------------------------------------------------------
1137 //
1138 // Songbird window watcher wait for window nsISupports implementation.
1139 //
1140 //------------------------------------------------------------------------------
1141 
1144 
1145 
1146 //------------------------------------------------------------------------------
1147 //
1148 // Songbird window watcher wait for window sbICallWithWindowCallback
1149 // implementation.
1150 //
1151 //------------------------------------------------------------------------------
1152 
1153 
1159 NS_IMETHODIMP
1160 sbWindowWatcherWaitForWindow::HandleWindowCallback(nsIDOMWindow* aWindow)
1161 {
1162  // Operate under the ready monitor.
1163  nsAutoMonitor autoReadyMonitor(mReadyMonitor);
1164 
1165  // Get the ready window.
1166  mWindow = aWindow;
1167  mReady = PR_TRUE;
1168 
1169  // Send notification that the window is ready.
1170  autoReadyMonitor.Notify();
1171 
1172  return NS_OK;
1173 }
1174 
1175 
1176 //------------------------------------------------------------------------------
1177 //
1178 // Songbird window watcher wait for window implementation.
1179 //
1180 //------------------------------------------------------------------------------
1181 
1189 /* static */
1190 nsresult
1192 {
1193  // Validate arguments.
1194  NS_ENSURE_ARG_POINTER(aWaitForWindow);
1195 
1196  // Function variables.
1197  nsresult rv;
1198 
1199  // Create the wait for window object.
1200  nsRefPtr<sbWindowWatcherWaitForWindow> waitForWindow;
1201  waitForWindow = new sbWindowWatcherWaitForWindow();
1202  NS_ENSURE_TRUE(waitForWindow, NS_ERROR_OUT_OF_MEMORY);
1203 
1204  // Initialize the wait for window object.
1205  rv = waitForWindow->Initialize();
1206  NS_ENSURE_SUCCESS(rv, rv);
1207 
1208  // Return results.
1209  NS_ADDREF(*aWaitForWindow = waitForWindow);
1210 
1211  return NS_OK;
1212 }
1213 
1214 
1220 {
1221  // Dispose of the monitor.
1222  if (mReadyMonitor)
1223  nsAutoMonitor::DestroyMonitor(mReadyMonitor);
1224  mReadyMonitor = nsnull;
1225 
1226  // Remove object references.
1227  mSBWindowWatcher = nsnull;
1228  mWindow = nsnull;
1229 }
1230 
1231 
1239 nsresult
1240 sbWindowWatcherWaitForWindow::Wait(const nsAString& aWindowType)
1241 {
1242  nsresult rv;
1243 
1244  // Set up to call this instance with a matching window.
1245  rv = mSBWindowWatcher->CallWithWindow(aWindowType, this, false);
1246  NS_ENSURE_SUCCESS(rv, rv);
1247 
1248  // Operate under the ready monitor.
1249  nsAutoMonitor autoReadyMonitor(mReadyMonitor);
1250 
1251  // Wait for a window to be ready.
1252  if (!mReady) {
1253  rv = autoReadyMonitor.Wait();
1254  NS_ENSURE_SUCCESS(rv, rv);
1255  }
1256 
1257  return NS_OK;
1258 }
1259 
1260 
1261 //------------------------------------------------------------------------------
1262 //
1263 // Internal Songbird window watcher wait for window implementation.
1264 //
1265 //------------------------------------------------------------------------------
1266 
1271 sbWindowWatcherWaitForWindow::sbWindowWatcherWaitForWindow() :
1272  mReadyMonitor(nsnull),
1273  mReady(PR_FALSE)
1274 {
1275 }
1276 
1277 
1282 nsresult
1283 sbWindowWatcherWaitForWindow::Initialize()
1284 {
1285  nsresult rv;
1286 
1287  // Get the Songbird window watcher service.
1288  mSBWindowWatcher =
1289  do_GetService("@songbirdnest.com/Songbird/window-watcher;1", &rv);
1290  NS_ENSURE_SUCCESS(rv, rv);
1291 
1292  // Create a monitor.
1293  mReadyMonitor =
1294  nsAutoMonitor::NewMonitor("sbWindowWatcherWaitForWindow::mReadyMonitor");
1295  NS_ENSURE_TRUE(mReadyMonitor, NS_ERROR_OUT_OF_MEMORY);
1296 
1297  return NS_OK;
1298 }
1299 
A callback interface that is called with a window.
return NS_OK
void waitForWindow(in AString aWindowType)
Wait until a window of the type specified by aWindowType is available or until shutdown. This method may not be called on the main thread. Since the available window can only be used on the main thread, the available window may become unavailable after waitForWindow returns but before processing continues on the main thread.
NS_IMPL_THREADSAFE_ISUPPORTS3(sbWindowWatcher, sbIWindowWatcher, nsIObserver, nsISupportsWeakReference) NS_IMETHODIMP sbWindowWatcher
Call callback specified by aCallback with a window of the type specified by aWindowType. Wait until a window of the specified type is available or until shutdown. Call callback with null window on shutdown. Call callback on main thread. If aWait is true, don't return until callback is called.
Songbird Window Watcher Definitions.
var event
let window
const nsIDOMWindow
nsresult AddEventListener(const char *aEventName)
NS_DECL_ISUPPORTS static NS_DECL_SBICALLWITHWINDOWCALLBACK nsresult New(sbWindowWatcherWaitForWindow **aWaitForWindow)
this _window
Definition: FeedWriter.js:1158
PRBool SB_IsMainThread(nsIThreadManager *aThreadManager)
#define TRACE(args)
Songbird Thread Utilities Definitions.
nsresult Wait(const nsAString &aWindowType)
Wait until a window of the type specified by aWindowType is available or until shutdown.
NS_DECL_ISUPPORTS NS_DECL_SBIWINDOWWATCHER NS_DECL_NSIOBSERVER sbWindowWatcher()
virtual ~sbWindowWatcher()
NS_DECL_ISUPPORTS static NS_DECL_NSIDOMEVENTLISTENER nsresult New(sbWindowWatcherEventListener **aListener, sbWindowWatcher *aSBWindowWatcher, nsIDOMWindow *aWindow)
SimpleArrayEnumerator prototype hasMoreElements
NS_IMPL_THREADSAFE_ISUPPORTS1(sbWindowWatcherEventListener, nsIDOMEventListener) NS_IMETHODIMP sbWindowWatcherEventListener
_getSelectedPageStyle s i
nsIDOMEventListener
_updateTextAndScrollDataForFrame aData