gecko-dev/widget/windows/ToastNotification.cpp

210 строки
6.0 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