зеркало из https://github.com/mozilla/gecko-dev.git
188 строки
5.5 KiB
C++
188 строки
5.5 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:set ts=2 sts=2 sw=2 et cin: */
|
|
/* 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 "ToastNotification.h"
|
|
|
|
#include "mozilla/WindowsVersion.h"
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIObserverService.h"
|
|
#include "nsString.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "ToastNotificationHandler.h"
|
|
#include "WinTaskbar.h"
|
|
|
|
namespace mozilla {
|
|
namespace widget {
|
|
|
|
NS_IMPL_ISUPPORTS(ToastNotification, nsIAlertsService, nsIObserver,
|
|
nsISupportsWeakReference)
|
|
|
|
ToastNotification::ToastNotification() = default;
|
|
|
|
ToastNotification::~ToastNotification() = default;
|
|
|
|
nsresult ToastNotification::Init() {
|
|
if (!IsWin8OrLater()) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
nsAutoString uid;
|
|
if (NS_WARN_IF(!WinTaskbar::GetAppUserModelID(uid))) {
|
|
// Windows Toast Notification requires AppId
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
nsresult rv =
|
|
NS_NewNamedThread("ToastBgThread", getter_AddRefs(mBackgroundThread));
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIObserverService> obsServ =
|
|
do_GetService("@mozilla.org/observer-service;1");
|
|
if (obsServ) {
|
|
obsServ->AddObserver(this, "quit-application", true);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult ToastNotification::BackgroundDispatch(nsIRunnable* runnable) {
|
|
return mBackgroundThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ToastNotification::Observe(nsISupports* aSubject, const char* aTopic,
|
|
const char16_t* aData) {
|
|
// Got quit-application
|
|
// The handlers destructors will do the right thing (de-register with
|
|
// Windows).
|
|
mActiveHandlers.Clear();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ToastNotification::ShowAlertNotification(
|
|
const nsAString& aImageUrl, const nsAString& aAlertTitle,
|
|
const nsAString& aAlertText, bool aAlertTextClickable,
|
|
const nsAString& aAlertCookie, nsIObserver* aAlertListener,
|
|
const nsAString& aAlertName, const nsAString& aBidi, const nsAString& aLang,
|
|
const nsAString& aData, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
|
|
bool aRequireInteraction) {
|
|
nsCOMPtr<nsIAlertNotification> alert =
|
|
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
|
if (NS_WARN_IF(!alert)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nsresult rv =
|
|
alert->Init(aAlertName, aImageUrl, aAlertTitle, aAlertText,
|
|
aAlertTextClickable, aAlertCookie, aBidi, aLang, aData,
|
|
aPrincipal, aInPrivateBrowsing, aRequireInteraction);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
return ShowAlert(alert, aAlertListener);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ToastNotification::ShowPersistentNotification(const nsAString& aPersistentData,
|
|
nsIAlertNotification* aAlert,
|
|
nsIObserver* aAlertListener) {
|
|
return ShowAlert(aAlert, aAlertListener);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ToastNotification::ShowAlert(nsIAlertNotification* aAlert,
|
|
nsIObserver* aAlertListener) {
|
|
if (NS_WARN_IF(!aAlert)) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
nsAutoString cookie;
|
|
nsresult rv = aAlert->GetCookie(cookie);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
nsAutoString name;
|
|
rv = aAlert->GetName(name);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
nsAutoString title;
|
|
rv = aAlert->GetTitle(title);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
nsAutoString text;
|
|
rv = aAlert->GetText(text);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
bool textClickable;
|
|
rv = aAlert->GetTextClickable(&textClickable);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
nsAutoString hostPort;
|
|
rv = aAlert->GetSource(hostPort);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
RefPtr<ToastNotificationHandler> handler = new ToastNotificationHandler(
|
|
this, aAlertListener, name, cookie, title, text, hostPort, textClickable);
|
|
mActiveHandlers.Put(name, handler);
|
|
|
|
rv = handler->InitAlertAsync(aAlert);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
mActiveHandlers.Remove(name);
|
|
return rv;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ToastNotification::CloseAlert(const nsAString& aAlertName,
|
|
nsIPrincipal* aPrincipal) {
|
|
RefPtr<ToastNotificationHandler> handler;
|
|
if (NS_WARN_IF(!mActiveHandlers.Get(aAlertName, getter_AddRefs(handler)))) {
|
|
return NS_OK;
|
|
}
|
|
mActiveHandlers.Remove(aAlertName);
|
|
return NS_OK;
|
|
}
|
|
|
|
bool ToastNotification::IsActiveHandler(const nsAString& aAlertName,
|
|
ToastNotificationHandler* aHandler) {
|
|
RefPtr<ToastNotificationHandler> handler;
|
|
if (NS_WARN_IF(!mActiveHandlers.Get(aAlertName, getter_AddRefs(handler)))) {
|
|
return false;
|
|
}
|
|
return handler == aHandler;
|
|
}
|
|
|
|
void ToastNotification::RemoveHandler(const nsAString& aAlertName,
|
|
ToastNotificationHandler* aHandler) {
|
|
// The alert may have been replaced; only remove it from the active
|
|
// handlers map if it's the same.
|
|
if (IsActiveHandler(aAlertName, aHandler)) {
|
|
// Terrible things happen if the destructor of a handler is called inside
|
|
// the hashtable .Remove() method. Wait until we have returned from there.
|
|
RefPtr<ToastNotificationHandler> kungFuDeathGrip(aHandler);
|
|
mActiveHandlers.Remove(aAlertName);
|
|
}
|
|
}
|
|
|
|
} // namespace widget
|
|
} // namespace mozilla
|