ChromeObserver.cpp (4424B)
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 5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 6 7 #include "ChromeObserver.h" 8 9 #include "mozilla/dom/Document.h" 10 #include "mozilla/dom/DocumentInlines.h" 11 #include "mozilla/dom/Element.h" 12 #include "nsContentUtils.h" 13 #include "nsIBaseWindow.h" 14 #include "nsIFrame.h" 15 #include "nsIMutationObserver.h" 16 #include "nsIWidget.h" 17 #include "nsPresContext.h" 18 #include "nsXULElement.h" 19 20 namespace mozilla::dom { 21 22 NS_IMPL_ISUPPORTS(ChromeObserver, nsIMutationObserver) 23 24 ChromeObserver::ChromeObserver(Document* aDocument) 25 : nsStubMutationObserver(), mDocument(aDocument) {} 26 27 ChromeObserver::~ChromeObserver() = default; 28 29 void ChromeObserver::Init() { 30 mDocument->AddMutationObserver(this); 31 Element* rootElement = mDocument->GetRootElement(); 32 if (!rootElement) { 33 return; 34 } 35 nsAutoScriptBlocker scriptBlocker; 36 uint32_t attributeCount = rootElement->GetAttrCount(); 37 for (uint32_t i = 0; i < attributeCount; i++) { 38 BorrowedAttrInfo info = rootElement->GetAttrInfoAt(i); 39 const nsAttrName* name = info.mName; 40 if (name->LocalName() == nsGkAtoms::customtitlebar) { 41 // Some linux windows managers have an issue when the customtitlebar is 42 // applied while the browser is loading (bug 1598848). For now, skip 43 // applying this attribute when initializing. 44 continue; 45 } 46 AttributeChanged(rootElement, name->NamespaceID(), name->LocalName(), 47 AttrModType::Addition, nullptr); 48 } 49 } 50 51 nsIWidget* ChromeObserver::GetWindowWidget() { 52 // only top level chrome documents can set the titlebar color 53 if (mDocument && mDocument->IsRootDisplayDocument()) { 54 nsCOMPtr<nsISupports> container = mDocument->GetContainer(); 55 if (nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container)) { 56 nsCOMPtr<nsIWidget> mainWidget = baseWindow->GetMainWidget(); 57 return mainWidget; 58 } 59 } 60 return nullptr; 61 } 62 63 void ChromeObserver::SetHideTitlebarSeparator(bool aState) { 64 nsIWidget* mainWidget = GetWindowWidget(); 65 if (mainWidget) { 66 // We can do this synchronously because SetHideTitlebarSeparator doesn't 67 // have any synchronous effects apart from a harmless invalidation. 68 mainWidget->SetHideTitlebarSeparator(aState); 69 } 70 } 71 72 void ChromeObserver::AttributeChanged(dom::Element* aElement, 73 int32_t aNamespaceID, nsAtom* aName, 74 AttrModType aModType, 75 const nsAttrValue* aOldValue) { 76 // We only care about changes to the root element. 77 if (!mDocument || aElement != mDocument->GetRootElement()) { 78 return; 79 } 80 81 if (IsAdditionOrRemoval(aModType)) { 82 const bool added = aModType == AttrModType::Addition; 83 if (aName == nsGkAtoms::hidechrome) { 84 HideWindowChrome(added); 85 } else if (aName == nsGkAtoms::customtitlebar) { 86 SetCustomTitlebar(added); 87 } else if (aName == nsGkAtoms::hidetitlebarseparator) { 88 SetHideTitlebarSeparator(added); 89 } else if (aName == nsGkAtoms::windowsmica) { 90 SetMica(added); 91 } 92 } 93 if (aName == nsGkAtoms::localedir) { 94 // if the localedir changed on the root element, reset the document 95 // direction 96 mDocument->ResetDocumentDirection(); 97 } 98 if (aName == nsGkAtoms::title && aModType != AttrModType::Removal) { 99 mDocument->NotifyPossibleTitleChange(false); 100 } 101 } 102 103 void ChromeObserver::NodeWillBeDestroyed(nsINode* aNode) { 104 mDocument = nullptr; 105 } 106 107 void ChromeObserver::SetMica(bool aEnable) { 108 if (nsIWidget* mainWidget = GetWindowWidget()) { 109 mainWidget->SetMicaBackdrop(aEnable); 110 } 111 } 112 113 void ChromeObserver::SetCustomTitlebar(bool aCustomTitlebar) { 114 if (nsIWidget* mainWidget = GetWindowWidget()) { 115 // SetCustomTitlebar can dispatch native events, hence doing it off a 116 // script runner 117 nsContentUtils::AddScriptRunner(NewRunnableMethod<bool>( 118 "SetCustomTitlebar", mainWidget, &nsIWidget::SetCustomTitlebar, 119 aCustomTitlebar)); 120 } 121 } 122 123 void ChromeObserver::HideWindowChrome(bool aShouldHide) { 124 if (nsCOMPtr<nsIWidget> mainWidget = GetWindowWidget()) { 125 mainWidget->HideWindowChrome(aShouldHide); 126 } 127 } 128 129 } // namespace mozilla::dom