NotificationChild.cpp (4302B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "NotificationChild.h" 8 9 #include "WindowGlobalChild.h" 10 #include "mozilla/dom/Event.h" 11 #include "mozilla/dom/Notification.h" 12 #include "mozilla/dom/WorkerRunnable.h" 13 #include "nsFocusManager.h" 14 #include "nsGlobalWindowInner.h" 15 16 namespace mozilla::dom::notification { 17 18 using IPCResult = mozilla::ipc::IPCResult; 19 20 NS_IMPL_ISUPPORTS(NotificationChild, nsISupports); 21 22 NotificationChild::NotificationChild(Notification* aNonPersistentNotification, 23 WindowGlobalChild* aWindow) 24 : mNonPersistentNotification(aNonPersistentNotification), mWindow(aWindow) { 25 if (mWindow) { 26 BindToOwner(mWindow->GetWindowGlobal()->AsGlobal()); 27 return; 28 } 29 } 30 31 class FocusWindowRunnable : public WorkerMainThreadRunnable { 32 public: 33 explicit FocusWindowRunnable(WorkerPrivate* aWorkerPrivate) 34 : WorkerMainThreadRunnable(aWorkerPrivate, 35 "Notification :: FocusWindowRunnable"_ns) {} 36 37 protected: 38 // Runnables don't support MOZ_CAN_RUN_SCRIPT, bug 1535398 39 MOZ_CAN_RUN_SCRIPT_BOUNDARY bool MainThreadRun() override { 40 RefPtr<nsPIDOMWindowInner> inner = mWorkerRef->Private()->GetWindow(); 41 if (inner->IsCurrentInnerWindow()) { 42 nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow(); 43 nsFocusManager::FocusWindow(outer, CallerType::System); 44 } 45 return true; 46 } 47 }; 48 49 // Step 2 of https://notifications.spec.whatwg.org/#activating-a-notification 50 // MOZ_CAN_RUN_SCRIPT_BOUNDARY because of DispatchEvent (boundary for now, bug 51 // 1748910) and FocusWindow. 52 // Bug 1539864 for IPDL not able to handle MOZ_CAN_RUN_SCRIPT. 53 // 54 // Note that FrozenCallback below makes sure we don't do anything here on 55 // bfcached page. 56 MOZ_CAN_RUN_SCRIPT_BOUNDARY IPCResult NotificationChild::RecvNotifyClick() { 57 // Step 2.1: Let intoFocus be the result of firing an event named click on the 58 // Notification object representing notification, with its cancelable 59 // attribute initialized to true. 60 bool intoFocus = true; 61 if (mNonPersistentNotification) { 62 RefPtr<Event> event = 63 NS_NewDOMEvent(mNonPersistentNotification, nullptr, nullptr); 64 event->InitEvent(u"click"_ns, /* canBubble */ false, /* cancelable */ true); 65 event->SetTrusted(true); 66 WantsPopupControlCheck popupControlCheck(event); 67 intoFocus = mNonPersistentNotification->DispatchEvent( 68 *event, CallerType::System, IgnoreErrors()); 69 } 70 71 if (!intoFocus) { 72 return IPC_OK(); 73 } 74 75 // Step 2.2: If intoFocus is true, then the user agent should bring the 76 // notification’s related browsing context’s viewport into focus. 77 if (mWindow) { 78 if (RefPtr<nsGlobalWindowInner> inner = mWindow->GetWindowGlobal()) { 79 if (inner->IsCurrentInnerWindow()) { 80 nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow(); 81 nsFocusManager::FocusWindow(outer, CallerType::System); 82 } 83 } 84 } else if (WorkerPrivate* wp = GetCurrentThreadWorkerPrivate()) { 85 if (!wp->IsDedicatedWorker()) { 86 // Only dedicated worker has a window to focus. 87 return IPC_OK(); 88 } 89 90 RefPtr<FocusWindowRunnable> runnable = 91 new FocusWindowRunnable(wp->GetTopLevelWorker()); 92 runnable->Dispatch(wp, Canceling, IgnoreErrors()); 93 } 94 return IPC_OK(); 95 } 96 97 void NotificationChild::ActorDestroy(ActorDestroyReason aWhy) { 98 if (RefPtr<Notification> notification = mNonPersistentNotification.get()) { 99 // We are being closed because the parent actor is gone, and that means the 100 // notification is closed 101 notification->MaybeNotifyClose(); 102 } 103 } 104 105 void NotificationChild::FrozenCallback(nsIGlobalObject* aOwner) { 106 // Make sure the closure below won't dispatch close event and still allow 107 // explicit close() call. 108 mNonPersistentNotification = nullptr; 109 // Closing on FrozenCallback makes sure that clicking the notification opens a 110 // new tab instead of pinging an inactive tab 111 Close(); 112 DisconnectFreezeObserver(); 113 } 114 115 } // namespace mozilla::dom::notification